1 /****^  ***********************************************************
  2         *                                                         *
  3         * Copyright, (C) Honeywell Bull Inc., 1987                *
  4         *                                                         *
  5         * Copyright, (C) Honeywell Information Systems Inc., 1982 *
  6         *                                                         *
  7         *********************************************************** */
  8 
  9 /* STOP_CPU - Remove a Central Processor.
 10    modified 3/5/76 by Noel I. Morris for new reconfig
 11    modified 03/01/77 by THVV for prds with branch
 12    modified 02/05/79 by BSG for port expanders
 13    modified September 1981 by J. Bongiovanni for set_procs_required
 14    modified April 1984 by Chris Jones to update config deck to its partition when changed
 15    except during shutdown (added shutdown entry too)
 16 */
 17 
 18 
 19 /****^  HISTORY COMMENTS:
 20   1) change(86-09-23,Beattie), approve(86-08-11,MCR7517),
 21      audit(86-10-23,Fawcett), install(86-11-03,MR12.0-1206):
 22      No BOS support for MR12.
 23                                                    END HISTORY COMMENTS */
 24 
 25 
 26 /* format: style4,delnl,insnl,indattr,ifthen,dclind10 */
 27 stop_cpu:
 28      proc (tag, rcode);
 29 
 30 dcl       tag                    fixed bin (3);
 31 dcl       rcode                  fixed bin (35);
 32 
 33 dcl       pdp                    ptr;                       /* pointer to correct element of processor data */
 34 dcl       new_pdp                ptr;                       /* pointer to correct element of processor data */
 35 dcl       new_tag                fixed bin (3);             /* tag of another CPU */
 36 dcl       found                  bit (1) aligned;           /* useful switch */
 37 dcl       mask_temp              fixed bin (71);            /* for call to wire_and_mask */
 38 dcl       ptp                    ptr;                       /* for call to wired_and_mask */
 39 dcl       cpu_mask               bit (8) aligned;           /* for set_procs_required */
 40 dcl       code                   fixed bin (35);            /* error code */
 41 dcl       timnow                 fixed bin (52);            /* time when waiting for CPU to stop */
 42 dcl       shutdown_entry         bit (1) aligned;
 43 
 44 dcl       LETTERS                char (8) static options (constant) init ("ABCDEFGH");
 45 dcl       my_name                char (8) static options (constant) init ("stop_cpu");
 46 
 47 dcl       prds$simulated_mask    ext,
 48           tc_data$ncpu           fixed bin ext;
 49 
 50 dcl       set_procs_required     entry (bit (8) aligned, fixed bin (35)),
 51           pxss$unthread_apte     entry (ptr),
 52           privileged_mode_ut$cioc
 53                                  entry (ptr),
 54           privileged_mode_ut$wire_and_mask
 55                                  entry (fixed bin (71), ptr),
 56           privileged_mode_ut$unwire_unmask
 57                                  entry (fixed bin (71), ptr),
 58           wire_proc$wire_me      entry,
 59           wire_proc$unwire_me    entry,
 60           scr_util$set_mask      entry (fixed bin (3), fixed bin (3), bit (72) aligned),
 61           scr_util$reassign_mask entry (fixed bin (3), fixed bin (3)),
 62           scr_util$set_port_enable
 63                                  entry (fixed bin (3), bit (1) unal),
 64           scr_util$update_export_xipmsk
 65                                  entry (fixed bin (3)),
 66           scr_util$set_export_enable
 67                                  entry (fixed bin (3), fixed bin (3), bit (1) aligned),
 68           mask_instruction$staq  entry returns (bit (36) aligned),
 69           mask_instruction$ldaq  entry returns (bit (36) aligned),
 70           config_$find_2         entry (char (4) aligned, fixed bin (35), ptr),
 71           config_$update         entry (),
 72           syserr$error_code      entry options (variable),
 73           syserr                 entry options (variable);
 74 
 75 dcl       1 pdata                based (pdp) like scs$processor_data aligned;
 76 dcl       1 npdata               based (new_pdp) like scs$processor_data aligned;
 77 
 78 dcl       (addr, clock, substr, unspec)
 79                                  builtin;
 80 ^L
 81 
 82           shutdown_entry = "0"b;
 83           goto SHUTDOWN_COMMON;
 84 
 85 shutdown:
 86      entry (tag, rcode);
 87 
 88           shutdown_entry = "1"b;
 89 
 90 SHUTDOWN_COMMON:                                            /* The following code effects the first steps in removing a processor. */
 91           pdp = addr (scs$processor_data (tag));            /* Get ptr to data for CPU to be deleted. */
 92           fgbxp = addr (flagbox$);                          /* Get pointer to BCE flagbox segment. */
 93 
 94 
 95 /* If the bootload processor is being removed, find another CPU
 96    to be the bootload processor.                                      */
 97 
 98           if tag = scs$bos_processor_tag then do;
 99                found = "0"b;                                /* Initialize switch. */
