/*
 * DATlib   Copyright (c) 1995-1996 Marcus Meissner &
 *          Friedrich-Alexander Universitaet Erlangen-Nuernberg (FAU), IMMD4
 *          All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by Marcus Meissner
 *    at the Friedrich-Alexander Universitaet Erlangen-Nuernberg (FAU), IMMD4
 *
 * 4. The name of the University or the author may not be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND THE AUTHOR ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR THE AUTHOR BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/* $Id: kernelp.c,v 1.3 1997/06/02 18:44:18 msmeissn Exp $
 *
 * $Log: kernelp.c,v $
 * Revision 1.3  1997/06/02 18:44:18  msmeissn
 * NULLs for extended_inquiry and read_buffer
 *
 * Revision 1.2  1997/04/24 10:56:03  msmeissn
 * *** empty log message ***
 *
 * Revision 1.1  1997/03/16 20:28:55  msmeissn
 * Initial revision
 *
 *
 */

#ifdef sun
/* 
 * Implementation der MT calls der datlib ueber einen gepatchten Kernel
 */

#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/mtio.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <unistd.h>
#include <errno.h>

int errno;

#include "datlib.h"
#include "mt_ext.h"

/* i don't want to include /usr/include/sys/scsi/generic/inquiry.h ... */
#ifndef DTYPE_SEQUENTIAL
#define DTYPE_SEQUENTIAL 1
#endif

int kernelp_get_version(int fd,char *buf,int bufsize);
int kernelp_create_partition(int fd,int size,int size_kind);
int kernelp_delete_partition(int fd);
int kernelp_switch_active_partition(int fd,int targetpart);
int kernelp_query_active_partition(int fd);
int kernelp_set_compression(int fd,int compression);
int kernelp_set_decompression(int fd,int decompression);
int kernelp_query_compression(int fd);
int kernelp_query_decompression(int fd);
int kernelp_get_log_page(int fd,int nr,unsigned char *logpage,int logsize);
int kernelp_get_mode_page(int fd,int nr,unsigned char *modepage,int modesize);
int kernelp_set_mode_page(int fd,unsigned char *modepage,int modesize);
int kernelp_get_inquiry(int fd,unsigned char *inqbuf,int inqsize);
int kernelp_request_sense(int fd,unsigned char *inqbuf,int inqsize);

static struct datlib_functions datlib_kernelp_funs={
	"kernelp",
	kernelp_get_version,
	kernelp_create_partition,
	kernelp_delete_partition,
	kernelp_switch_active_partition,
	kernelp_query_active_partition,
	kernelp_set_compression,
	kernelp_set_decompression,
	kernelp_query_compression,
	kernelp_query_decompression,
	kernelp_get_log_page,
	kernelp_get_mode_page,
	kernelp_set_mode_page,
	kernelp_get_inquiry,
	NULL,/*kernelp_request_sense*/
	NULL,/*get_extended_inquiry */
	NULL,/*read_buffer */
};

int
kernelp_get_version(int fd,char *buf,int bufsize) {
	char	xbuf[200];
	struct	mt_exver	mtexver;

	if (-1==ioctl(fd,MTIOEXVER,&mtexver))
		sprintf(xbuf,"datlib version: %s, no kernel patch version",
			DATLIBVERSION
		);
	else {
		if (strcmp(mtexver.mt_exver_version,DATLIBVERSION)) {
			fprintf(stderr,"kernelp.c:init:Warning: kernel driver version (%s) differs from datlib version(%s)!\n",
				mtexver.mt_exver_version,DATLIBVERSION
			);
		}
		sprintf(xbuf,"datlib version: %s, kernel patch version: %s",
			DATLIBVERSION,mtexver.mt_exver_version
		);
	}
	strncpy(buf,xbuf,bufsize);
	return strlen(xbuf);
}

struct datlib_functions *
datlib_kernelp_init(int fd) {
	unsigned char	inqbuf[100];
	struct	mt_exver mtexver;
	
	if (-1==ioctl(fd,MTIOEXVER,&mtexver))
		fprintf(stderr,"kernelp.c:init:kernel does not have versioning.\n");
	else {
		if (strcmp(mtexver.mt_exver_version,DATLIBVERSION)) {
			fprintf(stderr,"kernelp.c:init:Warning: kernel driver version (%s) differs from datlib version(%s)!\n",
				mtexver.mt_exver_version,DATLIBVERSION
			);
		}
	}
	if (-1==kernelp_get_inquiry(fd,inqbuf,100)) {
		return NULL;
	}
        /* FIXME: media changers? */
	if (inqbuf[0]!=DTYPE_SEQUENTIAL) {
		fprintf(stderr,"uscsicmd.c:init:Not a sequential access device.\n");
		errno=ENOTTY;
		return NULL;
	}
	if ((inqbuf[2]&0x3)!=2) {
		fprintf(stderr,"kernelp.c:init:Need to operate in SCSI-2 mode.\n");
		errno=ENOTTY;
		return NULL;
	}
	if (strncmp((char*)inqbuf+8,"ARCHIVE Python ",strlen("ARCHIVE Python"))) {
		inqbuf[inqbuf[4]+5]='\0';/* terminate string */
/*		fprintf(stderr,"kernelp.c:init:Warning: Drive is not a ARCHIVE Python (%s detected), but continuing anyway.\n",inqbuf+8);*/
	}
	return &datlib_kernelp_funs;
}

