
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.TYPE        Module
.NAME        iodev
.LANGUAGE    C
.AUTHOR      IPG-ESO Garching
.CATEGORY    Host operating system interfaces. Tape management.
.COMMENTS    Tape management. 
	     The functions of this module perform basic i/o to
	     magnetic tapes on AIX enviroments
.VERSION     [1.1] mhl obs lyon mars 1991

.ENVIRONMENT  System V
------------------------------------------------------------*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>

#include <sys/ioctl.h>
#include <sys/devinfo.h>  /* 3 include IBM  rs6000 */
#include <sys/scsi.h>
#include <sys/tape.h>


#include <osparms.h>
#include <osudef.h>
/*----------------------------------------------------------
fichier sys/tape.h , contient:
SCSI Tape Ioctls
#define STIOCTOP        0x01              * tape commands *
#define STIOCMD         0x02              * diagnostic commands *

* Structures and definitions for magnetic tape io control commands
 structure for STIOCTOP - streaming tape op command :
struct  stop    {
	 short   st_op;          * operations defined below *
	 daddr_t st_count;       * how many of them *
		 };

* operations *
#define STREW   6       * rewind *
#define STERASE 7       * erase tape, leave at load point *
#define STRETEN 8       * retension tape, leave at load point *
#define STWEOF  10      * write an end-of-file record *
#define STFSF   11      * forward space file *
#define STRSF   12      * reverse space file *
#define STFSR   13      * forward space record *
#define STRSR   14      * reverse space record *

------------------------------------------------------------*/

/* ----------- pour interfac avec les codes operations habituels sur bande --*/
#define MTIOREW STREW
#define MTIOWEOF STWEOF
#define MTIOFSF STFSF
#define MTIOBSF STRSF
#define MTIOFSR STFSR
#define MTIOBSR STRSR


/*#define TAPE_BLK 10240 */
#define TAPE_BLK 20480
/*#define DEBUG  */

static char class_name[] = "mt";	/* MAgnetic Tape Class */
 
extern int errno;
extern int oserror;
extern char *oserrmsg;

#define M_ST_SUCC 0x00
/*  #define M_ST_DATA 0x34   */
#define M_ST_DATA 110
#define M_ST_BOT  20
/* #define M_ST_TAPEM 0x1C */

	/* For debbuging */
/*char inv[] = "Invalid tape status\n"; */
/*char *tape_msg[M_ST_MASK] = {         */
/*	"Success\n",			*/ /* 001 */
/*	"Invalid command\n",		*/ /* 002 */
/*	"Command aborted\n",		*/ /* 003 */
/*	"Unit offline\n",		*/ /* 004 */
/*	"Unit available\n",		*/ /* 005 */
/*	"Write protected\n",		*/ /* 006 */
/*	"Compare error\n",		*/ /* 007 */
/*	"Data error\n",			*/ /* 010 */
/*	"Host buffer access error\n",	*/ /* 011 */
/*	"Controller error\n",		*/ /* 012 */
/*	"Drive error\n",		*/ /* 013 */
/*	"Formatter error\n",		*/ /* 014 */
/*	"BOT encountered\n",		*/ /* 015 */
/*	"Tape mark encountered\n",	*/ /* 016 */
/*	inv,				*/ /* 017 */
/*	"Record data truncated\n",	*/ /* 020 */
/*	"Position lost\n",		*/ /* 021 */
/*	"Serious exception\n",		*/ /* 022 */
/*	"LEOT detected\n",		*/ /* 023 */
/*	inv,inv,inv,inv,inv,inv,inv,inv,inv,inv,inv, 	*/ /* 024-036 */
/*	"Message from an internal diagnostic\n" 	*/ /* 037 */
/*	}; */

int ioctop(fd,op,count)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Skip forward space file on a tape. 
.RETURNS 0 / -1 (error)
.REMARKS System dependencies:
 -- UNIX: open(2), ioctl(2)