100                do new_tag = 0 to 7 while (^found);
101                     new_pdp = addr (scs$processor_data (new_tag));
102                                                             /* If booload processor, look for another. */
103 
104                     if npdata.online then                   /* If online ... */
105                          if new_tag ^= tag then             /* ... and we're not looking at CPU to be removed ... */
106                               if npdata.interrupt_cpu       /* ... and CPU can take interrupts */
107                                    & ^npdata.expanded_port then do;
108                                                             /* ...and not on expander */
109                                    found = "1"b;            /* Found candidate to be bootload processor. */
110                                    scs$bos_processor_tag = new_tag;
111                                    call syserr (ANNOUNCE, "^a: CPU ^a is now the bootload processor.", my_name,
112                                         substr (LETTERS, new_tag + 1, 1));
113                                    fgbx.hc_dbr = unspec (scs$idle_aptep (new_tag) -> apte.dbr);
114                               end;                          /* Save DBR of new bootload processor's idle process. */
115                end;
116                if ^found then do;
117                     rcode = rcerr_delcpu_no_good_blcpu;
118                     return;
119                end;
120           end;
121 
122 
123 /* Issue connect for processor to remove itself (it will reset procs
124    required when it goes offline) */
125 
126           cpu_mask = "0"b;
127           substr (cpu_mask, scs$bos_processor_tag + 1, 1) = "1"b;
128           call set_procs_required (cpu_mask, code);
129           if code ^= 0 then do;                             /* Couldn't run on bootload processor */
130                rcode = rcerr_sprq_failed;
131                return;
132           end;
133 
134           pdata.delete_cpu = "1"b;                          /* Set flag telling CPU to delete itself. */
135           call privileged_mode_ut$cioc (addr (scs$cow (tag).cow));
136                                                             /* Send connect to the CPU. */
137 
138           call set_procs_required ("0"b, code);             /* Run on any processor now. */
139 
140 /* Wait for processor to come to a stop. */
141 
142           timnow = clock;                                   /* Get time now. */
143           do while (^pdata.halted_cpu);                     /* Wait for processor to stop itself. */
144                if clock - timnow > 30000000 then do;        /* Allow 30 seconds. */
145                     rcode = rcerr_delcpu_no_stop;           /* Then return error code. */
146                     return;
147                end;
148           end;
149 ^L
150 /* The following code effects the final steps in removing a processor.
151    The processor has already stopped itself.                          */
152 
153           pdp = addr (scs$processor_data (tag));            /* Get pointer to processor data. */
154 
155 /* Now update config info. */
156 
157           scs$nprocessors = scs$nprocessors - 1;            /* Keep count of number of CPU's. */
158           tc_data$ncpu = tc_data$ncpu - 1;
159 
160           call syserr (ANNOUNCE, "^a: Removed CPU ^a.", my_name, substr (LETTERS, tag + 1, 1));
161           go to destroy;
162 
163 destroy_1:
164      entry (tag, rcode);
165 
166           shutdown_entry = "0"b;
167 
168 destroy:
169           pdp = addr (scs$processor_data (tag));            /* Get pointer to data for stopped processor. */
170 
171 /* Update the config deck. */
172 
173           if ^shutdown_entry then do;
174                call config_$find_2 (CPU_CARD_WORD, tag + 1, cpu_cardp);
175                                                             /* Get pointer to correct config card. */
176                cpu_card.state = "off ";
177                call config_$update ();
178           end;
179 
180 /* Destroy the idle process belonging to the stopped processor. */
181 
182           call pxss$unthread_apte ((scs$idle_aptep (tag))); /* Unthread APTE from idle queue */
183 
184 /* Disable all interrupts to the removed processor.  Turn off
185    the port enable bit for this processor in all controllers.         */
186 
187           call scr_util$set_mask (scs$interrupt_controller, (pdata.controller_port), scs$sys_level);
188                                                             /* Mask interrupts to stopped CPU. */
189 
190           if ^pdata.expanded_port                           /* Vanilla port? */
191                then
192                call scr_util$set_port_enable ((pdata.controller_port), "0"b);
193                                                             /* Disable the port in all controllers. */
194           else call scr_util$set_export_enable ((pdata.controller_port), (pdata.expander_port), "0"b);
195                                                             /* Leave gross disabling and interrupt disabling 'till last */
196 ^L
197 
198 /* If another running processor needs a controller mask, and the removed
199    processor had one, give the mask to the running processor.         */
200 
201           found = "0"b;                                     /* Initialize flag. */
202           if pdata.interrupt_cpu then do;                   /* If removed processor took interrupts ... */
203                do new_tag = 0 to 7 while (^found);          /* Search for CPU to give interrupts to. */
204                     new_pdp = addr (scs$processor_data (new_tag));
205 
206                     if npdata.online & ^npdata.interrupt_cpu then do;
207 
208 
209                          call scr_util$reassign_mask (tag, new_tag);
210                                                             /* Assign mask to new CPU. */
211 
212                          cpu_mask = "0"b;
213                          substr (cpu_mask, new_tag + 1, 1) = "1"b;
214                          call set_procs_required (cpu_mask, code);
215                                                             /* Run on specified CPU */
216                          if code ^= 0 then
217                               call syserr$error_code (CRASH, code, "^a: Unable to run on CPU ^a", my_name,
218                                    substr (LETTERS, new_tag + 1, 1));
219                          else do;
220                               found = "1"b;                 /* Found a candidate */
221                               call wire_proc$wire_me;       /* Wire this code down. */
222                               call privileged_mode_ut$wire_and_mask (mask_temp, ptp);
223                                                             /* Don't allow interrupts now. */
224 
225                               scs$mask_ptr (new_tag) = scs$mask_ptr (tag);
226                                                             /* Set mask pointer. */
227                               scs$set_mask (new_tag) = scs$set_mask (tag);
228                                                             /* Set SMCM instruction. */
229                               scs$read_mask (new_tag) = scs$read_mask (tag);
230                                                             /* Set RMCM instruction. */
231                               npdata.interrupt_cpu = "1"b;  /* CPU can now receive interrupts. */
232                               call privileged_mode_ut$unwire_unmask (mask_temp, ptp);
233                               call wire_proc$unwire_me;     /* No longer need to be wired and masked. */
234                               call set_procs_required ("0"b, code);
235                                                             /* Can continue running on any CPU. */
236 
237                               pdata.interrupt_cpu = "0"b;   /* This processor no longer will get interrupts. */
238                               scs$mask_ptr (tag) = addr (prds$simulated_mask);
239                                                             /* Set pointer to simulated mask. */
240                               scs$set_mask (tag) = mask_instruction$staq ();
241                                                             /* Make SMCM into STAQ. */
242                               scs$read_mask (tag) = mask_instruction$ldaq ();
243                                                             /* Make RMCM into LDAQ. */
244                          end;
245                     end;
246                end;
247           end;
248 
249 /* Set the port expander XIP enable bits the new way;
250    maybe disable entire SC port. */
251 
252           if pdata.expanded_port then do;
253                call scr_util$update_export_xipmsk ((pdata.controller_port));
254                call scr_util$set_export_enable ((pdata.controller_port), (pdata.expander_port), "0"b);
255                found = "0"b;                                /* Look for major port users */
256                do new_tag = 0 to 7 while (^found);
257                     new_pdp = addr (scs$processor_data (new_tag));
258                     if npdata.controller_port = pdata.controller_port & npdata.online & tag ^= new_tag then
259                          found = "1"b;
260                end;
261                if ^found then
262                     call scr_util$set_port_enable ((pdata.controller_port), "0"b);
263           end;
264 
265           rcode = 0;
266 
267           return;
268 ^L
269 %include rcerr;
270 %page;
271 %include config_cpu_card;
272 %page;
273 %include flagbox;
274 %page;
275 %include scs;
276 %page;
277 %include apte;
278 %page;
279 %include syserr_constants;
280 ^L
281 /* BEGIN MESSAGE DOCUMENTATION
282 
283    Message:
284    stop_mpx: CPU CPUTAG is now the bootload processor.
285 
286    S: $info
287 
288    T: In response to an operator "rcf dl cpu CPUTAG" command.
289 
290    M: The CPU whose tag is CPUTAG is now the processor on which
291    BCE will run at system shutdown or crash time, unless some
292    other processor is so designated in this way before the next
293    shutdown or crash time. Unless BCE is rebooted after
294    shutdown, that CPU will be the bootload processor of the next
295    bootload.
296 
297    A: $ignore
298 
299    Message:
300    stop_cpu: Removed CPU CPUTAG.
301 
302    S: $info
303 
304    T: In response to an operator "rcf dl cpu CPUTAG" command.
305 
306    M: The system has successfully deleted the CPU whose tag is CPUTAG
307    from the configuration. The CPU is now halted at a DIS instruction.
308 
309    A: The operator can, but need not, physically remove the CPU from
310    the configuration by disabling appropriate ports if desired.
311 
312    Message:
313    stop_cpu: Unable to run on CPU X ERRORMESSAGE
314 
315    S: $crash
316 
317    T: When deleting a CPU.
318 
319    M: The system has just deleted a CPU which owned an interrupt mask.
320    In trying to assign the mask to a different CPU (X), it was unable to
321    run on that CPU.  This indicates hardware or software malfunction.
322 
323    A: $recover
324 
325    END MESSAGE DOCUMENTATION */
326      end stop_cpu;