/****************************************************************************
 *									    *
 *			  COPYRIGHT (c) 1990 - 2004			    *
 *			   This Software Provided			    *
 *				     By					    *
 *			  Robin's Nest Software Inc.			    *
 *									    *
 * Permission to use, copy, modify, distribute and sell this software and   *
 * its documentation for any purpose and without fee is hereby granted,	    *
 * provided that the above copyright notice appear in all copies and that   *
 * both that copyright notice and this permission notice appear in the	    *
 * supporting documentation, and that the name of the author not be used    *
 * in advertising or publicity pertaining to distribution of the software   *
 * without specific, written prior permission.				    *
 *									    *
 * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 	    *
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN	    *
 * NO EVENT SHALL HE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL   *
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR    *
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS  *
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF   *
 * THIS SOFTWARE.							    *
 *									    *
 ****************************************************************************/
/*
 * Module:	dttape.c
 * Author:	Robin T. Miller
 * Date:	August 20, 1993
 *
 * Description:
 *	This file contains the tape support functions.
 *
 * Modification History:
 *
 * June 23rd, 2004 by Robin Miller.
 *      Added support for triggers on corruption.
 *
 * November 17th, 2003 by Robin Miller.
 *	Breakup output to stdout or stderr, rather than writing
 * all output to stderr.  If output file is stdout ('-') or a log
 * file is specified, then all output reverts to stderr.
 *
 * February 23rd, 2002 by Robin Miller.
 *      Make porting changes for HP-UX IA64.
 *
 * June 25th, 2001 by Robin Miller.
 *	Restructured code associated with Tru64 Unix EEI, so we obtain
 * the EEI status for all tape errors, not just EIO errors.
 *
 * January 15th, 2001 by Robin Miller.
 *	On errors, do not terminate() if the error limit is exceeded.
 * This way the caller can handle the failure (may expect an error :-).
 *
 * February 17th, 2000 by Robin Miller.
 *	For each tape operation, when debug is enabled, also report the
 * file and record numbers.
 *
 * January 22nd, 2000 by Robin Miller.
 *	Added support for Cygwin tape devices for Windows/NT.
 *
 * August 5th, 1999 by Robin Miller.
 *	Added tape commands for SCO UnixWare 7.
 *
 * July 29, 1999 by Robin Miller.
 *	Merge in changes made to compile on FreeBSD.
 *
 * February 25, 1999 by Robin Miller.
 *	Add support for multiple reset conditions.
 *
 * December 21, 1998 by Robin Miller.
 *	Add device information parameter to all tape functions.
 *
 * December 19, 1998 by Robin Miller.
 *	For DUNIX, display extended error information (if enabled).
 *
 * <date unknown>, by Robin Miller.
 *	Add DoWriteFileMark() function for QNX 4.22 Operating System.
 *
 */

#include "dt.h"

#if defined(_QNX_SOURCE)
#  include <sys/qioctl.h>
#elif defined(SCO)
#  include <sys/ioctl.h>
#  include <sys/tape.h>
#elif defined(__WIN32__)
#  include <sys/mtio.h>
#else /* !defined(_QNX_SOURCE) && !defined(SCO) */
#  include <sys/ioctl.h>
#  include <sys/mtio.h>
#endif /* defined(_QNX_SOURCE) */

#if !defined(_QNX_SOURCE) && !defined(SCO)
/************************************************************************
 *									*
 * DoMtOp()	Setup & Do a Magtape Operation.				*
 *									*
 * Inputs:	dip = The device information.				*
 *		cmd = The magtape command to issue.			*
 *		count = The command count (if any).			*
 *		msg = The error message for failures.			*
 *									*
 * Return Value:							*
 *		Returns 0 / -1 = SUCCESS / FAILURE.			*
 *									*
 ************************************************************************/
int
DoMtOp (dinfo_t *dip, short cmd, daddr_t count, caddr_t msgp)
{
    struct mtop Mtop;
    struct mtop *mtop = &Mtop;

    mtop->mt_op = cmd;

    /*
     * Setup the 'mt' command count (if any).
     */
    if ((mtop->mt_count = count) < 0) {
	 mtop->mt_count = 1;
    }

    if (debug_flag) {
	Printf(
	"Issuing '%s', count = %d (%#x) [file #%lu, record #%lu]\n",
			msgp,  mtop->mt_count, mtop->mt_count,
		(dip->di_mode == READ_MODE) ?
		 (dip->di_files_read + 1) : (dip->di_files_written + 1),
		(dip->di_mode == READ_MODE) ?
		 dip->di_records_read : dip->di_records_written);
    }
    return (DoIoctl (dip, MTIOCTOP, (caddr_t) mtop, msgp));
}

/************************************************************************
 *									*
 * DoXXXXX()	Setup & Do Specific Magtape Operations.			*
 *									*
 * Description:								*
 *	These functions provide a simplistic interface for issuing	*
 * magtape commands from within the program.  They all take 'count'	*
 * as an argument, except for those which do not take a count.		*
 *									*
 * Inputs:	fd = The file descriptor.				*
 *		count = The command count (if any).			*
 *									*
 * Return Value:							*
 *		Returns 0 / -1 = SUCCESS / FAILURE.			*
 *									*
 ************************************************************************/
