ftp.nice.ch/pub/next/unix/scsi/scsitools_new.N.bs.tar.gz#/scsitools/select.c

This is select.c in view mode; [Download] [Up]

/*
This program loads SCSI select page codes
*/
/*
                      USE AT YOUR OUR RISK. 
      I NOT NOT BE RESPONSIBLE FOR PROBLEM CAUSED BY THIS PROGRAM.

Note that I have only tested these programs on a small number of drives (see PARAMETERS directories). BE CAREFUL, if you do not know what you are doing, then I recommend that you not use it. But it is very useful for those people that do know.
 */

#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <nextdev/scsireg.h>

static char *dev_name="/dev/sg0";    /* generic scsi interface */
#define MAX_inq_dat 64
#define MAX_mod_hdr 4
#define MAX_mod_bdf 16
#define MAX_mod_pag 64
#define MAX_mod_dat 64
#define MAX_mod_buf 256

int scsi_open(int target, int lun);
int gs_inquiry(int fd, int lun, int clen, u_char *data);
int gs_mode_select(int fd, int lun, int clen, u_char *data);
int gs_mode_sense(int fd, int lun, int ccode, int cfield, int clen, u_char *data);
int gs_request_sense(int fd, int lun);
struct MODBDF {
	u_char data[MAX_mod_bdf];
	u_char mask[MAX_mod_bdf];
	};
struct  MODPAG {
	int flag;
	u_char data[MAX_mod_dat];
	u_char mask[MAX_mod_dat];
	};
u_char inq_dat[MAX_inq_dat];
u_char mod_hdr[MAX_mod_hdr];
u_char mod_buf[MAX_mod_buf];
int    mod_buf_len;
struct MODBDF mod_bdf;
struct MODPAG mod_pag[MAX_mod_pag];

