



		    add_scu.pl1                     11/11/89  1135.2r w 11/11/89  0800.9       59625



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) Honeywell Bull Inc., 1987                *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1982 *
        *                                                         *
        *********************************************************** */
/* ADD_SCU - Reconfiguration Procedure to Add and Remove a System Controller. */
/* adapted from code originally written by Roger R. Schell in July, 1970 */
/* Modified 3/9/76 by Noel I. Morris */
/* Modified 5/79 by BSG for 8cpu port expander */
/* Modified September 1981 by J. Bongiovanni for set_procs_required */
/* Modified June 1982 by J. A. Bush to clear cache in each cpu before Mem is added */
/* Modified April 1984 by Chris Jones to update config deck to its partition after modifying it. */

/* format: style4,delnl,insnl,indattr,ifthen,dclind10 */
add_scu:
     proc (tag, errtag, rcode);

dcl	tag		   fixed bin (3),		/* tag of controller to be added */
	errtag		   fixed bin (3),		/* tag of CPU or mask in error */
	rcode		   fixed bin (35);		/* error code */

dcl	cdp		   ptr,			/* pointer to single element of controller data */
	i		   fixed bin (3),		/* iteration variable */
	enabled		   bit (1) aligned,		/* port enabled bit */
	base		   fixed bin (17),		/* base address of controller */
	size		   fixed bin (17),		/* size of controller */
	interlace		   fixed bin (3),		/* memory interlace type */
	code		   fixed bin (35),		/* error code */
	cpu_mask		   bit (8) aligned;		/* bit mask for CPUs required */


dcl	init_scu		   entry (fixed bin (3), fixed bin (3), fixed bin (35)),
	init_scu$final_scu	   entry (fixed bin (3)),
	privileged_mode_ut$clear_cache
			   entry,
	scr_util$set_mask	   entry (fixed bin (3), fixed bin (3), bit (72) aligned),
	scr_util$enable_ports  entry (fixed bin (3)),
	scr_util$disable_ports entry (fixed bin (3)),
	rsw_util$port_info	   entry (fixed bin (3), bit (1) aligned, fixed bin (17), fixed bin (17), fixed bin (3)),
	rsw_util$set_rsw_mask  entry (fixed bin (3), bit (1) aligned),
	set_procs_required	   entry (bit (8) aligned, fixed bin (35)),
	config_$find_2	   entry (char (4) aligned, fixed bin (3), ptr),
	config_$update	   entry (),
	syserr		   entry options (variable);

dcl	store		   condition,		/* store fault */
	op_not_complete	   condition;		/* op not complete fault */

dcl	1 cdata		   based (cdp) aligned like scs$controller_data;
						/* single element of controller_data */

dcl	(addr, hbound, lbound, substr)
			   builtin;

/* The following code adds a system controller. */

	rcode = 0;
	cdp = addr (scs$controller_data (tag));		/* Get pointer to data for this controller. */

	on condition (store) go to add_fault;		/* Catch store fault if ports not enabled. */
	on condition (op_not_complete) go to add_fault;	/* Catch op not complete if controller not enabled. */

	do i = lbound (scs$processor_data, 1) to hbound (scs$processor_data, 1);/* Run each and every processor. */
	     if scs$processor_data (i).online then do;	/* If processor online ... */
		cpu_mask = "0"b;
		substr (cpu_mask, i + 1, 1) = "1"b;
		call set_procs_required (cpu_mask, code);
						/* Run that processor. */
		if code ^= 0 then do;
		     rcode = rcerr_sprq_failed;	/* Shouldn't */
		     goto add_err;
		end;

		call rsw_util$port_info (tag, enabled, base, size, interlace);
						/* Get poop on controller. */
		if ^enabled then do;		/* If port not enabled ... */
		     rcode = rcerr_addscu_enable;
		     go to add_err;
		end;
		if (base ^= cdata.base) |		/* If some switches are incorrrect ... */
		     (size ^= cdata.size) | ((interlace ^= 0) ^= cdata.ext_interlaced)
		     | ((interlace ^= 0) & ((interlace = 4) ^= cdata.four_word)) then do;
		     rcode = rcerr_addscu_switches;
		     go to add_err;
		end;

		call init_scu (tag, errtag, rcode);	/* Try to get info about the controller. */
		call privileged_mode_ut$clear_cache;	/* clear out this cpus cache, before mem is added */

		call set_procs_required ("0"b, code);	/* Give up this processor. */

		if rcode ^= 0 then
		     return;			/* If failure, give up now. */
	     end;
	end;

	do i = 1 to 4;				/* Look at each assigned interrupt mask. */
	     if cdata.eima_data (i).mask_assigned then	/* If mask is assigned ... */
		call scr_util$set_mask (tag, (cdata.eima_data (i).mask_assignment), scs$sys_level);
	end;					/* Don't allow any interrupts. */

	call scr_util$enable_ports (tag);		/* Set correct ports to be enabled. */

	cdata.online = "1"b;			/* reflect change in SCS */
	cdata.offline = "0"b;

	call config_$find_2 (MEM_CARD_WORD, tag + 1, mem_cardp);
						/* Find the correct MEM config card. */
	mem_card.state = "on  ";			/* Change the config card. */

	call rsw_util$set_rsw_mask (tag, "1"b);		/* All new processors must have this port enabled. */

	call config_$update ();
	call syserr (ANNOUNCE, "addmem: Added MEM ^a.", substr ("ABCDEFGH", tag + 1, 1));

	return;


add_fault:
	call init_scu$final_scu (tag);		/* Clear out SCAS entry for controller. */
	rcode = rcerr_addscu_fault;			/* Give back an error. */

add_err:
	call set_procs_required ("0"b, code);		/* Unset any required processor. */

	errtag = i;				/* Identify active module in error. */

	return;


/* The following code removes a system controller. */

remove_scu:
     entry (tag);


	cdp = addr (scs$controller_data (tag));		/* Get pointer to data for this controller. */

	call scr_util$disable_ports (tag);		/* Disable all ports on controller. */

	call init_scu$final_scu (tag);		/* Remove entry from the SCAS. */

	cdata.offline = "1"b;			/* reflect change in SCS */
	cdata.online = "0"b;

	call config_$find_2 (MEM_CARD_WORD, tag + 1, mem_cardp);
						/* Find correct MEM config card. */
	mem_card.state = "off ";			/* Change the config card. */

	call rsw_util$set_rsw_mask (tag, "0"b);		/* New processors do not need this port enabled. */

	call config_$update ();
	call syserr (ANNOUNCE, "delmem: Removed MEM ^a.", substr ("ABCDEFGH", tag + 1, 1));

	return;

%include rcerr;
%page;
%include config_mem_card;
%page;
%include scs;
%page;
%include syserr_constants;

/* BEGIN MESSAGE DOCUMENTATION

   Message:
   addmem: Added MEM X.

   S:	$info

   T:	$response

   M:	The system control unit X has been added.

   A:	$ignore


   Message:
   delmem: Removed MEM X.

   S:	$info

   T:	$response

   M:	The system control unit X has been deleted.

   A:	$ignore



   END MESSAGE DOCUMENTATION */

     end add_scu;
   



		    configure_test_cpu.pl1          11/11/89  1135.2r w 11/11/89  0800.0      266211



/****^  ***********************************************************
        *                                                         *
        * 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.      *
        *                                                         *
        *********************************************************** */


/* configure_test_cpu - procedure to do the physical work of CPU reconfiguration for ISOLTS. A primitive CPU
   confidence test of the CPU is also accomplished to assure that the storage system will not be
   compromised by user ring testing with ISOLTS

   Initial coding by J. A. Bush - 10/78
   Modified 9/16/80 by J. A. Bush for the DPS8/70M CPU
   Modified 4/81 by J. A. Bush to correct bug in read switch code for DPS8/70M CPU
   Modified October 1981 by J. Bongiovanni for set_procs_required
   Modified 12/81 by J. A. Bush to correct bug in assigning SCU masks for SCUs with type codes > "0010"b
   Modified 1/82 by J. A. Bush to report no response from RSW program, if inst. word 0 was not changed
   Modified April 1982 by J. Bongiovanni for expanded SCS switch data/masks
   Modified June 23, 1982 by J. A. Bush to clear cache while waiting for
   a response from the cpu under test, due to the isolts_/Multics address mismatch
   Modified Sept 21, 1983 by J. A. Bush to set scs$processor_data (tag).cache_size to ignore and
   to reserve 128K for DPS8 cpus
*/

/* format: style4 */

configure_test_cpu: proc (rcode);

dcl  rcode fixed bin (35);				/* entry parameter */

/* External entries */

dcl  scr_util$assign_mask entry (fixed bin (3), fixed bin (3));
dcl  scr_util$isolts_scu_p1 entry;
dcl  scr_util$isolts_scu_p2 entry;
dcl  scr_util$isolts_scu_p3 entry;
dcl  scr_util$set_mask entry (fixed bin (3), fixed bin (3), bit (72) aligned);
dcl  privileged_mode_ut$swap_sdw entry (ptr, ptr);
dcl  privileged_mode_ut$smic_port entry (bit (36) aligned, fixed bin (5));
dcl  privileged_mode_ut$cioc entry (ptr);
dcl  privileged_mode_ut$clear_cache entry;
dcl  privileged_mode_ut$wire_and_mask entry (fixed bin (71), ptr);
dcl  privileged_mode_ut$unwire_unmask entry (fixed bin (71), ptr);
dcl  wire_proc$wire_me entry;
dcl  wire_proc$unwire_me entry;
dcl  set_procs_required entry (bit (8) aligned, fixed bin (35));
dcl  pc_abs$remove_core entry (fixed bin, fixed bin, fixed bin (35));
dcl  freecore entry (fixed bin);
dcl  syserr$error_code entry options (variable);

/* External static */

dcl  isolts_abs_seg$ fixed bin ext;			/* abs seg for isolts */
dcl  fault_vector$ fixed bin ext;			/* fault vector segment */
dcl  pds$processid bit (36) aligned ext;
dcl  prds$processor_tag fixed bin (3) ext;
dcl  prds$processor_pattern bit (8) aligned ext;

/* Automatic */

dcl  (icpu, iscu) fixed bin (5);			/* ISOLTS CPU and SCU tags */
dcl  pdp ptr;					/* pointer to processor data for new CPU */
dcl  cdp ptr;					/* pointer to controller data */
dcl  old_pdp ptr;					/* pointer to processor data for CPU losing mask */
dcl  ptp ptr;					/* temporary for wire_and_mask */
dcl  mask_temp fixed bin (71);			/* temporary for wire_and_mask */
dcl  int_vec_save (2) bit (36) aligned;			/* for saving interrupt vector */
dcl  trouble_save (2) bit (36) aligned;			/* for saving trouble fault vector */
dcl  startup_save (2) bit (36) aligned;			/* for saving startup fault vector */
dcl  onc_save (2) bit (36) aligned;			/* for saving onc fault vector */
dcl  lockup_save (2) bit (36) aligned;			/* for saving lockup fault vector */
dcl  (i, j, k) fixed bin;				/* iteration variables */
dcl  l fixed bin (18);				/* iteration variable for > 128k */
dcl  abs_seg_p ptr;					/* pointer to abs_seg */
dcl  pip ptr;					/* pointer to port info */
dcl  switchp ptr;					/* pointer to switch readings */
dcl  found bit (1);					/* useful flag */
dcl  dps8 bit (1);					/* dps8 cpu flag */
dcl  reconfig_err bit (1);				/* flag for error checking */
dcl  remember (0:7) fixed bin;			/* base of controllers with vector template */
dcl  base fixed bin;				/* base address of controller */
dcl  size fixed bin;				/* size of a controller */
dcl  req_mem fixed bin;				/* Memory to reserve for ring 4 testing */
dcl  str_flt_operand bit (18);			/*  address that will generate store fault */
dcl  tcode fixed bin (35);				/* temporary for error code */
dcl  isolts_switch_mask (0:4) bit (36) aligned;		/* mask for checking switches */
dcl  isolts_switch_template (0:4) bit (36) aligned;	/* template for checking switches */
dcl  cpu_mask bit (8) aligned;			/* for set_procs_required */

/* Structures and based variables */

dcl  1 tsdw (0:7) aligned like sdw;			/* for saving abs_seg SDW's */
dcl  1 tsdw1 aligned like sdw;			/* automatic copy of SDW */
dcl  1 tsdw2 aligned like sdw;			/* safe storage for dedicated memory sdw */
dcl  1 pi like rsw_1_3.port_info based (pip) unal;	/* port info */
dcl  1 pdata like scs$processor_data based (pdp) aligned;	/* single element of processor data */
dcl  1 cdata based (cdp) like scs$controller_data aligned;	/* single element of controller data */
dcl  inst (0:262143) bit (36) based (abs_seg_p) aligned;	/* decicated memory as a 256k array */

/* Constants */

dcl  (trouble_fault init (31),			/* trouble fault number */
     startup_fault init (0),				/* startup fault number */
     store_fault init (1),				/* store fault number */
     onc_fault init (11),				/* onc fault number */
     lockup_fault init (7))				/* lockup fault number */
	fixed bin (5) static options (constant);
dcl  IGNORE_CACHE_SIZE fixed bin int static options (constant) init (7);
dcl  LETTERS char (8) int static options (constant) init ("ABCDEFGH");
dcl  cell12 bit (36) aligned static options (constant) init ("000040000000"b3);
dcl  (addr, bin, bit, bool, fixed, hbound, rel, stac, stacq, string, substr) builtin;
%page;
	if scs$reconfig_lock ^= pds$processid | ^scs$processor_test_data.active then do; /* if not ISOLTS process */
	     rcode = rcerr_isolts_not;		/* return error code */
	     return;
	end;
	else rcode = 0;				/* otherwise return 0 */
	reconfig_err = "0"b;			/* reset reconfiguration error flag */

	iscu = scs$processor_test_data.scu_tag;		/* copy scu and cpu tags */
	icpu = scs$processor_test_data.cpu_tag;
	cdp = addr (scs$controller_data (iscu));	/* Get ptr to data for this SCU. */

/* set up our read_switch template */

	isolts_switch_template, isolts_switch_mask = "0"b;/* clear them first */
	rswp = addr (isolts_switch_template (2));	/* set up rsw 2 first */
	switchp = addr (isolts_switch_mask (2));
	dps_rsw_2.fault_base = "0000010"b;		/* set up expected fault base */
	switchp -> dps_rsw_2.fault_base = "1111111"b;	/* set up fault base mask */
	dps_rsw_2.cpu_num = icpu;			/* set up expected cpu tag */
	switchp -> dps_rsw_2.cpu_num = 7;		/* set up cpu tag mask */
	if iscu < 4 then do;			/* pick rsw 1 if scu tags A, B, C, or D */
	     i = 1;
	     j = iscu;
	     switchp -> dps8_rsw_2.interlace_info (iscu) = "1"b; /* check possible interlace onf dps8 cpu */
	end;
	else do;					/* pick rsw 3 if scu tags E, F, G, or H */
	     i = 3;
	     j = iscu - 4;
	end;
	rswp = addr (isolts_switch_template (i));	/* set up rsw 1 - 3 data */
	pip = addr (rsw_1_3.port_info (j));		/* set template first */
	pi.port_enable = "1"b;			/* port enable bit must be on */
	rswp = addr (isolts_switch_mask (i));		/* set up mask for expected port info */
	pip = addr (rsw_1_3.port_info (j));
	pi.port_assignment = "7"b3;
	pi.initialize_enable = "1"b;
	pi.interlace_enable = "1"b;
	rswp = addr (isolts_switch_mask (4));		/* set rsw 4 mask */
	rsw_4.port_info (iscu).four = "1"b;
	rsw_4.port_info (iscu).half = "1"b;
	scs$processor_switch_data, scs$processor_switch_compare = "0"b; /* clear out switch data */
	switchp = addr (scs$processor_switch_compare (1));/* set pointer */

%page;
/* Find online CPU with mask set in this SCU */

	found = "0"b;
	do i = 1 to 4 while (^found);
	     if cdata.eima_data (i).mask_available then	/* if this mask available */
		if cdata.eima_data (i).mask_assigned then do; /* if this mask assigned */
		     do j = 0 to hbound (scs$processor_data, 1) while (^found);
			pdp = addr (scs$processor_data (j));
			if pdata.controller_port = cdata.eima_data (i).mask_assignment then
			     if pdata.online then do; /* if mask assigned to this cpu and online */
				found = "1"b;
				scs$processor_test_data.mask_cpu = j;
			     end;
		     end;
		end;
		else if cdata.type >= "0010"b then do;	/* mask not assigned to online cpu but avail. */
		     do j = 0 to hbound (scs$processor_data, 1) while (^found);
			pdp = addr (scs$processor_data (j));
			if pdata.online then do;	/* if this cpu is online, he is candidate for our mask cpu */
			     found = "1"b;
			     scs$processor_test_data.mask_cpu = j; /* save tag and assign mask to this cpu */
			     call scr_util$assign_mask ((iscu), (pdata.controller_port));
			end;
		     end;
		end;
	end;
	if ^found then do;				/* didn't find mask */
	     rcode = rcerr_isolts_no_mask;
	     return;
	end;

/* Force our process to run on the active CPU */

	cpu_mask = "0"b;
	substr (cpu_mask, scs$processor_test_data.mask_cpu + 1, 1) = "1"b;
	call set_procs_required (cpu_mask, tcode);
	if tcode ^= 0 then do;
	     rcode = rcerr_sprq_failed;
	     return;
	end;