------------------------------------------------------------*/
int fd;			/* IN:	Tape device file descriptor */
int op;			/* IN:  Operation */
int count;		/* IN:	How many of them */
{
	int stat, ret;
	struct stop mtoperation ; /* structure pour ioctl ibm */


#ifdef DEBUG
printf ("ioctop  ");
#endif
	oserror=0;stat=0;
	/*
	** First try to execute the command.
	** Even if fails, try to read the status
	*/
	/* en cas de weof, l'argument est le nombre de tape marks a ecrire */
#ifdef DEBUG
printf ("mh ioctl:%d  count=%d  ",op,count);
#endif

/* initialisation de la structure */

mtoperation.st_op=op;
mtoperation.st_count=count;

switch (op) 
	{
	case MTIOWEOF :
#ifdef DEBUG
		printf (" ioctl-weof ");
#endif
		if ((ret = ioctl(fd,STIOCTOP,&mtoperation)) == -1) oserror = errno; break;
	case MTIOFSF :
#ifdef DEBUG
		printf (" ioctl-fsf ");
#endif
		if ((ret = ioctl(fd,STIOCTOP,&mtoperation)) == -1) oserror = errno; break;
	case MTIOBSF :
#ifdef DEBUG
		printf (" ioctl-bsf ");
#endif
		if ((ret = ioctl(fd,STIOCTOP,&mtoperation)) == -1) 
			{
			if (errno == EIO )	 /* on doit etre en debut de bande */
				{
				stat = M_ST_BOT;
				}
			else oserror = errno;
			} break;
	case MTIOFSR :
#ifdef DEBUG
		printf (" ioctl-fsr ");
#endif
		if ((ret = ioctl(fd,STIOCTOP,&mtoperation)) == -1) oserror = errno; break;
	case MTIOBSR :
#ifdef DEBUG
		printf (" ioctl-bsr ");
#endif
		if ((ret = ioctl(fd,STIOCTOP,&mtoperation)) == -1) oserror = errno; break;
	case MTIOREW :
#ifdef DEBUG
		printf (" ioctl-rewind  op=%d  ",op);
#endif
		if ((ret = ioctl(fd,STIOCTOP,&mtoperation)) == -1)
			{
			oserror = errno;
			}
			break;
	default :
#ifdef DEBUG
		printf (" ioctl-default  op=%d  ",op);
#endif
		printf ("code operation inconnu");
		break;
	}

	/*
	** If there was an error,
	** the error condition must be cleared before continue
	*/
	if (ret == -1) 
		oserror = errno;
#ifdef DEBUG
	printf (" ret=%d oserror=%d\n",ret,oserror);
#endif
 	return(oserror ? -1 : stat);		
}

static int ioinfo(fd, s, fileno, blkno)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Retrieve Info concerning an opened device
.RETURNS 0 (success) / -1 (error)
------------------------------------------------------------*/
  	int	fd;	/* IN: File Descriptor		*/
	struct osustat	*s;	/* OUT: The filled components */
        int     *fileno;        /* OUT: Where we are    */
        long    *blkno;         /* OUT: Where we are    */
{
struct devinfo info_bande;
int ret;

#ifdef DEBUG
printf ("ioinfo\n");
#endif
if ((ret = ioctl(fd,IOCINFO,&info_bande)) == -1 ) oserror = errno;
if (ret != -1)
	{
	printf (" ioinfo , devtype %c \n",info_bande.devtype);
	printf ("ioinfo , scmt type %d blksize=%d\n",info_bande.un.scmt.type,info_bande.un.scmt.blksize);

	s->usize     = 0;
	s->blocksize = 0;
	s->density   = 0;
	s->isda = 0;        /* Not direct access */
	if ( info_bande.devtype == DD_SCTAPE ) s->istm = 1;
		else
		{
	 	s->istm = 0;
		oserror = -1;
		oserrmsg = "Device can't be a tape...";
		return(-1);
		}
    *fileno=-1;
	*blkno=-1;
	}
	return(ret);
}

static int ioopen(name,mode,den)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Open a tape device
.RETURNS File descriptor / -1 (error)
.REMARKS System dependencies:
 -- UNIX: open(2), fstat(2)
------------------------------------------------------------*/
char *name;		/* IN:	Physical name of tape device */
int mode;		/* IN:  Open mode */
int den;		/* IN:  Density. Not used */
{
	struct stat buf;
	int fd;
	int t;
	
#ifdef DEBUG
printf ("ioopen\n");
#endif
	/* 
	** First try to open device READ/WRITE.
	** If fail, try READ_ONLY
	*/

	switch(mode) {
		case READ       : t = O_RDONLY; break;
		case WRITE      : t = O_WRONLY; break;
		case READ_WRITE : t = O_RDWR; break;
		case APPEND     : t = O_RDWR; break;
		default         : oserror = EINVAL; return(-1);
	}
	
	if ( (fd = open(name,t)) == -1) {
#ifdef DEBUG
		printf (" mh  IOopen fd=%d errno=%d\n",fd,errno);
#endif
		oserror= errno;
		return(-1);
		}

	if ( fstat(fd,&buf) == -1) {
#ifdef DEBUG
		printf (" mh  IOopen  fstat=%d errno=%d\n",fstat,errno);
#endif
		oserror= errno;
		return(-1);
		}

	if ( (buf.st_mode & S_IFMT) != S_IFCHR) {
		oserror = -1;
		oserrmsg = "Osuopen: Not a character device";
		return(-1);
		}
	return(fd);
}


