Coherent4.2.10/conf/ft/src/ftCvt.c

/*
 * ftCvt.c
 *
 * Conversion routines between logical volume location and
 * either physical tape coordinates or diskette pseudo coordinates.
 */

/*
 * ----------------------------------------------------------------------
 * Includes.
 */
#include	<sys/coherent.h>
#include	<sys/cmn_err.h>
#include	<common/_tricks.h>

#include	<sys/ft.h>

/* Real (tape) and pseudo (diskette) parameters for each cartridge format. */
struct FtParm {
	/* Tape parameters. */
	uint	segPerTrk;
	uint	tracks;

	/* FDC pseudo parameters. */
	uint	blkPerTrk;
	uint	heads;
	uint	cyls;
};

/* The following is a read-only table.	*/

static struct FtParm	ftParm[] = {
/* segments/track, tracks, blocks/pseudotrack, heads, cylinders	*/
	{ 150, 28, 128, 7, 150 },		/* QIC-80, 307.5'	*/
	{ 100, 28, 128, 5, 150 },		/* QIC-80, 205'		*/
	{ 102, 20, 128, 2, 255 },		/* QIC-40, 307.5'	*/
	{  68, 20, 128, 2, 170 }		/* QIC-40, 205'		*/
};

static struct FtParm	ftP;

static int	formatSet;
static int	ftSegsPerVol;
static int	ftBlksPerVol;

/************************************************************************
 * ftCBlocksLeft
 *
 * Return number of blocks to end of present tape track.
 ***********************************************************************/

#if	__USE_PROTO__
int ftCBlocksLeft (struct ftTapeLocn * tlp)
#else
int
ftCBlocksLeft (tlp)
struct ftTapeLocn * tlp;
#endif
{
	int retval;

	retval = (FT_BLK_PER_SEG - tlp->ftTLblock)
	  + (ftP.segPerTrk - (tlp->ftTLsegment + 1))
	  * FT_BLK_PER_SEG;

#if FT_TRACE
	cmn_err (CE_NOTE,
	  "!ftCBlocksLeft : %d blocks left on track %d",
	  retval, tlp->ftTLtrack);
#endif

	return retval;
}

/************************************************************************
 * ftCBlksPerVol
 *
 * Return number of blocks per tape.
 *
 * Return -1 if no valid format is set.
 ***********************************************************************/

#if	__USE_PROTO__
int ftCBlksPerVol (void)
#else
int
ftCBlksPerVol ()
#endif
{
	if (!formatSet) {
#if FT_TRACE
		cmn_err(CE_WARN, "ftCBlksPerVol: unknown ft format");
#endif
		return -1;
	}

	return ftBlksPerVol;
}

/************************************************************************
 * ftCDLInc
 *
 * Increment by one a position given in fdc pseudocoordinates.
 *
 * Return -1 if format unknown or increment takes us past end of volume.
 ***********************************************************************/

#if	__USE_PROTO__
int ftCDLInc (struct ftDiskLocn * dlp)
#else
int
ftCDLInc (dlp)
struct ftDiskLocn * dlp;
#endif
{
	if (!formatSet) {
#if FT_TRACE
		cmn_err(CE_WARN, "ftCDLInc: unknown ft format");
#endif
		return -1;
	}

	dlp->ftDLsector++;
	if (dlp->ftDLsector > ftP.blkPerTrk) {

		/* Went over to next pseudotrack.  Sectors start at 1, not 0. */
		dlp->ftDLsector = 1;
		dlp->ftDLcylinder++;

		if (dlp->ftDLcylinder >= ftP.cyls) {

			/* Went over to next cylinder. */
			dlp->ftDLcylinder = 0;
			dlp->ftDLhead++;

			if (dlp->ftDLhead >= ftP.heads) {

				/* Went too far!  Past end of tape. */
#if FT_TRACE
				cmn_err (CE_WARN,
				  "ftCDLInc: Increment past EOT");
#endif
				return -1;
			}
		}
	}

	return 0;
}

/************************************************************************
 * ftCLBtoDL
 *
 * Given a 0-based logical block number, calculate diskette pseudocoordinates.
 *
 * Return 0 on success.
 * Return -1 if block number out of range or tape format is not known.
 ***********************************************************************/

