1 /* ***********************************************************
  2    *                                                         *
  3    * Copyright, (C) Honeywell Information Systems Inc., 1982 *
  4    *                                                         *
  5    * Copyright (c) 1972 by Massachusetts Institute of        *
  6    * Technology and Honeywell Information Systems, Inc.      *
  7    *                                                         *
  8    *********************************************************** */
  9 
 10 
 11 
 12 /* Printer DIM write module: responsible for actually sending print lines to the line printer and handling statuses
 13    returned from the printer by IOI */
 14 
 15 /* Created:  31 October 1974 by Noel I. Morris */
 16 /* Modified: 16 March 1977 by Noel I. Morris */
 17 /* Modified: June 1978 by J. C. Whitmore to suppress multiple error messages */
 18 /* Modified: 7 August 1980 by Art Beattie to send error messages every N times and wait */
 19 /* Modified: 27 November 1981 by G. Palter to fix entry number 0028 (phx04610) on the io_daemon error list:
 20       A power fault on a local printer will reset the VFC to the default state (6 lines/inch).  The entry in
 21       prt_status_table_ for "power fault" does not indicate that the VFC and train image are lost -- the fix for this bug
 22       is to add a new flag which is used by the printer DIM to indicate a VFC and image reload should be done after the
 23       operator readies the printer (the next special interrupt) */
 24 /* Modified 83-10-10 for urmpc/eurc partitioning, E. N. Kittlitz */
 25 
 26 
 27 prtdim_write:
 28      procedure (arg_sdb_ptr, wkspptr, offset, nelem, nelemt, iostatus);
 29 
 30 dcl  arg_sdb_ptr ptr,                                       /* pointer to stream data block */
 31      wkspptr ptr,                                           /* pointer to caller's data */
 32      offset fixed bin (24),                                 /* offset into caller data */
 33      nelem fixed bin (24),                                  /* number of elements to transmit */
 34      nelemt fixed bin (24),                                 /* number of elements actually transmitted */
 35      iostatus bit (72) aligned;                             /* IOS status */
 36 
 37 dcl  rcode fixed bin (35),                                  /* error code */
 38      cur_page fixed bin,                                    /* current page number */
 39      lp ptr,                                                /* pointer to next DCW block */
 40      prev_lp ptr,                                           /* pointer to last DCW block */
 41      dp ptr,                                                /* pointer to place for data */
 42      lth fixed bin (18),                                    /* remaining length of input */
 43      inptr ptr,                                             /* pointer to rest of input */
 44      char_cnt fixed bin (18),                               /* count of characters in output */
 45      word_cnt fixed bin (18),                               /* count of words in output */
 46      temp_iom_stat bit (72) aligned,                        /* temp area for iom status */
 47      errmess char (256) var,                                /* error message on bad status */
 48      tra bit (36) aligned;                                  /* prototype TDCW */
 49 
 50 dcl  last_iom_stat bit (72) aligned;                        /* last status an error msg was printed for */
 51 dcl  max_err_stat_count fixed bin init (10) int static options (constant); /* max no. of errors between reporting */
 52 dcl  same_err_stat_count fixed bin;                         /* counter for the same error status from printer */
 53 
 54 dcl (paper_low_flag init ("000000000000000001"b),           /* status flag for paper low */
 55      image_flag init ("000000000000000010"b),               /* status flag for destroyed train image */
 56      vfc_flag init ("000000000000000100"b),                 /* status flag for destroyed VFC image */
 57      slew_error init ("000000000000001000"b),               /* status flag for slew error on prev slew */
 58      power_fault_flag init ("000000000000010000"b))         /* status flag for power fault */
 59      bit (18) aligned static options (constant);
 60 
 61 dcl  dev_stat_bits bit (72) aligned int static options (constant) /* bits used by analyze_device_stat_ */
 62      init ("377700770000"b3 || (12) "0"b3);                 /* bit string in octal to mask all but */
 63                                                             /* power, maj, sub, channel and central status bits */
 64 %page;
 65 dcl  prt_conv_ entry (ptr, fixed bin (18), ptr, fixed bin (18), ptr),
 66      ioi_$connect entry (fixed bin, fixed bin (18), fixed bin (35)),
 67      ipc_$block entry (ptr, ptr, fixed bin (35)),
 68      convert_ipc_code_ entry (fixed bin (35)),
 69      analyze_device_stat_$rs entry (char (*) var, ptr, bit (72) aligned, bit (18) aligned),
 70      analyze_system_fault_ entry (char (*) aligned, bit (72) aligned),
 71      prtdim_util$load_image entry (ptr, fixed bin (35)),
 72      prtdim_util$load_vfc entry (ptr, fixed bin (35)),
 73      com_err_ entry options (variable);
 74 
 75 dcl  prt_status_table_$prt_status_table_ ext;
 76 
 77 
 78 dcl  wksp char (1) based unal;                              /* used for getting pointer to input string */
 79 
 80 dcl  error_table_$net_timeout ext fixed bin (35);
 81 dcl  error_table_$request_pending fixed bin (35) ext static;
 82 
 83 dcl 1 dcws aligned based (lp),                              /* DCW/data block */
 84     2 idcw bit (36),                                        /* instruction DCW */
 85     2 ddcw bit (36),                                        /* data xfer DCW */
 86     2 tdcw bit (36),                                        /* Transfer DCW or terminate DCW */
 87     2 data;                                                 /* data follows the DCW's */
 88 
 89 dcl 1 ipc_message aligned,
 90     2 chname fixed bin (71),                                /* Chan over which message arrived */
 91     2 message fixed bin (71),                               /* 2-word event message */
 92     2 sender bit (36),                                      /* Sending process */
 93     2 origin,                                               /* Origin of event message */
 94       3 devsignal bit (18),                                 /* 1 = device signal */
 95       3 ring bit (18),                                      /* Senders ring number */
 96     2 channel_index fixed bin;
 97 
 98 dcl (addr, addrel, bin, bit, divide, rel, string, substr, unspec) builtin;
 99 %page;
