
#ident "cda: @(#)scsi.c	1.6 -- 08/13/93" 
/************************************************************
*											*
*	Copyright (C) 1990 Analogic/CDA							*
*											*
*	scsi_io.c	low-level block-oriented SCSI i/o functions	*
*				for SunOS 4.0.0						*
*											*
*	09Nov89 (V. Michael Oratovsky)							*
*															*
+---------------------------------------------------------------------------+
	Modification History
+---------------------------------------------------------------------------+
When:		Who:		What:
+---------------------------------------------------------------------------+

08/04/93	imk		Added call scsi_read_blocks_silently
05/07/93	imk		Adapted for resource spooler
04/24/93	hdc		Modified for SunOS 5.1
11/09/89	vmo		Initial version
+---------------------------------------------------------------------------+
*****************************************************************************/

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/buf.h>

#ifndef SOLARIS

#include <sys/file.h>
#include <sun/dkio.h>
#include <sundev/sereg.h>
#include <sundev/scsi.h>

#else

#include <sys/scsi/impl/uscsi.h>
#include <sys/scsi/scsi.h>

#endif

#define DASM_BLOCK_SIZE	512
#define MAX_NUM_BLOCKS	0x7F	/* limited by Sun-3E SCSI controller */

static silently=0;

/*	+---------------------------+
*	|	Open raw SCSI device	|
*	+---------------------------+
*
*	Arguments:
*
*	devname -	string containing the name of character-special device
*				which corresponds to the desired SCSI unit - should
*				represent the slice of the entire disk device, such
*				as "/dev/rsd2c".
*
*	Return Value:
*
*	An integer file descriptor is returned on success, -1 otherwise.
*
**********************************************************************/


int scsi_open( devname )
char *devname ;
{
int fd ;

	if ((fd = open( devname, O_RDWR | O_NDELAY )) == -1)
	{
		/* rs_put_time(); */
		if(!silently)
		{
			perror("open");
			fprintf(stderr,"scsi_open:  could not open %s - errno %d\n",
					devname, errno);
		}
		return(-1);
	}
	else return( fd );
}

int scsi_open_silently(devname)
char *devname ;
{
	int fd ;
	silently=1;
	fd=scsi_open(devname);
	silently=0;
	return(fd);
}

/*	+---------------------------+
*	|	Close raw SCSI device	|
*	+---------------------------+
*
*	Arguments:
*
*	fd - file descriptor returned by scsi_open()
*
*	Return value:
*
*	0 on success, -1 otherwise.
*
************************************************/

int scsi_close( fd )
int fd ;
{
	if (close(fd) == -1)
	{
		/* rs_put_time(); */
		perror("close");
		fprintf(stderr,"scsi_close:  could not close - errno %d\n",errno);
		return( -1 );
	}
	else return( 0 );
}


/*	+-------------------------------------------------------+
*	|	Read a specified number of blocks from SCSI device	|
*	+-------------------------------------------------------+
*
*	Arguments:
*
*	fd				file descriptor returned by scsi_open()
*	buf 			address of buffer where to place incoming data
*	starting_block 	starting logical SCSI block number
*	num_blocks 		number of logical SCSI blocks to read
*
*	Return value:
*
*	0 on success, -1 otherwise.
*
******************************************************************/