static int ioclose(fd)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE 
.RETURNS 
.REMARKS System dependencies:
 -- UNIX: close(2) 
------------------------------------------------------------*/
int fd;			/* IN:	Tape file descriptor */
{
#ifdef DEBUG
printf ("ioclose\n");
#endif
	if (close(fd) == -1) {
		oserror = errno;
		return(-1);
		}
	return(0);
}


static int ioread(fd,buffer,size)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Read a block from a magnetic tape.
.RETURNS Bytes read / -1 if error
.REMARKS 0 Bytes read, means a File Mark was detected.
.REMARKS System dependencies:
 -- UNIX: read(2), ioctl(2)
------------------------------------------------------------*/
int fd;			/* IN:	Tape device file descriptor */
char *buffer;		/* IN:	Buffer for reading */
int size;		/* IN:	Length of bytes to be read */
{
	int length;

#ifdef DEBUG
	printf ("ioread  fd=%d size=%d  ",fd,size);
#endif
	if (size > TAPE_BLK ) size = TAPE_BLK;
	if ((length = read(fd,buffer,size)) == -1) 	
		oserror = errno;
	return(length);
}


static int iowrite(fd,buffer,size)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Write a block on a magnetic tape.
.RETURNS Bytes written / -1 (error)
.REMARKS System dependencies:
 -- UNIX: write(2), ioctl(2)
------------------------------------------------------------*/
int fd;			/* IN:	Tape device file descriptor */
char *buffer;		/* IN:	Buffer for reading */
int size;		/* IN:	Length of bytes to be read */
{
	int length;

	oserror = 0;

	if ((length = write(fd,buffer,size)) == -1)
        	oserror = errno;
#if DEBUG
        printf("iowrite %d to buffer of %d bytes\n", length, size);
#endif
	return(length);
}

static int ioweof(fd,ntm)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Write end-of-file record (tape_mark) on the tape.
.RETURNS Tape marks written/ -1 (error)
.REMARKS System dependencies:
 -- UNIX: ioctl(2)
------------------------------------------------------------*/
int fd;			/* IN:	Tape device file descriptor */
int ntm;		/* IN:	Number of tape marks */
{

#ifdef DEBUG
printf ("ioweof  ntm=%d\n",ntm);
#endif
	if (ioctop(fd,MTIOWEOF,ntm) == -1)
		return(-1);
	else 
		return(ntm);
}


static int iofsf(fd,ntm)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Skip forward space file on a tape. 
.RETURNS Tape marks skipped/ -1 (error)
.REMARKS System dependencies:
 -- UNIX: ioctl(2)
------------------------------------------------------------*/
int fd;			/* IN:	Tape device file descriptor */
int ntm;		/* IN:	Number of tape marks */
{
	int ret, stat;

#ifdef DEBUG
printf ("iofsf\n");
printf("lyon iofsf entered fd=%d ntm=%d\n",fd,ntm);
#endif
	stat = ioctop(fd,MTIOFSF,ntm);
#ifdef DEBUG
	printf("lyon iofsf stat = %d oserror=%d\n",stat,oserror);
#endif

	switch(stat) {
	case M_ST_SUCC:			/* Command OK */
		/*oserror = 0; */ /* mh 9.8.90 */
		ret = ntm; 
		break;
	case M_ST_DATA:			/* End of data */
		oserror = 0;
		ret = 0; 
		break;
	default: 
		ret = -1; 
		break;
	}
	return(ret);

}


static int iobsf(fd,ntm)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Skip backward space file on a tape. 
.RETURNS Tape marks skipped/ -1 (error)
.REMARKS System dependencies:
 -- UNIX: ioctl(2)
------------------------------------------------------------*/
int fd;			/* IN:	Tape device file descriptor */
int ntm;		/* IN:	Number of tape marks */
{
	int ret, stat;

#ifdef DEBUG
printf ("iobsf\n");
#endif
/* je recule de ntm+1 file mark et je re avance de 1 file mark, sauf si
en reculant j'ai atteint le debut de bande */
	stat = ioctop(fd,MTIOBSF,ntm+1);

	switch(stat) {
	case M_ST_SUCC:			/* Command OK  je ravance de 1 file mark*/
		stat=ioctop(fd,MTIOFSF,1);
		 switch(stat) {
		 case M_ST_SUCC:   
			ret = ntm;
			break;
		 default:
		    ret = -1;
		    break;
		 }
		break;
	case M_ST_BOT:			/* Beggining of tape */
		oserror = 0;
		ret = 0; 
		break;

	default: 
		ret = -1; 
		break;
	}
	return(ret);

}


static int iorew(fd)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Rewind tape
.RETURNS 0 / -1 (error)
.REMARKS System dependencies:
 -- UNIX: ioctl(2)
