mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-04-14 16:10:20 +02:00
545 lines
19 KiB
C
545 lines
19 KiB
C
/* HETTAPE.C (c) Copyright Roger Bowler, 1999-2012 */
|
|
/* Hercules Tape Device Handler for HETTAPE */
|
|
/* */
|
|
/* Released under "The Q Public License Version 1" */
|
|
/* (http://www.hercules-390.org/herclic.html) as modifications to */
|
|
/* Hercules. */
|
|
|
|
/* Original Author: Leland Lucius */
|
|
/* Prime Maintainer: Ivan Warren */
|
|
/* Secondary Maintainer: "Fish" (David B. Trout) */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* This module contains the HET emulated tape format support. */
|
|
/* The subroutines in this module are called by the general tape */
|
|
/* device handler (tapedev.c) when the tape format is HETTAPE. */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#include "hstdinc.h"
|
|
#include "hercules.h" /* need Hercules control blocks */
|
|
#include "tapedev.h" /* Main tape handler header file */
|
|
|
|
//#define ENABLE_TRACING_STMTS 1 // (Fish: DEBUGGING)
|
|
//#include "dbgtrace.h" // (Fish: DEBUGGING)
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Open an HET format file */
|
|
/* */
|
|
/* If successful, the het control blk is stored in the device block */
|
|
/* and the return value is zero. Otherwise the return value is -1. */
|
|
/*-------------------------------------------------------------------*/
|
|
int open_het (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
char pathname[MAX_PATH]; /* file path in host format */
|
|
|
|
|
|
/* Check for no tape in drive */
|
|
if (!strcmp (dev->filename, TAPE_UNLOADED))
|
|
{
|
|
build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Open the HET file */
|
|
hostpath(pathname, dev->filename, sizeof(pathname));
|
|
rc = het_open (&dev->hetb, pathname,
|
|
dev->tdparms.logical_readonly ? HETOPEN_READONLY :
|
|
sysblk.noautoinit ? 0 : HETOPEN_CREATE );
|
|
|
|
if (rc >= 0)
|
|
{
|
|
/* Keep file descriptor and handle synchronized */
|
|
dev->fd = dev->hetb->fd;
|
|
dev->fh = dev->hetb->fh;
|
|
|
|
if(dev->hetb->writeprotect)
|
|
{
|
|
dev->readonly=1;
|
|
}
|
|
rc = het_cntl (dev->hetb,
|
|
HETCNTL_SET | HETCNTL_COMPRESS,
|
|
dev->tdparms.compress);
|
|
if (rc >= 0)
|
|
{
|
|
rc = het_cntl (dev->hetb,
|
|
HETCNTL_SET | HETCNTL_METHOD,
|
|
dev->tdparms.method);
|
|
if (rc >= 0)
|
|
{
|
|
rc = het_cntl (dev->hetb,
|
|
HETCNTL_SET | HETCNTL_LEVEL,
|
|
dev->tdparms.level);
|
|
if (rc >= 0)
|
|
{
|
|
rc = het_cntl (dev->hetb,
|
|
HETCNTL_SET | HETCNTL_CHUNKSIZE,
|
|
dev->tdparms.chksize);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Check for successful open */
|
|
if (rc < 0)
|
|
{
|
|
int save_errno = errno;
|
|
het_close (&dev->hetb);
|
|
dev->fd = -1;
|
|
dev->fh = NULL;
|
|
errno = save_errno;
|
|
{
|
|
char msgbuf[128];
|
|
MSGBUF( msgbuf, "Het error '%s': '%s'", het_error(rc), strerror(errno));
|
|
WRMSG( HHC00205, "E", SSID_TO_LCSS(dev->ssid), dev->devnum,
|
|
dev->filename, "het", "het_open()", msgbuf );
|
|
}
|
|
|
|
strlcpy( dev->filename, TAPE_UNLOADED, sizeof(dev->filename) );;
|
|
build_senseX(TAPE_BSENSE_TAPELOADFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
if ( !sysblk.noautoinit && dev->hetb->created )
|
|
{
|
|
WRMSG( HHC00235, "I", SSID_TO_LCSS(dev->ssid),
|
|
dev->devnum, dev->filename, "het" );
|
|
}
|
|
|
|
return 0;
|
|
|
|
} /* end function open_het */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Close an HET format file */
|
|
/* */
|
|
/* The HET file is close and all device block fields reinitialized. */
|
|
/*-------------------------------------------------------------------*/
|
|
void close_het (DEVBLK *dev)
|
|
{
|
|
/* BHE 03/04/2010: This was the statement?? */
|
|
/* if(dev->hetb->fd >= 0) */
|
|
/* Caught it after a warning message */
|
|
if(dev->fd >= 0)
|
|
{
|
|
WRMSG (HHC00201, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het");
|
|
}
|
|
/* Close the HET file */
|
|
het_close (&dev->hetb);
|
|
|
|
/* Reinitialize the DEV fields */
|
|
dev->fd = -1;
|
|
dev->fh = NULL;
|
|
strlcpy( dev->filename, TAPE_UNLOADED, sizeof(dev->filename) );
|
|
dev->blockid = 0;
|
|
dev->fenced = 0;
|
|
|
|
return;
|
|
|
|
} /* end function close_het */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Rewind HET format file */
|
|
/* */
|
|
/* The HET file is close and all device block fields reinitialized. */
|
|
/*-------------------------------------------------------------------*/
|
|
int rewind_het(DEVBLK *dev,BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc;
|
|
rc = het_rewind (dev->hetb);
|
|
if (rc < 0)
|
|
{
|
|
/* Handle seek error condition */
|
|
char msgbuf[128];
|
|
MSGBUF( msgbuf, "Het error '%s': '%s'", het_error(rc), strerror(errno));
|
|
WRMSG (HHC00205, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_rewind()", msgbuf);
|
|
|
|
build_senseX(TAPE_BSENSE_REWINDFAILED,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
dev->nxtblkpos=0;
|
|
dev->prvblkpos=-1;
|
|
dev->curfilen=1;
|
|
dev->blockid=0;
|
|
dev->fenced = 0;
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Read a block from an HET format file */
|
|
/* */
|
|
/* If successful, return value is block length read. */
|
|
/* If a tapemark was read, the return value is zero, and the */
|
|
/* current file number in the device block is incremented. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int read_het (DEVBLK *dev, BYTE *buf, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
|
|
rc = het_read (dev->hetb, buf);
|
|
if (rc < 0)
|
|
{
|
|
/* Increment file number and return zero if tapemark was read */
|
|
if (rc == HETE_TAPEMARK)
|
|
{
|
|
dev->curfilen++;
|
|
dev->blockid++;
|
|
return 0;
|
|
}
|
|
|
|
/* Handle end of file (uninitialized tape) condition */
|
|
if (rc == HETE_EOT)
|
|
{
|
|
WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_read()", (off_t)dev->hetb->cblk, "end of file (uninitialized tape)");
|
|
|
|
/* Set unit exception with tape indicate (end of tape) */
|
|
build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
{
|
|
char msgbuf[128];
|
|
MSGBUF( msgbuf, "Het error '%s': '%s'", het_error(rc), strerror(errno));
|
|
WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_read()", (off_t)dev->hetb->cblk, msgbuf);
|
|
}
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
dev->blockid++;
|
|
/* Return block length */
|
|
return rc;
|
|
|
|
} /* end function read_het */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Write a block to an HET format file */
|
|
/* */
|
|
/* If successful, return value is zero. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int write_het (DEVBLK *dev, BYTE *buf, U32 blklen,
|
|
BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
off_t cursize; /* Current size for size chk */
|
|
|
|
if ( dev->hetb->writeprotect )
|
|
{
|
|
build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Check if we have already violated the size limit */
|
|
if(dev->tdparms.maxsize>0)
|
|
{
|
|
cursize=het_tell(dev->hetb);
|
|
if(cursize>=dev->tdparms.maxsize)
|
|
{
|
|
build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
}
|
|
/* Write the data block */
|
|
rc = het_write (dev->hetb, buf, blklen);
|
|
if (rc < 0)
|
|
{
|
|
/* Handle write error condition */
|
|
char msgbuf[128];
|
|
MSGBUF( msgbuf, "Het error '%s': '%s'", het_error(rc), strerror(errno));
|
|
WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_write()", (off_t)dev->hetb->cblk, msgbuf);
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
/* Check if we have violated the maxsize limit */
|
|
/* Also check if we are passed EOT marker */
|
|
if(dev->tdparms.maxsize>0)
|
|
{
|
|
cursize=het_tell(dev->hetb);
|
|
if(cursize>dev->tdparms.maxsize)
|
|
{
|
|
WRMSG (HHC00208, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het");
|
|
if(dev->tdparms.strictsize)
|
|
{
|
|
WRMSG (HHC00209, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het");
|
|
het_bsb(dev->hetb);
|
|
cursize=het_tell(dev->hetb);
|
|
ftruncate(dev->hetb->fd,cursize);
|
|
dev->hetb->truncated=TRUE; /* SHOULD BE IN HETLIB */
|
|
}
|
|
build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Return normal status */
|
|
dev->blockid++;
|
|
|
|
return 0;
|
|
|
|
} /* end function write_het */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Write a tapemark to an HET format file */
|
|
/* */
|
|
/* If successful, return value is zero. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int write_hetmark( DEVBLK *dev, BYTE *unitstat, BYTE code )
|
|
{
|
|
int rc; /* Return code */
|
|
|
|
if ( dev->hetb->writeprotect )
|
|
{
|
|
build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Write the tape mark */
|
|
rc = het_tapemark (dev->hetb);
|
|
if (rc < 0)
|
|
{
|
|
/* Handle error condition */
|
|
char msgbuf[128];
|
|
MSGBUF( msgbuf, "Het error '%s': '%s'", het_error(rc), strerror(errno));
|
|
WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_tapemark()", (off_t)dev->hetb->cblk, msgbuf);
|
|
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Return normal status */
|
|
dev->blockid++;
|
|
|
|
return 0;
|
|
|
|
} /* end function write_hetmark */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Synchronize a HET format file (i.e. flush its buffers to disk) */
|
|
/* */
|
|
/* If successful, return value is zero. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int sync_het(DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
|
|
/* Perform the flush */
|
|
rc = het_sync (dev->hetb);
|
|
if (rc < 0)
|
|
{
|
|
/* Handle error condition */
|
|
if (HETE_PROTECTED == rc)
|
|
build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code);
|
|
else
|
|
{
|
|
WRMSG (HHC00205, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_sync()", strerror(errno));
|
|
build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/* Return normal status */
|
|
return 0;
|
|
|
|
} /* end function sync_het */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Forward space over next block of an HET format file */
|
|
/* */
|
|
/* If successful, return value +1. */
|
|
/* If the block skipped was a tapemark, the return value is zero, */
|
|
/* and the current file number in the device block is incremented. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int fsb_het (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
|
|
/* Forward space one block */
|
|
rc = het_fsb (dev->hetb);
|
|
|
|
if (rc < 0)
|
|
{
|
|
/* Increment file number and return zero if tapemark was read */
|
|
if (rc == HETE_TAPEMARK)
|
|
{
|
|
dev->blockid++;
|
|
dev->curfilen++;
|
|
return 0;
|
|
}
|
|
{
|
|
char msgbuf[128];
|
|
MSGBUF( msgbuf, "Het error '%s': '%s'", het_error(rc), strerror(errno));
|
|
WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_fsb()", (off_t)dev->hetb->cblk, msgbuf);
|
|
}
|
|
/* Set unit check with equipment check */
|
|
if(rc==HETE_EOT)
|
|
{
|
|
build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
|
|
}
|
|
else
|
|
{
|
|
build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
dev->blockid++;
|
|
|
|
/* Return +1 to indicate forward space successful */
|
|
return +1;
|
|
|
|
} /* end function fsb_het */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Backspace to previous block of an HET format file */
|
|
/* */
|
|
/* If successful, return value will be +1. */
|
|
/* If the block is a tapemark, the return value is zero, */
|
|
/* and the current file number in the device block is decremented. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int bsb_het (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
|
|
/* Back space one block */
|
|
rc = het_bsb (dev->hetb);
|
|
if (rc < 0)
|
|
{
|
|
/* Increment file number and return zero if tapemark was read */
|
|
if (rc == HETE_TAPEMARK)
|
|
{
|
|
dev->blockid--;
|
|
dev->curfilen--;
|
|
return 0;
|
|
}
|
|
|
|
/* Unit check if already at start of tape */
|
|
if (rc == HETE_BOT)
|
|
{
|
|
build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
{
|
|
char msgbuf[128];
|
|
MSGBUF( msgbuf, "Het error '%s': '%s'", het_error(rc), strerror(errno));
|
|
WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename,
|
|
"het", "het_bsb()", (off_t)dev->hetb->cblk, msgbuf);
|
|
}
|
|
/* Set unit check with equipment check */
|
|
build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
dev->blockid--;
|
|
|
|
/* Return +1 to indicate back space successful */
|
|
return +1;
|
|
|
|
} /* end function bsb_het */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Forward space to next logical file of HET format file */
|
|
/* */
|
|
/* If successful, return value is zero, and the current file number */
|
|
/* in the device block is incremented. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int fsf_het (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
|
|
/* Forward space to start of next file */
|
|
rc = het_fsf (dev->hetb);
|
|
if (rc < 0)
|
|
{
|
|
char msgbuf[128];
|
|
MSGBUF( msgbuf, "Het error '%s': '%s'", het_error(rc), strerror(errno));
|
|
WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_fsf()", (off_t)dev->hetb->cblk, msgbuf);
|
|
|
|
if(rc==HETE_EOT)
|
|
{
|
|
build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
|
|
}
|
|
else
|
|
{
|
|
build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/* Maintain position */
|
|
dev->blockid = rc;
|
|
dev->curfilen++;
|
|
|
|
/* Return success */
|
|
return 0;
|
|
|
|
} /* end function fsf_het */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Check HET file is passed the allowed EOT margin */
|
|
/*-------------------------------------------------------------------*/
|
|
int passedeot_het (DEVBLK *dev)
|
|
{
|
|
off_t cursize;
|
|
if(dev->fd>0)
|
|
{
|
|
if(dev->tdparms.maxsize>0)
|
|
{
|
|
cursize=het_tell(dev->hetb);
|
|
if(cursize+dev->eotmargin>dev->tdparms.maxsize)
|
|
{
|
|
dev->eotwarning = 1;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
dev->eotwarning = 0;
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Backspace to previous logical file of HET format file */
|
|
/* */
|
|
/* If successful, return value is zero, and the current file number */
|
|
/* in the device block is decremented. */
|
|
/* If error, return value is -1 and unitstat is set to CE+DE+UC */
|
|
/*-------------------------------------------------------------------*/
|
|
int bsf_het (DEVBLK *dev, BYTE *unitstat,BYTE code)
|
|
{
|
|
int rc; /* Return code */
|
|
|
|
/* Exit if already at BOT */
|
|
if (dev->curfilen==1 && dev->nxtblkpos == 0)
|
|
{
|
|
build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
rc = het_bsf (dev->hetb);
|
|
if (rc < 0)
|
|
{
|
|
char msgbuf[128];
|
|
MSGBUF( msgbuf, "Het error '%s': '%s'", het_error(rc), strerror(errno));
|
|
WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_bsf()", (off_t)dev->hetb->cblk, msgbuf);
|
|
|
|
build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
|
|
return -1;
|
|
}
|
|
|
|
/* Maintain position */
|
|
dev->blockid = rc;
|
|
dev->curfilen--;
|
|
|
|
/* Return success */
|
|
return 0;
|
|
|
|
} /* end function bsf_het */
|