#if	__USE_PROTO__
int ftCLBtoDL	(int logicalBlk, struct ftDiskLocn * diskLoc)
#else
int
ftCLBtoDL (logicalBlk, diskLoc)
int			logicalBlk;
struct ftDiskLocn	* diskLoc;
#endif
{
	if (!formatSet) {
#if FT_TRACE
		cmn_err(CE_WARN, "ftCLBtoDL: unknown ft format");
#endif
		return -1;
	}

	if (logicalBlk < 0 || logicalBlk >= ftBlksPerVol) {
#if FT_TRACE
		cmn_err(CE_WARN, "ftCLBtoDL: block # %d invalid",
		  logicalBlk);
#endif
		return -1;
	}

	diskLoc->ftDLsector = (logicalBlk % ftP.blkPerTrk) + 1;
	logicalBlk /= ftP.blkPerTrk;

	diskLoc->ftDLcylinder = logicalBlk % ftP.cyls;
	logicalBlk /= ftP.cyls;

	diskLoc->ftDLhead = logicalBlk;

	diskLoc->ftDLsecsize = 3;	/* N=3 for 1024 bytes/block */

	return 0;
}

/************************************************************************
 * ftCLStoTL
 *
 * Given a 0-based logical segment number, calculate track and physical
 * segment number.
 *
 * Return 0 on success.
 * Return -1 if segment number out of range or tape format is not known.
 ***********************************************************************/

#if	__USE_PROTO__
int ftCLStoTL	(int logicalSeg, struct ftTapeLocn * tapeLoc)
#else
int
ftCLStoTL (logicalSeg, tapeLoc)
int			logicalSeg;
struct ftTapeLocn	* tapeLoc;
#endif
{
	if (!formatSet) {
#if FT_TRACE
		cmn_err(CE_WARN, "ftCLStoTL: unknown ft format");
#endif
		return -1;
	}

	if (logicalSeg < 0 || logicalSeg >= ftSegsPerVol) {
#if FT_TRACE
		cmn_err(CE_WARN, "ftCLStoTL: segment # %d invalid",
		  logicalSeg);
#endif
		return -1;
	}

	tapeLoc->ftTLtrack = logicalSeg / ftP.segPerTrk;
	tapeLoc->ftTLsegment = logicalSeg % ftP.segPerTrk;
	tapeLoc->ftTLblock = 0;

	return 0;
}

/************************************************************************
 * ftCSectoTL
 *
 * Given a 0-based logical sector number, calculate track, physical
 * segment number, and block (0..31) within segment.
 *
 * Return 0 on success.
 * Return -1 if sector number out of range or tape format is not known.
 ***********************************************************************/

#if	__USE_PROTO__
int ftCSectoTL	(int sector, struct ftTapeLocn * tapeLoc)
#else
int
ftCSectoTL (sector, tapeLoc)
int			sector;
struct ftTapeLocn	* tapeLoc;
#endif
{
	int	segment;

	if (!formatSet) {
#if FT_TRACE
		cmn_err(CE_WARN, "ftCSectoTL: unknown ft format");
#endif
		return -1;
	}

	if (sector < 0 || sector >= ftBlksPerVol) {
#if FT_TRACE
		cmn_err(CE_WARN, "ftCSectoTL: sector # %d invalid",
		  sector);
#endif
		return -1;
	}

	segment = sector / FT_BLK_PER_SEG;

	tapeLoc->ftTLblock = sector % FT_BLK_PER_SEG;
	tapeLoc->ftTLsegment = segment % ftP.segPerTrk;
	tapeLoc->ftTLtrack = segment / ftP.segPerTrk;

	return 0;
}

/************************************************************************
 * ftCDLtoSec
 *
 * Given a set of diskette pseudo coordinates, calculate the logical
 * sector number.
 *
 * Return 0 on success.
 * Return -1 if coordinates out of range or tape format is not known.
 ***********************************************************************/