/* safe store original config data for this SCU (to be restored later) and remove core in this SCU from paging pool */

	scs$cfg_data_save = scs$cfg_data (iscu);
	base = cdata.base;				/* set base and size values */
	size = cdata.size;
	call pc_abs$remove_core (base, size, tcode);
	if tcode ^= 0 then do;			/* some problem get out */
	     rcode = tcode;
	     return;
	end;
	scs$processor_test_data.scu_state = "01"b;	/* change scu state */
	call scr_util$isolts_scu_p1;			/* reconfig SCU */
%page;

/* Set scs$cpu_test_pattern to start interrupt level */

	scs$cpu_test_pattern = scs$processor_start_pattern;

/* Grab base 2k of all other non-bootload SCUs and pad with STA *, DIS pairs */

	remember = 0;				/* clear remember array */
	do i = 0 to hbound (scs$controller_data, 1);
	     if scs$controller_data (i).online & i ^= iscu & i ^= scs$interrupt_controller then do; /* if online */
		base = scs$controller_data (i).base;	/* and not bootload and not our SCU */
		call pc_abs$remove_core (base, 2, tcode); /* remove the core */
		if tcode = 0 then do;
		     call pad_mem (base, 2);		/* if no problem pad mem with STA *,DIS pairs */
		     remember (i) = base;		/* remember this scu */
		     string (tsdw (i)) = string (tsdw1);
		end;
	     end;
	end;

/* pad lower 256k of selected SCU's memory with STA *, DIS pairs */

	base = scs$controller_data (iscu).base;
	if scs$controller_data (iscu).size < 256 then	/* protect against store faults */
	     size = scs$controller_data (iscu).size;
	else size = 256;
	call pad_mem (base, size);
	tsdw2 = tsdw1;				/* save sdw to our dedicated memory */

/* Send connects to make all other processors suspend normal operation. */

	call wire_proc$wire_me;			/* Take no interrupts or page faults here. */
	call privileged_mode_ut$wire_and_mask (mask_temp, ptp);

	do while (^stac (addr (scs$connect_lock), pds$processid));
	end;					/* Lock up the connect lock. */

	scs$processor_start_wait = scs$processor & ^prds$processor_pattern;
						/* Stop all other processors. */
	do i = 0 to 7;				/* Loop through all processors. */
	     old_pdp = addr (scs$processor_data (i));	/* Get pointer to data for processor. */
	     if (i ^= prds$processor_tag) & old_pdp -> pdata.online then
		call privileged_mode_ut$cioc (old_pdp); /* Send connects to other processors. */
	end;

	do while (scs$processor_start_wait);		/* Wait for other processors to respond. */
	end;

/* Set up selected fault and interrupt vectors in system zero based memory */

	fvp = addr (fault_vector$);			/* Get pointer to fault vector. */

/* Set up STA *, DIS pair for CPU start interrupt. */
	int_vec_save (1) = fv.ipair (scs$processor_start_int_no).scu;
	int_vec_save (2) = fv.ipair (scs$processor_start_int_no).tra;
	fv.ipair (scs$processor_start_int_no).scu = rel (addr (fv.ipair (scs$processor_start_int_no).scu))
	     || "755200"b3;
	fv.ipair (scs$processor_start_int_no).tra = rel (addr (fv.ipair (scs$processor_start_int_no).tra))
	     || "616200"b3;

/* Set up STA *, DIS pair for trouble fault. */
	trouble_save (1) = fv.fpair (trouble_fault).scu;
	trouble_save (2) = fv.fpair (trouble_fault).tra;
	fv.fpair (trouble_fault).scu = rel (addr (fv.fpair (trouble_fault).scu)) || "755200"b3;
	fv.fpair (trouble_fault).tra = rel (addr (fv.fpair (trouble_fault).tra)) || "616200"b3;

/* Set up STA *, DIS pair for startup fault. */
	startup_save (1) = fv.fpair (startup_fault).scu;
	startup_save (2) = fv.fpair (startup_fault).tra;
	fv.fpair (startup_fault).scu = rel (addr (fv.fpair (startup_fault).scu)) || "755200"b3;
	fv.fpair (startup_fault).tra = rel (addr (fv.fpair (startup_fault).tra)) || "616200"b3;

/* Set up STA *, DIS pair for onc fault. */
	onc_save (1) = fv.fpair (onc_fault).scu;
	onc_save (2) = fv.fpair (onc_fault).tra;
	fv.fpair (onc_fault).scu = rel (addr (fv.fpair (onc_fault).scu)) || "755200"b3;
	fv.fpair (onc_fault).tra = rel (addr (fv.fpair (onc_fault).tra)) || "616200"b3;

/* Set up STA *, DIS pair for lockup fault */
	lockup_save (1) = fv.fpair (lockup_fault).scu;
	lockup_save (2) = fv.fpair (lockup_fault).tra;
	fv.fpair (lockup_fault).scu = rel (addr (fv.fpair (lockup_fault).scu)) || "755200"b3;
	fv.fpair (lockup_fault).tra = rel (addr (fv.fpair (lockup_fault).tra)) || "616200"b3;

/* Send processor start interrupt, open processor's mask, and wait for it to respond. */

	call int_test_cpu (tcode);

/* delay until the STA * takes effect */

	do i = 1 to 500 while (inst (0) = "000000755200"b3);
	     call privileged_mode_ut$clear_cache;	/* Make sure cache gets updated */
	end;

/* if location 0 of our dedicated memory did not change then something is wrong */

	if inst (0) = "000000755200"b3 then do;		/* failure */
	     reconfig_err = "1"b;			/* set error flag */

/* now check the bootload SCU to see if the switches were set wrong */

	     if fv.ipair (scs$processor_start_int_no).scu ^= rel (addr (fv.ipair (scs$processor_start_int_no).scu))
		|| "755200"b3 then do;
		tcode = rcerr_isolts_wrong_scu;	/* answered on wrong scu */
		switchp -> switch_w1.errtag = scs$interrupt_controller;
	     end;
	     else if fv.fpair (trouble_fault).scu ^= rel (addr (fv.fpair (trouble_fault).scu)) || "755200"b3 then do;
		tcode = rcerr_isolts_wrong_scu_cell;	/* trouble fault on bootload scu */
		switchp -> switch_w1.offset = rel (addr (fv.fpair (trouble_fault).scu));
		switchp -> switch_w1.valid = "1"b;
		switchp -> switch_w1.errtag = scs$interrupt_controller;
	     end;
	     else if fv.fpair (startup_fault).scu ^= rel (addr (fv.fpair (startup_fault).scu)) || "755200"b3 then do;
		tcode = rcerr_isolts_wrong_scu_cell;	/* got startup fault on bootload scu */
		switchp -> switch_w1.offset = rel (addr (fv.fpair (startup_fault).scu));
		switchp -> switch_w1.valid = "1"b;
		switchp -> switch_w1.errtag = scs$interrupt_controller;
	     end;
	     else if fv.fpair (onc_fault).scu ^= rel (addr (fv.fpair (onc_fault).scu)) || "755200"b3 then do;
		tcode = rcerr_isolts_wrong_scu_cell;	/* onc fault on bootload scu */
		switchp -> switch_w1.offset = rel (addr (fv.fpair (onc_fault).scu));
		switchp -> switch_w1.valid = "1"b;
		switchp -> switch_w1.errtag = scs$interrupt_controller;
	     end;
	     else if fv.fpair (lockup_fault).scu ^= rel (addr (fv.fpair (lockup_fault).scu)) || "755200"b3 then do;
		tcode = rcerr_isolts_wrong_scu_cell;	/* lockup fault on bootload scu */
		switchp -> switch_w1.offset = rel (addr (fv.fpair (lockup_fault).scu));
		switchp -> switch_w1.valid = "1"b;
		switchp -> switch_w1.errtag = scs$interrupt_controller;
	     end;
	end;

/* restore system fault and int vectors */

	fv.ipair (scs$processor_start_int_no).scu = int_vec_save (1);
	fv.ipair (scs$processor_start_int_no).tra = int_vec_save (2);
	fv.fpair (trouble_fault).scu = trouble_save (1);
	fv.fpair (trouble_fault).tra = trouble_save (2);
	fv.fpair (startup_fault).scu = startup_save (1);
	fv.fpair (startup_fault).tra = startup_save (2);
	fv.fpair (onc_fault).scu = onc_save (1);
	fv.fpair (onc_fault).tra = onc_save (2);
	fv.fpair (lockup_fault).scu = lockup_save (1);
	fv.fpair (lockup_fault).tra = lockup_save (2);

/* reset connect lock */

	if ^stacq (scs$connect_lock, (36)"0"b, scs$connect_lock) then ; /* just reset lock, null then cluse */

	call privileged_mode_ut$unwire_unmask (mask_temp, ptp);
	call wire_proc$unwire_me;			/* Can unwire now. */

/* if we had an error but did not find it above, check lower 2 k of all non-bootload scus */

	if reconfig_err & tcode = 0 then do;		/* check lower 2k of other non-bootload scus */
	     do i = 0 to 7 while (tcode = 0);		/* go through each scu if neccessary */
		if remember (i) ^= 0 then do;		/* if we deallocated core from this SCU */
		     call privileged_mode_ut$swap_sdw (abs_seg_p, addr (tsdw (i))); /* get correct sdw */
		     if inst (0) ^= "000000755200"b3 then /* answered on wrong SCU */
			tcode = rcerr_isolts_wrong_scu;

		     else do k = 2 to 2046 by 2 while (tcode = 0);
			if inst (k) ^= bit (bin (k, 18), 18) || "755200"b3 then do; /* found it */
			     tcode = rcerr_isolts_wrong_scu_cell;
			     switchp -> switch_w1.offset = bit (bin (k, 18), 18);
			     switchp -> switch_w1.valid = "1"b;
			end;
		     end;
		end;
	     end;
	     if tcode ^= 0 then			/* if we found error */
		switchp -> switch_w1.errtag = i - 1;	/* set error tag */
	end;

/* Now give back the double pages we borrowed */

	do i = 0 to hbound (scs$controller_data, 1);
	     base = remember (i);
	     if base > 0 then do;
		call freecore (base);
		call freecore (base + 1);
	     end;
	end;
	call privileged_mode_ut$swap_sdw (abs_seg_p, addr (tsdw2)); /* restore sdw to our dedicated memory */

/* if we had an error but did not find it above, check our dedicated memory */

	if reconfig_err & tcode = 0 then
	     call check_mem (0);			/* go check our dedicated memory */
	if tcode ^= 0 then do;			/* if some problem above - get out */
	     rcode = tcode;				/* copy error code */
	     return;
	end;

/* Execute read switch program to determine if cpu is configured correctly */

	inst (1) = "000001616200"b3;			/* set DIS instruction in loc 1 */

	dps8 = "0"b;				/* reset dps8 indicator */
	rswp = addr (scs$processor_switch_data (2));	/* preset rsw (2) ptr */
	do i = 1 to 4 while (^dps8);			/* read each of 4 possible read switch types */
	     do j = 1 to 2;				/* RSW first followed by STA */
		if j = 1 then			/* if first iteration set up RSW */
		     inst (0) = bit (bin (i, 18), 18) || "231200"b3; /* set RSW instruction */
		else inst (0) = "000000755200"b3;	/* 2nd iteration, set STA * in loc 0 */
		call int_test_cpu (tcode);		/* send interrupt */
		do k = 1 to 500;			/* delay awhile */
		end;
		call privileged_mode_ut$clear_cache;	/* Make sure cache gets updated */
		if j = 2 then			/* if second iteration */
		     if inst (0) ^= "000000755200"b3 then do; /* if we didn't time out.... */
			scs$processor_switch_data (i) = inst (0); /* copy rsw data out */
			if i = 2 then		/* if rsw (2) complete, check cpu type */
			     if dps8_rsw_2.cpu_type > 0 then /* If dps8 cpu */
				dps8 = "1"b;	/* quit now */
		     end;
		     else do;			/* no response from cpu we are adding */
			call check_mem (2);		/* go check if we answered on another int cell */
			rcode = tcode;		/* copy error code */
			scs$processor_switch_compare (2) = /* save RSW inst we were using */
			     bit (bin (i, 18), 18) || "231200"b3;
			return;			/* and let user report error */
		     end;
	     end;
	end;
	if dps8 then do;				/* set up for dps8 cpu */
	     req_mem, scs$processor_test_data.req_mem = 128; /* reserve 128K for DPS8s */
	     str_flt_operand = "400000"b3;		/* should take str flt at 128K */
	     isolts_switch_template (1) = isolts_switch_template (1) | "002002002002"b3;
	     isolts_switch_mask (1) = isolts_switch_mask (1) | "042042042042"b3;
	     isolts_switch_template (3), isolts_switch_mask (3) = "0"b; /* No RSW (3) for dps8 */
	end;
	else do;					/* /* set up for L68 cpu */
	     req_mem, scs$processor_test_data.req_mem = 64; /* reserve 64K for L68s */
	     str_flt_operand = "200000"b3;		/* should take str flt at 64K */
	     isolts_switch_template (1) = isolts_switch_template (1) | "001001001001"b3;
	     isolts_switch_mask (1) = isolts_switch_mask (1) | "041041041041"b3;
	     isolts_switch_template (3) = isolts_switch_template (3) | "001001001001"b3;
	     isolts_switch_mask (3) = isolts_switch_mask (3) | "041041041041"b3;
	end;

/* Exclusive or the switches with our switch template and "and" the result with our mask */

	scs$processor_switch_compare = (bool (scs$processor_switch_data, isolts_switch_template, "0110"b))
	     & isolts_switch_mask;

/* if any descrepencies exist return now */

	found = "0"b;				/* reset error indicator */
	do i = 1 to 4 while (^found);			/* go through each read switch data word */
	     if scs$processor_switch_compare (i) ^= "0"b then do;
		rcode = rcerr_isolts_bad_switches;
		return;
	     end;
	     if i = 2 then				/* if rsw (2) */
		if dps8 then			/* and a dps8 cpu... */
		     found = "1"b;			/* that is it, exit */
	end;
	scs$processor_switch_compare = scs$processor_switch_data; /* return good switch readings to user */

/* Check to see if a LDA instruction works correctly */

	inst (2) = "0"b;				/* set cell 2 of our dedicated memory area to 0 */
	inst (0) = "000002235200"b3;			/* set LDA 2 inst in loc 0 */
	call int_test_cpu (tcode);			/* issue interrupt to test cpu */
	do k = 1 to 500;				/* delay for awhile */
	end;
	inst (0) = "000000755200"b3;			/* set STA 0 in loc 0 */
	call int_test_cpu (tcode);
	do k = 1 to 500;				/* delay for awhile */
	end;
	call privileged_mode_ut$clear_cache;		/* Make sure cache gets updated */

/* if the LDA worked correctly, location 0 should contain a value of 0 */

	if inst (0) ^= "0"b then do;			/* LDA did not work correctly */
	     rcode = rcerr_isolts_lda_fail;
	     return;
	end;

/* Check to make sure that a LDA to an address >= <port_size> will generate a store fault */

	inst (0) = "000002710000"b3;			/* must tra out of vector to avoid trb flt */
	inst (2) = str_flt_operand || "235000"b3;	/* set lda to req_mem */
	call int_test_cpu (tcode);			/* issue interrupt to test cpu */
	do k = 1 to 500;				/* delay for awhile */
	end;
	call privileged_mode_ut$clear_cache;		/* Make sure cache gets updated */

/* If the store fault vector equals zero then a store fault occurred */

	if abs_seg_p -> fv.fpair (store_fault).scu = rel (addr (fv.fpair (store_fault).scu))
	     || "755200"b3 then do;			/* failure */
	     rcode = rcerr_isolts_no_str_flt;
	     return;
	end;

/* Since we will be using a simulated IOM 0 terminate interrupt for ISOLTS testing
   lets make sure that our test processor will answer it */

	scs$cpu_test_pattern = cell12;		/* set test pattern for interrupt cell 12 */
	call int_test_cpu (tcode);			/* execute simulated interrupt */
	do k = 1 to 500;				/* delay for awhile */
	end;
	call privileged_mode_ut$clear_cache;		/* Make sure cache gets updated */
	if abs_seg_p -> fv.ipair (12).scu = rel (addr (fv.ipair (12).scu))
	     || "755200"b3 then do;			/* interrupt failed */
	     rcode = rcerr_isolts_wrong_cell;
	     switchp -> switch_w1.cell = 12;		/* set cell number */
	     return;
	end;

/* Now we can return to the system all memory in our selected SCU above req_mem */

	call scr_util$isolts_scu_p2;			/* re-enable original active ports */
	call set_procs_required ("0"b, tcode);		/* reset proc required */

	if scs$controller_data (iscu).size > req_mem then do; /* only give it back if it is there */
	     base = scs$controller_data (iscu).base;	/* pick up system base and size of our SCU */
	     size = scs$controller_data (iscu).size;
	     do i = base + req_mem to size + base - 1;	/* give back each page */
		call freecore (i);
	     end;
	end;

/* Now set scu_state indicator to indicate that we only have lower memory now */

	scs$processor_test_data.scu_state = "11"b;
	scs$processor_data (icpu).cache_size = IGNORE_CACHE_SIZE; /* set so validate_cpu_card will ignore size */
	return;					/* return to caller */

%page;

/* int_test_cpu - entry to set up conditions to issue a SMIC instruction to the CPU being tested with ISOLTS */