int scsi_read_blocks( fd, buf, starting_block, num_blocks )
int fd ;
char *buf ;
int starting_block;
int num_blocks;
{

	if ((starting_block < 0) || (num_blocks < 1) || (num_blocks > MAX_NUM_BLOCKS))
	{
		/* rs_put_time(); */
		fprintf(stderr,"scsi_read_blocks:  bad function arguments\n");
		return(-1);
	}

	{
#ifndef SOLARIS
	struct dk_cmd scsi_command ;
	scsi_command.dkc_flags = DK_SILENT | DK_DIAGNOSE | DK_ISOLATE ;
	scsi_command.dkc_blkno = starting_block ;
	scsi_command.dkc_secnt = num_blocks ;
	scsi_command.dkc_bufaddr = buf ;
	scsi_command.dkc_buflen = num_blocks * DASM_BLOCK_SIZE ;
	scsi_command.dkc_cmd = SC_READ ;

	if (ioctl( fd, DKIOCSCMD, & scsi_command ) == -1)
	{
		/* rs_put_time(); */
		if(!silently)
		{
			perror("ioctl");
			fprintf(stderr,"scsi_read_blocks:  could not read - errno %d\n", errno);
		}
		return( -1 );
	}
	else return( 0 );
#else
	unsigned char cdb[6];
	struct uscsi_cmd ucmd;	
        cdb[0]=0x8; /* read(6) code */
        cdb[1]=0;
        cdb[2]=(starting_block&0xff00)>>8;
        cdb[3]=starting_block&0xff;
        cdb[4]=num_blocks;
        cdb[5]=0;
        ucmd.uscsi_flags=USCSI_READ|0x1;
        ucmd.uscsi_timeout=35;
        ucmd.uscsi_cdb=(caddr_t)cdb;
        ucmd.uscsi_bufaddr=buf;
        ucmd.uscsi_buflen=num_blocks*512;
        ucmd.uscsi_resid=0;
        ucmd.uscsi_cdblen=sizeof(cdb);
        if (ioctl(fd,0x4c9, &ucmd) == -1)
        {
			if(!silently)
			{
				perror("ioctl_read");
				fprintf(stderr,"scsi_read_blocks:  could not read - errno %d\n", errno);
			}
			return( -1 );
        }
        else return( 0 );

#endif
	}
}

int scsi_read_blocks_silently( fd, buf, starting_block, num_blocks )
int fd ;
char *buf ;
int starting_block;
int num_blocks;
{
	int err;
	silently=1;
	err=scsi_read_blocks( fd, buf, starting_block, num_blocks );
	silently=0;
	return(err);
}

/*	+-------------------------------------------------------+
*	|	Write a specified number of blocks to SCSI device	|
*	+-------------------------------------------------------+
*
*	Arguments:
*
*	fd				file descriptor returned by scsi_open()
*	buf 			address of buffer of data to write
*	starting_block 	starting logical SCSI block number
*	num_blocks 		number of logical SCSI blocks to write
*
*	Return value:
*
*	0 on success, -1 otherwise.
*
******************************************************************/

int scsi_write_blocks( fd, buf, starting_block, num_blocks )
int fd ;
char *buf ;
int starting_block;
int num_blocks;
{

	if ((starting_block < 0) || (num_blocks < 1) || (num_blocks > MAX_NUM_BLOCKS))
	{
		/* rs_put_time(); */
		fprintf(stderr,"scsi_write_blocks:  bad function arguments\n");
		return(-1);
	}

	{
#ifndef SOLARIS
	struct dk_cmd scsi_command ;
	scsi_command.dkc_flags = DK_SILENT | DK_DIAGNOSE | DK_ISOLATE ;
	scsi_command.dkc_blkno = starting_block ;
	scsi_command.dkc_secnt = num_blocks ;
	scsi_command.dkc_bufaddr = buf ;
	scsi_command.dkc_buflen = num_blocks * DASM_BLOCK_SIZE ;
	scsi_command.dkc_cmd = SC_WRITE ;

	if (ioctl( fd, DKIOCSCMD, & scsi_command ) == -1)
	{
		/* rs_put_time(); */
		perror("write_ioctl");
		fprintf(stderr,"scsi_write_blocks:  could not write - errno %d\n",
				errno);
		return( -1 );
	}
	return( 0 );
#else
	unsigned char cdb[6];
	struct uscsi_cmd ucmd;
        cdb[0]=0xA; /* write(6) code */
        cdb[1]=0;
        cdb[2]=(starting_block&0xff00)>>8;
        cdb[3]=starting_block&0xff;
        cdb[4]=num_blocks;
        cdb[5]=0;
        ucmd.uscsi_flags=1;
        ucmd.uscsi_timeout=0;
        ucmd.uscsi_cdb=(caddr_t)cdb;
        ucmd.uscsi_bufaddr=buf;
        ucmd.uscsi_buflen=num_blocks*512;
        ucmd.uscsi_resid=0;
        ucmd.uscsi_cdblen=sizeof(cdb);
        if (ioctl(fd,0x4C9, &ucmd) == -1)
        {
		/* rs_put_time(); */
                perror("ioctl_write");
                fprintf(stderr,"scsi_write_blocks:  could not write - errno %d\n", errno);
                return( -1 );
        }
                return( 0 );
#endif
	}
}
