			    NEW IRAF MAGTAPE DRIVER
				 October 1991
			        (design notes)


1. User Interface

1.1 Magtape Specification

	Old format:
	    
	    mtX.density[file.record]

	New format:

	    mtX['['file[.record][:(param|param@|param=value):...]']']

	e.g.,

	    mtexb1[4:nb:se@:ts=1200:so=/dev/ttya8]

	    mtX is used only as an index into the devices file, and is not
	    parsed.  The tape density is no longer singled out as a special
	    parameter.  If any parameters are specified, these parameters
	    override those given in the tapecap file entry.


1.2 TAPECAP file

	Current Format:

	    irafname [%NNNN] device aliases
	    e.g.,	 mtb.9	nrst8	rst8 nrst0 rst0

	Revised Format:

	    name[|alias|...]:cap=value:...:[tc=name:]

	Device parameters are specified in termcap file format.

	    mta|mtexb1|Exabyte drive 1:\
		:dv=nrst0:rd=rst0:\
		:al=rst0,rst8,rst16,rst24,nrst0,nrst8,nrst16,nrst24:\
		:tc=exb-sunst:
	    exb-sunst|Exabyte via SunOS ST driver:\
		:bs#0:dt=Exabyte:fs#2200:mr#65535:

	This feature will use the new GTY interface.  Modifications are
	required to 1) allow specification of parameters at open time which
	will override those given in the file, and 2) make the use of a #
	for numeric parameters optional (accept either # or =).


1.3 I/O Monitoring

	Device and tape type and capacity are given in tapecap.
	Keep track of tape usage along with file position in lock file.
	Lock file provides simple means to track usage.  A real time
	display may optionally be provided by the driver writing to
	a tape monitoring window via a file or socket, with the name
	given in tapecap or on the command line.


2. Code Changes

	OS,KI
	    zfiomt.c - all host versions are affected as calling sequence
	    has changed.  Network interface is affected (new tape system
	    and old iraf kernel servers are incompatible).

	    The UNIX version of the new driver needs additional code to
	    optionally log status information to a file or special file.
	    Support for tcp/ip status logging as well?

	ETC
	    Device allocation code is affected by the devices file syntax
	    changes.

	MTIO
	    Must be changed to reflect magtape specfication and devices file
	    specification changes, i.e., the density parameter is omitted,
	    the device name is not quite the same thing, and a general
	    device parameter mechanism is added.

	    The feature to keep track of the amount of tape used is device
	    and host independent (given adequate parameterization in the
	    devices file) hence can be implemented in MTIO.  Output to the
	    user, and preservation of tape usage status over device closes,
	    will be via the .lok file and DEVSTATUS.

	    The MTIO driver Z routines seem largely unaffected, except for
	    the status routine and the i/o routines, which need support added
	    for blocked devices.


3. Device Driver

3.1. Device Classes

	generic			generic device (open/close/read/write)
	reel			800,1600,6250 bpi 1/2inch reel tape
	cartridge		various QIC formats - fixed size blocks
	exabyte			variable size blocks
	dat			variable size blocks


3.2. Device Parameters

[[NOT KEPT UP TO DATE - refer to os$zfiomt.c for latest version. ]]]]

	CODE  TYPE  DEFAULT	DESCRIPTION

	bs    i     0		device block size (0 if variable)
	dn    i     none	density (bpi)
	dt    s     generic	drive type
	fs    i     0		filemark size (Kb)
	mr    i     65535	maximum record size
	or    i     63360	optimum record size
	rs    i     0		record gap size (bytes)
	ts    i     0		tape capacity (Mb)
	tt    s     unknown	tape type

	al    s     none	device allocation info
	dv    s     required	no-rewind device file
	rd    s     none	rewind device file
	so    s     none	status output device file or socket

	bo    b     no		BSF positions to BOF
	fc    b     no		device does a FSF on CLRO
	ir    b     no		treat all read errors as EOF
	nb    b     no		device cannot backspace
        nf    b     no          rewind and space forward to backspace file
	np    b     no		disable all positioning ioctls
	ow    b     no		backspace and overwrite EOT at append
	re    b     no		read at EOT returns ERR
	rf    b     no		use BSR,FSR to space over filemarks
	se    b     no		device will position past EOT in a read
	sk    b     no		skip record forward after a read error
	wc    b     no		OPWR-CLWR at EOF writes null file

	bf    i     builtin	BSF ioctl code
	br    i     builtin	BSR ioctl code
	ct    i     builtin	MTIOCTOP code
	ff    i     builtin	FSF ioctl code
	fr    i     builtin	FSR ioctl code
	ri    i     builtin	REW ioctl code


3.3. Host Level Device Operations

	open				(FILE I/O OPERATIONS)
	close
	read
	write
	wait		(not used)

	FSR				(POSITIONING IOCTLS)
	BSR
	FSF
	BSF
	REW

	WEOF		(not used)
	EOM		(not used) (SunOS - space to end of media)


