/****************************************************************************
* *
* 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