1 /****^  ***********************************************************
  2         *                                                         *
  3         * Copyright, (C) Honeywell Bull Inc., 1987                *
  4         *                                                         *
  5         * Copyright, (C) Honeywell Information Systems Inc., 1984 *
  6         *                                                         *
  7         * Copyright (c) 1972 by Massachusetts Institute of        *
  8         * Technology and Honeywell Information Systems, Inc.      *
  9         *                                                         *
 10         *********************************************************** */
 11 
 12 
 13 
 14 
 15 /****^  HISTORY COMMENTS:
 16   1) change(86-06-05,GJohnson), approve(86-06-05,MCR7387),
 17      audit(86-06-10,Martinson), install(86-07-11,MR12.0-1091):
 18      Correct error message documentation.
 19                                                    END HISTORY COMMENTS */
 20 
 21 
 22 /* TAPE_READER - Multics Standard Tape Reading Procedure for Initialization.
 23           recoded into PL/1 - 8/27/73 by N. I. Morris                           */
 24 /* BIM 7/82 tape_io renamed to boot_tape_io */
 25 
 26 tape_reader: proc (p, n);
 27 
 28           dcl     p                      ptr,               /* pointer to target data buffer */
 29                   n                      fixed bin (18);    /* # of words to read */
 30 
 31           dcl     (cur_p, cur_dp, cur_tp) ptr,              /* ptrs to current record header, data, trailer */
 32                   exprec                 fixed bin (18),    /* next expected record number */
 33                   datap                  ptr,               /* ptr to current position in target data */
 34                   count                  fixed bin (18),    /* # of words remaining to be transferred */
 35                   words_left             fixed bin (18),    /* # of words remaining in tape buffer */
 36                   copy_words             fixed bin (18),    /* # of words to be copied */
 37                   nrecs                  fixed bin,         /* # of records read before good record encountered */
 38                   retries                fixed bin,         /* # of times tape backspaced to retry */
 39                   majstat                fixed bin (5),     /* major status from tape I/O operation */
 40                   checksum               bit (36) aligned,  /* tape record checksum */
 41                   i                      fixed bin;         /* iteration variable */
 42 
 43           dcl     tape_count             fixed bin static;  /* count of tape drives used */
 44 
 45           dcl     data                   (copy_words) fixed bin (35) based; /* structure for copying data */
 46 
 47           dcl     1 physical_record_buffer$ ext,            /* physical record buffer */
 48                   ( 2 index              fixed bin (17),    /* index into current buffer */
 49                     2 pad                fixed bin (17)) unal,
 50                     2 cur_rec            (1040) fixed bin;  /* current record */
 51 
 52           dcl     (addr, addrel, divide, min, substr) builtin;
 53 
 54           dcl     syserr                 ext entry options (variable),
 55                   (boot_tape_io$read,
 56                   boot_tape_io$backspace,
 57                   boot_tape_io$rewind,
 58                   tape_checksum_         entry (ptr, ptr),
 59                   (boot_tape_io$init_tape,
 60                   boot_tape_io$final_tape)) entry;
 61 
 62 
 63 %include mstr;
 64 
 65 
 66 
 67 /* ^L */
 68 
 69           datap = p;                                        /* Get pointer to data target. */
 70           count = n;                                        /* Get # of words to be read. */
 71 
 72           cur_p = addr (physical_record_buffer$.cur_rec);   /* Get pointer to current record header. */
 73           cur_dp = addr (cur_p -> mstr.data);               /* Get pointer to current record data. */
 74 
 75 reader_loop:
 76           words_left = divide (cur_p -> mstr_header.data_bits_used, 36, 18, 0) - physical_record_buffer$.index;
 77                                                             /* Compute # of words remaining in tape buffer. */
 78           if words_left = 0 then do;                        /* If current buffer is used up ... */
 79                     cur_tp = addr (cur_p -> mstr.trail);    /* Get a pointer to current record trailer. */
 80                     exprec = cur_tp -> mstr_trailer.tot_rec + 1; /* Compute next expected record number. */
 81                     call get_next_buffer;                   /* Refill the record buffer. */
 82                     physical_record_buffer$.index = 0;      /* Reset index to buffer. */
 83                     go to reader_loop;                      /* Now use new record. */
 84                end;
 85 
 86           copy_words = min (count, words_left);             /* Copy as many words as possible. */
 87           count = count - copy_words;                       /* Decrement count of remaining words to copy. */
 88           if copy_words > 0 then datap -> data = addrel (cur_dp, physical_record_buffer$.index) -> data;
 89                                                             /* Copy the data. */
 90           physical_record_buffer$.index = physical_record_buffer$.index + copy_words;
 91                                                             /* Increment tape buffer index. */
 92           datap = addrel (datap, copy_words);               /* Bump the target data pointer. */
 93           if count > 0 then go to reader_loop;              /* Continue, if any words remaining. */
 94 
 95           return;                                           /* All finsihed.  Return to caller. */
 96 
 97 
 98 /* ^L */
 99 