3.4. Device Characteristics

	open		No known system/device dependencies.

	close		For a tape opened read-only, close positions to after
			the filemark of the current file on some SysV systems.
			This makes it impossible to rewind a device opened
			no-rewind (after the open/rewind/close the tape is
			left at the beginning of the second file).  On such
			systems the tape can only be rewound (left rewound
			at close) by opening and closing the rewind device.

			It is assumed that when a tape opened for writing is
			closed an EOT mark is written, and the tape is left
			positioned after the filemark of the last file
			written, ready to write the next file (true on all
			known systems, with some variations in how the EOT
			is represented).

	read		A read where the record size exceeds the size of the
			read request is assumed to be an error.

			A read at end of file should return a zero byte
			count and leave the file positioned after the file
			mark.  Some devices may return ERR when a tape mark
			is read.

			If the device block size is zero it is assumed that
			records can be any size up to the max record size,
			and that successive records can vary in size.

			If the device block size is nonzero it is assumed
			that the byte count for read and write requests (the
			record size) should be a multiple of the device
			block size.  Multiple physical device blocks are
			read or written to satisfy an i/o request.  On a
			read, all notion of the record size is lost, i.e.,
			a read of N blocks will return N blocks regardless
			of the blocking factor used in a write.

			A read at EOT may leave the tape positioned after
			the file mark just read or may result in a zero byte
			count being returned with no affect on the tape
			position.

			Following a read error when reading a data record the
			tape may be left 1) before the bad record, 2) after
			the bad record, 3) in an undefined position, e.g.,
			partway through the record.

	write		For variable record devices each write is assumed
			to write a tape record the size of the output buffer.
			For fixed block devices it is assumed that the size
			of the write request must be an integral multiple of
			the block size, and that multiple physical device
			blocks will be written to satisfy the request.

	wait		Wait (asynchronous i/o) is not currently used and
			is emulated in the driver.  Some systems (Ultrix
			and SunOS 4.1) provide facilities for multi-buffered
			asynchronous i/o which the iraf driver may make use
			of in the future.

	FSR		Forward skip record.  Some systems permit a FSR over
			a filemark and some do not.

	BSR		Backward skip record.  Some systems permit a BSR over
			a filemark and some do not.

	FSF		Forward skip file.  The tape is assumed to be left
			positioned after the filemark and before the first
			record of the next file.

	BSF		Backward skip file.  Some systems leave the tape
			positioned on the BOT side of the filemark, others
			leave the tape positioned to just before the first
			record of the file following the filemark.  A BSF with
			a zero count may or may not rewind the current file.

	REW		Rewinds the tape, leaving the tape positioned to BOT.
			No known system/device dependencies.  See the note
			on the "close" operation, above.

	WEOF		Not currently used.


3.5. Driver Options

	overwrite filemark (reel tapes only)
	disable all backspace operations
	skip record forward after a read error
	i/o logging to specified output device


3.6. Driver Functions

	ZZOPMT - open and position to desired file
	    zmtopen
	    zmtclose
	    zmtposition
		zmtrew
		zmtfsf
		zmtbsf
		zmtfsr
		zmtbsr

	ZZCLMT - close
	    zmtclose

	ZZRDMT - read next record
	    read
	    zmtbsf

	ZZWRMT - write record
	    write

	ZZWTMT - wait for i/o and return byte count

	ZZRWMT - rewind tape
	    zmtopen
	    zmtclose

	ZZSTMT - return device parameters


3.7. Notes on Specific Devices

3.7.1 Device Characteristics

3.7.2 Exabyte Drivers

	SunOS 4.1 ST Driver
	    BSF positions to BOT side of filemark (conventional behavior).
	    Driver does not allow positioning to after EOT.
	    Bug where driver loses track of file position is fixed.

	SunOS 4.0.3 ST Driver
	    BSF positions to first record of file following file mark.
	    BSF 0 rewinds the current file.
	    Driver does not allow positioning to after EOT, i.e., when
		positioning to EOT, after two successive zero reads,
		it is NOT necessary to backspace over the filemark.
	    Driver tries to keep track of current file position but has
		a bug which causes it to zero its counter when appending
		a file to a tape within open/close.
	    This bug has two ramifications:
		o  Will not position to a file before where it thinks
		   BOT is.
		o  Will rewind to get to file it thinks is at BOT.

	Earlier (SunOS 3.X) Sun drivers defaulted to fixed block mode, and
	    probably had other significant differences from the current
	    round of drivers.

	Ciprico RT Driver
	    Both fixed and variable block device entries.
	    rfsd_pr_errlog can get set to 1|2|8 in driver (/dev/mem) to
		turn on status messages.  Variable is commonly set to 2
		to get tape position readouts, but this will interfere
		with iraf networking.
	    BSF positions to BOT side of filemark (conventional behavior).
	    EOT is indicated by two file marks, and a read of the second mark
		will leave the tape positioned to after the mark, requiring
		a backspace to position to EOT (conventional behavior).
	    Status (NOP) ioctl implemented, but file/record count always zero.

	Sparcstation (4.1) ST driver
	    BSR over a filemark confuses the driver - looks like it thinks
		it saw the EOF when reading in the forward direction.
		The next read returns EOF and then the real EOF is read,
		so 2 EOFs in a row are seen (looks like EOT).  The file
		count in the driver gets messed up.
	    BSF causes all subsequent reads to return immediately with ERR.
		One (sometimes two!) REW ioctls are required to clear.
	    FSF and FSR work.

	R-Squared driver for Exabyte (Sun-3 running 4.1)
	    Opens drive in fixed block mode.
	    Read at EOF returns IOERR (driver bug).
	    Status (NOP) ioctl not implemented.