main(int argc, char *argv[])
{
    extern int optind;
    extern char *optarg;

    char c;
    int mismatch;
    FILE *infile;
    
    int fd;
    int target = -1;
    int lun = -1;

    infile = stdin;
    while ((c = getopt(argc, argv, "t:l:f:")) != EOF) {
    	switch (c) {
    	case 't':
    		target = atoi(optarg);
    		break;
    	case 'l':
    		lun = atoi(optarg);
    		break;
    	case 'f':
    		if ( (infile=fopen(optarg, "r")) == NULL) {
    			fprintf(stdout,"Error opening input file");
    			exit(0);
		}
		break;
	default:
    		fprintf(stderr,
    		    "usage: %s -t<target> [-l<lun>] [-f inputfile]\n",
    		    argv[0]);
    		exit(1);
    	}
    }
    if (target == -1) {
    	fprintf(stderr,
    		"usage: %s -t<target> [-l<lun>] [-f inputfile]\n",
    		argv[0]);
    	exit(1);
    }
    if (lun == -1) {
    	lun = 0;
    }
    get_input_data(infile);
    if ((fd = scsi_open(target, lun)) < 0) {
    	fputs("error opening scsi device\n", stderr);
    	exit(1);
    }
/*+start debug+/
    fprintf(stdout,"Target %d, Handle %d, Lun %d\n",target,fd,lun);
/-end debug-*/
    compare_inquire(fd, lun);
    compare_mode_sense(fd, lun);
    write_mode_select(fd, lun);
    exit(0);
}
get_input_data(FILE *input_file)
{
    char line[80];
    int inq_len,mod_len;
    int i,j,data,mask,page;
    int done;
    
    bzero(inq_dat,sizeof(inq_dat));
    bzero(mod_hdr,sizeof(mod_hdr));
    bzero(mod_bdf.data,sizeof(mod_bdf.data));
    bzero(mod_bdf.mask,sizeof(mod_bdf.mask));
    bzero(mod_pag,sizeof(mod_pag));
    done = 1;
    while (! feof(input_file) & done) {
        fgets(line,sizeof(line),input_file);
        line[sizeof(line)-1] = '\0';
        if (!strncmp(line,"#",1)) {
            continue;
        } else if (!strncmp(line,"-ilen",5)) {
            sscanf(&line[5],"%d",&inq_len);
            if (inq_len > MAX_inq_dat) {
                fprintf(stdout,"inq_len parameter %d greater than max %d\n"
                    ,inq_len,MAX_inq_dat);
            }
        } else if (!strncmp(line,"-idat",5)) {
    	    sscanf(&line[5],"%d %x",&i,&data);
    	    if (i > MAX_inq_dat)
    		fprintf(stdout,"inq_dat parameter %d greater than max %d\n"
    			,i,MAX_inq_dat);
    	    else inq_dat[i] = data & 0xff;
    	} else if (!strncmp(line,"-mlen",5)) {
    	    sscanf(&line[3],"%d",&mod_len);
    	    if (i > MAX_mod_dat)
    		fprintf(stdout,"mlen parameter %d greater than max %d\n"
    			,mod_len,MAX_mod_dat);
    	} else if (!strncmp(line,"-mhdr",5)) {
    	    sscanf(&line[5],"%d %x %x",&i,&data,&mask);
    	    if (i > MAX_mod_hdr)
    		fprintf(stdout,"mod_hdr parameter %d greater 	than max %d\n"
    			,i,MAX_mod_hdr);
    	    else {
	        mod_hdr[i] = data & 0xff;
	    }
	} else if (!strncmp(line,"-mbdf",5)) {
    	    sscanf(&line[5],"%d %x %x",&i,&data,&mask);
    	    if (i > MAX_mod_bdf)
    		fprintf(stdout,"mod_bdf parameter %d greater than max %d\n"
    			,i,MAX_mod_bdf);
    	    else {
	        mod_bdf.data[i] = data & 0xff;
	        mod_bdf.mask[i] = mask & 0xff;
	    }
    	} else if (!strncmp(line,"-mp",3)) {
    	    sscanf(&line[3],"%d %d %x %x",&page,&i,&data,&mask);
    	    if (page > MAX_mod_pag)
    		fprintf(stdout,"page parameter %d greater than max %d\n"
    			,page,MAX_mod_pag);
    	    else {
    	        mod_pag[page].flag = 1;
    	        if (i > MAX_mod_dat)
    		    fprintf(stdout,"mod_pag.data parameter %d, for page %d greater than max %d\n"
    			,i,page,MAX_inq_dat);
    		else {
		    mod_pag[page].data[i] = data & 0xff;
		    mod_pag[page].mask[i] = mask & 0xff;
		}
	    }
    	} else if (!strncmp(line,"end",3)) {
	    fprintf(stdout,"Encountered end statement\n");
	    done = 0;
    	} else {
	    fprintf(stdout,"Invalid input line\n");
	    fprintf(stdout,"%s",line);
	}
    }
    fprintf(stdout,"Done reading input\n");							
}
compare_inquire(int fd, int lun)
{
    u_char new_dat[MAX_inq_dat];
    char c;
    int mismatch;
   
    bzero(new_dat, sizeof(new_dat));
    if(gs_inquiry(fd, lun, sizeof(new_dat), new_dat)) {
    	fputs("error in inquiry\n", stderr);
    	close(fd);
    	exit(1);
    }
/*+start debug+/
    for (mismatch=0; mismatch<inq_dat[4]+5; mismatch++)
        fprintf(stdout," %2.2x",inq_dat[mismatch]);
    fprintf(stdout,"\n");
    for (mismatch=0; mismatch<new_dat[4]+5; mismatch++)
        fprintf(stdout," %2.2x",new_dat[mismatch]);
    fprintf(stdout,"\n");
/-end debug-*/
    inq_dat[inq_dat[4]+5] = '\0';
    new_dat[new_dat[4]+5] = '\0';
    mismatch = 0;
    if (new_dat[0] != inq_dat[0]) {
    	fprintf(stdout,"INQUIRY (byte 0)-Peripheral Device types not not match\n");
    	fprintf(stdout,"  input=%2x, disk=%2x\n",inq_dat[0], new_dat[0]);
    	mismatch = 1;
    }
    if (new_dat[1] != inq_dat[1]) {
    	fprintf(stdout,"INQUIRY (byte 1)Device type qualifiers or RMB do not match \n");
    	fprintf(stdout,"  input=%2x, disk=%2x\n",inq_dat[1], new_dat[1]);
    	mismatch = 1;
    }
    if (new_dat[2] != inq_dat[2]) {
    	fprintf(stdout," INQUIRY (byte 2)-ANSI version's do not not match\n");
    	fprintf(stdout,"  input=%2x, disk=%2x\n",inq_dat[2], new_dat[2]);
    	mismatch = 1;
    }
    if (new_dat[3] != inq_dat[3]) {
    	fprintf(stdout,"INQUIRY (byte 3)-Response Data Formats do not not match\n");
    	fprintf(stdout,"  input=%2x, disk=%2x\n",inq_dat[3], new_dat[3]);
    	mismatch = 1;
    }
    if (new_dat[4] != inq_dat[4]) {
    	fprintf(stdout,"INQUIRY (byte 4)-Additional lengths do not match\n");
    	fprintf(stdout,"  input=%2x, disk=%2x\n",inq_dat[4], new_dat[4]);
    	fprintf(stdout,"  (bytes 8-n)-Additional data\n");
    	fprintf(stdout,"  rest of input=\"%s\"\n",&inq_dat[8]);
    	fprintf(stdout,"  rest of disk =\"%s\"\n",&new_dat[8]);
    	mismatch = 1;
    }
    if (new_dat[5] != inq_dat[5]) {
    	fprintf(stdout,"INQUIRY (byte 5)-Request sense lengths do not match\n");
    	fprintf(stdout,"  input=%2x, disk=%2x\n",inq_dat[5], new_dat[5]);
    	mismatch = 1;
    }
    if (strcmp(&new_dat[8],&inq_dat[8])) {
    	fprintf(stdout,"INQUIRY (bytes 8-n)-Additional data does not match\n");
    	fprintf(stdout,"  rest of input=\"%s\"\n",&inq_dat[8]);
    	fprintf(stdout,"  rest of disk =\"%s\"\n",&new_dat[8]);
    	mismatch = 1;
    }
    if (mismatch) {
    	if (feof(stdin))
	    c = 'n';
    	else {
    	    fprintf(stdout,"Do you wish to continue? [y/n]: ");
	    gets(&c);
	}
    	if (! (c == 'y' | c == 'Y')) {
    		fprintf(stdout,"exiting due to error in SCSI INQUIRY data\n");
    		exit(1);
    	} else
    		fprintf(stdout,"continuing to reselect drive\n");
    }
}
compare_mode_sense(int fd, int lun)
{
    struct MODPAG new_dat;
    char c;
    int mismatch,change,i,j,page,old,new;
    u_char tmpmask;
/* compare header/bdf first, via SCSI MODE SENSE/PAGE 0 of current paramters (1)*/
    bzero(new_dat.data, sizeof(new_dat.data));
    bzero(new_dat.mask, sizeof(new_dat.mask));
    bzero(mod_buf, sizeof(mod_buf));
    mod_buf_len = 0;
    mod_buf[0] = 0;
    if(gs_mode_sense(fd, lun, 0, 1, sizeof(new_dat.mask), new_dat.mask)) {
    	fputs("error in MODE SENSE for header (page 0)\n", stderr);
    	close(fd);
    	exit(1);
    }
    if(gs_mode_sense(fd, lun, 0, 3, sizeof(new_dat.data), new_dat.data)) {
    	fputs("error in MODE SENSE for header (page 0)\n", stderr);
    	close(fd);
    	exit(1);
    }
/*+start debug+/
    for (mismatch=0; mismatch<new_dat.data[0]; mismatch++)
        fprintf(stdout," %2.2x",new_dat.data[mismatch]);
    fprintf(stdout,"\n");
    for (mismatch=0; mismatch<new_dat.data[0]; mismatch++)
        fprintf(stdout," %2.2x",new_dat.mask[mismatch]);
    fprintf(stdout,"\n");
/-end debug-*/
    mismatch = 0;
    change = 0;
/*+start debug+*/
    fprintf(stdout,"Compare header\n");
/*-end debug-*/
    for (i = 1; i <= 3; i++) {
        mod_buf_len++;
        mod_buf[mod_buf_len] = mod_hdr[i];
    }
    if (new_dat.data[1] != mod_hdr[1]) {
    	fprintf(stdout,"MODE SENSE (header byte 1)-Medium type does not match\n");
    	fprintf(stdout,"  input=%2x, disk=%2x\n",mod_hdr[1], new_dat.data[1]);
    	mismatch = 1;
    }
    if (new_dat.data[2] != mod_hdr[2]) {
    	fprintf(stdout,"MODE SENSE (header byte 2)-Write protect bit does not match\n");
    	fprintf(stdout,"  input=%2x, disk=%2x\n",mod_hdr[2], new_dat.data[2]);
    	mismatch = 1;
    }
    if (new_dat.data[3] != mod_hdr[3]) {
    	fprintf(stdout,"MODE SENSE (header byte 3)-Block Descriptor Length does not match\n");
    	fprintf(stdout,"  input=%2x, disk=%2x\n",mod_hdr[3], new_dat.data[3]);
    	mismatch = 1;
    } else for (i = 0; i < new_dat.data[3]; i++) {
        mod_buf_len++;
	tmpmask = mod_bdf.mask[i];
	mod_buf[mod_buf_len] = (mod_bdf.data[i]&tmpmask) | (new_dat.data[i+4]&~tmpmask);
        if ((new_dat.mask[i+4]|mod_bdf.mask[i]) != new_dat.mask[i+4]) {
    	    fprintf(stdout,"MODE SENSE (BDF byte %4.4d)-input mask not subset of disk mask\n",i);
	    fprintf(stdout," input mask=%x, disk mask=%x\n",mod_bdf.mask[i],new_dat.mask[i+4]);
    	    mismatch = 1;
	}
	if ((mod_bdf.data[i]&mod_bdf.mask[i]) != mod_bdf.data[i]) {
    	    fprintf(stdout,"MODE SENSE (BDF byte %4.4d)-input value not subset of input mask\n",i);
	    fprintf(stdout," input value=%2.2x, input mask=%2.2x\n",mod_bdf.data[i],mod_bdf.mask[i]);
    	    mismatch = 1;
	}
	if (mod_buf[mod_buf_len] != new_dat.data[i+4]) {
    	    fprintf(stdout,"MODE SENSE (BDF byte %4.4d)-disk value will be changed\n",i);
	    fprintf(stdout," old value=%2.2x, new value=%2.2x\n",new_dat.data[i+4],mod_buf[mod_buf_len]);
    	    change = 1;
	}
    }
/* compare page codes now, via SCSI MODE SENSE of current paramters (1)*/
    for (page = 0; page < MAX_mod_pag; page++) {
        if (mod_pag[page].flag != 0) {
/*+start debug+*/
	    fprintf(stdout,"Compare page %2.2d\n",page);
/*-end debug-*/
            bzero(new_dat.data, sizeof(new_dat.data));
            bzero(new_dat.mask, sizeof(new_dat.mask));
            if(gs_mode_sense(fd, lun, page, 1, sizeof(new_dat.mask), new_dat.mask)) {
    	        fprintf(stdout,"MODE SENSE error for page code %d reading masks\n",page);
    	        mismatch = 1;
            } else if(gs_mode_sense(fd, lun, page, 3, sizeof(new_dat.data), new_dat.data)) {
    	        fprintf(stdout,"MODE SENSE error for page code %d reading data\n",page);
    	        mismatch = 1;
            } else {
	        i = new_dat.data[3]+4;
	        if (new_dat.data[0]+1 == i) {
	            fprintf(stdout,"MODE SENSE (Page %2.2d)-No such page code on disk\n",page);
		    mismatch = 1;
	        } else if ((new_dat.data[i]&63) != (mod_pag[page].data[0]&63)) {
	            fprintf(stdout,"MODE SENSE (Page %2.2d,byte-0)-Page code does not match\n",page);
		    fprintf(stdout
			        ," input value=%2.2x, disk value=%2.2x\n"
			        ,mod_pag[page].data[0],new_dat.data[i]);
		    mismatch = 1;
	        } else if ((new_dat.data[i]&128) != (mod_pag[page].data[0]&128)) {
	            fprintf(stdout,"MODE SENSE (Page %2.2d,byte-0)-PS bit does not match\n",page);
		        fprintf(stdout
			        ," input value=%2.2x, disk value=%2.2x\n"
			        ,mod_pag[page].data[0],new_dat.data[i]);
		    mismatch = 1;
	        } else if (new_dat.data[i+1] != mod_pag[page].data[1]) {
	            fprintf(stdout,"MODE SENSE (Page %2.2d,byte-1)-Page length does not match\n",page);
		    fprintf(stdout
			        ," input value=%2.2x, disk value=%2.2x\n"
			        ,mod_pag[page].data[1],new_dat.data[i+1]);
		    mismatch = 1;
    	        } else for (j = 0; j < mod_pag[page].data[1]+2; j++) {
                    mod_buf_len++;
		    tmpmask = mod_pag[page].mask[j]&new_dat.mask[i+j];
	            if (j == 0) {
		        mod_buf[mod_buf_len] = mod_pag[page].data[0]&63;
			new_dat.data[i] = new_dat.data[i]&63;
		    } else {
		        mod_buf[mod_buf_len] = (mod_pag[page].data[j]&tmpmask) | (new_dat.data[i+j]&~tmpmask);
		    }
   	            if ((new_dat.mask[i+j]|mod_pag[page].mask[j]) != new_dat.mask[i+j]) {
  	  	        fprintf(stdout
			        ,"MODE SENSE (Page %2.2d byte %d)-input mask not subset of disk mask\n"
			        ,page,j);
		        fprintf(stdout
			        ," input mask=%2.2x, disk mask=%2.2x\n"
			        ,mod_pag[page].mask[j],new_dat.mask[i+j]);
    		        mismatch = 1;
		    } else if ((mod_pag[page].data[j]&mod_pag[page].mask[j]) != mod_pag[page].data[j]) {
    	    	        fprintf(stdout,
			        "MODE SENSE (Page %2.2d byte %d)-input value not subset of input mask\n"
			        ,page,j);
	    	        fprintf(stdout,
			        " input value=%2.2x, input mask=%2.2x\n"
			        ,mod_pag[page].data[j],mod_pag[page].mask[j]);
    	    		mismatch = 1;
		    } else if (mod_buf[mod_buf_len] != new_dat.data[i+j]) {
	    	        fprintf(stdout,"MODE SENSE (Page %2.2d byte %d)-disk value will be changed\n",page,j);
		        fprintf(stdout," old value=%2.2x, new value=%2.2x\n",new_dat.data[i+j],mod_buf[mod_buf_len]);
	    	        change = 1;
		    }
	        }
	    }
	}
    }
    if (mismatch) {
    	if (feof(stdin))
	    c = 'n';
    	else {
    	    fprintf(stdout,"Do you wish to continue? [y/n]: ");
            gets(&c);
	}
    	if (! (c == 'y' | c == 'Y')) {
    	    fprintf(stdout,"exiting due to error in SCSI SENSE MODE data\n");
    	    exit(1);
    	} else
    	    fprintf(stdout,"continuing to SELECT MODE drive\n");
    }
}
write_mode_select(int fd, int lun)
{
    char c;
    int i;
    mod_buf[0] = 0;
    mod_buf_len++;
    fprintf(stdout,"mod buffer output\n");
    for (i = 0; i < mod_buf_len; i++) {
        fprintf(stdout,"%2.2x %2.2x\n",i,mod_buf[i]);
    }
    if (feof(stdin))
	c = 'n';
    else {
    	fprintf(stdout,"Do you wish to continue with the scsi mode select of drive? [y/n]: ");
        gets(&c);
    }
    if (! (c == 'y' | c == 'Y')) {
    	fprintf(stdout,"exiting without doing SCSI SELECT MODE\n");
    	exit(1);
    } else {
    	fprintf(stdout,"continuing with doing SCSI SELECT MODE\n");
        if(gs_mode_select(fd, lun, mod_buf_len, mod_buf)) {
            fputs("error in mode select\n", stderr);
            close(fd);
            exit(1);
	} else {
	    fputs("exiting SCSI SELECT MODE successfully completed\n",stderr);
	}
    }
}   
int scsi_open(int target, int lun)
{
    struct scsi_adr sa;
    int fd;

    if ((fd = open(dev_name, O_RDWR)) < 0) {
    	fprintf(stderr,"\nCould not open %s\n",dev_name);
    	return(-1);
    }

    sa.sa_target = target;
    sa.sa_lun = lun;
    if (ioctl(fd,SGIOCSTL,&sa) < 0) {
    	fprintf(stderr,"Error setting target %d lun %d\n",target,lun);
    	close(fd);
    	return(-1);
    }

    if(gs_request_sense(fd, lun)) {		/* clear unit attention */
    	close(fd);
    	return(-1);
    }
    return(fd);
}