int_test_cpu: entry (rcode);

	if scs$reconfig_lock ^= pds$processid | ^scs$processor_test_data.active then do; /* if not ISOLTS process */
	     rcode = rcerr_isolts_not;		/* return error code */
	     return;
	end;
	else rcode = 0;				/* otherwise return 0 */

	if scs$processor_test_data.scu_state = "11"b then do; /* if running on lower memory */
	     cpu_mask = "0"b;
	     substr (cpu_mask, scs$processor_test_data.mask_cpu + 1, 1) = "1"b;
	     call set_procs_required (cpu_mask, rcode);	/* run on CPU with mask set */
	     if rcode ^= 0 then do;
		rcode = rcerr_sprq_failed;
		return;
	     end;
	end;

	call scr_util$set_mask ((scs$processor_test_data.scu_tag), /* mask to system level first */
	     (scs$processor_data (scs$processor_test_data.cpu_tag).controller_port),
	     "000000000017000000000017"b3 & scs$cpu_test_mask);

	call privileged_mode_ut$smic_port (scs$cpu_test_pattern, (scs$processor_test_data.scu_tag)); /* do the SMIC */

	call scr_util$set_mask ((scs$processor_test_data.scu_tag), /* open interrupts to test cpu */
	     (scs$processor_data (scs$processor_test_data.cpu_tag).controller_port), scs$cpu_test_mask);

	if scs$processor_test_data.scu_state = "11"b then /* if running on lower memory */
	     call set_procs_required ("0"b, (0));	/* reset proc required */

	return;

%page;

/* isolts_final - entry to remove SCU from ISOLTS test CPU depending on state of scs$processor_test_data.scu_state */

isolts_final: entry;

	i = fixed (scs$processor_test_data.scu_state, 2); /* convert scu_state to fixed bin */
	if i = 0 then return;			/* if scu_state = "00"b - NOP */

	iscu = scs$processor_test_data.scu_tag;		/* pick up scu_tag */
	cdp = addr (scs$controller_data (iscu));

	if i = 2 | i = 3 then do;			/* if either of these two states, we must restore SCU masks */
	     cpu_mask = "0"b;
	     substr (cpu_mask, scs$processor_test_data.mask_cpu + 1, 1) = "1"b;
	     call set_procs_required (cpu_mask, tcode);
	     if tcode ^= 0 then
		call syserr$error_code (CRASH, tcode, "configure_test_cpu: Unable to run on CPU ^a",
		     substr (LETTERS, scs$processor_test_data.mask_cpu + 1, 1));

	     call scr_util$isolts_scu_p3;		/* go change masks */
	     call set_procs_required ("0"b, (0));	/* reset cpu required */
	end;

	base = cdata.base;				/* pick up base address of controller */
	if i = 1 | i = 2 then			/* if state is "01"b | "10"b */
	     size = cdata.size;			/* restoe all of scus memory to system */
	else size = scs$processor_test_data.req_mem;	/* if state is = "11"b then only req_mem needs to be restored */

	do k = base to base + size - 1;		/* return memory to system */
	     call freecore (k);
	end;

	scs$cpu_test_mask, scs$cpu_test_pattern = "0"b;	/* reset ISOLTS specific info */
	scs$cfg_data_save = 0;

	return;					/* return to caller */

%page;

/* pad_mem - subroutine to pad up to 256k of desired memory with sta *, dis * instructions */

pad_mem: proc (base, pages);

dcl  (base, pages) fixed bin;

	abs_seg_p = addr (isolts_abs_seg$);		/* get ptr to isolts_abs_seg */
	string (tsdw1) = "0"b;			/* clear out  sdw */
	tsdw1.df = "1"b;
	tsdw1.read = "1"b;
	tsdw1.write = "1"b;
	tsdw1.unpaged = "1"b;
	tsdw1.add = bit (bin (base * 1024, 24), 24);
	tsdw1.bound = bit (bin (((pages * 1024) / 16) - 1, 14), 14); /* set bounds to number of pages */
	call privileged_mode_ut$swap_sdw (abs_seg_p, addr (tsdw1)); /* swap the sdw */

	do l = 0 to pages * 1024 - 2 by 2;		/* iterate through desired memory */
	     inst (l) = bit (l) || "755200"b3;
	     inst (l + 1) = bit (l) || "616200"b3;
	end;
     end pad_mem;

/* check_mem - subroutine to check if cpu answered on a different interrupt cell, than expected */

check_mem: proc (si);

dcl  si fixed bin;

	found = "0"b;
	do k = si to size - 2 by 2 while (^found);	/* check all of our memory */
	     if inst (k) ^= bit (bin (k, 18)) || "755200"b3 then /* found error */
		found = "1"b;
	end;
	if found then do;				/* if  we answered on wrong cell */
	     tcode = rcerr_isolts_wrong_cell;
	     switchp -> switch_w1.offset = bit (bin (k - 2, 18)); /* set offset */
	     switchp -> switch_w1.valid = "1"b;
	     switchp -> switch_w1.errtag = iscu;
	end;
	else tcode = rcerr_isolts_no_response;		/* if can't find no other reason */

     end check_mem;
%page;

%include rcerr;

%page;

%include scs;
%page;
%include rsw;
%page;

%include sdw;

%page;

%include fault_vector;

%include syserr_constants;

%page;
/* BEGIN MESSAGE DOCUMENTATION

   Message:
   configure_test_cpu: Unable to run on CPU X ERRORMESSAGE

   S: $crash

   T: When ISOLTS is terminating

   M: The system is attempting to restore the ISOLTS CPU to service.
   In attempting to reassign its interrupt mask, it was unable
   to run on that CPU.  This indicates hardware or software malfunction.

   A: $recover

   END MESSAGE DOCUMENTATION */

     end configure_test_cpu;
 



		    fv_iv_template.alm              11/11/89  1135.2rew 11/11/89  0800.9       13563



" ***********************************************************
" *                                                         *
" * 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.      *
" *                                                         *
" ***********************************************************

" FV_IV_TEMPLATE - Catch Unexpected Faults when Starting a Processor.
"	coded 2/76 by S. H. Webber
"	last modified 4/7/76 by Noel I. Morris
"	Converted to ALM macros (this was the last mexp program
"	  in all of hardcore!), 04/20/80 W. Olin Sibert


	name	fv_iv_template

	segdef	fv_iv_template
	segdef	rsw_data


"	This 2K segment is placed at the base of every system controller.
"	It will catch attempts to start up a processor with incorrect
"	address assignment switch settings.
"



	macro	fv_iv
	dup	992		"992=32*(15+16)
	tra	start-fv_iv_template
	nop
	dupend
	&end


" 

	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>

fv_iv_template:
	fv_iv

start:	eax0	3
	rsw	1,0
	sta	rsw_data-fv_iv_template,0
	eax0	-1,0
	tpl	-3,ic

	inhibit	on	<+><+><+><+><+><+><+><+><+><+><+><+>
	dis	*
	inhibit	off	<-><-><-><-><-><-><-><-><-><-><-><->
	tra	-1,ic

	org	2048-32
rsw_data:	bss	,32

	end
 



		    io_reconfig.pl1                 11/11/89  1135.2r w 11/11/89  0800.0      189387



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

/*  Add_channel and delete_channel entries written 5/83 by S. Krupp. */
/*  add_iom and delete_iom entries written 3/84 by Chris Jones */
/*  Modifed August 1984 by Chris Jones to fix "change ctep" bug in ensure_rpv_path */
/*  Modified November 1984 by M. Pandolf to call iom_switches$validate during IOM addition */


/****^  HISTORY COMMENTS:
  1) change(86-11-17,Farley), approve(86-11-20,MECR0002),
     audit(86-11-19,Fawcett), install(86-11-20,MR12.0-1222):
     Added check to delete_channel for active device assignments that require
     the channel. If one is found the operation is aborted.
  2) change(86-12-19,Farley), approve(86-12-19,MCR7587),
     audit(86-12-19,Fawcett), install(87-01-05,MR12.0-1253):
     Formal installation to close out above MECR0002.
  3) change(87-06-11,Lippard), approve(87-06-29,MCR7729),
     audit(87-07-08,Farley), install(87-08-06,MR12.1-1063):
     Modified cleanup handler to not unassign the channel from IOI if IOI
     was using it when we were called.
                                                   END HISTORY COMMENTS */


/* format: style4,delnl,insnl,indattr,ifthen,dclind10 */
io_reconfig:
     proc ();

/* Parameter */

dcl	p_chanid		   char (8) aligned;	/* (I) name of the channel in question */
dcl	p_code		   fixed bin (35);		/* (O) standard system status code */
dcl	p_tag		   fixed bin (3);		/* (I) IOM tag */

/* Automatic */

dcl	added		   bit (1) aligned;
dcl	adding_channel	   bit (1) aligned init ("0"b);
						/* Always init this. */
dcl	base_chnl		   bit (1) aligned;
dcl	chanid		   char (8) aligned;
dcl	chnl_required	   bit (1) aligned;
dcl	code		   fixed bin (35);
dcl	cv_status_ptr	   ptr;
dcl	deleting_channel	   bit (1) aligned init ("0"b);
						/* Always init this. */
dcl	device_active	   bit (1) aligned;
dcl	dtx		   fixed bin;
dcl	grp_chnl_active	   bit (1) aligned;
dcl	iom_active	   bit (1) aligned;
dcl	locked		   bit (1) aligned init ("0"b);
dcl	rel_chnl_active	   bit (1) aligned;
dcl	state_changed	   bit (1) aligned init ("0"b);
dcl	tag		   fixed bin (3);
dcl	temp_base_chnl_ptr	   ptr;
dcl	usurped_channel	   bit (1) aligned;

/* Builtin */

dcl	(addr, bin, hbound, lbound, null, ptr, rel, substr, unspec)
			   builtin;

/* Condition */

dcl	cleanup		   condition;

/* Entries */

dcl	config_$find_2	   entry (char (4) aligned, fixed bin, ptr);
dcl	config_$update	   entry ();
dcl	dctl$disk_inter	   entry (fixed bin (35), fixed bin (3), bit (36) aligned);
dcl	disk_control$add_channel
			   entry (fixed bin (8), fixed bin (35), bit (1) aligned);
dcl	ioi_assignment$lock_for_reconfig
			   entry;
dcl	ioi_assignment$unlock_for_reconfig
			   entry;
dcl	ioi_masked$interrupt   entry (fixed bin (35), fixed bin (3), bit (36) aligned);
dcl	ioi_usurp_channels$assign
			   entry (ptr, fixed bin (35));
dcl	ioi_usurp_channels$required
			   entry (ptr, fixed bin (35));
dcl	ioi_usurp_channels$unassign
			   entry (ptr, fixed bin (35));
dcl	iom_overhead$init	   entry (fixed bin (3), fixed bin (35));
dcl	iom_overhead$release   entry (fixed bin (3), fixed bin (35));
dcl	iom_switches$validate  entry (fixed bin (3), fixed bin (35));
dcl	pxss$addevent	   entry (bit (36) aligned);
dcl	pxss$wait		   entry ();
dcl	scr_util$set_port_enable
			   entry (fixed bin (3), bit (1) unal);
dcl	syserr		   entry () options (variable);

/* Static */

dcl	(
	error_table_$bad_channel,
	error_table_$chnl_already_added,
	error_table_$chnl_already_deleted,
	error_table_$chnl_being_deleted,
	error_table_$chnl_iom_active,
	error_table_$chnl_iom_inactive,
	error_table_$io_not_available,
	error_table_$io_not_defined,
	error_table_$iom_already_added,
	error_table_$iom_already_deleted,
	error_table_$no_base_chnl_active,
	error_table_$rel_chnl_active,
	error_table_$undeleted_device
	)		   fixed bin (35) ext static;

dcl	DUMMY_INDEX	   fixed bin (35) init (0) int static options (constant);

delete_channel:
     entry (p_chanid, p_code);

	deleting_channel = "1"b;
	usurped_channel = "0"b;
	idp = addr (ioi_data$);
	io_config_data_ptr = addr (io_config_data$);
	io_config_channel_table_ptr = ptr (io_config_data_ptr, io_config_data.channel_table_offset);
	io_config_iom_table_ptr = ptr (io_config_data_ptr, io_config_data.iom_table_offset);

/* Look in ioi_data for required info. */

	chanid = io_chnl_util$canonicalize_chanid (p_chanid);
	call get_ctep (chanid, ctep, code);
	call quit_if_error;

	call get_gtep (ctep, gtep);

	on cleanup call CLEANUP ();

/* Lock for reconfiguration. */

	call lock_for_reconfig;

/* Make some checks on state of channel and then mark it as being deleted. */

	if cte.deleted then
	     call ABORT (error_table_$chnl_already_deleted);
	else if cte.deleting then
	     call ABORT (error_table_$chnl_being_deleted);

	do dtx = 1 to ioi_data.ndt;			/* check if channel is required for an active device */
	     dtep = addr (ioi_data.dt (dtx));
	     if dte.in_use & ^dte.direct & dte.process_id ^= ""b then do;
						/* if IOI is managing this device and it is assigned... */
		if dte.channel_required = chanid then
		     call ABORT (error_table_$io_not_available);
	     end;
	end;


	state_changed = "1"b;
	cte.deleting = "1"b;

/* Get information relevant to deleting a channel. */

	call get_chnl_del_info (gtep, ctep, base_chnl, rel_chnl_active, grp_chnl_active);
	call get_device_info (gtep, ctep, device_active, chnl_required);

/* Make sure it is legal to delete this channel.

   Rules:  The channel must not be in use.  The channel may not be
   the only logical channel that can reach an as yet undeleted
   device. If the channel is a base channel, then all logical
   channels on the same physical channel must have been
   previously deleted.

   Notes:  rel_chnl_active = true means that there are other active
   channels that are on the same physical channel as chanid.

   grp_chnl_active = true means that there are other active
   channels in the same group as chanid, but they are not
   on the same physical channel as chanid.

   If chanid doesn't specify a base channel, then there is
   always at least one channel around to handle active devices
   if chanid is deleted.
*/

	if base_chnl then do;
	     if rel_chnl_active then
		call ABORT (error_table_$rel_chnl_active);
	     if device_active & ^grp_chnl_active then
		call ABORT (error_table_$undeleted_device);
	end;

/* If channel doesn't belong to ioi, try to get it. */

	if gte.disk_data_subsystem_idx ^= 0 then do;	/* Have disk chnl.  Try to usurp it. */
	     if ^cte.ioi_use then do;
		call ioi_usurp_channels$required (ctep, code);
		call quit_if_error;
		usurped_channel = "1"b;
	     end;
	end;
	else if ^cte.ioi_use then do;			/* Have non-ioi, non-disk type of chnl.  Try to grab it. */
	     call io_manager$assign (cte.chx, chanid, io_manager$ignore_interrupt, DUMMY_INDEX, cv_status_ptr, code);
	     call quit_if_error;
	     cte.ioi_use = "1"b;
	     usurped_channel = "1"b;
	end;

/* Wait for channel activity to clear. */

	do while (cte.connected);
	     call pxss$addevent (unspec (IO_CHANNEL_LOCK_TEMPLATE) || rel (ctep));
	     call pxss$wait ();
	end;

/* Delete the channel. */

	call io_manager$unassign_delete (cte.chx, code);
	call quit_if_error;
	cte.ioi_use = "0"b;
	cte.deleted = "1"b;
	cte.deleting = "0"b;
	call ensure_rpv_path_in_toehold;
	channel_table.channel_entry (cte.channel_table_idx).configured = "0"b;
	iom_table.iom_entry (channel_table.channel_entry (cte.channel_table_idx).iom_idx).n_configured_channels =
	     iom_table.iom_entry (channel_table.channel_entry (cte.channel_table_idx).iom_idx).n_configured_channels
	     - 1;

	if gte.disk_data_subsystem_idx ^= 0 then do;
	     call ioi_usurp_channels$assign (gtep, code); /* make sure we still have enough */
	     call quit_if_error;
	end;

	call unlock_for_reconfig;
	call syserr (LOG, "RCF: Deleted channel ^a.", chanid);
	p_code = 0;
	return;

add_channel:
     entry (p_chanid, p_code);

	adding_channel = "1"b;
	idp = addr (ioi_data$);
	io_config_data_ptr = addr (io_config_data$);
	io_config_channel_table_ptr = ptr (io_config_data_ptr, io_config_data.channel_table_offset);
	io_config_iom_table_ptr = ptr (io_config_data_ptr, io_config_data.iom_table_offset);

/* Look in ioi_data for required info. */

	chanid = io_chnl_util$canonicalize_chanid (p_chanid);
	call get_ctep (chanid, ctep, code);
	call quit_if_error;

	call get_gtep (ctep, gtep);
	call get_itep (ctep, itep);

	on cleanup call CLEANUP ();

/* Lock for reconfiguration. */

	call lock_for_reconfig;

/* Make some checks on state of channel. */

	if ^cte.deleted then do;
	     if (^cte.ioi_use) & (gte.disk_data_subsystem_idx ^= 0) then
		call disk_control$add_channel ((gte.disk_data_subsystem_idx), (cte.disktab_ctx), added);
	     if added then
		goto DONE_ADDING;
	     call ABORT (error_table_$chnl_already_added);
	end;
	else if cte.deleting then
	     call ABORT (error_table_$chnl_being_deleted);

/* Get information relevant to adding a channel. */

	call get_chnl_add_info (ctep, itep, base_chnl, iom_active);

/* Make sure it is legal to add this channel.

   Rules:  The channel must be connected to an active iom.  If the channel
   is not a base channel, its associated base channel must already
   be active.
*/

	if ^iom_active then
	     call ABORT (error_table_$chnl_iom_inactive);

	if ^base_chnl then do;
	     temp_base_chnl_ptr = ptr (ctep, cte.base_ctep);
	     if temp_base_chnl_ptr -> cte.deleted then
		call ABORT (error_table_$no_base_chnl_active);
	end;