int
DoForwardSpaceFile (dinfo_t *dip, daddr_t count)
{
	short cmd = MTFSF;
	return (DoMtOp (dip, cmd, count, "forward space file"));
}

int
DoBackwardSpaceFile (dinfo_t *dip, daddr_t count)
{
	short cmd = MTBSF;
	return (DoMtOp (dip, cmd, count, "backward space file"));
}

int
DoForwardSpaceRecord (dinfo_t *dip, daddr_t count)
{
	short cmd = MTFSR;
	return (DoMtOp (dip, cmd, count, "forward space record"));
}

int
DoBackwardSpaceRecord (dinfo_t *dip, daddr_t count)
{
	short cmd = MTBSR;
	return (DoMtOp (dip, cmd, count, "backward space record"));
}

int
DoRewindTape (dinfo_t *dip)
{
	short cmd = MTREW;
	return (DoMtOp (dip, cmd, (daddr_t) 0, "rewind tape"));
}

int
DoTapeOffline (dinfo_t *dip)
{
	short cmd = MTOFFL;
	return (DoMtOp (dip, cmd, (daddr_t) 0, "tape offline"));
}

#if !defined(OSFMK) && !defined(HP_UX) && !defined(AIX)
int
DoRetensionTape (dinfo_t *dip)
{
#if defined(FreeBSD)
	short cmd = MTRETENS;
#else /* !defined(FreeBSD) */
	short cmd = MTRETEN;
#endif /* defined(FreeBSD) */
	return (DoMtOp (dip, cmd, (daddr_t) 0, "retension tape"));
}
#endif /* !defined(OSFMK) && !defined(HP_UX) && !defined(AIX) */

#if defined(__osf__)			/* Really DEC specific. */

int
DoSpaceEndOfData (dinfo_t *dip)
{
	short cmd = MTSEOD;
	return (DoMtOp (dip, cmd, (daddr_t) 0, "space to end of data"));
}

int
DoEraseTape (dinfo_t *dip)
{
	short cmd = MTERASE;
	return (DoMtOp (dip, cmd, (daddr_t) 0, "erase tape"));
}

int
DoTapeOnline (dinfo_t *dip)
{
	short cmd = MTONLINE;
	return (DoMtOp (dip, cmd, (daddr_t) 0, "tape online"));
}

int
DoLoadTape (dinfo_t *dip)
{
	short cmd = MTLOAD;
	return (DoMtOp (dip, cmd, (daddr_t) 0, "load tape"));
}

int
DoUnloadTape (dinfo_t *dip)
{
	short cmd = MTUNLOAD;
	return (DoMtOp (dip, cmd, (daddr_t) 0, "unload tape"));
}

#endif /* defined(__osf__) */

#if defined(sun)

int
DoSpaceEndOfData (dinfo_t *dip)
{
	short cmd = MTEOM;
	return (DoMtOp (dip, cmd, (daddr_t) 0, "space to end of data"));
}

#endif /* defined(sun) */

int
DoWriteFileMark (dinfo_t *dip, daddr_t count)
{
	short cmd = MTWEOF;
	return (DoMtOp (dip, cmd, count, "write file mark"));
}

/************************************************************************
 *									*
 * DoIoctl()	Do An I/O Control Command.				*
 *									*
 * Description:								*
 *	This function issues the specified I/O control command to the	*
 * device driver.							*
 *									*
 * Inputs:	dip = The device information.				*
 *		cmd = The I/O control command.				*
 *		argp = The command argument to pass.			*
 *		msgp = The message to display on errors.		*
 *									*
 * Return Value:							*
 *		Returns 0 / -1 = SUCCESS / FAILURE.			*
 *									*
 ************************************************************************/
int
DoIoctl (dinfo_t *dip, int cmd, caddr_t argp, caddr_t msgp)
{
    int status;

#if defined(EEI)
retry:
#endif
    status = ioctl (dip->di_fd, cmd, argp);
#if defined(EEI)
    if ( (status == FAILURE) &&
	 (dip->di_dtype->dt_dtype == DT_TAPE) ) {
	if ( (errno == EIO) && eei_resets) {
	    if ( HandleTapeResets(dip) ) {
		goto retry;
	    } else if (dip->di_reset_condition) {
		return (status);	/* Resursive reset condition. */
	    }
	} else if (eei_flag) {
	    if ( !get_eei_status(dip->di_fd, dip->di_mt) ) {
		 print_mtstatus (dip->di_fd, dip->di_mt, TRUE);
	    }
	}
    }
#endif /* defined(EEI) */
    if (status == FAILURE) {
        dip->di_errno = errno;
	perror (msgp);
	(void)RecordError();
        ExecuteTrigger(dip, msgp);
    }
    return (status);
}

