1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 uncp:
33 procedure;
34 return;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 DEBUG
74
75 dcl 1 trace int static options (constant),
76 2 load bit (1) unal init ("1"b),
77 2 mailbox bit (1) unal init ("0"b),
78 2 buffer_in bit (1) unal init ("0"b),
79 2 buffer_out bit (1) unal init ("0"b);
80
81 dcl max_special_name fixed bin int static options (constant) init (12);
82 dcl special_name (12) bit (36) int static options (constant) init ("444665252362"b3,
83
84 "444665250000"b3,
85 "444665250101"b3,
86 "534521623145"b3,
87 "534521624646"b3,
88 "446443633145"b3,
89 "446443634646"b3,
90 "534346272020"b3,
91 "434621242020"b3,
92 "512226202020"b3,
93 "512226203145"b3,
94 "512226204646"b3);
95
96 dcl dial_name (12) char (8) int static options (constant) init ("d FTF
97 ", "d FTF
98 ", "d FTF
99 ", "d NASF
100 ", "d NASF
101 ", "Multics", "Multics", "d LOG
102 ", "d LOAD
103 ", "d RBF
104 ", "rbfdsa", "rbfdsa");
105
106 dcl qorig fixed bin (24),
107 da fixed bin (24);
108
109 dcl sub_mbx_sent bit (1);
110 dcl sub_mbx_no fixed bin;
111 dcl sub_mbx_array (8) bit (36) aligned based (subp);
112 dcl 1 local_sub_mbx aligned like sub_mbx;
113
114 dcl (bufp, charp, qptr, other_pcbp) ptr,
115 timw fixed bin (24),
116 (level, dno, i, ix, q_first, q_count, chars_left, numchars, k, j) fixed bin,
117
118 devx fixed bin,
119 operation fixed bin (8),
120 lano bit (3) unal,
121 nblocks fixed bin;
122
123 dcl fnp_name char (1) aligned;
124
125 dcl no_response bit (1) aligned;
126
127 dcl interrupt_entry bit (1);
128 dcl input_count fixed bin;
129 dcl inchain bit (18);
130
131 dcl chan_lctep ptr;
132 dcl inchain_ptr ptr;
133 dcl bits_per_char fixed bin;
134 dcl max_buf_chars fixed bin;
135
136 dcl wire_arg fixed bin (71);
137 dcl wire_ptr ptr;
138 dcl masked bit (1);
139 dcl queue_locked bit (1);
140
141 dcl syserr_severity fixed bin (35);
142
143 dcl SYSERR_announce fixed bin int static options (constant) init (0);
144 dcl SYSERR_crash fixed bin int static options (constant) init (1);
145 dcl SYSERR_beep fixed bin int static options (constant) init (3);
146 dcl SYSERR_log fixed bin int static options (constant) init (4);
147
148
149
150
151
152
153 dcl LOOP_LIMIT fixed bin int static options (constant) init (100000);
154
155 dcl FNP_DOWN fixed bin int static options (constant) init (2);
156
157 dcl initial_pcw bit (36) int static init ("000000000000000000000000000000111001"b);
158
159
160 dcl INT_LEVEL_1 fixed bin int static options (constant) init (1);
161 dcl INT_LEVEL_3 fixed bin int static options (constant) init (3);
162 dcl INT_LEVEL_7 fixed bin int static options (constant) init (7);
163
164 dcl BAUD_9600 fixed bin int static options (constant) init (9600);
165
166 dcl MAX_FREE_BUFFERS fixed bin (35) int static options (constant) init (16000000000);
167
168 dcl BPC_10 fixed bin int static options (constant) init (10);
169 dcl BPC_8 fixed bin int static options (constant) init (8);
170
171 dcl MAX_CHANNEL_BUFFER fixed bin int static options (constant) init (128);
172
173 dcl CMD_DATA_LEN_3 fixed bin int static options (constant) init (3);
174
175
176 dcl MAX_MBX_REQ_CNT fixed bin (35) int static options (constant) init (262143);
177
178 dcl EIGHT fixed bin int static options (constant) init (8);
179
180 dcl CONNECTION_TYPE_1 bit (12) int static options (constant) init ("3145"b3);
181 dcl CONNECTION_TYPE_2 bit (12) int static options (constant) init ("4646"b3);
182
183 dcl timwb (0:6) bit (1) based (addr (timw)),
184 used_string bit (7) based (addr (datanet_mbx.mbx_used_flags.used (0)));
185
186
187
188 dcl (addr, substr, stac, stacq, string, ptr, rel, index, fixed, divide, bin, max, min, null, length, bit, unspec, hbound,
189 lbound, size, verify) builtin;
190
191 dcl unal_number fixed bin (17) unal based,
192 chars char (numchars) based;
193
194 dcl input_chars char (chars_left) based;
195
196 dcl smbx_cmd_data_long bit (216) unaligned based (addr (sub_mbx.command_data));
197
198 dcl tc_data$system_shutdown ext fixed bin;
199 dcl pds$processid bit (36) aligned ext static;
200
201 dcl ff_cr_lf char (3) int static options (constant) init ("^L^M
202 ");
203
204 dcl form_feed init ("^L") char (1) int static options (constant);
205
206
207 dcl syserr entry options (variable),
208 ldac entry (ptr) returns (fixed bin (24)),
209 dn355_util$compute_parity entry (bit (36)) returns (bit (36)),
210 (
211 uncp_boot_interrupt,
212 uncp_boot_interrupt$system_fault
213 ) entry (fixed bin),
214 uncp_boot_interrupt$request_init entry (fixed bin),
215 pxss$ring_0_wakeup entry (bit (36) aligned, fixed bin (71), fixed bin (71), fixed bin (35)),
216 pxss$unique_ring_0_wakeup entry (bit (36) aligned, fixed bin (71), fixed bin (71), fixed bin (35)),
217 pxss$notify entry (fixed bin);
218
219 dcl pmut$wire_and_mask entry (fixed bin (71), ptr);
220 dcl pmut$unwire_unmask entry (fixed bin (71), ptr);
221 dcl 1 auto_net_event_message aligned like net_event_message;
222 dcl 1 auto_fnp_msg aligned like fnp_msg;
223 dcl fnp_event_message fixed bin (71);
224
225 dcl 1 q_entry aligned like fnp_queue_entry based (qptr);
226
227 dcl new_qp ptr;
228 dcl new_qrel fixed bin;
229
230 dcl 1 wrap_q_address aligned based (addr (sub_mbx.command_data (3))),
231
232 2 wrap_ptr bit (18) unal,
233 2 wrap_cnt fixed bin (18) unsigned unal;
234
235 dcl fault_name char (16);
236
237
238 dcl cleanup condition;
239 ^L
240 %include tty_buf;
241
242 %include uncp_buf;
243 ^L
244 %include tty_buffer_block;
245
246 %include lct;
247 %include pcb;
248 %include dn355_data;
249 ^L
250 dcl 1 gateway_buf aligned based (blockp),
251 2 cnt fixed bin (18) unsigned unaligned,
252 2 pad bit (18) unaligned;
253
254 dcl gateway_header bit (36) based (blockp);
255
256 dcl buf_words (256) fixed bin based;
257 ^L
258 %include dn355_mailbox;
259
260 dcl connect_to_slave_nowait init (76) fixed bin (8) init static options (constant);
261 ^L
262 %include mailbox_ops;
263 ^L
264 %include mcs_interrupt_info;
265
266 %include dn355_messages;
267 ^L
268 %include fnp_queue_entry;
269 %include channel_manager_dcls;
270 %include tty_space_man_dcls;
271 ^L
272 %include line_types;
273 %include baud_rates;
274
275 %include net_event_message;
276 %page;
277 %include fnp_mpx_msg_;
278 %include io_manager_dcls;
279 %page;
280 interrupt:
281 entry (x_dno, x_level, x_status);
282
283 dcl x_dno fixed bin (35);
284 dcl x_level fixed bin (3);
285 dcl x_status bit (36) aligned;
286
287 if tc_data$system_shutdown ^= 0
288 then return;
289 interrupt_entry = "1"b;
290
291 call setup;
292 level = x_level;
293 if datanet_info.trace
294 then do;
295 if level ^= INT_LEVEL_3 | ^fnp_info.running
296 then syserr_severity = SYSERR_announce;
297 else syserr_severity = SYSERR_log;
298 call syserr (syserr_severity,
299 "uncp: FNP ^a level ^d status ^w^[ running^]^[ bootloading^]^[ t_and_d_in_progress^]", fnp_name,
300 level, x_status, fnp_info.running, fnp_info.bootloading, fnp_info.t_and_d_in_progress);
301 end;
302 if level ^= INT_LEVEL_3 & level ^= INT_LEVEL_7
303 then do;
304 call syserr (SYSERR_beep, "uncp: FNP ^a invalid interrupt level ^o", fnp_name, level);
305 if fnp_info.bootloading
306 then if level = INT_LEVEL_1
307 then call uncp_boot_interrupt$system_fault (dno);
308 return;
309 end;
310
311 if (^fnp_info.t_and_d_in_progress) & (^fnp_info.running) & (^fnp_info.bootloading)
312 then return;
313
314 if ^stac (addr (lcte.lock), pds$processid)
315 then do;
316
317 do while (^stac (addr (fnp_info.queue_lock), pds$processid));
318 end;
319
320 if level = INT_LEVEL_7
321 then fnp_info.level_7_pending = "1"b;
322 else fnp_info.level_3_pending = "1"b;
323
324 if stac (addr (lcte.lock), pds$processid)
325 then call process_int_queue ("0"b);
326
327 else if ^stacq (fnp_info.queue_lock, "0"b, pds$processid)
328 then call syserr (SYSERR_crash, "uncp: inconsistent queue lock");
329 end;
330
331 else do;
332 call process_int (level);
333
334 do while (^stac (addr (fnp_info.queue_lock), pds$processid));
335 end;
336
337 call process_int_queue ("0"b);
338 end;
339
340 return;
341
342 global_exit:
343 if interrupt_entry
344 then do;
345 if stacq (lcte.lock, "0"b, pds$processid)
346 then if lcte.notify_reqd
347 then do;
348 lcte.notify_reqd = "0"b;
349 call pxss$notify (tty_ev);
350 end;
351
352 lcte.locked_for_interrupt = "0"b;
353
354 end;
355 return;
356 ^L
357
358 send_wcd:
359 entry (a_fnpp, a_pcbp, opa, chrsa, data);
360
361 dcl a_fnpp ptr,
362 a_pcbp ptr,
363 opa fixed bin (8),
364 data bit (*),
365 chrsa fixed bin (8);
366
367 dcl tdata bit (8 * 36);
368 dcl data_len fixed bin (8);
369
370 pcbp = a_pcbp;
371 go to send_join;
372
373 send_global_wcd:
374 entry (a_fnpp, opa, chrsa, data);
375
376 pcbp = null ();
377 fnpp = a_fnpp;
378 if opa = dial
379 then do;
380 do ix = 1 to max_special_name while (special_name (ix) ^= substr (data, 1, 36));
381 end;
382 if ix <= max_special_name
383 then fnp_info.active_bit (ix) = substr (data, 37, 1);
384 return;
385 end;
386
387 send_join:
388 interrupt_entry = "0"b;
389 fnpp = a_fnpp;
390 ttybp = addr (tty_buf$);
391 infop = addr (dn355_data$);
392 uncpbp = datanet_info.uncp_bufp;
393 lctep = fnp_info.lcte_ptr;
394 operation = opa;
395 if ^fnp_info.running &
396 (^fnp_info.bootloading | operation ^= init_complete)
397 then return;
398
399 no_response = "0"b;
400 dno = fnp_info.fnp_number;
401 mbxp = fnp_info.mbx_pt;
402 data_len = min (length (tdata), chrsa);
403 if data_len > 0
404 then tdata = substr (data, 1, data_len);
405 else tdata = "0"b;
406
407 if pcbp ^= null
408 then if operation = disconnect_this_line
409 then if pcb.dialed = "0"b
410 then return;
411
412 if operation = accept_direct_output
413 then if pcb.dumpout
414 then do;
415 call throw_away_output;
416 pcb.dumpout = "0"b;
417 end;
418
419 if operation = enter_receive
420 then do;
421 if pcb.connection_type = "10"b
422 then return;
423
424 ix = pcb.baud_rate;
425 if ix ^= BAUD_9600
426 then do;
427 pcb.turn = "1"b;
428 call send_dial;
429 return;
430 end;
431
432 if pcb.write_last ^= 0
433 then do;
434 blockp = ptr (ttybp, pcb.write_last);
435 buffer.turn = "1"b;
436 return;
437 end;
438 else do;
439 pcb.enter_receive_pending = "1"b;
440 if pcb.end_frame | ^pcb.send_output
441 then return;
442 else operation = accept_direct_output;
443 end;
444
445 end;
446
447 call assign_sub_mbx (sub_mbx_no, subp);
448 if sub_mbx_no = -1
449 then do;
450 call make_q_entry (operation, data_len, tdata);
451 fnp_info.mbx_unavailable = fnp_info.mbx_unavailable + 1;
452
453 end;
454
455 else do;
456 if pcbp ^= null ()
457 then do;
458 string (sub_mbx.line_number) = string (pcb.line_number);
459
460 devx = pcb.devx;
461 end;
462
463 else string (sub_mbx.line_number) = "0"b;
464
465 sub_mbx.op_code = operation;
466 sub_mbx.cmd_data_len = divide (data_len, 6, 17, 0);
467
468 if operation = accept_direct_output
469 then do;
470 if ^pcb.flags.dialed
471 then call throw_away_output;
472
473 else call process_send_output (sub_mbx_no, "0"b);
474 end;
475
476 else do;
477 sub_mbx.io_cmd = wcd;
478 smbx_cmd_data_long = substr (tdata, 1, data_len);
479
480 call send_mbx (sub_mbx_no);
481 fnp_info.output_control_transactions = fnp_info.output_control_transactions + 1;
482 end;
483
484 if ^sub_mbx_sent
485 then call release_sub_mbx (sub_mbx_no);
486
487 if no_response
488 then call report_fnp_no_response;
489 end;
490
491
492 return;
493 ^L
494 process_interrupt_queue:
495 entry (x_dno);
496
497 interrupt_entry = "0"b;
498 call setup;
499 on cleanup call check_lock;
500 masked = "1"b;
501 call pmut$wire_and_mask (wire_arg, wire_ptr);
502
503 do while (^stac (addr (fnp_info.queue_lock), pds$processid));
504 end;
505 queue_locked = "1"b;
506
507 call process_int_queue ("1"b);
508 return;
509 ^L
510 setup:
511 proc;
512
513 ttybp = addr (tty_buf$);
514 dno = x_dno;
515 infop = addr (dn355_data$);
516 uncpbp = datanet_info.uncp_bufp;
517
518 fnpp = addr (datanet_info.per_datanet (dno));
519 fnp_name = fnp_info.fnp_tag;
520 mbxp = fnp_info.mbx_pt;
521 lctep = fnp_info.lcte_ptr;
522 n_pcbs = fnp_info.no_of_channels;
523
524 return;
525 end setup;
526 ^L
527 process_int_queue:
528 proc (caller_masked);
529
530
531
532 dcl caller_masked bit (1);
533
534 do while (dequeue (level));
535 fnp_info.processed_from_q = fnp_info.processed_from_q + 1;
536
537 if ^stacq (fnp_info.queue_lock, "0"b, pds$processid)
538 then call syserr (SYSERR_crash, "uncp: inconsistent queue lock");
539
540 queue_locked = "0"b;
541 if caller_masked
542 then call pmut$unwire_unmask (wire_arg, wire_ptr);
543 masked = "0"b;
544
545 call process_int (level);
546
547 if caller_masked
548 then do;
549 masked = "1"b;
550 call pmut$wire_and_mask (wire_arg, wire_ptr);
551 end;
552
553 do while (^stac (addr (fnp_info.queue_lock), pds$processid));
554 end;
555 queue_locked = "1"b;
556 end;
557
558 lcte.locked_for_interrupt = "0"b;
559 if ^stacq (lcte.lock, "0"b, pds$processid)
560 then call syserr (SYSERR_crash, "uncp: LCTE lock ^^= processid");
561
562 if ^stacq (fnp_info.queue_lock, "0"b, pds$processid)
563 then call syserr (SYSERR_crash, "uncp: inconsistent queue lock");
564
565 queue_locked = "0"b;
566 if caller_masked
567 then call pmut$unwire_unmask (wire_arg, wire_ptr);
568 masked = "0"b;
569
570 if lcte.notify_reqd
571 then do;
572 lcte.notify_reqd = "0"b;
573 call pxss$notify (tty_ev);
574 end;
575
576 return;
577
578 dequeue:
579 proc (a_level) returns (bit (1));
580
581 dcl a_level fixed bin;
582
583 if fnp_info.level_3_pending
584 then do;
585 fnp_info.level_3_pending = "0"b;
586 a_level = INT_LEVEL_3;
587 return ("1"b);
588 end;
589
590 else if fnp_info.level_7_pending
591 then do;
592 fnp_info.level_7_pending = "0"b;
593 a_level = INT_LEVEL_7;
594 return ("1"b);
595 end;
596
597 else return ("0"b);
598
599 end ;
600 end ;
601 ^L
602 process_int:
603 proc (a_level);
604
605
606
607 dcl a_level fixed bin;
608
609 level = a_level;
610
611 lcte.locked_for_interrupt = "1"b;
612 if level = INT_LEVEL_7
613 then do;
614
615 if fnp_info.t_and_d_in_progress
616 then do;
617 if fnp_info.t_and_d_lev_7_occurred
618 then return;
619 fnp_info.t_and_d_lev_7_occurred = "1"b;
620 t_and_d_join:
621 if fnp_info.t_and_d_notify_requested
622 then do;
623 call pxss$notify (tty_ev);
624 fnp_info.t_and_d_notify_requested = "0"b;
625 end;
626 unspec (auto_net_event_message) = "0"b;
627 auto_net_event_message.version = NET_EVENT_MESSAGE_VERSION_1;
628 auto_net_event_message.network_type = MCS_NETWORK_TYPE;
629 auto_net_event_message.handle = dno;
630 auto_net_event_message.type = level;
631 unspec (net_event_message_arg) = unspec (auto_net_event_message);
632 call pxss$unique_ring_0_wakeup (fnp_info.boot_process_id, fnp_info.boot_ev_chan,
633 net_event_message_arg, 0);
634 return;
635 end;
636
637 fault_name = "STOPPING DATANET";
638 call syserr (SYSERR_beep, "uncp: emergency interrupt from FNP ^a: ^a", fnp_info.fnp_tag, fault_name);
639 timw = ldac (addr (datanet_mbx.term_inpt_mpx_wd));
640 if fnp_info.running
641 then call purge_write_texte;
642
643
644 call report_fnp_crash;
645 return;
646 end;
647
648 if unspec (datanet_mbx.mailbox_requests) = "777777000000"b3
649 then do;
650 datanet_mbx.mailbox_requests = datanet_mbx.mailbox_requests + 1;
651
652 if trace.load
653 then call syserr (SYSERR_log, "uncp: request_init");
654
655 timw = ldac (addr (datanet_mbx.term_inpt_mpx_wd));
656 if fnp_info.running
657 then call purge_write_texte;
658 call uncp_boot_interrupt$request_init (dno);
659 fnp_info.uncp_pcbx1, fnp_info.uncp_pcbx2 = 0;
660 return;
661 end;
662
663 if fnp_info.bootloading
664 then do;
665 timw = ldac (addr (datanet_mbx.term_inpt_mpx_wd));
666 if timwb (0)
667 then do;
668 subp = addr (datanet_mbx.dn355_sub_mbxes (0));
669 datanet_mbx.mbx_used_flags.used (0) = "0"b;
670
671 datanet_mbx.num_in_use = datanet_mbx.num_in_use - 1;
672 if (sub_mbx.io_cmd = wcd) & (sub_mbx.op_code = init_complete)
673 then do;
674
675 if trace.load
676 then call syserr (SYSERR_log, "uncp: WCD init_complete acknowledgement");
677
678 call uncp_boot_interrupt (dno);
679 fnp_info.uncp_pcbx1, fnp_info.uncp_pcbx2 = 0;
680 end;
681 end;
682 return;
683 end;
684
685
686
687
688 if fnp_info.t_and_d_in_progress
689 then do;
690 if fnp_info.t_and_d_lev_3_occurred
691 then return;
692 fnp_info.t_and_d_lev_3_occurred = "1"b;
693 go to t_and_d_join;
694 end;
695
696 if ^fnp_info.running
697 then return;
698
699
700 no_response = "0"b;
701
702
703
704
705 if used_string ^= (7)"1"b
706 then call spend_submailboxes;
707 ^L
708
709
710 timw = ldac (addr (datanet_mbx.term_inpt_mpx_wd));
711
712
713
714
715 do i = lbound (timwb, 1) to hbound (timwb, 1);
716
717 if timwb (i) & ^no_response
718 then do;
719 sub_mbx_no = i;
720 unspec (local_sub_mbx) = unspec (datanet_mbx.dn355_sub_mbxes (sub_mbx_no));
721 subp = addr (local_sub_mbx);
722 if trace.mailbox
723 then call syserr (SYSERR_log, "uncp: mbx received # ^o ^2( ^/ ^4( ^w ^) ^)", sub_mbx_no,
724 sub_mbx_array);
725 datanet_mbx.mbx_used_flags.used (sub_mbx_no) = "0"b;
726
727 sub_mbx_no = -1;
728
729 datanet_mbx.num_in_use = datanet_mbx.num_in_use - 1;
730 fnp_info.cumulative_mbx_in_use = fnp_info.cumulative_mbx_in_use + datanet_mbx.num_in_use;
731 fnp_info.mbx_in_use_updated = fnp_info.mbx_in_use_updated + 1;
732
733
734 call get_line_number;
735
736
737
738 if sub_mbx.io_cmd = wcd
739 then do;
740 if (devx ^= -1) & (sub_mbx.op_code = disconnect_this_line)
741 then do;
742 if pcb.dialed
743 then do;
744 call throw_away_output;
745 if pcb.connection_type ^= "01"b
746 then call channel_manager$interrupt (devx, HANGUP, ""b);
747 disconnect_other_line:
748 if (pcb.connection_type ^= "00"b) & (pcb.uncp_pcbx ^= 0)
749 then do;
750 other_pcbp = addr (fnp_info.pcb_array_ptr -> pcb_array (pcb.uncp_pcbx));
751 if other_pcbp -> pcb.dialed
752 then do;
753 string (sub_mbx.line_number) = string (other_pcbp -> pcb.line_number);
754 call return_mbx (sub_mbx_no);
755 end;
756 end;
757 end;
758 pcb.dialed = "0"b;
759 pcb.baud_rate = 0;
760 end;
761
762 if (devx ^= -1) & (sub_mbx.op_code = disconnect_accepted)
763 then do;
764 sub_mbx.op_code = disconnect_this_line;
765 goto disconnect_other_line;
766 end;
767
768
769 end;
770
771 else do;
772
773
774
775 if sub_mbx.io_cmd = wtx
776 then do;
777 pcb.output_mbx_pending = "0"b;
778 if pcb.connection_type = "10"b
779 then pcbp = addr (fnp_info.pcb_array_ptr -> pcb_array (pcb.uncp_pcbx));
780 if sub_mbx.command_data (3) ^= "0"b
781 then do;
782 da = bin (sub_mbx.data_addr, 18) - tty_buf.absorig;
783
784 blockp = ptr (ttybp, da);
785 gateway_header = sub_mbx.command_data (3);
786
787
788 call tty_space_man$free_chain ((pcb.devx), OUTPUT, blockp);
789
790
791
792
793 end;
794 end;
795
796
797
798 else if sub_mbx.io_cmd = rcd
799 then do;
800 if (sub_mbx.op_code = accept_direct_input) | (sub_mbx.op_code = send_output)
801 then do;
802
803
804 fnp_info.bleft_355 = 0;
805
806 if fnp_info.free_size > MAX_FREE_BUFFERS
807 then do;
808 fnp_info.free_size = 0;
809 fnp_info.free_count = 0;
810 end;
811
812 fnp_info.free_size = fnp_info.free_size + fnp_info.bleft_355;
813 fnp_info.free_count = fnp_info.free_count + 1;
814 end;
815 if sub_mbx.op_code = accept_direct_input
816 then fnp_info.input_data_transactions = fnp_info.input_data_transactions + 1;
817 else fnp_info.input_control_transactions = fnp_info.input_control_transactions + 1;
818
819
820
821
822
823 if sub_mbx.op_code = accept_new_terminal
824 then do;
825 if devx = -1
826 then do;
827 sub_mbx.io_cmd = wcd;
828 sub_mbx.op_code = terminal_rejected;
829 sub_mbx.cmd_data_len = 0;
830 call return_mbx (sub_mbx_no);
831 end;
832 else do;
833
834
835 pcb.line_type = LINE_ASCII;
836 pcb.send_lf = "0"b;
837
838
839
840 pcb.baud_rate = BAUD_9600;
841
842
843 do j = 1 to n_sync_line_types while (sync_line_type (j) ^= pcb.line_type);
844 end;
845 pcb.sync_line = (j <= n_sync_line_types);
846
847 if ^pcb.sync_line
848 then bits_per_char = BPC_10;
849 else bits_per_char = BPC_8;
850
851
852 max_buf_chars =
853 divide (divide (pcb.baud_rate, bits_per_char, 17, 0), buf_per_second, 17, 0);
854 pcb.max_buf_size = min (16 * divide (max_buf_chars + 67, 64, 17, 0), 128);
855
856 if pcb.line_type = LINE_COLTS
857 then pcb.max_buf_size = MAX_CHANNEL_BUFFER;
858
859 pcb.dialed, pcb.enter_receive_pending, pcb.turn, pcb.dumpout, pcb.send_output =
860 "0"b;
861 pcb.connection_type = "00"b;
862
863 sub_mbx.op_code = terminal_accepted;
864
865 sub_mbx.cmd_data_len = CMD_DATA_LEN_3;
866
867 if ^pcb.high_speed
868 then addr (sub_mbx.command_data) -> unal_number = 2;
869
870 else addr (sub_mbx.command_data) -> unal_number = 4;
871
872 sub_mbx.io_cmd = wcd;
873 call return_mbx (sub_mbx_no);
874 end;
875 end;
876
877
878
879 else if sub_mbx.op_code = disconnected_line
880 then do;
881 if pcb.dialed
882 then do;
883 call throw_away_output;
884 if pcb.connection_type ^= "01"b
885 then call channel_manager$interrupt (devx, HANGUP, ""b);
886 end;
887 pcb.dialed = "0"b;
888 sub_mbx.io_cmd = wcd;
889 sub_mbx.op_code = disconnect_accepted;
890 call return_mbx (sub_mbx_no);
891 end;
892
893
894
895 else if sub_mbx.op_code = break_condition
896 then do;
897 if pcb.dialed
898 then do;
899 if pcb.hndlquit
900 then call throw_away_output;
901 call channel_manager$interrupt (devx, QUIT, ""b);
902 pcb.turn = "1"b;
903 end;
904 sub_mbx.io_cmd = wcd;
905 sub_mbx.op_code = break_acknowledged;
906 sub_mbx.cmd_data_len = 0;
907 call return_mbx (sub_mbx_no);
908 call make_q_entry (accept_direct_output, 0, ""b);
909
910 end;
911
912
913
914 else if sub_mbx.op_code = send_output
915 then do;
916 if pcb.dialed
917 then do;
918 if pcb.connection_type = "10"b
919 then pcb.turn = "1"b;
920 call process_send_output (sub_mbx_no, "1"b);
921 end;
922
923 end;
924
925
926
927 else if sub_mbx.op_code = accept_direct_input
928 then do;
929 if pcb.dialed
930 then call process_accept_input;
931 end;
932
933
934
935
936 else if (sub_mbx.op_code = connect_to_slave) | (sub_mbx.op_code = connect_to_slave_nowait)
937 then do;
938 pcb.extra_nl, pcb.lfecho = "0"b;
939 do ix = 1 to max_special_name while (special_name (ix) ^= sub_mbx.command_data (1));
940 end;
941 if ix <= max_special_name
942 then do;
943 if (dial_name (ix) = "Multics") | (dial_name (ix) = "rbfdsa")
944 then fnp_info.active_bit (ix) = "1"b;
945
946 if ^fnp_info.active_bit (ix)
947 then do;
948 sub_mbx.io_cmd = wcd;
949 sub_mbx.op_code = disconnect_this_line;
950 call return_mbx (sub_mbx_no);
951 goto no_dialup;
952 end;
953 end;
954
955 if ix > max_special_name
956 then do;
957 ix = BAUD_9600;
958 pcb.turn, pcb.extra_nl, pcb.lfecho = "1"b;
959 end;
960 else do;
961 pcb.baud_rate = ix;
962 if index (special_name (ix), CONNECTION_TYPE_1) ^= 0
963 then pcb.connection_type = "01"b;
964 if index (special_name (ix), CONNECTION_TYPE_2) ^= 0
965 then pcb.connection_type = "10"b;
966 end;
967
968 pcb.dialed = "1"b;
969
970 if pcb.connection_type = "01"b
971 then do;
972 pcb.uncp_pcbx = 0;
973 if fnp_info.uncp_pcbx1 = 0
974 then do;
975 fnp_info.uncp_pcbx1 = j;
976 sub_mbx.op_code = enter_receive;
977 call return_mbx (sub_mbx_no);
978 end;
979 else if fnp_info.uncp_pcbx2 = 0
980 then fnp_info.uncp_pcbx2 = j;
981 goto no_dialup;
982 end;
983
984 if pcb.connection_type = "10"b
985 then do;
986 if fnp_info.uncp_pcbx1 = 0
987 then do;
988 call syserr (SYSERR_announce,
989 "uncp: Connection on output only not awaited. (dial '^a')",
990 dial_name (ix));
991 goto no_dialup;
992 end;
993 else do;
994 other_pcbp =
995 addr (fnp_info.pcb_array_ptr -> pcb_array (fnp_info.uncp_pcbx1));
996 other_pcbp -> pcb.uncp_pcbx = j;
997 pcb.uncp_pcbx = fnp_info.uncp_pcbx1;
998 pcb.turn = "1"b;
999 if dial_name (ix) = "Multics"
1000 then other_pcbp -> pcb.extra_nl = "1"b;
1001
1002 if (dial_name (ix) = "Multics") | (dial_name (ix) = "rbfdsa")
1003 then other_pcbp -> pcb.baud_rate, pcb.baud_rate = BAUD_9600;
1004
1005
1006 fnp_info.uncp_pcbx1 = 0;
1007 if fnp_info.uncp_pcbx2 ^= 0
1008 then do;
1009 other_pcbp =
1010 addr (fnp_info.pcb_array_ptr -> pcb_array (fnp_info.uncp_pcbx2));
1011 fnp_info.uncp_pcbx1 = fnp_info.uncp_pcbx2;
1012 fnp_info.uncp_pcbx2 = 0;
1013 string (sub_mbx.line_number) = string (other_pcbp -> pcb.line_number);
1014 sub_mbx.op_code = enter_receive;
1015 call return_mbx (sub_mbx_no);
1016 j = fnp_info.hsla_idx (0);
1017 do j = j to fnp_info.no_of_channels while (fnp_info.uncp_pcbx2 = 0);
1018 other_pcbp = addr (fnp_info.pcb_array_ptr -> pcb_array (j));
1019 if other_pcbp -> pcb.dialed
1020 & (other_pcbp -> pcb.connection_type = "01"b)
1021 & (other_pcbp -> pcb.uncp_pcbx = 0)
1022 then if (fnp_info.uncp_pcbx1 ^= j)
1023 then fnp_info.uncp_pcbx2 = j;
1024 end;
1025 end;
1026 end;
1027 end;
1028
1029 dialup_info.line_type = LINE_ASCII;
1030 dialup_info.receive_mode_device = "0"b;
1031 if pcb.connection_type = "00"b
1032 then dialup_info.receive_mode_device = "1"b;
1033 dialup_info.baud_rate = ix;
1034 dialup_info.max_buf_size = pcb.max_buf_size;
1035 dialup_info.buffer_pad = 0;
1036 dialup_info.pad = "0"b;
1037 interrupt_info = unspec (dialup_info);
1038 call channel_manager$interrupt (devx, DIALUP, interrupt_info);
1039 call process_send_output (sub_mbx_no, "1"b);
1040 no_dialup:
1041 end;
1042
1043 else if devx ^= -1
1044 then call syserr (SYSERR_announce,
1045 "uncp: unrecognized op code ^o with rcd from FNP ^a for devx ^o", sub_mbx.op_code,
1046 substr ("abcdefgh", dno, 1), devx);
1047
1048
1049 end;
1050
1051
1052
1053 else if sub_mbx.io_cmd = rtx
1054 then do;
1055 call process_rtx;
1056 if pcb.connection_type = "01"b
1057 then do;
1058 sub_mbx.op_code = enter_receive;
1059 call return_mbx (sub_mbx_no);
1060 end;
1061 end;
1062 else call syserr (SYSERR_beep, "uncp: unrecognized io command ^o from FNP ^a for line ^o",
1063 sub_mbx.io_cmd, substr ("abcdefgh", dno, 1), bin (string (sub_mbx.line_number), 10));
1064
1065 end;
1066
1067
1068 end;
1069 end;
1070
1071
1072
1073
1074 if ^no_response & used_string ^= (7)"1"b
1075 then
1076 call spend_submailboxes;
1077
1078
1079
1080
1081 if no_response
1082 then call report_fnp_no_response;
1083
1084
1085
1086 return;
1087 end ;
1088 ^L
1089
1090
1091
1092 spend_submailboxes:
1093 proc;
1094
1095 if fnp_info.count ^= 0
1096 then call process_q;
1097
1098
1099 do while (datanet_mbx.mailbox_requests ^= datanet_mbx.last_mbx_req_count);
1100
1101 call assign_sub_mbx (sub_mbx_no, subp);
1102 if sub_mbx_no = -1
1103 then return;
1104 sub_mbx.io_cmd = rcd;
1105 call send_mbx (sub_mbx_no);
1106 datanet_mbx.last_mbx_req_count = datanet_mbx.last_mbx_req_count + 1;
1107 if datanet_mbx.last_mbx_req_count > MAX_MBX_REQ_CNT
1108 then datanet_mbx.last_mbx_req_count = 0;
1109 if ^sub_mbx_sent
1110 then call release_sub_mbx (sub_mbx_no);
1111 end;
1112 end ;
1113 ^L
1114 process_q:
1115 proc;
1116
1117
1118
1119
1120
1121 q_first = fnp_info.cur_ptr;
1122 q_count = fnp_info.count;
1123 sub_mbx_no = 0;
1124
1125 do while (q_count > 0 & sub_mbx_no >= 0);
1126 call assign_sub_mbx (sub_mbx_no, subp);
1127 if sub_mbx_no >= 0
1128 then do;
1129 qptr = ptr (ttybp, q_first);
1130 if q_entry.pcb_offset ^= "0"b
1131 then do;
1132 pcbp = ptr (ttybp, q_entry.pcb_offset);
1133 string (sub_mbx.line_number) = string (pcb.line_number);
1134 devx = pcb.devx;
1135 end;
1136 else string (sub_mbx.line_number) = ""b;
1137
1138 if q_entry.opcode = accept_direct_output
1139 then if pcb.dialed
1140 then call process_send_output (sub_mbx_no, "0"b);
1141 else ;
1142
1143 else do;
1144 sub_mbx.io_cmd = wcd;
1145 sub_mbx.op_code = q_entry.opcode;
1146 sub_mbx.cmd_data_len = divide (q_entry.cmd_count, 6, 8, 0);
1147 smbx_cmd_data_long = substr (q_entry.cmd_data, 1, q_entry.cmd_count);
1148 call send_mbx (sub_mbx_no);
1149 fnp_info.output_control_transactions = fnp_info.output_control_transactions + 1;
1150 end;
1151
1152 if no_response
1153 then goto update_q_ptrs;
1154
1155 q_first = q_entry.next;
1156 q_count = q_count - 1;
1157 call tty_space_man$free_space (size (q_entry), qptr);
1158 if ^sub_mbx_sent
1159 then call release_sub_mbx (sub_mbx_no);
1160 end;
1161
1162 else fnp_info.mbx_unavailable = fnp_info.mbx_unavailable + 1;
1163 end;
1164
1165 update_q_ptrs:
1166 fnp_info.cur_ptr = q_first;
1167 fnp_info.count = q_count;
1168 if q_count = 0
1169 then fnp_info.last_ptr = 0;
1170
1171 return;
1172 end ;
1173 ^L
1174 send_dial:
1175 proc;
1176 pcb.send_output = "1"b;
1177 devx = pcb.devx;
1178
1179 if pcb.write_last ^= 0
1180 then do;
1181 blockp = ptr (ttybp, pcb.write_last);
1182 if buffer.turn
1183 then pcb.turn = "1"b;
1184 call throw_away_output;
1185 end;
1186
1187 if pcb.turn = "1"b
1188 then do;
1189 call tty_space_man$get_chain (devx, 16, 1, INPUT, inchain_ptr);
1190 if inchain_ptr = null
1191 then do;
1192 call syserr (SYSERR_announce, "uncp: special_dial, Failure of buffer to make '^a'", dial_name (ix));
1193 call channel_manager$interrupt (devx, QUIT, ""b);
1194 return;
1195 end;
1196 inchain = rel (inchain_ptr);
1197 blockp = inchain_ptr;
1198 numchars = EIGHT;
1199 bufp = addr (dial_name (ix));
1200 charp = addr (buffer.chars);
1201 charp -> chars = bufp -> chars;
1202 buffer.tally = numchars;
1203 rtx_info.break_char = "1"b;
1204 rtx_info.output_in_fnp = "0"b;
1205 rtx_info.output_in_ring_0 = "0"b;
1206 rtx_info.input_count = EIGHT;
1207 rtx_info.chain_head = inchain;
1208 rtx_info.chain_tail = rel (blockp);
1209 interrupt_info = unspec (rtx_info);
1210 call channel_manager$interrupt (devx, ACCEPT_INPUT, interrupt_info);
1211 pcb.baud_rate = BAUD_9600;
1212 pcb.dumpout = "1"b;
1213 end;
1214 call channel_manager$interrupt (devx, SEND_OUTPUT, ""b);
1215 return;
1216
1217 end send_dial;
1218 ^L
1219
1220
1221 process_send_output:
1222 proc (a_mbx_num, interrupt_entry);
1223
1224 dcl a_mbx_num fixed bin;
1225 dcl mbx_num fixed bin;
1226 dcl interrupt_entry bit (1) aligned;
1227
1228 mbx_num = a_mbx_num;
1229
1230 if pcb.end_frame | pcb.output_mbx_pending
1231 then do;
1232 pcb.flags.send_output = "1"b;
1233 if pcb.turn = "1"b
1234 then call channel_manager$interrupt (devx, SEND_OUTPUT, ""b);
1235
1236 return;
1237 end;
1238
1239 if pcb.enter_receive_pending | pcb.send_lf
1240 then do;
1241 sub_mbx.op_code = enter_receive;
1242 call send_mbx (mbx_num);
1243 return;
1244 end;
1245
1246 if pcb.write_first = 0
1247 then do;
1248
1249 pcb.flags.send_output = "1"b;
1250 call channel_manager$interrupt (devx, SEND_OUTPUT, ""b);
1251 end;
1252
1253 else do;
1254 ix = pcb.baud_rate;
1255 if ix ^= BAUD_9600
1256 then do;
1257 call send_dial;
1258 return;
1259 end;
1260
1261 if pcb.turn = "0"b
1262 then return;
1263
1264 if mbx_num = -1
1265 then do;
1266 call assign_sub_mbx (mbx_num, subp);
1267 if mbx_num = -1
1268 then do;
1269 call make_q_entry (accept_direct_output, 0, ""b);
1270 fnp_info.mbx_unavailable = fnp_info.mbx_unavailable + 1;
1271 return;
1272 end;
1273 else do;
1274 string (sub_mbx.line_number) = string (pcb.line_number);
1275 end;
1276 end;
1277
1278
1279 pcb.flags.send_output = "0"b;
1280
1281
1282
1283
1284 blockp = ptr (ttybp, pcb.write_first);
1285 if buffer.tally = 0
1286 then call syserr (SYSERR_crash, "uncp: output buffer at ^o has zero tally", pcb.write_first);
1287
1288
1289
1290
1291 pcb.write_first = buffer.next;
1292 pcb.write_cnt = pcb.write_cnt - buffer.tally;
1293
1294
1295 if buffer.flags.end_of_page
1296 then pcb.flags.end_frame = "1"b;
1297
1298
1299 if pcb.write_first ^= 0
1300 then buffer.flags.turn = "0"b;
1301
1302
1303 sub_mbx.op_code = accept_direct_output;
1304 if buffer.flags.turn
1305 then pcb.flags.end_frame = "0"b;
1306 if buffer.flags.turn | buffer.flags.end_of_page
1307 then do;
1308 sub_mbx.op_code = accept_last_output;
1309 pcb.turn = "0"b;
1310 end;
1311
1312 sub_mbx.command_data (1) = "0"b;
1313 sub_mbx.data_addr = bit (bin (bin (rel (blockp), 18) + tty_buf.absorig, 18), 18);
1314 j = bin (buffer.tally, 18);
1315 sub_mbx.word_cnt = 1 + divide (j + 3, 4, 18, 0);
1316 buffer.next = 0;
1317 sub_mbx.command_data (3) = gateway_header;
1318 gateway_buf.cnt = j;
1319 gateway_buf.pad = "0"b;
1320 sub_mbx.io_cmd = wtx;
1321
1322 if trace.buffer_out
1323 then call syserr (SYSERR_log, "uncp: buffer = ^v( ^w ^) ", sub_mbx.word_cnt, blockp -> buf_words);
1324
1325 if pcb.connection_type = "01"b & sub_mbx.op_code = accept_direct_output
1326 then string (sub_mbx.line_number) =
1327 string (addr (fnp_info.pcb_array_ptr -> pcb_array (pcb.uncp_pcbx)) -> pcb.line_number);
1328 pcb.output_mbx_pending = "1"b;
1329 call send_mbx (mbx_num);
1330 fnp_info.output_data_transactions = fnp_info.output_data_transactions + 1;
1331
1332 if pcb.write_first = 0
1333 then do;
1334 pcb.write_last = 0;
1335 if interrupt_entry
1336 then call channel_manager$interrupt (devx, SEND_OUTPUT, ""b);
1337
1338 end;
1339 end;
1340
1341 return;
1342 end;
1343 ^L
1344
1345
1346 process_accept_input:
1347 proc;
1348
1349 input_count = fixed (substr (sub_mbx.command_data (1), 1, 18), 18) + 4;
1350
1351
1352 j = divide (input_count + 3, 4, 17, 0);
1353
1354 do while (^stac (addr (uncp_buf.cq_lock), pds$processid));
1355
1356 end;
1357
1358 k = uncp_buf.cq_max_size - uncp_buf.cq_next;
1359 if j <= uncp_buf.cq_free
1360 then if enough_input_space (j)
1361 then do;
1362 if j > k
1363 then if j <= uncp_buf.cq_free - k
1364 then uncp_buf.cq_next = 0;
1365 else go to reject;
1366
1367 qorig = tty_buf.absorig + fixed (rel (addr (uncp_buf.circular_queue (0))));
1368
1369
1370 uncp_buf.cq_free = uncp_buf.cq_free - j;
1371
1372 if uncp_buf.circular_queue_size > MAX_FREE_BUFFERS
1373 then do;
1374 uncp_buf.circular_queue_size = 0;
1375 uncp_buf.queue_ave_cnt = 0;
1376 end;
1377 uncp_buf.circular_queue_size = uncp_buf.circular_queue_size +
1378
1379 (uncp_buf.cq_max_size - uncp_buf.cq_free);
1380
1381 uncp_buf.queue_ave_cnt = uncp_buf.queue_ave_cnt + 1;
1382
1383
1384 uncp_buf.circular_queue (uncp_buf.cq_next) = 0;
1385 sub_mbx.data_addr = bit (bin (qorig + uncp_buf.cq_next, 18), 18);
1386
1387 uncp_buf.cq_next = uncp_buf.cq_next + j;
1388
1389 wrap_ptr = "0"b;
1390 wrap_cnt = 0;
1391
1392 if uncp_buf.cq_next > uncp_buf.cq_max_size
1393 then do;
1394 wrap_ptr = bit (bin (qorig, 18), 18);
1395
1396 uncp_buf.cq_next = uncp_buf.cq_next - uncp_buf.cq_max_size;
1397
1398 wrap_cnt = input_count - 4 * (j - uncp_buf.cq_next);
1399
1400 sub_mbx.word_cnt = input_count - wrap_cnt;
1401
1402 end;
1403
1404
1405
1406 else sub_mbx.word_cnt = j;
1407
1408 if uncp_buf.cq_next = uncp_buf.cq_max_size
1409 then uncp_buf.cq_next = 0;
1410
1411
1412 if trace.buffer_in
1413 then call syserr (SYSERR_log, "uncp$process_accept_input: cq_next = ^w , cq_free = ^w , count = ^w ",
1414 uncp_buf.cq_next, uncp_buf.cq_free, j);
1415
1416 sub_mbx.op_code = input_accepted;
1417 sub_mbx.io_cmd = rtx;
1418 call return_mbx (sub_mbx_no);
1419 end;
1420
1421 else go to reject;
1422
1423 else do;
1424 uncp_buf.queue_full_cnt = uncp_buf.queue_full_cnt + 1;
1425
1426 reject:
1427 sub_mbx.io_cmd = wcd;
1428 sub_mbx.op_code = reject_request_temp;
1429
1430 call return_mbx (sub_mbx_no);
1431 fnp_info.input_reject_count = fnp_info.input_reject_count + 1;
1432 call channel_manager$interrupt (devx, INPUT_REJECTED, ""b);
1433 end;
1434
1435 if ^stacq (uncp_buf.cq_lock, "0"b, pds$processid)
1436 then call syserr (SYSERR_crash, "uncp: inconsistent circular queue lock.");
1437
1438 end ;
1439 ^L
1440
1441 process_rtx:
1442 proc;
1443
1444 dcl (real_word_cnt, real_wrap_cnt) fixed bin;
1445 dcl chars_to_move fixed bin;
1446 dcl left_in_buffer fixed bin;
1447 dcl char_array (0:numchars) char (1) unaligned based;
1448
1449 sub_mbx.command_data (3) = "0"b;
1450
1451 bufp = ptr (ttybp, bin (sub_mbx.data_addr, 24) - tty_buf.absorig);
1452 real_word_cnt = bufp -> unal_number;
1453 if real_word_cnt = 0
1454 then goto update_free;
1455
1456 real_wrap_cnt = wrap_cnt;
1457 lcte.meters.in_bytes = lcte.meters.in_bytes + real_word_cnt;
1458
1459 rtx_info.break_char = "1"b;
1460 call check_ff ("0"b);
1461 input_count = real_word_cnt + real_wrap_cnt;
1462 if input_count ^= 0
1463 then do;
1464
1465 rtx_info.output_in_fnp = "0"b;
1466 rtx_info.output_in_ring_0 = (pcb.write_first ^= 0);
1467 rtx_info.input_count = input_count;
1468 if input_count > (tty_buf.bleft - abs_buf_limit) * 4
1469
1470 then go to no_input_space;
1471
1472 nblocks = divide (input_count + bsizec - 1, bsizec, 17, 0);
1473
1474 call tty_space_man$get_chain (devx, 16, nblocks, INPUT, inchain_ptr);
1475 if inchain_ptr = null
1476 then do;
1477 no_input_space:
1478 call syserr (SYSERR_announce,
1479 "uncp: Unable to allocate input buffers for line ^o, input has been lost",
1480 string (pcb.line_number));
1481 call channel_manager$interrupt (devx, QUIT, ""b);
1482
1483 go to update_free;
1484 end;
1485 inchain = rel (inchain_ptr);
1486
1487 bufp = ptr (ttybp, bin (sub_mbx.data_addr, 24) - tty_buf.absorig + 1);
1488
1489
1490 if trace.buffer_in
1491 then call syserr (SYSERR_log, "uncp: compte = ^w , buffer recu : ^v( ^w ^) ", input_count,
1492 divide (input_count + 3, 4, 17, 0), bufp -> buf_words);
1493
1494 chars_left = real_word_cnt + real_wrap_cnt;
1495 blockp = inchain_ptr;
1496 charp = addr (buffer.chars);
1497 chars_to_move = real_word_cnt;
1498 left_in_buffer = bsizec;
1499
1500 do while (chars_left > 0);
1501 numchars = min (left_in_buffer, chars_to_move);
1502 charp -> chars = bufp -> chars;
1503 chars_left = chars_left - numchars;
1504 chars_to_move = chars_to_move - numchars;
1505 buffer.tally = buffer.tally + numchars;
1506
1507 if chars_left > 0
1508 then do;
1509 if chars_to_move <= 0
1510 then if real_wrap_cnt > 0
1511 then do;
1512 bufp = addr (uncp_buf.circular_queue (0));
1513 chars_to_move = real_wrap_cnt;
1514 end;
1515 else ;
1516
1517 else bufp = addr (bufp -> char_array (numchars));
1518
1519 if buffer.tally = bsizec
1520 then do;
1521 blockp = ptr (ttybp, buffer.next);
1522
1523 charp = addr (buffer.chars);
1524 left_in_buffer = bsizec;
1525 end;
1526
1527 else do;
1528 charp = addr (charp -> char_array (numchars));
1529 left_in_buffer = left_in_buffer - numchars;
1530 end;
1531 end;
1532 end;
1533
1534 rtx_info.chain_head = inchain;
1535 rtx_info.chain_tail = rel (blockp);
1536 interrupt_info = unspec (rtx_info);
1537 call channel_manager$interrupt (devx, ACCEPT_INPUT, interrupt_info);
1538 pcb.turn = "1"b;
1539 if pcb.lfecho
1540 then pcb.send_lf = "1"b;
1541 end;
1542
1543
1544
1545
1546 update_free:
1547 uncp_buf.cq_free = uncp_buf.cq_free + sub_mbx.word_cnt;
1548
1549 call make_q_entry (accept_direct_output, 0, ""b);
1550
1551 return;
1552 ^L
1553 check_ff:
1554 proc (in_mbx);
1555
1556 dcl in_mbx bit (1);
1557 dcl wrapped bit (1);
1558
1559 rtx_info.formfeed_present = "0"b;
1560 if pcb.sync_line
1561 then return;
1562 wrapped = "0"b;
1563
1564
1565
1566 if wrap_ptr = "0"b
1567 then do;
1568 bufp = ptr (ttybp, bin (sub_mbx.data_addr, 24) - tty_buf.absorig + 1);
1569 chars_left = real_word_cnt;
1570 end;
1571
1572
1573 if pcb.extra_nl
1574 then substr (bufp -> input_chars, chars_left, 1) = "
1575 ";
1576
1577 if substr (bufp -> input_chars, chars_left, 1) = form_feed
1578
1579 then rtx_info.formfeed_present = "1"b;
1580 if pcb.flags.end_frame & rtx_info.break_char
1581 then do;
1582 if (chars_left <= 2) & ^wrapped
1583 then if verify (substr (bufp -> input_chars, 1, chars_left), ff_cr_lf) = 0
1584 then do;
1585 if in_mbx
1586 then numchars = 0;
1587 else real_word_cnt = 0;
1588 end;
1589 pcb.flags.end_frame = "0"b;
1590 pcb.turn = "1"b;
1591 if pcb.enter_receive_pending
1592 then call make_q_entry (accept_direct_output, 0, "0"b);
1593
1594
1595 if pcb.flags.send_output
1596 then if pcb.write_first ^= 0
1597 then call make_q_entry (accept_direct_output, 0, ""b);
1598
1599 else call channel_manager$interrupt (devx, SEND_OUTPUT, ""b);
1600 end;
1601
1602 end ;
1603
1604 end ;
1605 ^L
1606
1607
1608 enough_input_space:
1609 proc (count) returns (bit (1));
1610
1611 dcl count fixed bin;
1612
1613 lctp = tty_buf.lct_ptr;
1614 chan_lctep = addr (lct.lcte_array (devx));
1615 return (chan_lctep -> lcte.input_words + count <= divide (tty_buf.bleft, input_bpart, 17, 0));
1616 end ;
1617 ^L
1618
1619
1620
1621 make_q_entry:
1622 proc (opc, cnt, databits);
1623
1624 dcl (opc, cnt) fixed bin (8),
1625 databits bit (8 * 36);
1626
1627 call tty_space_man$get_space (size (q_entry), new_qp);
1628 if new_qp = null
1629 then do;
1630 call syserr (SYSERR_crash, "uncp: unable to allocate block for delay queue");
1631 return;
1632 end;
1633
1634 if opc = accept_direct_output
1635 then pcb.flags.send_output = "0"b;
1636 new_qrel = bin (rel (new_qp));
1637 if fnp_info.cur_ptr = 0
1638 then fnp_info.cur_ptr = new_qrel;
1639 else do;
1640 qptr = ptr (ttybp, fnp_info.last_ptr);
1641 q_entry.next = new_qrel;
1642 end;
1643
1644 fnp_info.last_ptr = new_qrel;
1645 qptr = new_qp;
1646 fnp_info.count = fnp_info.count + 1;
1647 fnp_info.q_entries_made = fnp_info.q_entries_made + 1;
1648
1649 q_entry.opcode = opc;
1650 q_entry.cmd_count = cnt;
1651 if pcbp ^= null ()
1652 then q_entry.pcb_offset = rel (pcbp);
1653 else q_entry.pcb_offset = "0"b;
1654 q_entry.next = 0;
1655 q_entry.cmd_data = databits;
1656 return;
1657 end;
1658 ^L
1659
1660
1661 get_line_number:
1662 proc;
1663
1664 pcbp = null;
1665 devx = -1;
1666
1667 if string (sub_mbx.line_number) ^= "0"b
1668 then do;
1669 sub_mbx.line_number.is_hsla = "1"b;
1670 lano = sub_mbx.line_number.la_no;
1671 if sub_mbx.is_hsla
1672 then j = fnp_info.hsla_idx (fixed (lano));
1673 else j = fnp_info.lsla_idx (fixed (lano));
1674 do j = j to fnp_info.no_of_channels;
1675 pcbp = addr (fnp_info.pcb_array_ptr -> pcb_array (j));
1676 if string (pcb.line_number) = string (sub_mbx.line_number)
1677 then go to match;
1678 end;
1679 if (sub_mbx.io_cmd = rcd) & (sub_mbx.op_code = accept_new_terminal)
1680 then do;
1681 devx = -1;
1682 return;
1683 end;
1684 else if sub_mbx.io_cmd ^= wcd
1685 then do;
1686 call syserr (SYSERR_beep, "uncp$interrupt: no slot number match for sub mbx ^o, FNP ^a", i,
1687 substr ("abcdefgh", dno, 1));
1688 sub_mbx.io_cmd = 0;
1689 end;
1690 return;
1691 match:
1692 devx = pcb.devx;
1693 if pcb.connection_type = "01"b
1694 then do;
1695 other_pcbp = addr (fnp_info.pcb_array_ptr -> pcb_array (pcb.uncp_pcbx));
1696 devx = other_pcbp -> pcb.devx;
1697 end;
1698 end;
1699 return;
1700
1701 end ;
1702 ^L
1703
1704
1705
1706 assign_sub_mbx:
1707 proc (a_sub_mbx_no, a_subp);
1708
1709 dcl a_sub_mbx_no fixed bin;
1710 dcl a_subp ptr;
1711 dcl sub_mbx_num fixed bin;
1712
1713 sub_mbx_num = index (used_string, "0"b) - 1;
1714 if sub_mbx_num = -1
1715 then do;
1716 a_sub_mbx_no = -1;
1717 a_subp = null ();
1718 return;
1719 end;
1720
1721 datanet_mbx.mbx_used_flags.used (sub_mbx_num) = "1"b;
1722
1723 datanet_mbx.num_in_use = datanet_mbx.num_in_use + 1;
1724 fnp_info.max_mbx_in_use = max (fnp_info.max_mbx_in_use, datanet_mbx.num_in_use);
1725 fnp_info.cumulative_mbx_in_use = fnp_info.cumulative_mbx_in_use + datanet_mbx.num_in_use;
1726 fnp_info.mbx_in_use_updated = fnp_info.mbx_in_use_updated + 1;
1727 unspec (datanet_mbx.dn355_sub_mbxes (sub_mbx_num)) = "0"b;
1728 sub_mbx_sent = "0"b;
1729 a_sub_mbx_no = sub_mbx_num;
1730 a_subp = addr (datanet_mbx.dn355_sub_mbxes (sub_mbx_num));
1731 return;
1732 end assign_sub_mbx;
1733 %skip (3);
1734
1735
1736 release_sub_mbx:
1737 proc (a_sub_mbx_no);
1738
1739 dcl a_sub_mbx_no fixed bin;
1740
1741 if a_sub_mbx_no < 0 | a_sub_mbx_no > 6
1742 then return;
1743 datanet_mbx.mbx_used_flags.used (a_sub_mbx_no) = "0"b;
1744
1745
1746 fnp_info.cumulative_mbx_in_use = fnp_info.cumulative_mbx_in_use - datanet_mbx.num_in_use;
1747 fnp_info.mbx_in_use_updated = fnp_info.mbx_in_use_updated - 1;
1748 datanet_mbx.num_in_use = datanet_mbx.num_in_use - 1;
1749 return;
1750 end release_sub_mbx;
1751 ^L
1752
1753
1754 return_mbx:
1755 send_mbx:
1756 proc (a_mbx_no);
1757
1758 dcl a_mbx_no fixed bin;
1759 dcl mbx_no fixed bin;
1760 dcl counter fixed bin;
1761 dcl output_data_ptr ptr;
1762 dcl output_data (3) bit (36) aligned based (output_data_ptr);
1763 dcl 1 ima aligned like io_manager_arg;
1764
1765 mbx_no = a_mbx_no;
1766 if mbx_no = -1
1767 then do;
1768 call assign_sub_mbx (mbx_no, subp);
1769 if mbx_no = -1
1770 then do;
1771 call syserr (SYSERR_crash, "uncp: unable to re-assign fnp sub-mailbox.");
1772 return;
1773 end;
1774 unspec (sub_mbx) = unspec (local_sub_mbx);
1775 a_mbx_no = mbx_no;
1776 end;
1777
1778 if ^fnp_info.io_manager_assigned
1779 then do;
1780 no_response = "1"b;
1781 return;
1782 end;
1783
1784 do counter = 1 to LOOP_LIMIT while (datanet_mbx.dia_pcw.command ^= "0"b);
1785
1786 end;
1787 if counter > LOOP_LIMIT
1788 then no_response = "1"b;
1789
1790 else do;
1791 no_response = "0"b;
1792
1793 if (mbx_no >= 0) & (mbx_no <= 6)
1794 then do;
1795 sub_mbx.dn355_no = substr (bit (fnp_info.fnp_number), 7);
1796 if sub_mbx.op_code = enter_receive
1797 then do;
1798 sub_mbx.io_cmd = wtx;
1799 output_data_ptr = fnp_info.dcw_list_array_ptr;
1800 output_data (*) = ""b;
1801
1802 sub_mbx.command_data (1) = "0"b;
1803 sub_mbx.command_data (2) = "0"b;
1804 sub_mbx.command_data (3) = "0"b;
1805 if pcb.send_lf
1806 then do;
1807 sub_mbx.op_code = accept_direct_output;
1808 unspec (output_data (2)) = "000001000000"b3;
1809 unspec (output_data (3)) = "012000000000"b3;
1810 sub_mbx.word_cnt = 2;
1811 sub_mbx.data_addr =
1812 bit (bin (tty_buf.absorig + fixed (rel (addr (output_data (2)))), 18), 18);
1813 pcb.send_lf = "0"b;
1814 end;
1815 else do;
1816 sub_mbx.op_code = accept_last_output;
1817 output_data (1) = "0"b;
1818 sub_mbx.word_cnt = 1;
1819 sub_mbx.data_addr =
1820 bit (bin (tty_buf.absorig + fixed (rel (addr (output_data (1)))), 18), 18);
1821 pcb.enter_receive_pending, pcb.turn = "0"b;
1822 end;
1823 call get_line_number;
1824 pcb.output_mbx_pending = "1"b;
1825 end;
1826
1827 if sub_mbx.op_code = accept_last_output
1828 then do;
1829 call get_line_number;
1830 if pcb.connection_type = "10"b
1831 then do;
1832 pcb.turn = "1"b;
1833 sub_mbx.op_code = accept_direct_output;
1834 end;
1835 end;
1836
1837 if (sub_mbx.io_cmd = rtx) | (sub_mbx.io_cmd = wtx)
1838 then sub_mbx.pad3 = (15)"0"b3 || "777"b3;
1839 end;
1840
1841 sub_mbx.line_number.is_hsla = "0"b;
1842
1843 if trace.mailbox
1844 then call syserr (SYSERR_log, "uncp$send_mbx: # ^o ^2( ^/ ^4( ^w ^) ^)", mbx_no, sub_mbx_array);
1845
1846 string (datanet_mbx.dia_pcw) = initial_pcw;
1847 datanet_mbx.dia_pcw.mbx_no = bit (fixed (mbx_no + 1, 6), 6);
1848
1849
1850 string (datanet_mbx.dia_pcw) = dn355_util$compute_parity (string (datanet_mbx.dia_pcw));
1851
1852
1853
1854 ima.chx = fnp_info.io_manager_chx;
1855 ima.ptp = fnp_info.ptp;
1856 call io_manager$connect_direct (ima);
1857 sub_mbx_sent = "1"b;
1858
1859 return;
1860 end;
1861 end send_mbx;
1862 ^L
1863
1864
1865 hangup_fnp_lines:
1866 entry (a_fnp_no);
1867
1868 dcl a_fnp_no fixed bin;
1869
1870 infop = addr (dn355_data$);
1871 ttybp = addr (tty_buf$);
1872 uncpbp = datanet_info.uncp_bufp;
1873 call hangup_fnp (a_fnp_no);
1874 return;
1875
1876
1877 hangup_fnp:
1878 proc (fnp_no);
1879
1880 dcl fnp_no fixed bin;
1881
1882 fnpp = addr (datanet_info.per_datanet (fnp_no));
1883 do j = 1 to fnp_info.no_of_channels;
1884 pcbp = addr (fnp_info.pcb_array_ptr -> pcb_array (j));
1885 if pcb.dialed
1886 then do;
1887 call throw_away_output;
1888 if pcb.connection_type ^= "10"b
1889 then call channel_manager$interrupt ((pcb.devx), CRASH, ""b);
1890 end;
1891 end;
1892
1893 if fnp_info.count > 0
1894 then do;
1895 q_count = fnp_info.count;
1896 q_first = fnp_info.cur_ptr;
1897 do q_count = q_count to 0 by -1 while (q_first ^= 0);
1898 qptr = ptr (ttybp, q_first);
1899 q_first = qptr -> q_entry.next;
1900 call tty_space_man$free_space (size (q_entry), qptr);
1901 end;
1902
1903 fnp_info.count, fnp_info.cur_ptr, fnp_info.last_ptr = 0;
1904 end;
1905
1906 end;
1907
1908
1909
1910 throw_away_output:
1911 proc;
1912
1913
1914
1915 if pcb.write_first ^= 0
1916 then do;
1917 call tty_space_man$free_chain ((pcb.devx), OUTPUT, ptr (ttybp, pcb.write_first));
1918 pcb.write_first, pcb.write_last, pcb.write_cnt = 0;
1919
1920 end;
1921
1922 pcb.end_frame = "0"b;
1923
1924 return;
1925 end ;
1926 ^L
1927
1928
1929 report_fnp_no_response:
1930 proc;
1931
1932 call syserr (SYSERR_beep, "uncp: FNP ^a did not respond to mailbox interrupt", fnp_info.fnp_tag);
1933 call report_fnp_crash;
1934 return;
1935
1936 end ;
1937
1938
1939
1940
1941 report_fnp_crash:
1942 proc;
1943
1944 fnp_info.running = "0"b;
1945
1946
1947
1948
1949 if ^fnp_info.bootloading
1950 then
1951 call hangup_fnp (dno);
1952 else fnp_info.bootloading = "0"b;
1953
1954 auto_fnp_msg.state = FNP_DOWN;
1955 auto_fnp_msg.fnp_no = dno;
1956 auto_fnp_msg.flags = "0"b;
1957 unspec (fnp_event_message) = unspec (auto_fnp_msg);
1958 call pxss$ring_0_wakeup (fnp_info.boot_process_id, fnp_info.boot_ev_chan, fnp_event_message, 0);
1959
1960 return;
1961
1962 end report_fnp_crash;
1963 ^L
1964 purge_write_texte:
1965 proc;
1966 do i = 0 to 6;
1967 if timwb (i)
1968 then do;
1969 subp = addr (datanet_mbx.dn355_sub_mbxes (i));
1970 call get_line_number;
1971 if sub_mbx.io_cmd = wtx
1972 then do;
1973 if pcb.output_mbx_pending & sub_mbx.command_data (3) ^= "0"b
1974 then do;
1975 da = bin (sub_mbx.data_addr, 18) - tty_buf.absorig;
1976 blockp = ptr (ttybp, da);
1977 if pcb.connection_type = "10"b
1978 then pcbp = addr (fnp_info.pcb_array_ptr -> pcb_array (pcb.uncp_pcbx));
1979 gateway_header = sub_mbx.command_data (3);
1980 call tty_space_man$free_chain ((pcb.devx), OUTPUT, blockp);
1981 end;
1982 end;
1983 if sub_mbx.io_cmd = rtx
1984 then if sub_mbx.word_cnt ^= 0
1985 then do;
1986 uncp_buf.cq_free = uncp_buf.cq_free + sub_mbx.word_cnt;
1987 sub_mbx.word_cnt = 0;
1988 end;
1989 datanet_mbx.mbx_used_flags.used (i) = "0"b;
1990 datanet_mbx.num_in_use = datanet_mbx.num_in_use - 1;
1991 end;
1992 end;
1993 return;
1994 end;
1995 ^L
1996 check_lock:
1997 proc;
1998
1999
2000
2001 if queue_locked
2002 then call syserr (SYSERR_crash, "uncp: attempted crawlout with FNP queue locked");
2003
2004 else if masked
2005 then call pmut$unwire_unmask (wire_arg, wire_ptr);
2006
2007 return;
2008 end check_lock;
2009 %page;
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224 end uncp;