int 
kernelp_create_partition(int fd,int size,int size_kind) {
	struct	mtop	xmtop;

	if (size_kind<SIZE_BYTE || size_kind>SIZE_MBYTE)
		RETURN(-EINVAL);
	if (size<=0 || size>65535)
		RETURN(-EINVAL);

	switch (size_kind) {
	case SIZE_BYTE:
		size_kind=MTSIZEBYTES;
		break;
	case SIZE_KBYTE:
		size_kind=MTSIZEKBYTES;
		break;
	case SIZE_MBYTE:
		size_kind=MTSIZEMBYTES;
		break;
	default:errno=EINVAL;
		return -1;
	}
	xmtop.mt_op=MTCRTPART;
	xmtop.mt_count=size|size_kind;
	if (-1==ioctl(fd,MTIOCTOP,&xmtop))
		return -1;
	return 0; /* SUCCESS */
}

int
kernelp_delete_partition(int fd) {
	struct	mtop	xmtop;
	xmtop.mt_op=MTDELPART;
	if (-1==ioctl(fd,MTIOCTOP,&xmtop))
		return	-1;
	return 0;
}

int
kernelp_switch_active_partition(int fd,int target) {
	struct	mtop	xmtop;

	if (target<0 || target>1)
		RETURN(-EINVAL);
	xmtop.mt_op=MTPARTTO;
	xmtop.mt_count=target;
	if (-1==ioctl(fd,MTIOCTOP,&xmtop))
		return -1;
	return 0;
}

int
kernelp_query_active_partition(int fd) {
	struct	mtop	xmtop;

	xmtop.mt_op=MTGETPART;
	if (-1==ioctl(fd,MTIOCTOP,&xmtop))
		return -1;
	return xmtop.mt_count;
}

int
kernelp_set_compression(int fd,int compress) {
	struct	mtop	xmtop;

	xmtop.mt_op=MTSCOMP;
	xmtop.mt_count=compress;
	if (-1==ioctl(fd,MTIOCTOP,&xmtop))
		return -1;
	return 0;
}

int
kernelp_set_decompression(int fd,int decompress) {
	struct	mtop	xmtop;

	xmtop.mt_op=MTSDECOMP;
	xmtop.mt_count=decompress;
	if (-1==ioctl(fd,MTIOCTOP,&xmtop))
		return -1;
	return 0;
}

int
kernelp_query_compression(int fd) {
	struct	mtop	xmtop;

	xmtop.mt_op=MTGCOMP;
	if (-1==ioctl(fd,MTIOCTOP,&xmtop))
		return -1;
	return xmtop.mt_count;
}

int
kernelp_query_decompression(int fd) {
	struct	mtop	xmtop;

	xmtop.mt_op=MTGDECOMP;
	if (-1==ioctl(fd,MTIOCTOP,&xmtop))
		return -1;
	return xmtop.mt_count;
}

int
kernelp_get_log_page(int fd,int nr,unsigned char *logpage,int logsize) {
	struct	mt_logpage	*xmtlp;

	if (logsize<=0)
		RETURN(-EINVAL);
	if (logsize>65535 || logsize<0)
		logsize=65535;

	xmtlp=(struct mt_logpage*)malloc(sizeof(struct mt_logpage)+logsize);
	xmtlp->nr=nr;
	xmtlp->len=logsize;
	if (-1==ioctl(fd,MTIOQLPAGE,xmtlp))
		return -1;
	memcpy(logpage,&(xmtlp->buf[0]),logsize);
	free(xmtlp);
	return logsize;
}

int
kernelp_set_mode_page(int fd,unsigned char *modepage,int modesize) {
	struct	mt_modepage	*xmtmp;

	if (modesize<=0)
		RETURN(-EINVAL);
	if (modesize>65535 || modesize<0)
		modesize=65535;

	xmtmp=(struct mt_modepage*)malloc(sizeof(struct mt_modepage)+modesize);
	xmtmp->len=modesize;
	memcpy(&(xmtmp->buf[0]),modepage,modesize);
	if (-1==ioctl(fd,MTIOSMPAGE,&xmtmp)) {
		free(xmtmp);
		return -1;
	}
	free(xmtmp);
	return 0;
}
int
kernelp_get_mode_page(int fd,int nr,unsigned char *modepage,int modesize) {
	struct	mt_modepage	*xmtmp;

	if (modesize<=0)
		RETURN(-EINVAL);
	if (modesize>65535 || modesize<0)
		modesize=65535;

	xmtmp=(struct mt_modepage*)malloc(sizeof(struct mt_modepage)+modesize);
	xmtmp->nr=nr;
	xmtmp->len=modesize;
	if (-1==ioctl(fd,MTIOQMPAGE,xmtmp))
		return -1;
	memcpy(modepage,&(xmtmp->buf[0]),modesize);
	free(xmtmp);
	return modesize;
}

int
kernelp_get_inquiry(int fd,unsigned char *inqbuf,int inqsize) {
	struct	mt_inquiry	*xmtinq;

	if (inqsize<=0)
		RETURN(-EINVAL);
	if (inqsize>255) 
		inqsize=255;
	xmtinq=(struct mt_inquiry*)malloc(sizeof(struct mt_inquiry)+inqsize);
	xmtinq->len=inqsize;
	if (-1==ioctl(fd,MTIOINQUIRY,xmtinq))
		return -1;
	memcpy(inqbuf,&(xmtinq->buf[0]),inqsize);
	free(xmtinq);
	return inqsize;
}
#else
 
#include <errno.h>
#include <stdio.h>
int errno;

struct datlib_functions*
datlib_kernelp_init(int fd) {
	errno=ENOENT;
	return NULL;
}
#endif