100 % include prt_sdb;
101 %page;
102 % include prt_info;
103 %page;
104 % include prt_conv_info;
105 
106 
107 % include ioi_stat;
108 % include status_flags;
109 ^L
110 % include iom_pcw;
111 % include iom_dcw;
112 %page;
113           iostatus = "0"b;                                  /* Clear IOS status. */
114 
115           sdb_ptr = arg_sdb_ptr;                            /* Copy pointer to stream data block. */
116           pip = addr (sdb.info);                            /* Get pointer to printer info structure. */
117           pcip = addr (sdb.conv_info);                      /* Get pointer to conversion info structure. */
118           last_iom_stat = ""b;                              /* start clean on each write */
119           same_err_stat_count = 0;
120 
121           rcode = 0;                                        /* Clear the error code. */
122           nelemt = 0;                                       /* Zero elements transmitted. */
123           lth = nelem;                                      /* Get initial length of input string. */
124           inptr = addr (substr (wkspptr -> wksp, offset+1, 1)); /* Get pointer to input string. */
125 
126           do while (lth > 0);                               /* Loop until all elements transmitted. */
127                cur_page = pci.page_count;                   /* Remember current page count. */
128 
129                if sdb.stop > sdb.bgin then                  /* If adding to end of workspace segment ... */
130                     call set_io;                            /* Add some more. */
131                else if sdb.stop + 68 < sdb.bgin then        /* If adding to beginning of workspace segment ... */
132                     call set_io;
133                else if sdb.prev = sdb.bgin then             /* If cold starting ... */
134                     call set_io;
135 
136                else                                         /* Cannot add more lines.  Wait for I/O completion. */
137                call wait_io;
138 
139                if rcode ^= 0 then do;
140                     substr (iostatus, 1, 36) = unspec (rcode);
141                     substr (iostatus, 41, 1) = "1"b;
142                     sdb.chars_printed = sdb.chars_printed + nelem - lth; /* boost the number done */
143                     return;
144                end;
145 
146                if cur_page ^= pci.page_count then do;       /* If going to a new page ... */
147                     sdb.stop_counter = sdb.stop_counter + 1; /* Bump the page stop counter. */
148 
149                     if sdb.single_page | (sdb.stop_every ^= 0 & sdb.stop_counter >= sdb.stop_every) then do;
150                          sdb.stop_counter = 0;              /* If time to stop ... */
151                          sdb.chars_printed = sdb.chars_printed + nelem - lth; /* boost the number done */
152                          substr (iostatus, 1, 36) = unspec (error_table_$request_pending);
153                          return;
154                     end;
155                end;
156           end;
157 
158           sdb.chars_printed = sdb.chars_printed + nelem - lth; /* boost the number done */
159           return;
160 %page;
161 set_io:   proc;                                             /* procedure to set new DCW and data block */
162 
163 
164                lp = addr (wseg (sdb.stop));                 /* Get ptr to place for next DCW block. */
165                dp = addr (lp -> dcws.data);                 /* Get pointer to place for data. */
166 
167                call prt_conv_ (inptr, lth, dp, char_cnt, pcip); /* Perform code conversion. */
168                word_cnt = divide (char_cnt + 3, 4, 18, 0);  /* Compute number of words to write. */
169                nelemt = nelem - lth;                        /* Update the number of elements xmitted. */
170 
171                if sdb.noprint then return;                  /* Just return if print suppressed. */
172 
173                dcws.tdcw = prt_info.term_idcw;              /* Set terminator at end of block. */
174 
175                dcwp = addr (dcws.ddcw);                     /* Get pointer to data transfer DCW. */
176                string (dcw) = "0"b;                         /* Clear the DCW. */
177                dcw.address = rel (dp);                      /* Set address to point to data. */
178                dcw.tally = bit (bin (word_cnt, 12));        /* Set tally of DCW. */
179 
180                dcws.idcw = prt_info.print_idcw;             /* Set the IDCW to print line. */
181 
182                if sdb.running then do;                      /* If channel is running ... */
183                     sdb.marker_count = sdb.marker_count + word_cnt; /* Bump the marker count. */
184                     if sdb.marker_count > 512 then do;      /* If workspace segment more than half filled ... */
185                          idcwp = addr (dcws.idcw);          /* Get pointer to IDCW for printing line. */
186                          idcw.control = "11"b;              /* Set marker bits in IDCW. */
187                          sdb.marker_count = 0;              /* Reset the count. */
188                     end;
189                end;
190 
191                if sdb.prev ^= sdb.stop then do;             /* If previous line queued ... */
192                     tdcwp = addr (tra);                     /* Get pointer to prototype TDCW. */
193                     tra = "0"b;                             /* Clear it. */
194                     tdcw.address = bit (bin (sdb.stop, 18)); /* Set target of transfer. */
195                     tdcw.type = "10"b;                      /* Identify as TDCW. */
196 
197                     prev_lp = addr (wseg (sdb.prev));       /* Get pointer to previous line. */
198                     prev_lp -> dcws.tdcw = tra;             /* Copy into list. */
199                end;
200 
201                sdb.prev = sdb.stop;                         /* Save index to this line. */
202                sdb.stop = sdb.stop + word_cnt + 3;          /* Get offset of first word past current block. */
203                if sdb.stop + 68 >= 1024 then sdb.stop = 0;  /* Lap if buffer size exceeded. */
204 
205                if ^sdb.running then call start_io;          /* If channel stopped, start it up again. */
206 
207                return;
208 
209 
210           end set_io;
211 %page;
212 start_io: proc;                                             /* procedure to start up printer */
213 
214                if ^sdb.wait_flag then if sdb.prev ^= sdb.stop then do; /* If not waiting for special and something to do ... */
215                          sdb.marker_count = 0;              /*  Reset marker count. */
216                          sdb.running = "1"b;                /* Indicate device now running. */
217 
218                          call ioi_$connect (prt_info.devx, sdb.bgin, rcode); /* Fire up the device. */
219 
220                     end;
221 
222                return;
223 
224 
225           end start_io;
226 
227 
228 
229 wait_io:  proc;                                             /* procedure to wait for I/O completion */
230 
231 
232                if ^sdb.running then                         /* If printer not running ... */
233                     call start_io;                          /* Get it in motion. */
234 
235                call ipc_$block (addr (sdb.ev_list), addr (ipc_message), rcode);
236                if rcode ^= 0 then do;                       /* Wait for I/O completion. */
237                     call convert_ipc_code_ (rcode);
238                     return;
239                end;
240 
241                call stat_check;                             /* Examine status and set flags. */
242 
243                return;
244 
245 
246           end wait_io;
247 %page;
248 stat_check: proc;                                           /* Printer status check entry  -  a la Dijkstra */
249 
250 dcl  flags bit (18) aligned,
251      found_dcw bit (1) aligned,
252      lx fixed bin (18);
253 
254                flags = "0"b;                                /* Clear flags. */
255 
256                imp = addr (ipc_message.message);            /* get pointer to ioi message */
257                if imess.level = "111"b then do;             /* if a special interupt... */
258                     sdb.wait_flag = "0"b;                   /* not waiting any more */
259                     if sdb.reload_vfc_train_after_special then do;    /* whatever required operator intervention ... */
260                          call prtdim_util$load_image (sdb_ptr, (0));  /* ... also destroyed the train and VFC images */
261                          call prtdim_util$load_vfc (sdb_ptr, (0));
262                          sdb.reload_vfc_train_after_special = "0"b;
263                     end;
264                     return;
265                end;
266 
267                if imess.st then do;                         /* if status present */
268                     if imess.time_out then do;              /* if caused by time out */
269                          rcode = error_table_$net_timeout;  /* indicate error */
270                          sdb.running = "0"b;                /* not running any more */
271                          return;
272                     end;
273 
274                     if bin (imess.level) <= 5 then do;      /* If terminate, marker, or system fault ... */
275                          temp_iom_stat = imess.status;      /* copy status to double word */
276                          lx = bin (imess.offset);           /* Copy list index for this status */
277 
278                          if imess.er then do;               /* If error occurred ... */
279                               if imess.level = "001"b then do; /* If system fault ... */
280                                    call analyze_system_fault_ (prt_info.devname, temp_iom_stat);
281                                    sdb.wait_flag = "1"b;    /* Wait for operator intervention. */
282                                    sdb.error_count = sdb.error_count + 1;
283                               end;
284                               else do;                      /* If terminate ... */
285                                    call analyze_device_stat_$rs (errmess, addr (prt_status_table_$prt_status_table_),
286                                         temp_iom_stat, flags);
287 
288                                    if flags & paper_low_flag then
289                                         if pci.overflow_off then /* If in overflow_off mode ... */
290                                              flags = flags | report_flag | halt_flag;
291                                                             /* Stop now to avoid printing on perf. */
292                                         else if ^sdb.paper_low then do; /* Report paper low only once. */
293                                              sdb.paper_low = "1"b;
294                                              flags = flags | report_flag;
295                                         end;
296 
297                                    if flags & power_fault_flag then   /* power fault: VFC/train images no longer valid */
298                                         sdb.reload_vfc_train_after_special = "1"b;
299 
300                                    if flags & report_flag then do; /* If error should be reported ... */
301                                         sdb.error_count = sdb.error_count + 1;
302 
303                                         if (temp_iom_stat & dev_stat_bits) ^= last_iom_stat then do; /* if not reported */
304                                              last_iom_stat = (temp_iom_stat & dev_stat_bits); /* save for next error */
305                                              same_err_stat_count = 1;
306                                              call com_err_ (0, prt_info.devname, errmess);
307                                         end;
308                                         else do;
309                                              same_err_stat_count = same_err_stat_count + 1;
310                                                             /* Allow only a resonable amount of unreported */
311                                                             /* errors to occur.  Then report again. */
312                                                             /* Also want to report again if need to wait. */
313                                              if same_err_stat_count >= max_err_stat_count | (flags&halt_flag) ^= "0"b
314                                              then do;
315                                                   sdb.wait_flag = "1"b;
316                                                   call com_err_ (0, prt_info.devname, errmess);
317                                              end;
318                                         end;
319                                    end;
320                                    sdb.wait_flag = ((flags & halt_flag) ^= "0"b) | sdb.wait_flag;
321                                                             /* Decide if operator intervention required. */
322 
323                                    if flags & image_flag then do; /* If train image destroyed ... */
324                                         call prtdim_util$load_image (sdb_ptr, rcode);
325                                         if rcode ^= 0 then return;
326                                    end;
327 
328                                    if flags & vfc_flag then do; /* If VFC image destroyed ... */
329                                         call prtdim_util$load_vfc (sdb_ptr, rcode);
330                                         if rcode ^= 0 then return;
331                                    end;
332                               end;
333 
334                               if sdb.wait_flag then do;
335                                    same_err_stat_count = 0;
336                                    call com_err_ (0, prt_info.devname, "***** OPERATOR INTERVENTION REQUIRED^/");
337                               end;
338 
339                          end;
340 
341                          else                               /* If no error ... */
342                          sdb.paper_low = "0"b;              /* Reset paper low flag. */
343 
344                          idcwp = addr (wseg (lx));          /* Get pointer to last DCW processed. */
345                          found_dcw = "0"b;                  /* Clear flag. */
346 
347                          if flags & backup_flag then do while (idcw.code ^= "111"b);
348                               lx = lx - 1;                  /* Back up to last print IDCW. */
349                               idcwp = addrel (idcwp, -1);
350                          end;
351 
352                          else if bin (imess.level) <= 3 then /* If termination status ... */
353                               do while (^found_dcw);        /* Search for terminate IDCW or TDCW. */
354                               if string (idcw) = prt_info.term_idcw then do;
355                                    lx, sdb.prev = sdb.stop; /* If end of list, reset. */
356                                    found_dcw = "1"b;
357                               end;
358                               else if idcw.code = "111"b then do; /* If at print IDCW ... */
359                                    found_dcw = "1"b;        /* Stay at this point. */
360                               end;
361                               else if idcwp -> tdcw.type = "10"b then do;
362                                    lx = bin (idcwp -> tdcw.address, 18);
363                                    found_dcw = "1"b;        /* If TDCW, follow the thread. */
364                               end;
365                               else do;                      /* Must be IOTD DCW. */
366                                    lx = lx + 1;             /* Step to third DCW slot. */
367                                    idcwp = addrel (idcwp, 1);
368                               end;
369                          end;
370                          else;                              /* Don't do anything for marker status. */
371 
372                          sdb.bgin = lx;                     /* Set new starting point. */
373                          sdb.running = imess.run;           /* Set running flag. */
374                     end;
375 
376                end;
377 
378                return;
379 
380           end stat_check;
381 %page;
382 prtdim_resetwrite: entry (arg_sdb_ptr, iostatus);           /* entry to scrap unprinted information */
383 
384 
385           iostatus = "0"b;
386 
387           sdb_ptr = arg_sdb_ptr;
388           pip = addr (sdb.info);
389           pcip = addr (sdb.conv_info);
390 
391           rcode = 0;
392 
393           do while (sdb.running);                           /* Wait for printer to stop. */
394                call wait_io;
395                if rcode ^= 0 then do;
396                     substr (iostatus, 1, 36) = unspec (rcode);
397                     return;
398                end;
399           end;
400 
401           sdb.prev,
402                sdb.bgin,
403                sdb.stop = 0;                                /* Reset all indices. */
404 
405           return;                                           /* Output all scrapped. */
406 %page;
407 runout:   entry (arg_sdb_ptr, iostatus);                    /* entry to disgorge unprinted information */
408 
409 
410           iostatus = "0"b;
411 
412           sdb_ptr = arg_sdb_ptr;
413           pip = addr (sdb.info);
414           pcip = addr (sdb.conv_info);
415 
416           rcode = 0;
417 
418           do while (sdb.prev ^= sdb.stop);                  /* Force connects until all caught up. */
419                call wait_io;                                /* Start printer and wait for completion. */
420                if rcode ^= 0 then do;
421                     substr (iostatus, 1, 36) = unspec (rcode);
422                     return;
423                end;
424           end;
425 
426           return;                                           /* Output all flushed. */
427 
428 
429 
430      end prtdim_write;