3.8. Pseudocode for Driver Functions


# ZZOPMT -- Open the magtape device and position to the given file.

procedure zzopmt (device, acmode, oldrec, oldfile, newfile, chan)
begin
	# Open device for positioning.
	open no-rewind raw device read-only

	# Do not move the tape if opened newfile=0.
	if (newfile != 0) {
	    # Rewind to get to known position if position uncertain.
	    if (current position unknown) {
		rewind tape
		oldrec = 1
		oldfile = 1
	    }

	    # Position to given file.
	    newfile = zmtfpos (chan, oldfile, oldrec, newfile)
	}

	# Reopen if necessary for i/o.
	if (need write access)
	    reopen device for writing
end


# ZZCLMT -- Close the magtape device.

procedure zzclmt (chan, acmode, nrecords, nfiles, status)
begin
	close device

	nfiles = 0
	nrecords = 0

	if (acmode == read && device: FSF on close read-only)
	    nfiles = 1
	else if (acmode == write && !(at BOF && device: no EOF if no write))
	    nfiles = 1
end


# ZZRDMT -- Initiate a read of the next tape record into the user buffer.

procedure zzrdmt (chan, buf, maxbytes)
begin
	physically read tape
	save read status for zzwtmt
end


# ZZWRMT -- Initiate a write of the next tape record.

procedure zzwrmt (chan, buf, nbytes)
begin
	physically write record
	save write status for zzwtmt
end


# ZZWTMT -- Wait for i/o to complete and return the byte count and the
# change to the tape position in files and records.

procedure zzwtmt (chan, nrecords, nfiles, nbytes)
begin
	nrecords = 0
	nfiles = 0

	if (io error) {
	    nbytes = ERR
	} else if (read 0 bytes) {
	    if (at BOF) {
		# At EOT.
		if (device: read at EOT will go past EOT)
		    if (device: cannot backspace) {
			zmtrew()
			nfiles = -ARB
			nrecords = -ARB
		    } else
			zmtbsf (1)
	    } else
		nfiles = 1
	} else {
	    nrecords = 1
	    clear at BOF flag
	}
end


# ZZRWMT -- Rewind the named device.

procedure zzrwmt (device, status)
begin
	if (device: rewind device specified)
	    close (open (rewind-at-close device read-only))
	else {
	    open no rewind device
	    zmtrew
	    close
	}
end


# ZMTFPOS -- Position to the indicated file.

int procedure zmtfpos (chan, oldfile, oldrec, newfile)
begin
	# Already positioned to desired file; don't do anything.
	if (newfile == oldfile && oldrec == 1)
	    return (newfile)

	# Move the tape.
	if (newfile == 1) {
	    # Rewind.
	    zzrwmt()
	} else if (newfile <= oldfile && newfile != EOT) {
	    # Backspace to desired file.
	    if (device: cannot backspace) {
		zmtrew()
		oldfile = 1
		oldrec = 1
		goto fwd_
	    } else if (device: BSF positions to BOF) {
		zmtbsf (oldfile - newfile)
	    } else {
		zmtbsf (oldfile - newfile + 1)
		zmtfsf (1)
	    }
	} else {
	    # Space forward to desired file or EOT.
fwd_	    while (oldfile < newfile || newfile == EOT) {
		n = read (next record)
		if (n == 0 && oldrec == 1) {
		    # At EOT.
		    if (device: read at EOT will go past EOT) {
			if (device: cannot backspace) {
			    newfile = oldfile
			    zmtrew()
			    oldfile = 1
			    oldrec = 1
			    goto fwd_
			} else
			    zmtbsf (1)
		    }
		    if (writing && device: overwrite EOF) {
			if (!device: cannot backspace) {
			    if (device: BSF positions to BOF)
				zmtbsf (0)
			    else {
				zmtbsf (1)
				zmtfsf (1)
			    }
			}
		    }
		    break
		} else if (n > 0)
		    zmtfsf (1)

		oldfile++
		oldrec = 1
	    }
	    newfile = oldfile
	}

	return (newfile)
end