/* If channel belonged to someone else originally, give it back. */

	state_changed = "1"b;
	if gte.disk_data_subsystem_idx ^= 0 then do;	/* Have disk chnl. */
	     call io_manager$assign_add (cte.chx, chanid, dctl$disk_inter,
		dskdcl_chans_per_subsys * gte.disk_data_subsystem_idx + cte.disktab_ctx - 1, cv_status_ptr, code);
	     call quit_if_error;
	     cte.statusp = cv_status_ptr;
	     cte.deleted = "0"b;
	     cte.ioi_use = "1"b;			/* so it will be given back */
	     call ioi_usurp_channels$unassign (gtep, code);
	     call quit_if_error;
	end;
	else if ^gte.mplex then do;			/* Have non-ioi, non-disk type of chnl. */
	     call io_manager$assign_add (cte.chx, chanid, io_manager$ignore_interrupt, DUMMY_INDEX, cv_status_ptr, code)
		;
	     call quit_if_error;
	     cte.deleted = "0"b;
	     call io_manager$unassign (cte.chx, code);
	     call quit_if_error;
	end;
	else do;
	     call io_manager$assign_add (cte.chx, chanid, ioi_masked$interrupt, bin (rel (ctep)), cv_status_ptr, code);
	     call quit_if_error;
	     cte.deleted = "0"b;
	     cte.ioi_use = "1"b;
	end;

	channel_table.channel_entry (cte.channel_table_idx).configured = "1"b;
	iom_table.iom_entry (channel_table.channel_entry (cte.channel_table_idx).iom_idx).n_configured_channels =
	     iom_table.iom_entry (channel_table.channel_entry (cte.channel_table_idx).iom_idx).n_configured_channels
	     + 1;
	call syserr (LOG, "RCF: Added channel ^a.", chanid);

DONE_ADDING:
	call unlock_for_reconfig;
	p_code = 0;

	return;

ERROR_RETURN:
	return;

add_iom:
     entry (p_tag, p_code);

	call setup_and_find_iom_entry;
	call lock_for_reconfig;
	if iom_table.iom_entry (ite.iom_table_idx).configured then do;
	     call unlock_for_reconfig;
	     p_code = error_table_$iom_already_added;
	     return;
	end;
	iom_data.per_iom (tag).on_line = "1"b;
	call iom_overhead$init (tag, code);
	if code ^= 0 then do;
	     iom_data.per_iom (tag).on_line = "0"b;
	     call unlock_for_reconfig;
	     p_code = code;
	     return;
	end;
	call scr_util$set_port_enable (iom_card.port, "1"b);
						/* allow all SCUs at the IOM */

	call iom_switches$validate (tag, code);
	if code ^= 0 then
	     call syserr (CRASH, "io_reconfig: Unable to validate switches for IOM ^a.", substr ("abcd", tag, 1));

	ite.deleted = "0"b;
	iom_table.iom_entry (ite.iom_table_idx).configured = "1"b;
	iom_card.state = "on";
	call config_$update;
	call unlock_for_reconfig;
	call syserr (ANNOUNCE, "RCF: Added IOM ^a.", substr ("abcd", tag, 1));
	p_code = 0;
	return;

delete_iom:
     entry (p_tag, p_code);

	call setup_and_find_iom_entry;
	call lock_for_reconfig;
	if iom_table.iom_entry (ite.iom_table_idx).n_configured_channels ^= 0 then do;
	     call unlock_for_reconfig;
	     p_code = error_table_$chnl_iom_active;
	     return;
	end;
	if ^iom_table.iom_entry (ite.iom_table_idx).configured then do;
	     call unlock_for_reconfig;
	     p_code = error_table_$iom_already_deleted;
	     return;
	end;

	call iom_overhead$release (tag, code);
	if code ^= 0 then do;
	     call unlock_for_reconfig;
	     p_code = code;
	     return;
	end;

	call scr_util$set_port_enable (iom_card.port, "0"b);
						/* disable all SCU's access to this IOM */
	ite.deleted = "1"b;
	iom_table.iom_entry (ite.iom_table_idx).configured = "0"b;
	iom_data.per_iom (tag).on_line = "0"b;
	iom_card.state = "off";
	call config_$update;
	call unlock_for_reconfig;
	call syserr (ANNOUNCE, "RCF: Deleted IOM ^a.", substr ("abcd", tag, 1));
	p_code = 0;
	return;

setup_and_find_iom_entry:
     proc;

dcl	itx		   fixed bin;

	tag = p_tag;
	iom_cardp = null ();
	call config_$find_2 (IOM_CARD_WORD, (tag), iom_cardp);
	if iom_cardp = null () then
	     goto IOM_NOT_CONFIGURED;

	idp = addr (ioi_data$);
	iom_data_ptr = addr (iom_data$);
	io_config_data_ptr = addr (io_config_data$);
	io_config_iom_table_ptr = ptr (io_config_data_ptr, io_config_data.iom_table_offset);
	do itx = lbound (ioi_data.it, 1) to hbound (ioi_data.it, 1);
	     itep = addr (ioi_data.it (itx));
	     if tag = ite.tag then
		return;
	end;

IOM_NOT_CONFIGURED:
	p_code = error_table_$io_not_defined;
	goto ERROR_RETURN;

     end setup_and_find_iom_entry;

/* Procedure to ensure that the toehold has a non-deleted path to RPV when deleting a channel. */

ensure_rpv_path_in_toehold:
     proc;

dcl	iomno		   fixed bin (3);
dcl	channo		   fixed bin (7);
dcl	iopx		   fixed bin;
dcl	saved_ctep	   ptr;
dcl	saved_iopx	   fixed bin;
dcl	toehold_channel_left   bit (1) aligned;

dcl	1 path_word	   aligned,
	  2 port		   fixed bin (3) uns unal,
	  2 iom		   fixed bin (15) uns unal,
	  2 channel	   fixed bin unal;

dcl	path_word_as_integer   fixed bin (35) based (addr (path_word));

dcl	1 toehold$	   ext like toe_hold;

	call io_chnl_util$name_to_iom (cte.chanid, iomno, channo, (0));

	do iopx = lbound (toehold$.paths, 1) to hbound (toehold$.paths, 1);
	     if (toehold$.paths (iopx).iom_number = iomno) & (toehold$.paths (iopx).channel_number = channo) then
		goto FOUND_TOEHOLD_CHANNEL;
	end;
	return;					/* no problem since toehold doesn't use this channel */

FOUND_TOEHOLD_CHANNEL:
	saved_iopx = iopx;
	toehold_channel_left = "0"b;
	do iopx = lbound (toehold$.paths, 1) to hbound (toehold$.paths, 1) while (^toehold_channel_left);
	     if iopx ^= saved_iopx then
		if toehold$.paths (iopx).channel_number ^= 0 then
		     toehold_channel_left = "1"b;
	end;
	if toehold_channel_left then do;
	     call set_toehold_path (saved_iopx, 0);
	     return;				/* not to worry */
	end;

/**** We must find another channel and put it in the toehold ****/

	saved_ctep = ctep;
	do ctep = ptr (ctep, ptr (ctep, cte.gtep) -> gte.ctep) repeat ptr (ctep, cte.next_ctep)
	     while (cte.deleted | cte.deleting | (cte.base_ctep ^= rel (ctep)));
	end;
	call io_chnl_util$name_to_iom (cte.chanid, iomno, channo, (0));
	call config_$find_2 (IOM_CARD_WORD, (iomno), iom_cardp);
	path_word.port = iom_card.port;
	path_word.iom = iomno;
	path_word.channel = channo;
	call set_toehold_path (saved_iopx, path_word_as_integer);
	ctep = saved_ctep;
	return;

set_toehold_path:
	proc (path_idx, path_word_value);

dcl	path_idx		   fixed bin;
dcl	path_word_value	   fixed bin (35);
dcl	path_word_ptr	   ptr;

dcl	path_word		   fixed bin (35) based (path_word_ptr);

	     path_word_ptr = addr (toehold$.paths (path_idx).port_number);
	     path_word = path_word_value;

	end set_toehold_path;

     end ensure_rpv_path_in_toehold;

quit_if_error:
     proc;

	if code ^= 0 then
	     call ABORT (code);

     end quit_if_error;

ABORT:
     proc (a_code);

dcl	a_code		   fixed bin (35);

	call CLEANUP ();
	p_code = a_code;
	goto ERROR_RETURN;

     end ABORT;


CLEANUP:
     proc ();

	if (gtep ^= null ()) & (ctep ^= null ()) & (state_changed) then do;
	     if deleting_channel then do;
		if usurped_channel then do;
		     if gte.disk_data_subsystem_idx > 0 then
			call ioi_usurp_channels$unassign (gtep, (0));
		     else if ^gte.mplex & cte.chx > 0 then do;
			call io_manager$unassign (cte.chx, (0));
			cte.ioi_use = "0"b;
		     end;
		end;
		cte.deleted = "0"b;
		cte.deleting = "0"b;
	     end;
	     else if adding_channel then do;
		if gte.disk_data_subsystem_idx ^= 0 then
		     call ioi_usurp_channels$assign (gtep, code);
		else if ^gte.mplex & cte.chx > 0 then do;
		     call io_manager$assign (cte.chx, chanid, io_manager$ignore_interrupt, DUMMY_INDEX, cv_status_ptr,
			code);
		     if code = 0 then
			cte.statusp = cv_status_ptr;
		end;
		cte.deleted = "1"b;
	     end;
	end;
	if locked then
	     call ioi_assignment$unlock_for_reconfig;

     end CLEANUP;

lock_for_reconfig:
     proc;

	call ioi_assignment$lock_for_reconfig;
	locked = "1"b;

     end lock_for_reconfig;

unlock_for_reconfig:
     proc;

	call ioi_assignment$unlock_for_reconfig;
	locked = "0"b;

     end unlock_for_reconfig;

get_chnl_del_info:
     proc (arg_gtep, arg_ctep, arg_base_chnl, arg_rel_chnl_active, arg_grp_chnl_active);

/* Automatic */

dcl	cptr		   ptr;
dcl	ctx		   fixed bin;
dcl	gptr		   ptr;
dcl	my_base_rptr	   bit (18) aligned;

/* Parameter */

dcl	arg_base_chnl	   bit (1) aligned;
dcl	arg_ctep		   ptr;
dcl	arg_grp_chnl_active	   bit (1) aligned;
dcl	arg_gtep		   ptr;
dcl	arg_rel_chnl_active	   bit (1) aligned;

	arg_rel_chnl_active, arg_grp_chnl_active = "0"b;
	arg_base_chnl = (arg_ctep -> cte.base_ctep = rel (arg_ctep));

	my_base_rptr = arg_ctep -> cte.base_ctep;
	gptr = arg_gtep;

	do ctx = 1 to ioi_data.nct;
	     cptr = addr (ioi_data.ct (ctx));
	     if ^(cptr -> cte.deleted | cptr = arg_ctep) then do;
		if cptr -> cte.base_ctep = my_base_rptr then
		     arg_rel_chnl_active = "1"b;
		else if cptr -> cte.gtep = rel (gptr) then
		     arg_grp_chnl_active = "1"b;
	     end;
	end;

     end get_chnl_del_info;

get_chnl_add_info:
     proc (arg_ctep, arg_itep, arg_base_chnl, arg_iom_active);

/* Parameter */

dcl	arg_base_chnl	   bit (1) aligned;
dcl	arg_ctep		   ptr;
dcl	arg_iom_active	   bit (1) aligned;
dcl	arg_itep		   ptr;

	if ^arg_itep -> ite.deleted then
	     arg_iom_active = "1"b;
	else arg_iom_active = "0"b;

	arg_base_chnl = (arg_ctep -> cte.base_ctep = rel (arg_ctep));

     end get_chnl_add_info;

get_device_info:
     proc (arg_gtep, arg_ctep, arg_device_active, arg_chnl_required);

/* Automatic */

dcl	chanid		   char (8) aligned;
dcl	done		   bit (1) aligned;
dcl	dptr		   ptr;
dcl	gptr		   ptr;
dcl	initial_dtep	   bit (18);

/* Parameter */

dcl	arg_chnl_required	   bit (1) aligned;
dcl	arg_ctep		   ptr;
dcl	arg_device_active	   bit (1) aligned;
dcl	arg_gtep		   ptr;

	arg_device_active, arg_chnl_required = "0"b;
	chanid = arg_ctep -> cte.chanid;
	gptr = arg_gtep;

	initial_dtep = gptr -> gte.dtep;
	done = "0"b;
	do dptr = ptr (arg_ctep, initial_dtep) repeat ptr (dptr, dptr -> dte.next_dtep) while (^done);
	     if ^(dptr -> dte.deleted) then do;
		arg_device_active = "1"b;
		if dptr -> dte.channel_required = chanid then
		     arg_chnl_required = "1"b;
	     end;
	     done = (dptr -> dte.next_dtep = initial_dtep);
	end;

     end get_device_info;

get_ctep:
     proc (arg_chanid, arg_ctep, arg_code);

/* Automatic */

dcl	i		   fixed bin;

/* Parameter */

dcl	arg_chanid	   char (8) aligned;
dcl	arg_code		   fixed bin (35);
dcl	arg_ctep		   ptr;

	arg_ctep = null;
	arg_code = 0;

	do i = 1 to ioi_data.nct;
	     if ioi_data.ct (i).chanid = arg_chanid then do;
		arg_ctep = addr (ioi_data.ct (i));
		return;
	     end;
	end;

	arg_code = error_table_$bad_channel;

     end get_ctep;


get_gtep:
     proc (arg_ctep, arg_gtep);

/* Parameter */

dcl	arg_ctep		   ptr;
dcl	arg_gtep		   ptr;

	arg_gtep = ptr (arg_ctep, arg_ctep -> cte.gtep);

     end get_gtep;


get_itep:
     proc (arg_ctep, arg_itep);

/* Parameter */

dcl	arg_ctep		   ptr;
dcl	arg_itep		   ptr;

	arg_itep = ptr (arg_ctep, arg_ctep -> cte.itep);

     end get_itep;

%include config_iom_card;
%page;
%include dskdcl;
%page;
%include ioi_data;
%page;
%include io_config_data;
%page;
%include io_manager_dcls;
%page;
%include io_chnl_util_dcls;
%page;
%include iom_data;
%page;
%include syserr_constants;
%page;
%include toe_hold;

     end io_reconfig;
 



		    reconfig.pl1                    11/11/89  1135.2r w 11/11/89  0800.0      189954



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

/* This program is the ring zero portion of the dynamic reconfiguration software
   for system controllers and processors. It is callable only through hphcs_ and assumes
   the caller has validated the arguments so that they within proper range.

   Modified March 1976 by Steve Webber -- Initial coding
   modified 4/6/76 by Noel I. Morris
   last modified 4/13/78 by J. A. Bush to add code for cpu testing
   Modified 16 Feb 79 by D. Spector to recompute write_limit when reconfiguring memory
   Modified 09/11/80 by J. A. Bush for the DPS8/70M cpu
   Modified April 1982 by J. Bongiovanni for expanded SCS switch/mask
   Modified June 1982 by J. Bongiovanni to fix bug in adding an SCU with
   less memory than the port size
   Modified Sept 1983 by J. A. Bush to increase ISOLTS required memory to 128K for DPS8 cpus
   Modified 6/14/83 by S. Krupp to add rc_lock entry.

*/
/* format: style4,delnl,insnl,indattr,ifthen,dclind10 */

reconfig:
     proc;

/* Parameters */

dcl	tag		   fixed bin (3);
dcl	(cpu_tag, scu_tag, scu_port)
			   fixed bin (5);
dcl	switches		   (4) bit (36) aligned;
dcl	lace		   bit (1) aligned;
dcl	badtag		   fixed bin (3);
dcl	code		   fixed bin (35);
dcl	first_frame	   fixed bin;
dcl	n_frames		   fixed bin;
dcl	(rci_ptr, wseg_p)	   ptr;

/* Automatic */

dcl	tcode		   fixed bin (35);
dcl	errtag		   fixed bin (3);
dcl	first		   fixed bin (3);
dcl	last		   fixed bin (3);
dcl	(i, k)		   fixed bin;
dcl	j		   fixed bin (3);
dcl	vl		   fixed bin (3);
dcl	req_mem		   fixed bin;
dcl	size		   fixed bin;
dcl	base		   fixed bin;
dcl	top		   fixed bin;
dcl	abs_seg_p		   ptr;
dcl	p_mess		   bit (1);
dcl	switchesp		   ptr;
dcl	1 tsdw		   aligned like sdw;

/* Based */

dcl	based_switches	   (4) bit (36) aligned based (switchesp);

/* External */

dcl	error_table_$bad_subr_arg fixed bin(35) ext static;
dcl	pds$processid	   bit (36) aligned ext;
dcl	pds$process_group_id   char (32) aligned ext;
dcl	isolts_abs_seg$	   ext;

/* Entries */

dcl	syserr		   entry options (variable);
dcl	start_cpu		   entry (fixed bin (3), fixed bin (35));
dcl	configure_test_cpu	   entry (fixed bin (35));
dcl	configure_test_cpu$isolts_final
			   entry;
dcl	level$get		   entry returns (fixed bin (3));
dcl	privileged_mode_ut$swap_sdw
			   entry (ptr, ptr);
dcl	config_$find_2	   entry (char (4) aligned, fixed bin, ptr);
dcl	config_$update	   entry ();
dcl	stop_cpu		   entry (fixed bin (3), fixed bin (35));
dcl	add_scu		   entry (fixed bin (3), fixed bin (3), fixed bin (35));
dcl	freecore		   entry (fixed bin);
dcl	pc_abs$remove_core	   entry (fixed bin, fixed bin, fixed bin (35));
dcl	add_scu$remove_scu	   entry (fixed bin (3));
dcl	validate_cpu_card	   entry (fixed bin (3), ptr);