#if	__USE_PROTO__
int ftCDLtoSec	(struct ftDiskLocn * diskLoc, int * logSector)
#else
int
ftCDLtoSec (diskLoc, logSector)
struct ftDiskLocn	* diskLoc;
int			* logSector;
#endif
{
	int	lsn;	/* logical *sector* number, as in QIC standards */

	if (!formatSet) {
#if FT_TRACE
		cmn_err(CE_WARN, "ftCDLtoSec: unknown ft format");
#endif
		return -1;
	}

#if FT_TRACE
	if (diskLoc->ftDLhead >= ftP.heads) {
		cmn_err(CE_WARN, "ftCDLtoSec: C=%d/H=%d/R=%d:H invalid",
		  diskLoc->ftDLcylinder, diskLoc->ftDLhead, diskLoc->ftDLsector);
	}

	if (diskLoc->ftDLcylinder >= ftP.cyls) {
		cmn_err(CE_WARN, "ftCDLtoSec: C=%d/H=%d/R=%d:C invalid",
		  diskLoc->ftDLcylinder, diskLoc->ftDLhead, diskLoc->ftDLsector);
	}

	if (diskLoc->ftDLsector - 1 >= ftP.blkPerTrk) {
		cmn_err(CE_WARN, "ftCDLtoSec: C=%d/H=%d/R=%d:R invalid",
		  diskLoc->ftDLcylinder, diskLoc->ftDLhead, diskLoc->ftDLsector);
	}
#endif

	/* Sort applying Horner's rule here... */

	lsn = diskLoc->ftDLhead;
	lsn *= ftP.cyls;
	lsn += diskLoc->ftDLcylinder;
	lsn *= ftP.blkPerTrk;
	lsn += diskLoc->ftDLsector - 1;

	* logSector = lsn;

	return 0;
}

/************************************************************************
 * ftCDLtoLS
 *
 * Given a set of diskette pseudo coordinates, calculate the logical
 * segment number.
 *
 * Return 0 on success.
 * Return -1 if coordinates out of range or tape format is not known.
 ***********************************************************************/

#if	__USE_PROTO__
int ftCDLtoLS	(struct ftDiskLocn * diskLoc, int * logicalSeg)
#else
int
ftCDLtoLS (diskLoc, logicalSeg)
struct ftDiskLocn	* diskLoc;
int			* logicalSeg;
#endif
{
	int	lsn;	/* logical *sector* number, as in QIC standards */

	if (ftCDLtoSec (diskLoc, &lsn))
		return -1;

	* logicalSeg = lsn / FT_BLK_PER_SEG;

	return 0;
}

/************************************************************************
 * ftCvtSetFmt
 *
 * Initialize conversion routines for a specific QIC-80 or QIC-40 format.
 *
 * Return 0 on success.
 * Return -1 if format number is invalid.
 ***********************************************************************/

#if	__USE_PROTO__
int ftCvtSetFmt	(int format)
#else
int
ftCvtSetFmt (format)
int	format;
#endif
{
	if (format < 0 || format >= __ARRAY_LENGTH(ftParm)) {
#if FT_TRACE
		cmn_err(CE_WARN, "ftCvtSetFmt: format # %d invalid", format);
#endif
		formatSet = 0;
		return -1;
	}
	formatSet = 1;
	ftP = ftParm [format];

	ftSegsPerVol = ftP.segPerTrk * ftP.tracks;
	ftBlksPerVol = ftSegsPerVol * FT_BLK_PER_SEG;

	return 0;
}

/************************************************************************
 * ftCvtSetFtParms
 *
 * Initialize conversion routines for a specific QIC-80 or QIC-40 format.
 * Like ftCvtSetFmt, except get individual parameter values (e.g. from
 * tape header segment), and use default values for any zero arguments.
 ***********************************************************************/

#if	__USE_PROTO__
void ftCvtSetFtParms (unsigned int spt, unsigned int tracks,
  unsigned int heads, unsigned int cyls)
#else
void
ftCvtSetFtParms (spt, tracks, heads, cyls)
unsigned int spt;
unsigned int tracks;
unsigned int heads;
unsigned int cyls;
#endif
{
	formatSet = 1;

	if (spt > 0)
		ftP.segPerTrk = spt;

	if (tracks > 0)
		ftP.tracks = tracks;

	if (heads > 0)
		ftP.heads = heads;

	if (cyls > 0)
		ftP.cyls = cyls;

	ftSegsPerVol = ftP.segPerTrk * ftP.tracks;
	ftBlksPerVol = ftSegsPerVol * FT_BLK_PER_SEG;
}

/************************************************************************
 * ftCvtUnsetFmt
 *
 * Set tape format invalid (e.g., new tape).
 ***********************************************************************/

#if	__USE_PROTO__
void ftCvtUnsetFmt	(void)
#else
void
ftCvtUnsetFmt ()
#endif
{
	formatSet = 0;
}