/* *********************************************************** * * * Copyright, (C) Honeywell Information Systems Inc., 1982 * * * * Copyright (c) 1972 by Massachusetts Institute of * * Technology and Honeywell Information Systems, Inc. * * * *********************************************************** */ /* format: style3,linecom,ifthenstmt,indthenelse,^indnoniterdo,indend,dclind5,idind32 */ tape_nstd_attach: proc (iocb_ptr, args, loud_sw, arg_code); /* tape_nstd_ created 05/03/76 by Richard Bratt This program is a temporary dim. It is intended to serve as a rough iox_ writearound to the ios_ dim nstd_. This dim evolved from repeated attempts to bash ntape_ into usefulness. When the smoke cleared little remained of ntape_; hence the new name, tape_nstd_. This dim makes no pretense at being pretty or clever. Last modified: * 09/19/77 by R.J.C. Kissel to get buffer size from a control argument, * and to add the entry max_buf_size to return the buffer size. * 11/01/77 by M. R. Jordan to fix forward_record control call. * 04/07/78 by M. R. Jordan for major overhaul. Changes included: * adding -density control argument, implementing all * nstd control orders, and changes to -block processing * such that nstd_ now handles it. * 01/3/79 by Maria Bozzuto to add -com control argument. * 4/79 by R.J.C. Kissel to add 6250 bpi support. * 05/10/79 by C. D. Tavares to add name canonicalization support. * 4/82 by J. A. Bush to compile with iocb.incl.pl1 NOTES: * Since this dim does not copy buffers and since it calls nstd_ directly, bufptr * in the read and write calls must be word aligned. In addition, buflen must be 0 modulo 4 * for write calls. */ /* Parameters. */ dcl actlen fixed (21); dcl args (*) char (*) varying; dcl buflen fixed (21); dcl bufptr ptr; dcl extend_bit bit (1) aligned; dcl iocb_ptr ptr; dcl loud_sw bit (1) aligned; dcl mode fixed; dcl arg_code fixed bin (35); /* Automatic. */ dcl actual_iocb_ptr ptr; dcl density char (9) varying; dcl block char (13) varying; dcl pic pic "zzzzz9"; dcl blkptr ptr; dcl block_size fixed bin (21); dcl fix_num fixed; dcl nn fixed bin; dcl code fixed (35); dcl 1 ics aligned, 2 sdbptr ptr, 2 dimptr ptr, 2 entry fixed; dcl mask fixed (35); dcl comment char (256) aligned varying; dcl n fixed (21); dcl (leader_ok, eof_ok) bit (1) aligned; dcl reel char (32) varying; dcl track char (8) varying; dcl chars fixed; dcl st bit (12) aligned; dcl status_story char (100) varying; dcl 1 status aligned, 2 code fixed (35), 2 bits bit (36); dcl write_sw bit (1); dcl order_index fixed bin; dcl reel_name char (256); /* Based. */ dcl 1 blk aligned based (blkptr), 2 sdbptr ptr, 2 dimptr ptr, 2 attach char (59) varying, 2 write_ring bit (1) unaligned, 2 extend bit (1) unaligned, 2 open char (31) varying, 2 maxbuf fixed bin (18); /* Internal static. */ dcl free_blks_ptr ptr int static init (null ()); /* Procedures. */ dcl com_err_ ext entry options (variable); dcl cv_dec_check_ entry (char (*), fixed bin (35)) returns (fixed bin (35)); dcl cu_$arg_list_ptr ext entry () returns (ptr); dcl cu_$gen_call ext entry (entry, ptr); dcl default_handler_$set ext entry (entry); dcl error entry variable options (variable) init (ERROR); dcl hcs_$assign_linkage ext entry (fixed, ptr) returns (fixed (35)); dcl hcs_$set_ips_mask ext entry (fixed (35), fixed (35)); dcl hcs_$reset_ips_mask ext entry (fixed (35), fixed (35)); dcl iox_$ios_call ext entry options (variable); dcl iox_$ios_call_attach ext entry options (variable); dcl iox_$propagate ext entry (ptr); dcl nstd_$nstd_module fixed ext; dcl analyze_device_stat_$rsnnl entry (char (*) varying, ptr, bit (72) aligned, bit (18) aligned); /* Constants. */ dcl error_table_$bad_arg fixed (35) ext; dcl error_table_$bad_conversion fixed bin (35) ext; dcl error_table_$bad_mode fixed (35) ext; dcl error_table_$bad_tapeid fixed bin (35) ext; dcl error_table_$badopt fixed (35) ext; dcl error_table_$end_of_info fixed (35) ext; dcl error_table_$long_record fixed (35) ext; dcl error_table_$noarg fixed (35) ext; dcl error_table_$not_detached fixed (35) ext; dcl error_table_$tape_error fixed (35) ext; dcl error_table_$invalid_record_length fixed (35) ext; dcl error_table_$undefined_order_request fixed bin (35) ext; dcl tape_status_table_$tape_status_table_ ext; dcl iox_$err_not_attached ext entry options (variable); dcl iox_$err_not_closed ext entry options (variable); dcl iox_$err_not_open ext entry options (variable); dcl detach_offset fixed int static init (1); dcl read_offset fixed int static init (2); dcl write_offset fixed int static init (3); dcl order_offset fixed int static init (5); dcl leader_status fixed (35) based (addr (leader_bits)); dcl leader_bits bit (36) int static init ("100000000000000000000000000101001000"b); dcl sequential_input_mode fixed int static init (4); dcl sequential_output_mode fixed int static init (5); dcl 1 ORDER_TAB (24) internal static options (constant), 2 NAME char (20) init ("backspace_file", "backspace_record", "bcd", "binary", "d1600", "d200", "d556", "d6250", "d800", "data_security_erase", "erase", "fixed_record_length", "forward_file", "forward_record", "io_call", "nine", "protect", "request_status", "reset_status", "retry_count", "rewind", "saved_status", "unload", "write_eof"), 2 ACTION fixed bin init (1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 5, 6, 0, 0, 7); dcl sequential_input_output_mode fixed int static init (6); /* Built-in. */ dcl (addr, divide, hbound, index, length, mod, null, rtrim, size, substr, bin, ltrim, min, maxlength) builtin; /* Beginning of entry point ..... tape_nstd_$tape_nstd_attach(iocb_ptr,args,loud_sw) ..... */ arg_code = 0; mask = 0; comment = ""; call default_handler_$set (HANDLER); if hbound (args, 1) < 1 then call error (error_table_$noarg, "tape_nstd_", "No volume id specified."); n = index (args (1), " ") - 1; if n < 0 then n = length (args (1)); if n = 0 | n > maxlength (reel) then call error (error_table_$bad_tapeid, "tape_nstd_", "^a", args (1)); reel = substr (args (1), 1, n); write_sw = "0"b; track = ""; density = ""; block_size = 2800 * 4; block = ""; do n = 2 to hbound (args, 1); if args (n) = "-write" then write_sw = "1"b; else if args (n) = "-track" | args (n) = "-tk" then do; n = n + 1; if n > hbound (args, 1) then call error (error_table_$noarg, "tape_nstd_", "No value specified following the ^a control argument.", args (n - 1)); fix_num = cv_dec_check_ ((args (n)), code); if code ^= 0 then fix_num = 0; if fix_num = 7 then track = ",7track"; else if fix_num = 9 then track = ",9track"; else call error (error_table_$bad_arg, "tape_nstd_", "Bad track specification. ^a", args (n)); end; else if args (n) = "-density" | args (n) = "-den" then do; n = n + 1; if n > hbound (args, 1) then call error (error_table_$noarg, "tape_nstd_", "No value specified following the ^a control argument.", args (n - 1)); fix_num = cv_dec_check_ ((args (n)), code); if code ^= 0 then fix_num = 0; if fix_num = 200 then density = ",den=200"; else if fix_num = 556 then density = ",den=556"; else if fix_num = 800 then density = ",den=800"; else if fix_num = 1600 then density = ",den=1600"; else if fix_num = 6250 then density = ",den=6250"; else call error (error_table_$bad_arg, "tape_nstd_", "Bad density specification. ^a", args (n)); end; else if args (n) = "-block" | args (n) = "-bk" then do; n = n + 1; if n > hbound (args, 1) then call error (error_table_$noarg, "tape_nstd_", "No size specified following the ^a control argument.", args (n - 1)); block_size = cv_dec_check_ ((args (n)), code); if block_size = 0 | code ^= 0 | mod (block_size, 4) ^= 0 then call error (error_table_$bad_arg, "tape_nstd_", "Bad block size specification. ^a", args (n)); end; else if args (n) = "-comment" | args (n) = "-com" then do; n = n + 1; if n > hbound (args, 1) then call error (error_table_$noarg, "tape_nstd_", "No comment specified following the ^a control argument", args (n - 1)); if length (args (n)) > maxlength (comment) - 2 then call error (error_table_$bad_arg, "tape_nstd_", "Comment '^a' longer than ^d characters", args (n), maxlength (comment) - 2); comment = ",*" || args (n); end; else call error (error_table_$badopt, "tape_nstd_", "^a", args (n)); end; pic = divide (block_size, 4, 18); block = ",blk=" || ltrim (pic); if iocb_ptr -> iocb.attach_data_ptr ^= null () then call error (error_table_$not_detached, "tape_nstd_", "^a", iocb_ptr -> iocb.name); ics.dimptr = addr (nstd_$nstd_module); ics.sdbptr = null; reel_name = reel || track || density || block || comment; call iox_$ios_call_attach (iocb_ptr -> iocb.name, "nstd_", reel_name, substr ("rw", 1, 1 + bin (write_sw, 1)), status, addr (ics)); if status.code ^= 0 then call error (status.code, "tape_nstd_"); call hcs_$set_ips_mask (0, mask); if iocb_ptr -> iocb.attach_descrip_ptr ^= null () then go to unattach; blkptr = free_blks_ptr; if blkptr ^= null () then free_blks_ptr = blkptr -> blk.sdbptr; else code = hcs_$assign_linkage (size (blkptr -> blk), blkptr); if blkptr = null () then do; unattach: call hcs_$reset_ips_mask (mask, mask); ics.entry = detach_offset; call iox_$ios_call (addr (ics), "", "", status); call error (code, "tape_nstd_", "^a", iocb_ptr -> iocb.name); end; blkptr -> blk.sdbptr = ics.sdbptr; blkptr -> blk.dimptr = ics.dimptr; blkptr -> blk.attach = "tape_nstd_ " || rtrim (reel_name); if write_sw then blkptr -> blk.attach = blkptr -> blk.attach || " -write"; blkptr -> blk.open = ""; blkptr -> blk.write_ring = write_sw; blkptr -> blk.extend = "0"b; blkptr -> blk.maxbuf = divide (block_size, 4, 18); iocb_ptr -> iocb.attach_descrip_ptr = addr (blkptr -> blk.attach); iocb_ptr -> iocb.attach_data_ptr = blkptr; iocb_ptr -> iocb.detach_iocb = tape_detach; iocb_ptr -> iocb.open = tape_open; call iox_$propagate (iocb_ptr); call hcs_$reset_ips_mask (mask, mask); return; /* This entry processes iox_$detach_iocb requests for tape_nstd_. */ tape_detach: entry (iocb_ptr, arg_code); arg_code = 0; mask = 0; call default_handler_$set (HANDLER); call hcs_$set_ips_mask (0, mask); blkptr = iocb_ptr -> iocb.attach_data_ptr; ics.sdbptr = blkptr -> blk.sdbptr; ics.dimptr = blkptr -> blk.dimptr; ics.entry = detach_offset; call iox_$ios_call (addr (ics), "", "", status); if status.code ^= 0 then do; call hcs_$reset_ips_mask (mask, mask); arg_code = status.code; return; end; blkptr -> blk.sdbptr = free_blks_ptr; free_blks_ptr = blkptr; iocb_ptr -> iocb.attach_descrip_ptr, iocb_ptr -> iocb.attach_data_ptr = null; iocb_ptr -> iocb.detach_iocb = iox_$err_not_attached; iocb_ptr -> iocb.open = iox_$err_not_attached; call iox_$propagate (iocb_ptr); call hcs_$reset_ips_mask (mask, mask); return; /* This entry processes iox_$open requests for tape_nstd_. */ tape_open: entry (iocb_ptr, mode, extend_bit, arg_code); if extend_bit then do; arg_code = error_table_$bad_arg; return; end; mask = 0; call default_handler_$set (HANDLER); call hcs_$set_ips_mask (0, mask); call SETUP; if mode = sequential_input_mode then blkptr -> blk.open = "sequential_input"; else if blkptr -> blk.write_ring & mode = sequential_output_mode then blkptr -> blk.open = "sequential_output"; else if blkptr -> blk.write_ring & mode = sequential_input_output_mode then blkptr -> blk.open = "sequential_input_output"; else do; call hcs_$reset_ips_mask (mask, mask); arg_code = error_table_$bad_mode; return; end; actual_iocb_ptr -> iocb.open_descrip_ptr = addr (blkptr -> blk.open); actual_iocb_ptr -> iocb.detach_iocb = iox_$err_not_closed; actual_iocb_ptr -> iocb.open = iox_$err_not_closed; actual_iocb_ptr -> iocb.close = tape_close; actual_iocb_ptr -> iocb.control = tape_control; if mode ^= sequential_output_mode then actual_iocb_ptr -> iocb.read_record = tape_read; if mode ^= sequential_input_mode then actual_iocb_ptr -> iocb.write_record = tape_write; call iox_$propagate (actual_iocb_ptr); call hcs_$reset_ips_mask (mask, mask); return; /* This entry processes all iox_$close requests for tape_nstd_. */ tape_close: entry (iocb_ptr, arg_code); call SETUP; ics.entry = order_offset; call iox_$ios_call (addr (ics), "rewind", null (), status); mask = 0; call default_handler_$set (HANDLER); call hcs_$set_ips_mask (0, mask); actual_iocb_ptr = iocb_ptr -> iocb.actual_iocb_ptr; actual_iocb_ptr -> iocb.open_descrip_ptr = null; actual_iocb_ptr -> iocb.detach_iocb = tape_detach; actual_iocb_ptr -> iocb.open = tape_open; actual_iocb_ptr -> iocb.close = iox_$err_not_open; actual_iocb_ptr -> iocb.read_record = iox_$err_not_open; actual_iocb_ptr -> iocb.write_record = iox_$err_not_open; call iox_$propagate (actual_iocb_ptr); call hcs_$reset_ips_mask (mask, mask); return; /* This entry processes all iox_$read_record requests for tape_nstd_. */ tape_read: entry (iocb_ptr, bufptr, buflen, actlen, arg_code); call SETUP; actlen = 0; if buflen < 1 then return; ics.entry = read_offset; call iox_$ios_call (addr (ics), bufptr, 0, (min (blkptr -> blk.maxbuf, divide (buflen, 4, 17, 0))), nn, status); actlen, chars = 4 * nn; call SET_CODE; if buflen < chars then arg_code = error_table_$long_record; else arg_code = code; return; /* This entry processes all iox_$write_record requests for tape_nstd_. */ tape_write: entry (iocb_ptr, bufptr, buflen, arg_code); call SETUP; if buflen < 1 then return; if mod (buflen, 4) ^= 0 then do; arg_code = error_table_$invalid_record_length; return; end; ics.entry = write_offset; nn = divide (buflen, 4, 17, 0); if nn > blkptr -> blk.maxbuf then arg_code = error_table_$long_record; else do; call iox_$ios_call (addr (ics), bufptr, 0, nn, 1, status); call SET_CODE; arg_code = code; end; return; /* This entry processes all iox_$control requests for tape_nstd_. */ tape_control: entry (iocb_ptr, order, info_ptr, arg_code); dcl order char (*); dcl info_ptr ptr; call SETUP; ics.entry = order_offset; do order_index = 1 to hbound (ORDER_TAB, 1); if ORDER_TAB.NAME (order_index) = order then goto ACT (ORDER_TAB.ACTION (order_index)); end; arg_code = error_table_$undefined_order_request; return; ACT (0): /* no mapping or special handling */ call iox_$ios_call (addr (ics), order, info_ptr, status); call SET_CODE; arg_code = code; return; ACT (1): /* backspace_file */ leader_ok, eof_ok = "1"b; goto ACT (0); ACT (2): /* backspace_record */ call MAPPED_ORDER ("back"); if status.code = leader_status then arg_code = error_table_$end_of_info; else arg_code = code; return; ACT (3): /* forward_file */ eof_ok = "1"b; goto ACT (0); ACT (4): /* io_call */ call IO_CALL (); arg_code = code; return; ACT (5): /* retry_count */ call MAPPED_ORDER ("err_count"); arg_code = code; return; ACT (6): /* rewind */ leader_ok = "1"b; goto ACT (0); ACT (7): /* write_eof */ call MAPPED_ORDER ("eof"); arg_code = code; return; /* Internal procedure to handle all attach errors. Calls "com_err_" if the "loud_sw" is set. In any case, returns to caller of attach external procedure with proper error code after ensuring that the IPS interrupt mask is restored. */ ERROR: proc (c); dcl c fixed (35); if mask ^= 0 then call hcs_$reset_ips_mask (mask, mask); if loud_sw then call cu_$gen_call (com_err_, (cu_$arg_list_ptr ())); arg_code = c; go to return; end ERROR; return: return; /* Internal procedure to handle faults while IPS interrupts are masked. While not masked, any signals are simply passed on up the stack to their normal handlers. For a fault while masked, the process is terminated (with the reason "unable to do critical I/O") because the I/O control blocks are in an inconsistent state, and we can tolerate neither spawning a command loop with interrupts masked nor a restart with a possibly changed mask. */ HANDLER: proc (p1, name, p2, p3, continue); dcl (p1, p2, p3) ptr; dcl name char (*); dcl continue bit (1) aligned; dcl error_table_$unable_to_do_io fixed (35) ext; dcl terminate_process_ ext entry (char (*), ptr); dcl 1 ti aligned, 2 version fixed, 2 code fixed (35); if mask ^= 0 then do; ti.version = 0; ti.code = error_table_$unable_to_do_io; call terminate_process_ ("fatal_error", addr (ti)); end; if name ^= "cleanup" then continue = "1"b; return; end HANDLER; /* This procedure processes all order calls that must be handled special for io_call. */ IO_CALL: proc (); io_call_infop = info_ptr; if io_call_info.order_name = "request_status" | io_call_info.order_name = "saved_status" then do; call iox_$ios_call (addr (ics), io_call_info.order_name, addr (st), status); if status.code = 0 then do; call analyze_device_stat_$rsnnl (status_story, addr (tape_status_table_$tape_status_table_), (st), ("0"b)); if status_story = "" then call io_call_info.report ("no interesting status"); else call io_call_info.report ("status:^-^a", status_story); end; code = status.code; end; else if io_call_info.order_name = "fixed_record_length" then call IO_CALL_W_FB ("fixed_record_length"); else if io_call_info.order_name = "retry_count" then call IO_CALL_W_FB ("err_count"); else code = error_table_$undefined_order_request; return; IO_CALL_W_FB: proc (ord); dcl ord char (*); dcl value fixed bin (35); if io_call_info.nargs < 1 then do; call io_call_info . error (error_table_$noarg, io_call_info.caller_name, "Argument for ^a control order missing.", order); code = 0; return; end; value = cv_dec_check_ ((io_call_info.args (1)), code); if code ^= 0 then do; call io_call_info . error (error_table_$bad_conversion, io_call_info.caller_name, "Error converting ""^a"" to binary.", io_call_info.args (1)); code = 0; return; end; call iox_$ios_call (addr (ics), ord, addr (value), status); call SET_CODE (); return; end IO_CALL_W_FB; end IO_CALL; /* The mapped order procedure handles nstd_ calls where the order name is to be mapped to an nstd_ compatible order. */ MAPPED_ORDER: proc (ord); dcl ord char (*); call iox_$ios_call (addr (ics), ord, info_ptr, status); call SET_CODE; return; end MAPPED_ORDER; /* The SET_CODE procedure interprets status and sets code accordingly. */ SET_CODE: proc; dcl 1 s aligned based (addr (status.code)), 2 ( io bit (1), junk bit (25), major bit (4), minor bit (6) ) unaligned; if status.code = 0 then code = 0; else if ^s.io then code = status.code; else if status.code = leader_status then if leader_ok then code = 0; else code = error_table_$tape_error; else if (s.major = "0100"b) & s.io then if eof_ok then code = 0; else code = error_table_$end_of_info; else code = error_table_$tape_error; return; end SET_CODE; /* The procedure setup performs setup common to a number of entries. */ SETUP: proc; actual_iocb_ptr = iocb_ptr -> iocb.actual_iocb_ptr; blkptr = actual_iocb_ptr -> iocb.attach_data_ptr; ics.sdbptr = blkptr -> blk.sdbptr; ics.dimptr = blkptr -> blk.dimptr; leader_ok, eof_ok = "0"b; arg_code, code = 0; return; end SETUP; %include iocb; %include io_call_info; end tape_nstd_attach; */ ----------------------------------------------------------- Historical Background This edition of the Multics software materials and documentation is provided and donated to Massachusetts Institute of Technology by Group Bull including Bull HN Information Systems Inc. as a contribution to computer science knowledge. This donation is made also to give evidence of the common contributions of Massachusetts Institute of Technology, Bell Laboratories, General Electric, Honeywell Information Systems Inc., Honeywell Bull Inc., Groupe Bull and Bull HN Information Systems Inc. to the development of this operating system. Multics development was initiated by Massachusetts Institute of Technology Project MAC (1963-1970), renamed the MIT Laboratory for Computer Science and Artificial Intelligence in the mid 1970s, under the leadership of Professor Fernando Jose Corbato. Users consider that Multics provided the best software architecture for managing computer hardware properly and for executing programs. Many subsequent operating systems incorporated Multics principles. Multics was distributed in 1975 to 2000 by Group Bull in Europe , and in the U.S. by Bull HN Information Systems Inc., as successor in interest by change in name only to Honeywell Bull Inc. and Honeywell Information Systems Inc. . ----------------------------------------------------------- Permission to use, copy, modify, and distribute these programs and their documentation for any purpose and without fee is hereby granted,provided that the below copyright notice and historical background appear in all copies and that both the copyright notice and historical background and this permission notice appear in supporting documentation, and that the names of MIT, HIS, Bull or Bull HN not be used in advertising or publicity pertaining to distribution of the programs without specific prior written permission. Copyright 1972 by Massachusetts Institute of Technology and Honeywell Information Systems Inc. Copyright 2006 by Bull HN Information Systems Inc. Copyright 2006 by Bull SAS All Rights Reserved */