int gs_inquiry(int fd, int lun, int clen, u_char *data)
{
	struct scsi_req sr;
	struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6;

	bzero((char *)&sr, sizeof(sr));
	cdbp->c6_opcode = C6OP_INQUIRY;
	cdbp->c6_lun    = lun;
	cdbp->c6_lba	= 0;
	cdbp->c6_len	= clen;
	sr.sr_dma_dir	= SR_DMA_RD;
	sr.sr_addr	= (caddr_t)data;
	sr.sr_dma_max	= clen;
	sr.sr_ioto	= 10;
	return(do_ioc(fd, &sr));
}

int gs_mode_select(int fd, int lun, int clen, u_char *ddat)
{
    struct scsi_req sr;
    struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6;

    bzero((char *)&sr, sizeof(sr));
    cdbp->c6_opcode = C6OP_MODESELECT;
    cdbp->c6_lun    = lun;
    cdbp->c6_lba	= 0x110000 ; /* use pf=1 & sp=1 to save parameters */
/*    cdbp->c6_lba	= (( (pf&1) << 21) | (sp&1) << 17);*/
    cdbp->c6_len	= clen;
    sr.sr_dma_dir	= SR_DMA_WR;
    sr.sr_addr	= (caddr_t)ddat;
    sr.sr_dma_max	= clen;
    sr.sr_ioto	= 10;
    return(do_ioc(fd, &sr));
}