100 get_next_buffer: proc;
101 
102 
103           retries = 0;                                      /* Initialize retry count. */
104 
105 retry:    if retries > 64 then /* Give up after 64 tries. */
106                call syserr (1, "tape_reader: Unable to read system tape.");
107           nrecs = 0;                                        /* Initialize record count. */
108 
109 again:    nrecs = nrecs + 1;                                /* Count one record. */
110 
111 eof:      call do_io (boot_tape_io$read, "001100000010000"b); /* Read a tape record. */
112           if majstat ^= 0 then do;                          /* If non-zero major status ... */
113                     if majstat = 3 then /* If device data alert ... */
114                          go to again;                       /* Try reading again. */
115                     if majstat = 4 then /* If EOF ... */
116                          go to eof;
117                     if majstat = 11 then /* If MPC device data alert ... */
118                          go to again;
119                end;
120 
121           if cur_p -> mstr_header.c1 ^= header_c1 | /* Compare check bit patterns. */
122                cur_p -> mstr_header.c2 ^= header_c2 |
123                cur_tp -> mstr_trailer.c1 ^= trailer_c1 |
124                cur_tp -> mstr_trailer.c2 ^= trailer_c2 then
125                go to again;
126 
127           call tape_checksum_ (cur_p, addr (checksum));     /* Compute record checksum. */
128           if checksum ^= cur_p -> mstr_header.checksum then
129                go to again;                                 /* Check the checksum. */
130           if cur_p -> mstr_header.flags.admin then /* If administrative record ... */
131                go to admin_record;                          /* Handle it properly. */
132 validate:
133           if cur_tp -> mstr_trailer.tot_rec < exprec then
134                go to retry;                                 /* If we backspaced too much. */
135           if cur_tp -> mstr_trailer.tot_rec > exprec then
136                go to back_up;                               /* If we read too much. */
137 
138           return;                                           /* Record OK.  Return. */
139 
140 
141 admin_record:
142           if cur_p -> mstr_header.flags.eor then /* If end of reel ... */
143                go to validate;
144           go to again;                                      /* Otherwise, ignore as spurious. */
145 
146 
147 back_up:  retries = retries + 1;                            /* Count another attempt. */
148           do i = 1 to nrecs + 2;                            /* Back the tape up. */
149                call do_io (boot_tape_io$backspace, "000110000000000"b);
150                if majstat = 5 then go to retry;             /* If at BOT, retry reading. */
151           end;
152           go to retry;
153 
154      end get_next_buffer;
155 
156 /* ^L */
157 
158 init: entry;
159 
160           call boot_tape_io$init_tape;                      /* Initialize tape I/O package. */
161           tape_count = 0;                                   /* Initialize count of tapes. */
162           return;                                           /* Return to caller. */
163 
164 
165 final: entry;
166 
167           call do_io (boot_tape_io$rewind, (15)"0"b);       /* Rewind the last tape. */
168           call boot_tape_io$final_tape;                     /* Turn off the tape I/O package. */
169           return;
170 
171 
172 
173 do_io: proc (e, s);
174 
175           dcl     e                      entry (fixed bin (5)), /* boot_tape_io entry to call */
176                   s                      bit (15) aligned;  /* control bits for examining major status */
177 
178 
179 call:     call e (majstat);                                 /* Call boot_tape_io routine. */
180 
181           if majstat ^= 0 then /* If tape error ... */
182                if majstat >= 16 then /* If power off bit is on ... */
183                     go to call;                             /* Try over again. */
184                else if substr (s, majstat, 1) then /* If control bit on ... */
185                     return;                                 /* Let caller handle this. */
186                else if majstat <= 2 then /* If attention or busy ... */
187                     go to call;                             /* Try again. */
188                else /* Otherwise ... */
189                     call syserr (1, "tape_reader: bad major status = ^o", majstat);
190 
191           return;
192 
193 
194      end do_io;
195 ^L
196 /* BEGIN MESSAGE DOCUMENTATION
197 
198    Message:
199    tape_reader: unable to read system tape
200 
201    S: $crash
202 
203    T: $init
204 
205    M: The bootload tape is unreadable.
206 
207    A: $boot_tape
208 
209    Message:
210    tape_reader: bad_major_status: SSS
211 
212    S: $crash
213 
214    T: $init
215 
216    M: The bootload tape is unreadable.
217 
218    A: $boot_tape
219    Try another tape drive.
220 
221    END MESSAGE DOCUMENTATION */
222 
223      end tape_reader;