/*        Turning off sequential loading on a TZ88 */
/*	Considering that I managed to change two different parameters
	using the same code, I'm reasonably certain that the program
	is correct.  I'll include a copy here for reference though
	since it isn't that big.  Many of the VMS Storage Management
	products need to turn off sequential loading, so they're
	probably going to be doing this one way or another.
*/
/*
 *	Author:  Alan Rollow, StorageWorks Software, Digital Equipment Corp.
 *	File:	 %M%
 *	Date:	 %G%
 *	Version: %I%
 *
 *	%M% - Send a Mode Select via the rzdisk interface to
 *	change EEPROM parameters.
 */
#ifndef	lint
static	char	SccsId[] = "%W% (scsi) %G%" ;
#endif

#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

#include <io/common/iotypes.h>

#include <io/cam/rzdisk.h>

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>

#define SCSI_EEPROM     (0x3e)

typedef struct {
	u_char	sense_key ;
	u_char	asc ;
	u_char	ascq ;
} scsi_status_t ;

request_sense(int fd, char *device, scsi_status_t *sp)
{
        struct extended_sense sense ;

        memset((void *)sp, 0, sizeof(scsi_status_t)) ;

        if( ioctl(fd, SCSI_GET_SENSE, &sense) == -1 )
                fprintf(stderr, "Request Sense Failed on %s: %s.\n",
                        device, strerror(errno)) ;
        else {
                sp->sense_key = sense.snskey ;
                sp->asc       = sense.asc ;
                sp->ascq      = sense.rb2 ;
        }
}

char *mode_select_failed = "Mode Select failed on %s: %s (%d,%x,%x)\n" ;

mode_select(int fd, char *option, char *value, char *device)
{
	scsi_status_t			status ;
	struct mode_sel_sns_params	params ;
	struct mode_sel_sns_data	data ;
	struct page_header		*hp ;

	/*
	 *	Clear these out.
	 */
	memset((void *)&params, 0, sizeof(params)) ;
	memset((void *)&data,   0, sizeof(data)) ;

	/*
	 *	Set up the I/O control data.
	 */
	params.msp_addr   = (caddr_t)&data ;	/* Address of data (pages) */
        params.msp_pgcode = SCSI_EEPROM ;	/* The pages to send/get   */
        params.msp_pgctrl = SAVED_VALUES ;	/* The values to send/get  */

	/*
	 *	First, do the real data, since we need the length for the
	 *	header.
	 */
	sprintf(data.ms_pages + 2, "%s %s", option, value) ;

	/*
	 *	Then the page header.
	 */
	hp = (struct page_header *)data.ms_pages ;

	hp->pgcode   = SCSI_EEPROM ;
	hp->ps       = 0 ;
	hp->pglength = strlen(data.ms_pages + 2) ;

	printf("Data:   \"%s\", Length: %d\n", data.ms_pages + 2,
		hp->pglength) ;

	/*
	 *	Even though we don't use it, set the block descriptor
	 *	length.
	 */
	data.ms_hdr.blk_des_len = 8 ;

	/*
	 *	The parameter list is the mode_sel_sns_header +
	 *	block_descriptor + 2 + pglength.
	 */
        params.msp_length = sizeof(struct mode_sel_sns_header) +
			    sizeof(struct block_descriptor) +
			    hp->pglength + 2 ;

	if( ioctl(fd, SCSI_MODE_SELECT, &params) == -1 ) {
		request_sense(fd, device, &status) ;

		fprintf(stderr, mode_select_failed, device, strerror(errno),
			status.sense_key, status.asc, status.ascq) ;
	}
}

main(int argc, char *argv[])
{
	int	bus, target, lun ;
	int	fd ;
	char	*device ;
	char	*parameter ;
	char	*value ;

	if( argc < 4 ) {
		fprintf(stderr, "usage: %s special parameter value\n",
			argv[0]) ;
		exit(-1) ;
	}
	else {
		device    = argv[1] ;
		parameter = argv[2] ;
		value     = argv[3] ;
	}

	if((fd = open(device, O_RDWR)) == -1 ) {
		fprintf(stderr, "Can't open %s: %s.\n", device,
			strerror(errno)) ;

		exit(errno) ;
	}

	mode_select(fd, parameter, value, device) ;

	if( close(fd) == -1 )
		fprintf(stderr, "Can't close %s: %s.\n", device,
			strerror(errno)) ;

	return 0 ;
}