#elif defined(_QNX_SOURCE)
/************************************************************************
 *									*
 * DoXXXXX()	Setup & Do Specific Magtape Operations.			*
 *									*
 * Description:								*
 *	These functions provide a simplistic interface for issuing	*
 * magtape commands from within the program.  They all take 'count'	*
 * as an argument, except for those which do not take a count.		*
 *									*
 * Inputs:	dip = The device information.				*
 *		count = The command count (if any).			*
 *									*
 * Return Value:							*
 *		Returns 0 / -1 = SUCCESS / FAILURE.			*
 *									*
 ************************************************************************/
int
DoForwardSpaceFile (dinfo_t *dip, daddr_t count)
{
	int cmd = T_SEEK_FM;
	return (DoIoctl (dip, cmd, count, "forward space file"));
}

int
DoForwardSpaceRecord (dinfo_t *dip, daddr_t count)
{
	int cmd = T_SKIP_FWD_A_BLOCK;
	return (DoIoctl (dip, cmd, count, "forward space record"));
}

int
DoBackwardSpaceRecord (dinfo_t *dip, daddr_t count)
{
	int cmd = T_SKIP_BWD_A_BLOCK;
	return (DoIoctl (dip, cmd, count, "backward space record"));
}

int
DoRewindTape (dinfo_t *dip)
{
	int cmd = T_BOT;
	return (DoIoctl (dip, cmd, 0, "rewind tape"));
}

int
DoRetensionTape (dinfo_t *dip)
{
	int cmd = T_RETENSION;
	return (DoIoctl (dip, cmd, 0, "retension tape"));
}

int
DoSpaceEndOfData (dinfo_t *dip)
{
	int cmd = T_SEEK_EOD;
	return (DoIoctl (dip, cmd, 0, "space to end of data"));
}

int
DoEraseTape (dinfo_t *dip)
{
	int cmd = T_ERASE;
	return (DoIoctl (dip, cmd, 0, "erase tape"));
}

int
DoWriteFileMark (dinfo_t *dip, daddr_t count)
{
	int cmd = T_WRITE_FM;
	return (DoIoctl (dip, cmd, count, "write file mark"));
}

int
DoIoctl (dinfo_t *dip, int cmd, int count, caddr_t msgp)
{
	QIC02_MSG_STRUCT qic02ms;
	int status;

	if (debug_flag) {
	    Printf ("Issuing '%s', count = %d (%#x)\n",
					msgp,  count, count);
	}
	bzero((char *)&qic02ms, sizeof(qic02ms));
	qic02ms.Header.Command = (unsigned short)cmd;

	while (count--) {
	    status = qnx_ioctl (dip->di_fd,
				QCTL_RAW_CMD,
				&qic02ms, sizeof (QIC02_HEADER_STRUCT),
				&qic02ms, sizeof (QIC02_MSG_STRUCT));
	    if (status == FAILURE) {
		perror (msgp);
		if (RecordError() >= error_limit) {
		    return (FAILURE);
		}
	    }
	}
	return (status);
}

#elif defined(SCO)

int
DoForwardSpaceFile (dinfo_t *dip, daddr_t count)
{
	int cmd = T_SFF;
	return (DoIoctl (dip, cmd, count, "forward space file"));
}

int
DoBackwardSpaceFile (dinfo_t *dip, daddr_t count)
{
	int cmd = T_SFB;
	return (DoIoctl (dip, cmd, count, "backward space file"));
}

int
DoForwardSpaceRecord (dinfo_t *dip, daddr_t count)
{
	int cmd = T_SBF;
	return (DoIoctl (dip, cmd, count, "forward space record"));
}

int
DoBackwardSpaceRecord (dinfo_t *dip, daddr_t count)
{
	int cmd = T_SBB;
	return (DoIoctl (dip, cmd, count, "backward space record"));
}

int
DoRewindTape (dinfo_t *dip)
{
	int cmd = T_RWD;
	return (DoIoctl (dip, cmd, 0, "rewind tape"));
}

int
DoRetensionTape (dinfo_t *dip)
{
	int cmd = T_RETENSION;
	return (DoIoctl (dip, cmd, 0, "retension tape"));
}

int
DoSpaceEndOfData (dinfo_t *dip)
{
	int cmd = T_EOD;
	return (DoIoctl (dip, cmd, 0, "space to end of data"));
}

int
DoEraseTape (dinfo_t *dip)
{
	int cmd = T_ERASE;
	return (DoIoctl (dip, cmd, 0, "erase tape"));
}

int
DoWriteFileMark (dinfo_t *dip, daddr_t count)
{
	int cmd = T_WRFILEM;
	return (DoIoctl (dip, cmd, count, "write file mark"));
}

int
DoIoctl (dinfo_t *dip, int cmd, int count, caddr_t msgp)
{
	int status;

	if (debug_flag) {
	    Printf ("Issuing '%s', count = %d (%#x)\n",
					msgp,  count, count);
	}
	status = ioctl (dip->di_fd, cmd, count);
	if (status == FAILURE) {
	    perror (msgp);
	    (void)RecordError();
	}
	return (status);
}

#endif /* defined(SCO) */


syntax highlighted by Code2HTML, v. 0.9.1