/* Builtins */

dcl	(addr, bin, bit, divide, hbound, max, mod, null, rel, stac, stacq, string, substr, unspec)
			   builtin;

/* constants */

dcl	letters		   char (15) int static options (constant) init ("abcdefghijklmo");

/*
   ADD_CPU               ADD_CPU               ADD_CPU

   This entry is called to add a processor to the system

*/

add_cpu:
     entry (tag, switches, code);

	if check_lock () then
	     return;				/* not locked to us */

	if scs$processor_data (tag).online then do;	/* If already online ... */
	     code = rcerr_online;
	     call UNLOCK;
	     return;
	end;

	if ^scs$processor_data (tag).offline then do;	/* If not offline ... */
	     code = rcerr_no_config;
	     call UNLOCK;
	     return;
	end;

	call start_cpu (tag, tcode);			/* do the work */

/* Perform error checking and recovery. */

	if tcode ^= 0 then do;
	     code = tcode;				/* Return the error code. */
	     switchesp = addr (scs$processor_switch_compare (1));
	     switches = based_switches;		/* Return switch 1-4 descrepancies */

	end;

	call UNLOCK;

	return;

/*
   DEL_CPU               DEL_CPU               DEL_CPU


   This entry is called to delete a processor from the system

*/

del_cpu:
     entry (tag, code);

	if check_lock () then
	     return;

	if ^scs$processor_data (tag).online then do;	/* If not online ... */
	     code = rcerr_not_online;
	     call UNLOCK;
	     return;
	end;

	if scs$nprocessors <= 1 then do;		/* If only one processor ... */
	     code = rcerr_delcpu_last;
	     call UNLOCK;
	     return;
	end;

	call stop_cpu (tag, tcode);
	if tcode ^= 0 then
	     code = tcode;

	call UNLOCK;

	return;

/*
   ADD_SCU               ADD_SCU               ADD_SCU

   This entry is called to add a system controller and its memory to the system. If the
   system controller is one of a pair of externally interlaced
   controllers, both controllers are added.

*/

add_scu:
     entry (tag, lace, badtag, code);

	if check_lock () then
	     return;

	if scs$controller_data (tag).online then do;	/* If already online ... */
	     code = rcerr_online;
	     call UNLOCK;
	     return;
	end;
	if ^scs$controller_data (tag).offline then do;	/* If not offline ... */
	     code = rcerr_no_config;
	     call UNLOCK;
	     return;
	end;
	if scs$controller_data (tag).ext_interlaced then do;
	     first = tag - mod (tag, 2);
	     last = first + 1;
	     lace = "1"b;
	end;
	else do;
	     first, last = tag;
	     lace = "0"b;
	end;

	do j = first to last;
	     call add_scu (j, errtag, tcode);
	     if tcode ^= 0 then do;
		code = tcode;			/* Return the error code. */
		badtag = errtag;

		if (first ^= last) & (j = last) then	/* must undo for first */
		     call add_scu$remove_scu (first);

		call UNLOCK;

		return;
	     end;
	end;

	do j = first to last;
	     call free_all_of (j);
	end;

	call UNLOCK;

	call recompute_write_limit;

	return;

/*
   DEL_SCU               DEL_SCU               DEL_SCU


   This entry is called to delete a system controller and its memory from the system. If the system
   controller is one of a pair of externally interlaced controllers, the
   other controller of the pair is also deleted.

*/

del_scu:
     entry (tag, lace, code);

	if check_lock () then
	     return;

	if ^scs$controller_data (tag).online then do;
	     code = rcerr_not_online;
	     call UNLOCK;
	     return;
	end;
	if scs$controller_data (tag).ext_interlaced then do;
	     first = tag - mod (tag, 2);
	     last = first + 1;
	     lace = "1"b;
	end;
	else do;
	     first, last = tag;
	     lace = "0"b;
	end;

	do j = first to last;
	     base = scs$controller_data (j).base;
	     size = scs$controller_config_size (j);


	     call pc_abs$remove_core (base, size, tcode);
	     if tcode ^= 0 then do;
		if (first ^= last) & (j ^= first) then
		     call free_all_of (first);

		call UNLOCK;

		if tcode = 1 then
		     code = rcerr_delmain_nomem;
		else if tcode = 2 then
		     code = rcerr_delmain_abs_wired;
		else code = tcode;

		return;
	     end;
	end;

	do j = first to last;
	     call add_scu$remove_scu (j);
	end;

	call UNLOCK;

	call recompute_write_limit;

	return;

/*
   ADD_MAIN              ADD_MAIN              ADD_MAIN


   This entry is used to add a subregion of a controller to the system.

*/

add_main:
     entry (first_frame, n_frames, code);

	if check_lock () then
	     return;

	if check_range () then
	     return;

	do k = first_frame to first_frame + n_frames - 1;
	     call freecore (k);
	end;

	call UNLOCK;

	call recompute_write_limit;

	return;




/*
   DEL_MAIN              DEL_MAIN              DEL_MAIN


   This entry is used to remove selected regions of a controller from the system

*/

del_main:
     entry (first_frame, n_frames, code);

	if check_lock () then
	     return;

	if check_range () then
	     return;

	call pc_abs$remove_core (first_frame, n_frames, tcode);
	if tcode ^= 0 then do;
	     if tcode = 1 then
		code = rcerr_delmain_nomem;
	     else if tcode = 2 then
		code = rcerr_delmain_abs_wired;
	     else code = tcode;
	end;

	call UNLOCK;

	call recompute_write_limit;

	return;

/*	RECOMPUTE_WRITE_LIMIT		RECOMPUTE_WRITE_LIMIT

   When memory is reconfigured, write_limit is set to 1/8 of pages used
   (but no less than 30).  This overrides any explicit change via
   change_tuning_parameters.

*/

recompute_write_limit:
     proc;

declare  sst$write_limit	  fixed bin (35) external static;
declare  sst$nused		  fixed bin (35) external static;

	sst$write_limit = max (30, divide (sst$nused, 8, 17, 0));

     end;

/*
   RC_FORCE_UNLOCK       RC_FORCE_UNLOCK       RC_FORCE_UNLOCK


   This entry is called to unlock the reconfig lock.

*/

rc_unlock:
     entry;

	if scs$reconfig_lock ^= pds$processid then
	     return;				/* not locked to us */


rc_force_unlock:
     entry;

	call UNLOCK;

	return;


/*
   RC_LOCK               RC_LOCK               RC_LOCK

   This entry is called to set the reconfiguration lock.

   If the lock is already locked, the error code set by check_lock
   is returned. Otherwise, check_lock locks the lock and a code of 0
   is returned.
*/

rc_lock:
     entry (code);

	if ^check_lock () then
	     code = 0;

	return;


/* UNLOCK                UNLOCK                UNLOCK */

UNLOCK:
     proc;

	if ^stacq (scs$reconfig_lock, (36)"0"b, scs$reconfig_lock) then
	     call syserr (0, "reconfig: trouble unlocking scs$reconfig_lock");

     end UNLOCK;



/* CHECK_LOCK            CHECK_LOCK            CHECK_LOCK */

check_lock:
     proc returns (bit (1) aligned);

	code = 0;

	if ^stac (addr (scs$reconfig_lock), pds$processid) then do;
	     code = rcerr_locked;
	     return ("1"b);
	end;

	else do;
	     scs$reconfig_locker_id = pds$process_group_id;
	     return ("0"b);
	end;


     end check_lock;

/* FREE_ALL_OF           FREE_ALL_OF           FREE_ALL_OF */

free_all_of:
     proc (mem);

dcl	mem		   fixed bin (3);

dcl	i		   fixed bin;
dcl	base		   fixed bin;
dcl	top		   fixed bin;

	base = scs$controller_data (mem).base;
	top = scs$controller_config_size (mem) + base - 1;
	do i = base to top;
	     call freecore (i);
	end;

     end free_all_of;



/* CHECK_RANGE           CHECK_RANGE           CHECK_RANGE */

check_range:
     proc returns (bit (1) aligned);

dcl	i		   fixed bin;
dcl	base		   fixed bin;
dcl	top		   fixed bin;

	if n_frames < 0 then do;
	     code = error_table_$bad_subr_arg;
	     goto check_range_error;
	end;

	do i = 0 to 7;
	     if scs$controller_data (i).online then do;
		base = scs$controller_data (i).base;
		top = base + scs$controller_config_size (i) - 1;
		if (first_frame >= base) & (first_frame + n_frames - 1 <= top) then
		     return ("0"b);
	     end;
	end;

	code = rcerr_range;
check_range_error:
	call UNLOCK;

	return ("1"b);

     end check_range;

/*
   RECONFIG_INFO         RECONFIG_INFO         RECONFIG_INFO


   This entry is used to return information about the current configuration. The reconfig lock in
   scs is also set. If the lock is not settable (locked to other logged in process) the
   process_group_id of that process is returned, along with an error code

*/

reconfig_info:
     entry (rci_ptr, code);

	if ^stac (addr (scs$reconfig_lock), pds$processid) then do;
	     rci_ptr -> rci.locker_group_id = scs$reconfig_locker_id;
	     code = rcerr_locked;
	     return;
	end;

	code = 0;
	scs$reconfig_locker_id = pds$process_group_id;

/* Now copy the data from the SCS */

	rci_ptr -> rci.controller_data = scs$controller_data;
	rci_ptr -> rci.processor_data = scs$processor_data;

	return;

/*
   CHECK_RESOURCE	CHECK_RESOURCE	CHECK_RESOURCE


   This entry is the initial entry for the ISOlTS reconfiguration software. It is called by the ISOLTS driver
   to check if the Processor and Memory resources required to test a CPU are present. Note that the reconfig
   lock is set upon entry but is not reset on exit. The reconfig lock will remain set until the destroy_cpu_test_env
   entry is called.
*/

check_resource:
     entry (cpu_tag, scu_tag, scu_port, code);

	code = 0;					/* preset return code  to 0 */

	if check_lock () then do;			/* lock reconfig lock if possible */
	     code = rcerr_isolts_locked;		/* data base already locked */
	     return;
	end;

	if cpu_tag > hbound (scs$processor_data, 1) then do;
						/* trying to test non existant cpu */
	     code = rcerr_isolts_illegal_cpu;
	     call UNLOCK;				/* unlock reconfig lock */
	     return;
	end;

	if scs$processor_data (cpu_tag).online then do;	/* cpu must be offline */
	     code = rcerr_isolts_cpu_online;
	     call UNLOCK;
	     return;
	end;

	if ^scs$processor_data (cpu_tag).offline then do; /* trying to test cpu that is not configured */
	     code = rcerr_isolts_no_config;
	     call UNLOCK;
	     return;
	end;

	if scu_tag = -1 then do;			/* We will determine which SCU to use */

/* find scu that is not zero based and has the smallest amount of memory */

	     k = -1;
	     do i = 0 to hbound (scs$controller_data, 1); /* iterate through all possible scu's */
		if scs$controller_data (i).online then	/* if scu online */
		     if scs$controller_data (i).base ^= 0 then
						/* and not zero based */
			if scs$controller_data (i).size >= 128 then
						/* and if memory size is at least 128k */
			     if ^scs$controller_data (i).abs_wired then
						/* and no abs wired pages */
				if ^scs$controller_data (i).ext_interlaced then
						/* and not ext interlaced */
				     if k ^= -1 then/* not first time through */
					if scs$controller_data (i).size <
						/* if size of this scu is less */
					     scs$controller_data (k).size then
						/* then previous saved */
					     k = i;
						/* save this tag */
					else ;
				     else k = i;	/* first time through, save this tag */
	     end;

	     if k = -1 then do;			/* Not enough SCUs to continue */
		code = rcerr_isolts_two_scu;
		call UNLOCK;
		return;
	     end;
	     scu_tag = k;				/* save the scu tag to return to user */
	end;

	else do;					/* user wants to run with particular SCU */

	     if scu_tag > hbound (scs$controller_data, 1) then do;
						/* check it for legality */
		code = rcerr_isolts_illegal_scu;
		call UNLOCK;
		return;
	     end;

	     if scu_tag = scs$interrupt_controller then do;
						/* can't use bootload controller */
		code = rcerr_isolts_bootload_scu;
		call UNLOCK;
		return;
	     end;

	     if ^scs$controller_data (scu_tag).online then do;
						/* scu must be online */
		code = rcerr_isolts_scu_not;
		call UNLOCK;
		return;
	     end;

	end;

	scu_port = scs$processor_data (cpu_tag).controller_port;
						/* set port for user */

	return;					/*  return with no error and reconfig lock locked */

/*
   CREATE_CPU_TEST_ENV	CREATE_CPU_TEST_ENV	CREATE_CPU_TEST_ENV


   This entry is called by the ISOLTS driver after  manual reconfiguration of a CPU to test and the SCU to be
   used for testing is accomplished by the Operator.

*/

create_cpu_test_env:
     entry (cpu_tag, scu_tag, switches, wseg_p, code);

	code = 0;					/* preset return code */
	wseg_p = null;				/* set work seg ptr to null initially */

	if scs$reconfig_lock ^= pds$processid then do;	/* not locked to us */
	     code = rcerr_isolts_not;
	     return;
	end;
	scs$processor_test_data.cpu_tag = cpu_tag;	/* initialize  processor_test_data structure */
	scs$processor_test_data.scu_tag = scu_tag;
	scs$processor_test_data.scu_state = "00"b;
	scs$processor_test_data.active = "1"b;		/* set active flag */

	call configure_test_cpu (tcode);		/* go do the work */
	switchesp = addr (scs$processor_switch_compare (1));
	switches = based_switches;			/* return switch info 1-4 */
	if tcode ^= 0 then do;			/* bad problems */
	     call destroy_cpu_test_env_no_mess;		/* give back all resources */
	     code = tcode;
	     return;
	end;
	abs_seg_p = addr (isolts_abs_seg$);		/* get ptr to isolts_abs_seg */
	req_mem = scs$processor_test_data.req_mem;	/* get auto copy of memory required */

/* set up an sdw for isolts_abs_seg that points to the base of our scu */

	vl = level$get ();				/* get users current validation level */
	string (tsdw) = "0"b;
	tsdw.add = bit (bin (scs$controller_data (scu_tag).base * 1024, 24), 24);
	tsdw.r1, tsdw.r2, tsdw.r3 = bit (bin (vl, 3), 3); /* set ring brks to users validation level */
	tsdw.df = "1"b;				/* do not want seg fault on this segment */
	tsdw.read = "1"b;
	tsdw.write = "1"b;				/* set read and write access for user */
	tsdw.unpaged = "1"b;			/* this is an unpaged segment */
	tsdw.bound = bit (bin (divide (req_mem * 1024, 16, 14) - 1, 14), 14);
						/* set bounds for <req_mem>k */
	call privileged_mode_ut$swap_sdw (abs_seg_p, addr (tsdw));
						/* swap new sdw with current one */
	wseg_p = abs_seg_p;				/* give ptr to isolts abs seg to user */
	call config_$find_2 (CPU_CARD_WORD, cpu_tag + 1, cpu_cardp);
						/* set up target cpu card */
	cpu_card.state = "test";			/* for test state */
	call config_$update ();
	call validate_cpu_card ((cpu_tag), addr (scs$processor_switch_compare (2)));
						/* validate cpu type and model */

	call syserr (0, "reconfig: Assigned CPU ^a to ^a for testing",
						/* tell operator what we are doing */
	     substr (letters, cpu_tag + 1, 1), pds$process_group_id);
	call syserr (0, "reconfig: Using base ^dk of MEM ^a for testing CPU ^a", req_mem,
	     substr (letters, scu_tag + 1, 1), substr (letters, cpu_tag + 1, 1));

	return;					/* return to caller */

/*
   DESTROY_CPU_TEST_ENV	DESTROY_CPU_TEST_ENV	DESTROY_CPU_TEST_ENV

   This entry is called by the ISOLTS driver to undo any reconfiguration that was done for cpu testing.
   It is also called by the answering service hardcore module deact_proc if the condition of the reconfig_lock is set
   with the process_id of the process in termination and the processor_test_data.active flag is on.
   this acts as a system cleanup handler in case of ISOLTS process abnormal termination.

*/

destroy_cpu_test_env:
     entry;

	p_mess = "1"b;				/* set flag to display unassign message */
	go to destroy_test_env_com;			/* go join common code */

destroy_cpu_test_env_no_mess:
     entry;

	p_mess = "0"b;				/* reset flag do not print unassign messages */

destroy_test_env_com:
	if scs$processor_test_data.active then do;	/* if test active */
	     call configure_test_cpu$isolts_final;	/* give back SCU and memory to system */
	     abs_seg_p = addr (isolts_abs_seg$);	/* destroy users sdw to isolts_abs_seg */
	     string (tsdw) = "0"b;
	     call privileged_mode_ut$swap_sdw (abs_seg_p, addr (tsdw));
	     call config_$find_2 (CPU_CARD_WORD, scs$processor_test_data.cpu_tag + 1, cpu_cardp);
	     cpu_card.state = "off ";			/* reset cpu state to off */
	     call config_$update ();
	     if p_mess then do;			/* only output messages if entry by destroy_cpu_test_env */
		call syserr (0, "reconfig: Unassigned CPU ^a from ^a",
						/* tell operator what we are doing */
		     substr (letters, scs$processor_test_data.cpu_tag + 1, 1), scs$reconfig_locker_id);
		call syserr (0, "reconfig: Releasing base ^dk of MEM ^a", scs$processor_test_data.req_mem,
		     substr (letters, scs$processor_test_data.scu_tag + 1, 1));
	     end;
	     unspec (scs$processor_test_data) = "0"b;	/* initialize test data structure */
	end;