------------------------------------------------------------*/
int fd;			/* IN:	Tape device file descriptor */
{
#ifdef DEBUG
printf ("iorew\n");
#endif
	if (ioctop(fd,MTIOREW,1) == -1)
		return(-1);
	else 
		return(0);
}


static int iofsr(fd,count)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Forward space record on tape
.RETURNS records skipped/ -1 (error)
.REMARKS System dependencies:
 -- UNIX: ioctl(2)
------------------------------------------------------------*/
int fd;			/* IN:	Tape device file descriptor */
int count; 		/* IN:	Number of records */
{
	int ret, stat;

#ifdef DEBUG
printf ("iofsr\n");
#endif

	stat = ioctop(fd,MTIOFSR,count);

	switch(stat) {
	case M_ST_SUCC:			/* Command OK */
		ret = count; 
		break;
	case M_ST_DATA:			/* End of records */
		oserror = 0;
		ret = 0; 
		break;
	default: 
		ret = -1; 
		break;
	}
	return(ret);

}


static int iobsr(fd,count)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Backward space record on tape
.RETURNS records skipped/ -1 (error)
.REMARKS System dependencies:
 -- UNIX: ioctl(2)
------------------------------------------------------------*/
int fd;			/* IN:	Tape device file descriptor */
int count;		/* IN:	Number of records */
{
	int ret, stat;

#ifdef DEBUG
printf ("iobsr\n");
#endif
	stat = ioctop(fd,MTIOBSR,count);

	switch(stat) {
	case M_ST_SUCC:			/* Command OK */
		ret = count; 
		break;
/*	case M_ST_BOT:		
*		oserror = 0;
*		ret = 0; 
*		break;
*/
	default: 
		ret = -1; 
		break;
	}
	return(ret);

}


int iocse(fd)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Clear a serious exception.
.RETURNS 0 / -1 (error)
.REMARKS System dependencies:
 -- UNIX: ioctl(2)
------------------------------------------------------------*/
int fd;			/* IN:	Tape device file descriptor */
{

#ifdef DEBUG
printf("iocse\n");
#endif
	return(-1);	/* MTCSE does not exit */
}

static int ioeom(fd)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Move to EOMedia
.RETURNS 0 (OK) / -1 (not done, error)
------------------------------------------------------------*/
int fd;                 /* IN:  Tape device file descriptor */
{
#ifdef DEBUG
	printf ("ioeom \n");
#endif
	return(-1);
}

static int iosread(fd, spos, ssize, buffer, size)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Read a block from a unit
.RETURNS Bytes read / -1 if error
------------------------------------------------------------*/
int     fd;     	/* IN:  File descriptor */
long    spos;   	/* IN:  Sector Number */
int     ssize;  	/* IN:  Size of one sector */
char    *buffer;        /* IN:  Buffer for reading */
int     size;   	/* IN:  Length of bytes to be read */
{
#ifdef DEBUG
printf ("iosread\n");
#endif
	return(-1);
}

static int ioswrite(fd, spos, ssize, buffer, size)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Read a block from a unit
.RETURNS Bytes read / -1 if error
------------------------------------------------------------*/
int     fd;     	/* IN:  File descriptor */
long    spos;   	/* IN:  Sector Number */
int     ssize;  	/* IN:  Size of one sector */
char    *buffer;        /* IN:  Buffer for reading */
int     size;   	/* IN:  Length of bytes to be read */
{	
#ifdef DEBUG
printf ("ioswrite\n");
#endif
	return(-1);
}


/*=====================================================================
 * 		Definition of the structure returned to osu
 *=====================================================================*/

/*   struct iolist *iodev1();*/	/* Next iodev in List */


static OPITEM list_of_functions[] = {
	{ U_INFO,	ioinfo},
	{ U_OPEN,	ioopen},			
	{ U_CLOSE,  	ioclose},			
	{ U_READ,	ioread},			
	{ U_WRITE,	iowrite},			
	{ U_REWIND, 	iorew},				
	{ U_WEOF,	ioweof},			
        { U_SREAD,      iosread},     
        { U_SWRITE,     ioswrite},    
	{ U_FMF,	iofsf},
	{ U_FMB,	iobsf},
	{ U_BMF,	iofsr},
	{ U_BMB,	iobsr}
 };

static struct iolist this_dev = {
	(IODEV)0,		/* No Next iodev in List */
	class_name,	/* How it's written in DEVCAPFILE */
	sizeof(list_of_functions)/sizeof(list_of_functions[0]),
	list_of_functions
 };
 
struct iolist *iodev()
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Get All definitions concerning this class of Devices
.RETURNS The iolist
.REMARKS Simply returns the local iolist address...
------------------------------------------------------------*/
{
  	return(&this_dev);
}