int gs_mode_sense(int fd, int lun, int ccode, int cfield, int clen, u_char *data)
{
	struct scsi_req sr;
	struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6;

	bzero((char *)&sr, sizeof(sr));
	cdbp->c6_opcode = C6OP_MODESENSE;
	cdbp->c6_lun    = lun;
	cdbp->c6_lba	= ((cfield << 14) & 0xc000) | ((ccode << 8) & 0x3f00);
	cdbp->c6_len	= clen;
	sr.sr_dma_dir	= SR_DMA_RD;
	sr.sr_addr	= (caddr_t)data;
	sr.sr_dma_max	= clen;
	sr.sr_ioto	= 10;
	return(do_ioc(fd, &sr));
}


int do_ioc(int fd, struct scsi_req *sr)
{
    if (ioctl(fd, SGIOCREQ, sr) < 0) {
    	perror("ioctl(SGIOCREQ)");
    	return(-1);
    }
    if(sr->sr_io_status) {
    	fprintf(stderr,"sr_io_status = 0x%02X\n",sr->sr_io_status);
    	if(sr->sr_io_status == SR_IOST_CHKSV) {
    		fprintf(stderr,
    			"sense key = 0x%02X, sense code = 0x%02X\n",
    			sr->sr_esense.er_sensekey,
    			sr->sr_esense.er_addsensecode);
    	}
    	fprintf(stderr,"SCSI status = 0x%02X\n", sr->sr_scsi_status);
    	return(-1);
    }
    return(0);
}

int gs_request_sense(int fd, int lun)
{
    struct scsi_req sr;
    struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6;
    u_char sbuf[128];

    bzero((char *)&sr, sizeof(sr));
    cdbp->c6_opcode = C6OP_REQSENSE;
    cdbp->c6_lun    = lun;
    cdbp->c6_len	= 18;
    sr.sr_dma_dir	= SR_DMA_RD;
    sr.sr_addr	= (caddr_t)sbuf;
    sr.sr_dma_max	= 128;
    sr.sr_ioto	= 10;
    return(do_ioc(fd, &sr));
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.