/* reset reconfig_lock, and return */

	call UNLOCK;

	return;

%include config_cpu_card;
%page;
%include scs;
%page;
%include sdw;
%page;
%include rcerr;
%include rci;

/* BEGIN MESSAGE DOCUMENTATION

   Message:
   reconfig: trouble unlocking scs$reconfig_lock

   S:	$info

   T:	$run

   M:	The reconfiguration lock
   could not be unlocked.
   It is left in its current state.
   Further attempts at reconfiguration may fail.

   A:	$ignore

   Message:
   reconfig: Assigned CPU <cputag> to <Person.Project.instance> for testing

   S: $info

   T: $run

   M: Successful reconfiguration of the indicated processor has been
   performed by the processor testing (ISOLTS) subsystem.

   A: $ignore

   Message:
   reconfig: Using base <req_mem>k of MEM <scutag> for testing CPU cputag

   S: $info

   T: $run

   M: Successful reconfiguration of the indicated memory has been
   performed by the processor testing (ISOLTS) subsystem.

   A: $ignore

   Message:
   reconfig: Unassigned CPU <cputag> from <Person.Project.instance>

   S: $info

   T: $run

   M: Processor testing has been terminated and the indicated
   processor is now available for reconfiguration.

   A: $ignore

   Message:
   reconfig: Releasing base <req_mem>k of MEM <scutag>

   S: $info

   T: $run

   M: Processor testing has been terminated and the indicated
   memory is now available for reconfiguration.

   A: $ignore

   END MESSAGE DOCUMENTATION */

     end reconfig;
  



		    start_cpu.pl1                   11/11/89  1135.2r w 11/11/89  0800.0      245799



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


/****^  HISTORY COMMENTS:
  1) change(86-10-23,Fawcett), approve(86-10-23,MCR7517),
     audit(86-10-30,Beattie), install(86-11-03,MR12.0-1206):
     Changed to remove the word BOS from Error message documentation.
                                                   END HISTORY COMMENTS */


/* START_CPU - Start Up a Processor.
   Last Modified: (Date and Reason)
   10/04/83 by Keith Loepere for paged idle_dsegs.
   04/09/84 by Chris Jones to update config deck to its partition when changed.
   04/09/82 by J. Bongiovanni to check data switches on non-bootload CPU
   12/30/81 by J. A. Bush to interagate cpu switches when cpu types are different
   11/11/81 by J. A. Bush to not check ID PROM on the bootload CPU
   10/22/81 by J. Bongiovanni for set_procs_required
   03/05/81 by J. Bongiovanni to set segment bound and access for prds
   on non-bootload CPUs
   09/08/80 by J. A. Bush for the DPS8/70M CPU
   02/05/79 by B. Greenberg for port expanders.
   02/05/76 by Steve Webber & Noel Morris as part of reconfiguration rewrite
   08/12/71 by Richard H. Gumpertz to take out the call to move subroutine
   7/14/72 by Craig Jensen to convert for the follow-on 645.
*/

/* format: style4,delnl,insnl,indattr,ifthen,dclind10 */
start_cpu:
     proc (tag, rcode);

dcl	tag		   fixed bin (3),
	rcode		   fixed bin (35);

dcl	abs_ptr		   ptr,			/* pointer to abs_seg$ */
	prds_sdwp		   ptr,			/* pointer to SDW for new prds */
	prds_sdw		   bit (72) aligned,	/* SDW for new prds */
	prds_astep	   ptr,			/* AST entry pointer for new prds */
	prds_no		   fixed bin (18),		/* segment number of prds */
	pdp		   ptr,			/* pointer to processor data for new CPU */
	old_pdp		   ptr,			/* pointer to processor data for CPU losing mask */
	old_tag		   fixed bin (3),		/* tag of CPU losing mask */
	found_mask	   bit (1) aligned,		/* "1"b when CPU with mask found */
	ptp		   ptr,			/* temporary for wire_and_mask */
	mask_temp		   fixed bin (71),		/* temporary for wire_and_mask */
	int_vec_save	   bit (36) aligned,	/* for saving interrupt vector */
	trouble_save	   bit (36) aligned,	/* for saving trouble fault vector */
	startup_save	   bit (36) aligned,	/* for saving startup fault vector */
	onc_save		   bit (36) aligned,	/* for saving onc fault vector */
	lockup_save	   bit (36) aligned,	/* for saving lockup fault vector */
	i		   fixed bin,		/* iteration variable */
	abs_seg_p		   ptr,			/* pointer to abs_seg */
	fv_iv_p		   ptr,			/* pointer to fault/interrupt vector template */
	switch_rel	   fixed bin (18),		/* place in template for switch readings */
	switchp		   ptr,			/* pointer to switch readings */
	rsw1_68p		   ptr,			/* points to rsw1 data for L68, for switch checking */
	rsw1_8p		   ptr,			/* points to rsw1 data for DPS8M, for switch checking */
	rsw4p		   ptr,			/* points to rsw4 data for switch checking */
	cmpp		   ptr,			/* points to rsw1 discrepancy data for switch checking */
	trgp		   ptr,			/* points to add target rsw1 data, for switch checking */
	(tbase, tsize)	   fixed bin (24),		/* port base and size in words, for switch checking */
	L68_prt_sze	   fixed bin (24),		/* used for computing true port size of L68 port */
	found		   bit (1) aligned,		/* useful flag */
	dps8_add		   bit (1) aligned,		/* cpu type flag for switch checking */
	remember		   (0:7) fixed bin,		/* base of controllers with vector template */
	base		   fixed bin,		/* base address of controller */
	tcode		   fixed bin (35),		/* temporary for error code */
	cpu_mask		   bit (8) aligned,		/* for set_procs_required */
	cpu_model		   char (13) aligned,	/* storage for cpu model number (from ID PROM) */
	cpu_serial	   char (13) aligned,	/* storage for cpu serial number (from ID PROM) */
	cpu_ship_date	   char (8) aligned;	/* storage for cpu ship date (from ID PROM) */

dcl	1 tsdw		   (0:7) aligned like sdw,	/* for saving abs_seg SDW's */
	1 tsdw1		   aligned like sdw,	/* automatic copy of SDW */
	fv_iv_copy	   (2048) fixed bin based (fv_iv_p),
						/* for copying vector template */
	based_switches	   (0:4) bit (36) aligned based (switchp);
						/* for checking switch readings */


dcl	LETTERS		   char (8) static options (constant) init ("ABCDEFGH");

dcl	abs_seg$		   ext,
	sst_seg$		   ext,
	idle_dsegs$	   (0:8 * 1024 - 1 /* max size */) bit (72) aligned ext,
	prds$		   ext,
	dseg$		   ext,
	fault_vector$	   ext,
	pds$processid	   bit (36) aligned ext,
	prds$idle_ptr	   ptr ext,
	prds$processor_tag	   fixed bin (3) ext,
	prds$processor_pattern bit (8) aligned ext,
	tc_data$prds_length	   fixed bin (18) ext,
	tc_data$ncpu	   fixed bin ext,
	fv_iv_template$fv_iv_template
			   ext,
	fv_iv_template$rsw_data
			   (4) bit (36) aligned ext,
	init_processor$wait_flag
			   fixed bin (35) ext,
	init_processor$new_dbr fixed bin (71) ext,
	init_processor$first_tra
			   bit (36) aligned ext,
	init_processor$trouble_tra
			   bit (36) aligned ext,
	init_processor$startup_tra
			   bit (36) aligned ext,
	init_processor$onc_tra bit (36) aligned ext,
	init_processor$lockup_tra
			   bit (36) aligned ext,
	init_processor$controller_data
			   bit (8) aligned ext,
	sys_info$system_type   fixed bin ext;

dcl	init_processor$start_bootload_cpu
			   entry,
	stop_cpu$destroy_1	   entry (fixed bin (3), fixed bin (35)),
	scr_util$reassign_mask entry (fixed bin (3), fixed bin (3)),
	scr_util$set_mask	   entry (fixed bin (3), fixed bin (3), bit (72) aligned),
	scr_util$set_port_enable
			   entry (fixed bin (3), bit (1) unal),
	scr_util$update_export_xipmsk
			   entry (fixed bin (3)),
	scr_util$set_export_enable
			   entry (fixed bin (3), fixed bin (3), bit (1) aligned),
	mask_instruction$smcm  entry returns (bit (36) aligned),
	mask_instruction$rmcm  entry returns (bit (36) aligned),
	config_$find_2	   entry (char (4) aligned, fixed bin, ptr),
	config_$update	   entry (),
	syserr		   entry options (variable),
	syserr$error_code	   entry options (variable),
	privileged_mode_ut$swap_sdw
			   entry (ptr, ptr),
	privileged_mode_ut$smic
			   entry (bit (36) aligned),
	privileged_mode_ut$cioc
			   entry (ptr),
	privileged_mode_ut$wire_and_mask
			   entry (fixed bin (71), ptr),
	privileged_mode_ut$unwire_unmask
			   entry (fixed bin (71), ptr),
	privileged_mode_ut$read_id_prom
			   entry (char (*) aligned, fixed bin),
	validate_cpu_card	   entry (fixed bin (3), ptr),
	wire_proc$wire_me	   entry,
	get_ptrs_$given_astep  entry (ptr) returns (bit (72)),
	wire_proc$unwire_me	   entry,
	set_procs_required	   entry (bit (8) aligned, fixed bin (35)),
	pc_wired$wire_wait	   entry (ptr, fixed bin, fixed bin),
	pc_abs$remove_core	   entry (fixed bin, fixed bin, fixed bin (35)),
	freecore		   entry (fixed bin),
	prds_init		   entry (ptr, fixed bin (3), ptr),
	pxss$thread_in_idle	   entry (ptr);

dcl	1 pdata		   like scs$processor_data based (pdp) aligned;
						/* single element of processor data */
dcl	1 opdata		   like scs$processor_data based (old_pdp) aligned;
						/* Old interrupt CPU's pdata */

dcl	(addr, baseno, bin, bit, bool, divide, fixed, ptr, rel, stac, stacq, string, substr, unspec)
			   builtin;
%page;
	abs_ptr = addr (abs_seg$);			/* set pointer to abs_seg$ */
	prds_sdwp = addr (prds_sdw);

	fgbxp = addr (flagbox$);			/* Get pointer to flagbox. */


/* Fill in APT entry for idle process. */

	aptep = scs$idle_aptep (tag);			/* get pointer to previously allocated APTE */
	apte.processid = rel (aptep) || (6)"101"b;	/* set process ID */
	apte.flags.loaded = "1"b;			/* loaded and elegible */
	apte.flags.eligible = "1"b;
	apte.flags.idle = "1"b;			/* it is idle proc */
	apte.flags.default_procs_required = "0"b;	/* not system default */
	apte.procs_required = "0"b;
	substr (apte.procs_required, tag + 1, 1) = "1"b;	/* the CPU we want */
	apte.flags.state = bit (bin (2, 18));		/* set state to ready */
	apte.timax = 16000000;			/* low priority */
	call pxss$thread_in_idle (aptep);		/* thread entry into ready list */


/* Initialize PRDS. */

	if tag = scs$bos_processor_tag then
	     prds$idle_ptr = aptep;
	else do;					/* cpu is not bootload-cpu */
	     prds_astep = ptr (addr (sst_seg$), apte.prds);
	     prds_sdw = get_ptrs_$given_astep (prds_astep);
	     addr (prds_sdw) -> sdw.access = addr (dseg$) -> sdwa.access (fixed (baseno (addr (prds$)), 18));
	     addr (prds_sdw) -> sdw.bound = bit (divide (tc_data$prds_length - 1, 16, 14), 14);
	     call pc_wired$wire_wait (prds_astep, 0, divide (tc_data$prds_length + 1023, 1024, 17, 0));
						/* wire down prds */
	     prds_no = bin (baseno (addr (prds$)), 18);
	     do i = 0 to tag - 1;
		if scs$processor_data (i).offline | scs$processor_data (i).online then
		     if sys_info$system_type = ADP_SYSTEM then
			prds_no = prds_no + 1024;
		     else prds_no = prds_no + 512;	/* size of dsegs reserved for them */
	     end;
	     idle_dsegs$ (prds_no) = prds_sdw;
	     call privileged_mode_ut$swap_sdw (abs_ptr, prds_sdwp);
						/* abs_seg is the new prds. */
	     call prds_init (abs_ptr, tag, aptep);	/* Initialize prds. */
	end;
%page;
/* Assign a system controller mask to the processor. */

	pdp = addr (scs$processor_data (tag));		/* Get pointer to processor data. */
	found_mask = "0"b;				/* Initialize flag. */
	if ^pdata.interrupt_cpu then do;		/* If processor does not have a mask ... */
	     do old_tag = 0 to 7 while (^found_mask);
		old_pdp = addr (scs$processor_data (old_tag));
						/* Get pointer to other processor data. */
		if opdata.interrupt_cpu &		/* If this one gets interrupts and not BCE CPU ... */
		     (old_tag ^= scs$bos_processor_tag) then do;
		     found_mask = "1"b;		/* Got a candidate. */

		     if opdata.online then do;	/* If candidate is running now ... */
			cpu_mask = "0"b;
			substr (cpu_mask, old_tag + 1, 1) = "1"b;
			call set_procs_required (cpu_mask, tcode);
						/* Run on that CPU */
			if tcode ^= 0 then do;	/* Shouldn't happen */
			     rcode = rcerr_sprq_failed;
			     return;		/* Give up */
			end;
			call wire_proc$wire_me;	/* Don't allow page faults. */
			call privileged_mode_ut$wire_and_mask (mask_temp, ptp);
		     end;				/* Don't allow interrupts. */
		     opdata.interrupt_cpu = "0"b;	/* Take interrupts away from candidate. */
		     scs$mask_ptr (old_tag) = scs$mask_ptr (tag);
						/* Set mask pointer to simulated cell. */
		     scs$set_mask (old_tag) = scs$set_mask (tag);
						/* Make SMCM into STAQ. */
		     scs$read_mask (old_tag) = scs$read_mask (tag);
						/* Make RMCM into LDAQ. */
		     if opdata.online then do;	/* If we wired and masked before ... */
			call privileged_mode_ut$unwire_unmask (mask_temp, ptp);
			call wire_proc$unwire_me;
			call set_procs_required ("0"b, (0));
		     end;
		     if opdata.expanded_port & opdata.online then
			call scr_util$update_export_xipmsk ((opdata.controller_port));
		     call scr_util$reassign_mask (old_tag, tag);
						/* Reassign the mask now. */
		end;
	     end;

	     if ^found_mask then			/* If no mask was found for new processor ... */
		call scr_util$reassign_mask (-1, tag);	/* There must be a spare mask. */

	     scs$mask_ptr (tag) = addr (scs$port_addressing_word (scs$interrupt_controller));
						/* Set pointer for masking. */
	     scs$set_mask (tag) = mask_instruction$smcm ();
						/* Set SMCM instruction. */
	     scs$read_mask (tag) = mask_instruction$rmcm ();
						/* Set RMCM instruction. */
	     pdata.interrupt_cpu = "1"b;		/* We can now take interrupt on this CPU. */
	end;

/* Set up expected switch readings for processor. */

	rswp = addr (scs$processor_switch_template (2));	/* Get pointer to expected data. */
	dps_rsw_2.cpu_num = tag;			/* Set correct processor ID. */
%page;
/* Try to get the processor running. */

	init_processor$new_dbr = apte.dbr;		/* Set DBR value for new idle process. */

	if tag ^= scs$bos_processor_tag then do;	/* If not the bootload CPU ... */

/* Lay down dummy fault and interrupt vectors in any SCU's we can */

	     remember = 0;				/* array is cleared */
	     string (tsdw1) = "0"b;
	     tsdw1.df = "1"b;
	     tsdw1.read = "1"b;
	     tsdw1.write = "1"b;
	     tsdw1.bound = bit (bin (127, 14), 14);
	     tsdw1.unpaged = "1"b;
	     abs_seg_p = addr (abs_seg$);
	     fv_iv_p = addr (fv_iv_template$fv_iv_template);

	     do i = 0 to 7;
		base = scs$controller_data (i).base;
		if (base ^= 0) & scs$controller_data (i).online then do;
		     call pc_abs$remove_core (base, 2, tcode);
		     if tcode = 0 then do;		/* we got the pages */
			tsdw (i) = tsdw1;
			tsdw (i).add = bit (bin (base * 1024, 24), 24);
			call privileged_mode_ut$swap_sdw (abs_seg_p, addr (tsdw (i)));
			abs_seg_p -> fv_iv_copy = fv_iv_p -> fv_iv_copy;
			remember (i) = base;
		     end;
		end;
	     end;

/* Mask interrupts for new processor and enable all controller ports to new processor. */

	     call scr_util$set_mask (scs$interrupt_controller, (pdata.controller_port), scs$sys_level);
						/* Allow no interrupts. */
	     call scr_util$set_port_enable ((pdata.controller_port), "1"b);
						/* Set port enaobled on all controllers. */
	     if pdata.expanded_port then do;		/* Update port expander bits */
		call scr_util$set_export_enable ((pdata.controller_port), (pdata.expander_port), "1"b);
		call scr_util$update_export_xipmsk ((pdata.controller_port));
						/* Make mask from pdata.interrupt_cpu's */
	     end;
%page;
/* Initialize variables in init_processor. */

	     init_processor$wait_flag = rcerr_addcpu_no_response;
						/* Set flag to await processor startup. */
	     init_processor$controller_data = "0"b;	/* Clear controller bits. */
	     do i = 0 to 7;				/* Set bit for each online controller. */
		substr (init_processor$controller_data, i + 1, 1) = scs$controller_data (i).online;
	     end;

/* Send connects to make all other processors suspend normal operation. */

	     call privileged_mode_ut$wire_and_mask (mask_temp, ptp);
	     call wire_proc$wire_me;			/* Take no interrupts or page faults here. */

	     do while (^stac (addr (scs$connect_lock), pds$processid));
	     end;					/* Lock up the connect lock. */

	     scs$processor_start_wait = scs$processor & ^prds$processor_pattern;
						/* Stop all other processors. */
	     do i = 0 to 7;				/* Loop through all processors. */
		old_pdp = addr (scs$processor_data (i));/* Get pointer to data for processor. */
		if (i ^= prds$processor_tag) & old_pdp -> pdata.online then
		     call privileged_mode_ut$cioc (addr (scs$cow (i).cow));
						/* Send connects to other processors. */
	     end;

	     do while (scs$processor_start_wait);	/* Wait for other processors to respond. */
	     end;

/* Set up fault and interrupt vectors for starting CPU. */

	     fvp = addr (fault_vector$);		/* Get pointer to fault vector. */
	     int_vec_save = fv.ipair (scs$processor_start_int_no).scu;
	     fv.ipair (scs$processor_start_int_no).scu = init_processor$first_tra;
						/* Set up TRA for CPU start interrupt. */
	     trouble_save = fv.fpair (FAULT_NO_TRB).scu;
	     fv.fpair (FAULT_NO_TRB).scu = init_processor$trouble_tra;
						/* Set up TRA for trouble fault. */
	     startup_save = fv.fpair (FAULT_NO_SUF).scu;
	     fv.fpair (FAULT_NO_SUF).scu = init_processor$startup_tra;
						/* Set up TRA for startup fault. */
	     onc_save = fv.fpair (FAULT_NO_ONC).scu;
	     fv.fpair (FAULT_NO_ONC).scu = init_processor$onc_tra;
						/* Set up TRA for onc fault. */
	     lockup_save = fv.fpair (FAULT_NO_LUF).scu;
	     fv.fpair (FAULT_NO_LUF).scu = init_processor$lockup_tra;
						/* Set up TRA for lockup fault. */
%page;
/* Send processor start interrupt, open processor's mask, and wait for it to respond. */

	     call privileged_mode_ut$smic (scs$processor_start_pattern);
						/* Send interrupt to start processor. */
	     call scr_util$set_mask (scs$interrupt_controller, (pdata.controller_port), scs$processor_start_mask);
						/* Let new CPU get the interrupt. */
to_loop:
	     do i = 1 to 5000 while (init_processor$wait_flag = rcerr_addcpu_no_response);
	     end;					/* Wait for flag to change. */
	     rcode = init_processor$wait_flag;		/* Get error code, if any. */

/* If init_processor returns a bad switch code, this could be because we are attempting to add a processor that
   is of a different type (i.e.  L68 vs DPS8M or vis-a-versa) than what the scs$processor_switch_template was set up
   from (usally the bootload processor).  When this happens, the values of the rsw (1) memory size and the assignment
   switches must be computed for equality, since there values on the L68 and DPS8M processors are potentially
   different.  This is also true of the interlace info bits (rsw (2) bits 0 - 3 for the DPS8M, rsw (4) for the L68). */

	     if rcode = rcerr_addcpu_bad_switches then do;
		scs$processor_switch_compare = scs$processor_switch_compare & scs$processor_switch_mask;
		cmpp = addr (scs$processor_switch_compare (2));
						/* look at rsw 2 descrepencies */
		if cmpp -> dps8_rsw_2.cpu_type ^= 0 &	/* if adding a different kind of cpu */
		     scs$processor_switch_compare (3) = "0"b then do;
						/* no rsw3 data on mixed system */
		     if dps_rsw_2.cpu_type = 0 then do; /* template cpu is L68, cpu we are adding is dps8 */
			dps8_add = "1"b;		/* set switch indicating adding dps8 */
			rsw4p = addr (scs$processor_switch_template (4));
						/* set rsw 4 ptr */
			rsw1_68p = addr (scs$processor_switch_template (1));
						/* set L68 rsw1 ptr */
			rsw1_8p = addr (scs$processor_switch_data (1));
						/* set dps8 rsw1 ptr */
			switchp = addr (scs$processor_switch_data (2));
						/* set dps8 rsw2 ptr */
		     end;
		     else do;			/* template cpu is dps8, cpu we are adding is L68 */
			dps8_add = "0"b;		/* set switch indicating not adding dps8 */
			rsw4p = addr (scs$processor_switch_data (4));
						/* set rsw 4 ptr */
			rsw1_68p = addr (scs$processor_switch_data (1));
						/* set L68 rsw1 ptr */
			rsw1_8p = addr (scs$processor_switch_template (1));
						/* set dps8 rsw1 ptr */
			switchp = addr (scs$processor_switch_template (2));
						/* set dps8 rsw2 ptr */
			rswp = addr (scs$processor_switch_data (2));
						/* set L68 rsw2 ptr */
		     end;
		     cmpp = addr (scs$processor_switch_compare (1));
						/* set compare ptr */
		     trgp = addr (scs$processor_switch_data (1));
						/* set add target RSW1 ptr */
		     found = "0"b;
		     do i = 0 to 3;			/* go through each port */
			if scs$controller_data (i).online |
						/* check port only if mem */
			     scs$controller_data (i).offline then do;
						/* card in config deck */
			     L68_prt_sze = dps_mem_size_table (rsw1_68p -> rsw_1_3.port_info (i).mem_size);
			     if rsw4p -> rsw_4.port_info (i).half then
						/* if half switch is on... */
				L68_prt_sze = divide (L68_prt_sze, 2, 24, 0);
						/* divide patch plug size by 2 */
			     if L68_prt_sze ^= dps8_mem_size_table (rsw1_8p -> rsw_1_3.port_info (i).mem_size) then
				found = "1"b;	/* memory sizes are not = */
			     else cmpp -> rsw_1_3.port_info (i).mem_size = 0;
						/* reset compare data in case other switch error */
			     tbase = scs$controller_data (i).base * 1024;
						/* get abs base */
			     if dps8_add then	/* get target memory size */
				tsize = dps8_mem_size_table (trgp -> rsw_1_3.port_info (i).mem_size);
			     else tsize = dps_mem_size_table (trgp -> rsw_1_3.port_info (i).mem_size);

			     if trgp -> rsw_1_3.port_info (i).port_assignment
				^= bit (divide (tbase, tsize, 3, 0), 3) then
				found = "1"b;	/* port assignment switch error */
			     else cmpp -> rsw_1_3.port_info (i).port_assignment = "0"b;
						/* reset compare data in case other switch error */
			end;
			else do;			/* memory not there, reset compare data */
			     cmpp -> rsw_1_3.port_info (i).mem_size = 0;
			     cmpp -> rsw_1_3.port_info (i).port_assignment = "0"b;
			end;
			if cmpp -> rsw_1_3.port_info (i).port_enable then
			     found = "1"b;		/* port_enable  not set correctly */
			if cmpp -> rsw_1_3.port_info (i).initialize_enable then
			     found = "1"b;		/* initialize enable not set correctly */
			if cmpp -> rsw_1_3.port_info (i).interlace_enable then
			     found = "1"b;		/* interlace enable not set correctly */
			if rsw1_68p -> rsw_1_3.port_info (i).interlace_enable then
			     if rsw4p -> rsw_4.port_info (i).four ^= switchp -> dps8_rsw_2.interlace_info (i) then
				found = "1"b;	/* interlace types not equal */
		     end;
		     if ^found then do;		/* no error, return to init_processor */
			init_processor$wait_flag = rcerr_addcpu_no_response;
						/* allow init_processor to continue */
			go to to_loop;		/* and wait for completion */
		     end;
		end;
		init_processor$wait_flag = -1;	/* allow init_processor to die in a DIS */
	     end;


/* Restore original fault and interrupt vector contents. */

	     fv.ipair (scs$processor_start_int_no).scu = int_vec_save;
	     fv.fpair (FAULT_NO_TRB).scu = trouble_save;	/* Restore fault and interrupt vectors. */
	     fv.fpair (FAULT_NO_SUF).scu = startup_save;
	     fv.fpair (FAULT_NO_ONC).scu = onc_save;
	     fv.fpair (FAULT_NO_LUF).scu = lockup_save;

	     if ^stacq (scs$connect_lock, (36)"0"b, scs$connect_lock) then
		;				/* just reset lock, null then cluse */

	     call wire_proc$unwire_me;		/* Can unwire now. */
	     call privileged_mode_ut$unwire_unmask (mask_temp, ptp);

/* Perform error checking. */

	     if rcode = rcerr_addcpu_no_response then do; /* If CPU did not respond ... */
		switch_rel = bin (rel (addr (fv_iv_template$rsw_data)), 18) - bin (rel (fv_iv_p), 18);
		switchp = ptr (abs_seg_p, switch_rel);	/* See if CPU responded in another controller. */
		found = "0"b;			/* Clear switch. */
		do i = 0 to 7 while (^found);		/* Search the base of all controllers. */
		     if remember (i) ^= 0 then do;
			call privileged_mode_ut$swap_sdw (abs_seg_p, addr (tsdw (i)));
			if unspec (based_switches) then do;
			     scs$processor_switch_compare =
				bool (scs$processor_switch_template, based_switches, "0110"b);
			     scs$processor_switch_compare =
				scs$processor_switch_compare & scs$processor_switch_mask;
			     rcode = rcerr_addcpu_bad_switches;
						/* Change the error code. */
			     init_processor$wait_flag = -1;
						/* allow init_processor to die in a DIS */
			     found = "1"b;
			end;
		     end;
		end;
	     end;
%page;
/* Now give back the double pages we borrowed */

	     do i = 0 to 7;
		base = remember (i);
		if base > 0 then do;
		     call freecore (base);
		     call freecore (base + 1);
		end;
	     end;

	     string (tsdw1) = "0"b;
	     call privileged_mode_ut$swap_sdw (abs_seg_p, addr (tsdw1));
	     if rcode ^= 0 then do;			/* If an error occurred ... */
		call stop_cpu$destroy_1 (tag, tcode);	/* Clean up the mess we made. */
		return;
	     end;
	end;					/* Mask the discrepancy data. */

/* If initializing the bootload CPU, make simple call out. */

	else do;					/* If bootload CPU ... */
	     call init_processor$start_bootload_cpu;	/* Start up idle process. */
	     fgbx.hc_dbr = unspec (apte.dbr);		/* Place idle process DBR in flagbox. */
	end;

/* Update the config card for this processor. */

	call config_$find_2 (CPU_CARD_WORD, tag + 1, cpu_cardp);
						/* Find correct CPU card. */
	cpu_card.state = "on  ";			/* Set correct processor state. */
	call config_$update ();
	scs$nprocessors = scs$nprocessors + 1;		/* Count number of CPU's. */
	tc_data$ncpu = tc_data$ncpu + 1;
	rswp = addr (scs$processor_switch_data (2));	/*  lets look at cpu type */
	pdata.cpu_type = dps_rsw_2.cpu_type;		/* copy cpu type to processor data */
	call validate_cpu_card (tag, rswp);		/* validate cpu type and model */

	if tag ^= scs$bos_processor_tag then do;	/* If not during system initialization ... */
	     call syserr (ANNOUNCE, "start_cpu: Added CPU ^a.", substr (LETTERS, tag + 1, 1));
	     if pdata.cpu_type > 0 then		/* if DPS8 cpu... */
		if addr (scs$processor_switch_data (2)) -> dps8_rsw_2.id_prom then do;
						/* and id prom present */
		     cpu_mask = "0"b;
		     substr (cpu_mask, tag + 1, 1) = "1"b;
		     call set_procs_required (cpu_mask, tcode);
						/* Run on that CPU. */
		     if tcode ^= 0 then
			call syserr$error_code (CRASH, tcode, "start_cpu: Unable to run on CPU ^a",
			     substr (LETTERS, tag + 1, 1));
		     call privileged_mode_ut$read_id_prom (cpu_model, 0);
						/* get cpu model from ID PROM */
		     call privileged_mode_ut$read_id_prom (cpu_serial, 13);
						/* get cpu serial # from ID PROM */
		     call privileged_mode_ut$read_id_prom (cpu_ship_date, 26);
						/* get ship date from ID PROM */
		     call set_procs_required ("0"b, (0));
		     call syserr (LOG, "start_cpu: CPU ^a: Model #: ^a; Serial #: ^a; Ship date: ^a.",
			substr (LETTERS, tag + 1, 1), cpu_model, cpu_serial, cpu_ship_date);
						/* log info from ID PROM */
		end;
	     if scs$processor_switch_data (0) ^= scs$processor_data_switch_value then
		call syserr (ANNOUNCE, "start_cpu: CPU ^a data switches are ^w, should be ^w",
		     substr (LETTERS, tag + 1, 1), scs$processor_switch_data (0), scs$processor_data_switch_value);
	end;
	rcode = 0;
	return;
%page;
%include rcerr;
%page;
%include config_cpu_card;
%page;
%include flagbox;
%page;
%include scs;
%page;
%include rsw;
%page;
%include apte;
%page;
%include sdw;
%page;
%include fault_vector;
%page;
%include syserr_constants;
%page;
%include system_types;
%page;
/* BEGIN MESSAGE DOCUMENTATION

   Message:
   start_cpu: Added CPU CPUTAG

   S: $info

   T: In response to an operator "rcf add cpu CPUTAG" command, or at bootload
   time.

   M: The system has successfully added the CPU whose tag is CPUTAG to the
   configuration.

   A: $ignore

   Message:
   start_cpu: CPU CPUTAG: Model #: MODEL; Serial #: SERIAL; Ship date: YY/MM/DD.

   S: $log

   T: When a DPS8 CPU, whose tag is CPUTAG is added to the system.

   M: The MODEL, SERIAL and YY/MM/DD information is read from the DPS8 cpu's ID PROM.
   It is intended to be used as historical information
   for identifing CPUs, regardless of what their current tag is assigned as.

   A: $ignore

   Message:
   start_cpu: CPU CPUTAG data switches are XXXXXXXXXXXX, should be YYYYYYYYYYYY

   S: $info

   T: In response to an "rcf add cpu CPUTAG" command

   M: The data switches on the CPU indicated are not set properly. The proper
   value is given.

   A: The incorrect value will prevent returning to BCE on that CPU by means
   of EXECUTE SWITCHES. Certain incorrect values will activate software
   debugging traps. The switches should be corrected. This can be done
   while the CPU is running.

   Message:
   start_cpu: Unable to run on CPU x ERRORMESSAGE

   S: $crash

   T: In response to an "rcf add cpu CPUTAG" command or at bootload

   M: After adding a CPU, the system was unable to run on that CPU.
   This indicates hardware or software failure.

   A: $recover

   END MESSAGE DOCUMENTATION */
     end start_cpu;
 



		    stop_cpu.pl1                    11/11/89  1135.2r w 11/11/89  0800.9      102006



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

/* STOP_CPU - Remove a Central Processor.
   modified 3/5/76 by Noel I. Morris for new reconfig
   modified 03/01/77 by THVV for prds with branch
   modified 02/05/79 by BSG for port expanders
   modified September 1981 by J. Bongiovanni for set_procs_required
   modified April 1984 by Chris Jones to update config deck to its partition when changed
   except during shutdown (added shutdown entry too)
*/


/****^  HISTORY COMMENTS:
  1) change(86-09-23,Beattie), approve(86-08-11,MCR7517),
     audit(86-10-23,Fawcett), install(86-11-03,MR12.0-1206):
     No BOS support for MR12.
                                                   END HISTORY COMMENTS */


/* format: style4,delnl,insnl,indattr,ifthen,dclind10 */
stop_cpu:
     proc (tag, rcode);

dcl	tag		   fixed bin (3);
dcl	rcode		   fixed bin (35);

dcl	pdp		   ptr;			/* pointer to correct element of processor data */
dcl	new_pdp		   ptr;			/* pointer to correct element of processor data */
dcl	new_tag		   fixed bin (3);		/* tag of another CPU */
dcl	found		   bit (1) aligned;		/* useful switch */
dcl	mask_temp		   fixed bin (71);		/* for call to wire_and_mask */
dcl	ptp		   ptr;			/* for call to wired_and_mask */
dcl	cpu_mask		   bit (8) aligned;		/* for set_procs_required */
dcl	code		   fixed bin (35);		/* error code */
dcl	timnow		   fixed bin (52);		/* time when waiting for CPU to stop */
dcl	shutdown_entry	   bit (1) aligned;

dcl	LETTERS		   char (8) static options (constant) init ("ABCDEFGH");
dcl	my_name		   char (8) static options (constant) init ("stop_cpu");

dcl	prds$simulated_mask	   ext,
	tc_data$ncpu	   fixed bin ext;

dcl	set_procs_required	   entry (bit (8) aligned, fixed bin (35)),
	pxss$unthread_apte	   entry (ptr),
	privileged_mode_ut$cioc
			   entry (ptr),
	privileged_mode_ut$wire_and_mask
			   entry (fixed bin (71), ptr),
	privileged_mode_ut$unwire_unmask
			   entry (fixed bin (71), ptr),
	wire_proc$wire_me	   entry,
	wire_proc$unwire_me	   entry,
	scr_util$set_mask	   entry (fixed bin (3), fixed bin (3), bit (72) aligned),
	scr_util$reassign_mask entry (fixed bin (3), fixed bin (3)),
	scr_util$set_port_enable
			   entry (fixed bin (3), bit (1) unal),
	scr_util$update_export_xipmsk
			   entry (fixed bin (3)),
	scr_util$set_export_enable
			   entry (fixed bin (3), fixed bin (3), bit (1) aligned),
	mask_instruction$staq  entry returns (bit (36) aligned),
	mask_instruction$ldaq  entry returns (bit (36) aligned),
	config_$find_2	   entry (char (4) aligned, fixed bin (35), ptr),
	config_$update	   entry (),
	syserr$error_code	   entry options (variable),
	syserr		   entry options (variable);

dcl	1 pdata		   based (pdp) like scs$processor_data aligned;
dcl	1 npdata		   based (new_pdp) like scs$processor_data aligned;

dcl	(addr, clock, substr, unspec)
			   builtin;


	shutdown_entry = "0"b;
	goto SHUTDOWN_COMMON;

shutdown:
     entry (tag, rcode);

	shutdown_entry = "1"b;

SHUTDOWN_COMMON:					/* The following code effects the first steps in removing a processor. */
	pdp = addr (scs$processor_data (tag));		/* Get ptr to data for CPU to be deleted. */
	fgbxp = addr (flagbox$);			/* Get pointer to BCE flagbox segment. */


/* If the bootload processor is being removed, find another CPU
   to be the bootload processor.				*/

	if tag = scs$bos_processor_tag then do;
	     found = "0"b;				/* Initialize switch. */
	     do new_tag = 0 to 7 while (^found);
		new_pdp = addr (scs$processor_data (new_tag));
						/* If booload processor, look for another. */

		if npdata.online then		/* If online ... */
		     if new_tag ^= tag then		/* ... and we're not looking at CPU to be removed ... */
			if npdata.interrupt_cpu	/* ... and CPU can take interrupts */
			     & ^npdata.expanded_port then do;
						/* ...and not on expander */
			     found = "1"b;		/* Found candidate to be bootload processor. */
			     scs$bos_processor_tag = new_tag;
			     call syserr (ANNOUNCE, "^a: CPU ^a is now the bootload processor.", my_name,
				substr (LETTERS, new_tag + 1, 1));
			     fgbx.hc_dbr = unspec (scs$idle_aptep (new_tag) -> apte.dbr);
			end;			/* Save DBR of new bootload processor's idle process. */
	     end;
	     if ^found then do;
		rcode = rcerr_delcpu_no_good_blcpu;
		return;
	     end;
	end;


/* Issue connect for processor to remove itself (it will reset procs
   required when it goes offline) */

	cpu_mask = "0"b;
	substr (cpu_mask, scs$bos_processor_tag + 1, 1) = "1"b;
	call set_procs_required (cpu_mask, code);
	if code ^= 0 then do;			/* Couldn't run on bootload processor */
	     rcode = rcerr_sprq_failed;
	     return;
	end;

	pdata.delete_cpu = "1"b;			/* Set flag telling CPU to delete itself. */
	call privileged_mode_ut$cioc (addr (scs$cow (tag).cow));
						/* Send connect to the CPU. */

	call set_procs_required ("0"b, code);		/* Run on any processor now. */

/* Wait for processor to come to a stop. */

	timnow = clock;				/* Get time now. */
	do while (^pdata.halted_cpu);			/* Wait for processor to stop itself. */
	     if clock - timnow > 30000000 then do;	/* Allow 30 seconds. */
		rcode = rcerr_delcpu_no_stop;		/* Then return error code. */
		return;
	     end;
	end;

/* The following code effects the final steps in removing a processor.
   The processor has already stopped itself.			*/

	pdp = addr (scs$processor_data (tag));		/* Get pointer to processor data. */

/* Now update config info. */

	scs$nprocessors = scs$nprocessors - 1;		/* Keep count of number of CPU's. */
	tc_data$ncpu = tc_data$ncpu - 1;

	call syserr (ANNOUNCE, "^a: Removed CPU ^a.", my_name, substr (LETTERS, tag + 1, 1));
	go to destroy;

destroy_1:
     entry (tag, rcode);

	shutdown_entry = "0"b;

destroy:
	pdp = addr (scs$processor_data (tag));		/* Get pointer to data for stopped processor. */

/* Update the config deck. */

	if ^shutdown_entry then do;
	     call config_$find_2 (CPU_CARD_WORD, tag + 1, cpu_cardp);
						/* Get pointer to correct config card. */
	     cpu_card.state = "off ";
	     call config_$update ();
	end;

/* Destroy the idle process belonging to the stopped processor. */

	call pxss$unthread_apte ((scs$idle_aptep (tag))); /* Unthread APTE from idle queue */

/* Disable all interrupts to the removed processor.  Turn off
   the port enable bit for this processor in all controllers.	*/

	call scr_util$set_mask (scs$interrupt_controller, (pdata.controller_port), scs$sys_level);
						/* Mask interrupts to stopped CPU. */

	if ^pdata.expanded_port			/* Vanilla port? */
	     then
	     call scr_util$set_port_enable ((pdata.controller_port), "0"b);
						/* Disable the port in all controllers. */
	else call scr_util$set_export_enable ((pdata.controller_port), (pdata.expander_port), "0"b);
						/* Leave gross disabling and interrupt disabling 'till last */


/* If another running processor needs a controller mask, and the removed
   processor had one, give the mask to the running processor.	*/

	found = "0"b;				/* Initialize flag. */
	if pdata.interrupt_cpu then do;		/* If removed processor took interrupts ... */
	     do new_tag = 0 to 7 while (^found);	/* Search for CPU to give interrupts to. */
		new_pdp = addr (scs$processor_data (new_tag));

		if npdata.online & ^npdata.interrupt_cpu then do;


		     call scr_util$reassign_mask (tag, new_tag);
						/* Assign mask to new CPU. */

		     cpu_mask = "0"b;
		     substr (cpu_mask, new_tag + 1, 1) = "1"b;
		     call set_procs_required (cpu_mask, code);
						/* Run on specified CPU */
		     if code ^= 0 then
			call syserr$error_code (CRASH, code, "^a: Unable to run on CPU ^a", my_name,
			     substr (LETTERS, new_tag + 1, 1));
		     else do;
			found = "1"b;		/* Found a candidate */
			call wire_proc$wire_me;	/* Wire this code down. */
			call privileged_mode_ut$wire_and_mask (mask_temp, ptp);
						/* Don't allow interrupts now. */

			scs$mask_ptr (new_tag) = scs$mask_ptr (tag);
						/* Set mask pointer. */
			scs$set_mask (new_tag) = scs$set_mask (tag);
						/* Set SMCM instruction. */
			scs$read_mask (new_tag) = scs$read_mask (tag);
						/* Set RMCM instruction. */
			npdata.interrupt_cpu = "1"b;	/* CPU can now receive interrupts. */
			call privileged_mode_ut$unwire_unmask (mask_temp, ptp);
			call wire_proc$unwire_me;	/* No longer need to be wired and masked. */
			call set_procs_required ("0"b, code);
						/* Can continue running on any CPU. */

			pdata.interrupt_cpu = "0"b;	/* This processor no longer will get interrupts. */
			scs$mask_ptr (tag) = addr (prds$simulated_mask);
						/* Set pointer to simulated mask. */
			scs$set_mask (tag) = mask_instruction$staq ();
						/* Make SMCM into STAQ. */
			scs$read_mask (tag) = mask_instruction$ldaq ();
						/* Make RMCM into LDAQ. */
		     end;
		end;
	     end;
	end;

/* Set the port expander XIP enable bits the new way;
   maybe disable entire SC port. */

	if pdata.expanded_port then do;
	     call scr_util$update_export_xipmsk ((pdata.controller_port));
	     call scr_util$set_export_enable ((pdata.controller_port), (pdata.expander_port), "0"b);
	     found = "0"b;				/* Look for major port users */
	     do new_tag = 0 to 7 while (^found);
		new_pdp = addr (scs$processor_data (new_tag));
		if npdata.controller_port = pdata.controller_port & npdata.online & tag ^= new_tag then
		     found = "1"b;
	     end;
	     if ^found then
		call scr_util$set_port_enable ((pdata.controller_port), "0"b);
	end;

	rcode = 0;

	return;

%include rcerr;
%page;
%include config_cpu_card;
%page;
%include flagbox;
%page;
%include scs;
%page;
%include apte;
%page;
%include syserr_constants;

/* BEGIN MESSAGE DOCUMENTATION

   Message:
   stop_mpx: CPU CPUTAG is now the bootload processor.

   S: $info

   T: In response to an operator "rcf dl cpu CPUTAG" command.

   M: The CPU whose tag is CPUTAG is now the processor on which
   BCE will run at system shutdown or crash time, unless some
   other processor is so designated in this way before the next
   shutdown or crash time. Unless BCE is rebooted after
   shutdown, that CPU will be the bootload processor of the next
   bootload.

   A: $ignore

   Message:
   stop_cpu: Removed CPU CPUTAG.

   S: $info

   T: In response to an operator "rcf dl cpu CPUTAG" command.

   M: The system has successfully deleted the CPU whose tag is CPUTAG
   from the configuration. The CPU is now halted at a DIS instruction.

   A: The operator can, but need not, physically remove the CPU from
   the configuration by disabling appropriate ports if desired.

   Message:
   stop_cpu: Unable to run on CPU X ERRORMESSAGE

   S: $crash

   T: When deleting a CPU.

   M: The system has just deleted a CPU which owned an interrupt mask.
   In trying to assign the mask to a different CPU (X), it was unable to
   run on that CPU.  This indicates hardware or software malfunction.

   A: $recover

   END MESSAGE DOCUMENTATION */
     end stop_cpu;
  



		    validate_cpu_card.pl1           11/11/89  1135.2rew 11/11/89  0800.9       67266



/****^  ***********************************************************
        *                                                         *
        * 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: style4 */

validate_cpu_card: proc (tag, rswp);

/* validate_cpu_card - entry to validate (and change if necessary) the cpu
   type and model fields on a cpu config card image.

   The entry parameter rswp is a pointer and is declared in rsw.incl.pl1
   The pointer, rswp should be pointing to the RSW (2) data that will be used to get
   the correct type and model of the desired cpu.

   Last Modified (Date and Reason)
   09/11/80 by J. A. Bush initial coding for the DPS8/70M CPU
   07/20/81 by J. A. Bush to remove references to the hc_psp segment.
   03/25/83 by J. A. Bush to correct DPS8/52 and DPS8/62 RSW (2) decodes.
   09/20/83 by J. A. Bush to add cpu cache size to cpu card image.
   04/09/84 by Chris Jones to use modern include files.
*/


/****^  HISTORY COMMENTS:
  1) change(86-10-23,Fawcett), approve(86-10-23,MCR7517),
     audit(86-10-30,Beattie), install(86-11-03,MR12.0-1206):
     Changed to remove the word BOS from Error message documentation.
                                                   END HISTORY COMMENTS */


dcl  (unspec, substr) builtin;
dcl  tag fixed bin (3);				/* tag of cpu to be validated */
dcl  ctype char (4);				/* for checking cpu type in config card */
dcl  cmodel fixed bin;				/*  for checking cpu model in config card */
dcl  cs_idx fixed bin;
dcl  (discrep, set_fields) bit (1);
dcl  LETTERS char (8) static options (constant) init ("ABCDEFGH");
dcl  CS_ARRAY (0:5) fixed bin int static options (constant) init (0, 2, 8, 8, 16, 32);
dcl  FENCE bit (36) int static options (constant) init ("777777777777"b3);
dcl  IGNORE_CACHE_SIZE fixed bin int static options (constant) init (7);
dcl  config_$find_2 entry (char (4) aligned, fixed bin, ptr);
dcl  syserr entry options (variable);

	discrep, set_fields = "0"b;			/* reset error flag */
	call config_$find_2 (CPU_CARD_WORD, tag + 1, cpu_cardp); /* Find correct CPU card. */
	cardp = cpu_cardp;

	cs_idx = scs$processor_data (tag).cache_size;	/* get auto cache size index */

/* determine correct type and model info from rsw (2) data */

	if dps8_rsw_2.cpu_type > 0 then do;		/* if DPS8 cpu */
	     ctype = "dps8";
	     if dps8_rsw_2.cpu_speed = "0000"b then	/* if model 70 */
		cmodel = 70;
	     else if dps8_rsw_2.cpu_speed = "0001"b then	/* else if model 52 */
		cmodel = 52;
	     else if dps8_rsw_2.cpu_speed = "0100"b then	/* else if model 62 */
		cmodel = 62;
	     else cmodel = 77;			/* this indicates a bad cpu_speed code */
	end;
	else do;					/* must be  DPS or L68 cpu */
	     if dps_rsw_2.dps_option then		/* if this is on it must be DPS cpu */
		ctype = "dps ";
	     else ctype = "l68 ";			/* otherwise must be L68 */
	     if dps_rsw_2.cache2 then			/* if we have cache */
		cmodel = 80;
	     else cmodel = 60;			/* no cache */
	end;

/* now check type and model values obtained from rsw (2) data against current cpu card values */

	if cpu_card.type ^= ctype then do;		/* cpu type field is wrong */
	     set_fields = "1"b;			/* set flag to correct card image */
	     if unspec (cpu_card.type) ^= FENCE then do;	/* CPU type recorded incorrectly? */
		call syserr (BEEP, "validate_cpu_card: CPU type for CPU ^a is incorrect, should be ""^a""",
		     substr (LETTERS, tag + 1, 1), ctype);
		discrep = "1"b;
	     end;
	end;

	if cpu_card.model ^= cmodel then do;		/* cpu model field is wrong */
	     set_fields = "1"b;			/* set flag to correct card image */
	     if cpu_card.model ^= -1 then do;		/* cpu model recorded incorrectly? */
		call syserr (BEEP, "validate_cpu_card: CPU model for CPU ^a is incorrect, should be ""^d.""",
		     substr (LETTERS, tag + 1, 1), cmodel);
		discrep = "1"b;			/* set error flag */
	     end;
	end;
	if cs_idx ^= IGNORE_CACHE_SIZE then		/* if not being called by ISOLTS reconfig.. */
	     if cpu_card.cache_size ^= CS_ARRAY (cs_idx) then do; /* cpu cache size is wrong */
		set_fields = "1"b;			/* set flag to correct card image */
		if cpu_card.cache_size ^= -1 then do;	/* cpu cache size recorded incorrectly? */
		     call syserr (BEEP, "validate_cpu_card: CPU cache size for CPU ^a is incorrect, should be ""^d.""",
			substr (LETTERS, tag + 1, 1), CS_ARRAY (cs_idx));
		     discrep = "1"b;		/* set error flag */
		end;
	     end;
	if set_fields then do;			/* if we must set/reset cpu card image fields */
	     if discrep then			/* if some discrepency exists ... */
		call syserr (ANNOUNCE,
		     "validate_cpu_card: CPU type, model, and/or cache size discrepencies will be corrected");
	     cpu_card.type = ctype;			/* set correct cpu type */
	     cpu_card.model = cmodel;			/* and model */
	     if cs_idx = IGNORE_CACHE_SIZE then do;	/* if being called by isolts, don't set cache size */
		if config_card.n_fields < 5 then	/* if cpu type/model not defined */
		     config_card.n_fields = 5;	/* do it now */
	     end;
	     else do;				/* set cache size as well */
		cpu_card.cache_size = CS_ARRAY (cs_idx);/* and cache_size */
		if config_card.n_fields < 6 then	/* if not enough fields defined */
		     config_card.n_fields = 6;	/* set it */
	     end;
	     config_card.field_type (4) = CONFIG_STRING_TYPE;
	     config_card.field_type (5) = CONFIG_DECIMAL_TYPE; /* and decimal for model */
	     config_card.field_type (6) = CONFIG_DECIMAL_TYPE; /* and decimal for cache size */
	end;

%include config_deck;
%page;
%include config_cpu_card;
%page;
%include rsw;
%page;
%include syserr_constants;
%page;
%include scs;
%page;
/* BEGIN MESSAGE DOCUMENTATION

   Message:
   validate_cpu_card: CPU type for CPU CPUTAG is incorrect, should be "CPUTYPE"

   S:	$beep

   T:	$run

   M:	The CPUTYPE as determined from RSW (2) information, did not match the
   CPUTYPE in the cpu type field of the config card image for CPU CPUTAG.

   A:	$ignore

   Message:
   validate_cpu_card: CPU model for CPU CPUTAG is incorrect, should be "CPUMODEL."

   S:	$beep

   T:	$run

   M:	The CPUMODEL as determined from RSW (2) information, did not match the
   CPUMODEL in the cpu model field of the config card image for CPU CPUTAG.

   A:	$ignore

   Message:
   validate_cpu_card: CPU cache size for CPU CPUTAG is incorrect, should be "CACHE_SIZE."

   S:	$beep

   T:	$run

   M:	The CACHE_SIZE as determined from cpu registers, did not match the
   CACHE_SIZE in the cpu cache size field of the config card image for CPU
   CPUTAG.

   A:	$ignore

   Message:
   validate_cpu_card: CPU type, model, and/or cache size discrepencies will be corrected

   S: $info

   T: $run

   M:	The indicated discrepencies in the cpu type, model, and cache size
   fields, will be corrected by validate_cpu_card.

   A:	The type, model, and/or cache size fields of the indicated cpu
   config card image should be corrected at BCE, before the next bootload.

   END MESSAGE DOCUMENTATION */

     end validate_cpu_card;





		    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

