ftp.nice.ch/pub/next/unix/archiver/TarChive.0.71.N.bsd.tar.gz#/TarChive/mtsense.c

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


/*
 How to make the MT-02 SCSI tape drive useable ...

	*****This post has no warranty*****

NeXT Answers hardware.762 gives details of how to set the NeXT st
driver into fixed block mode, allowing it to work with QIC style tape
drives.  This has enabled my tape drive to work, but my drive has
performed badly, often bombing out with write errors. I knew it wasn't
the drive or the media because they both work when connected to a sun,
and the tape works in other drives. The clue came from the NeXT
Console where I found the following message.

st: cmd = 0xa sr_io_status = 2H
    Sense key = 0x1  Sense Code = 0x0

A sense key of 0x1 indicates a recoverable error, ie one that the tape
drive fixed, e.g. a write failed but was sucessful on a subsequent
retry (provided the max retry limit wasn't reached). Some tape drivers
report the number of recoverable errors, and on some machines "mt
status" will report the number.

Anyway it turns out that the MT-02 tape controller has a bit which
controls how it handles soft errors. The default case when connected
to a NeXT is to for the tape drive to issue a CHECK CONDITION status
code after it executes a command if a recoverable error occured. The
NeXT st driver seems to handle this as if it were a real error and
bombs out at this point. The other mode is to have the drive
accumulate the number of soft errors, so that they can be collected
later by the REQUEST SENSE command.

The following tape utility adds to the code in NA.762 and gives the
option of setting the SEC bit. It also allows the user to set the
driver back to variable block mode, and execute the MODE SENSE and
REQUEST SENSE scsi commands.



Mark Andrews
abekas!mark@pyramid.com		<non-NeXT mail>
abekas!cookie!mark@pyramid.com	<NeXT mail ok>

*/


/* */
/* NeXT scsi tape driver utility */
/* Mark Andrews 1992 */
/* This Code is Supplied as is with NO WARRANTY of any kind */
/* No resposibility can or will be accepted for any damage that using */
/* this program may cause */
/* It has only been tested on a SCSI tape drive with an MT-02 tape controller */
/* Note the SEC bit is part of the VENDOR unique stuff and may or may not */
/* work with other drives.  In particular it doesn't work with Exabyte. */
/* The MTIOCFIXBLK code is from NA.562 */
/* The REQUEST SENSE code is from a posting by louie@sayshell.umd.edu 3/10/92 */
/* */

#include <stdio.h>
#include <libc.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/mtio.h>
#include <nextdev/scsireg.h>

#define	SEC	0x1
#define	QUIET	0
#define	VERBOSE	1

char *tape_name;
int tape;
struct modesel_parms msp;
struct scsi_req sr;

main(argc,argv)
int argc;
char *argv[];
{
  char c;
  int sf,sv,ms,rs,sc;

  sf=sv=ms=rs=sc=0;
  
  


/*		strcpy(tape_name,"/dev/rst0");*/
tape_name=getenv("TAPE");
if  (tape_name == 0) tape_name = "/dev/nrxt0" ;



  while((c=getopt(argc,argv,"hvrmsf:b:")) !=EOF)
    {
    if(c=='f') strcpy(tape_name,optarg);/* set device from cmd lineman */
    if(c=='b') if(optarg!=NULL)sf=atoi(optarg);else sf=512;	/* set to fixed block mode */
    if(c=='v') sv=1;		/* set to variable block mode */
    if(c=='m') ms=1;		/* mode sense */
    if(c=='r') rs=1;		/* request sense */
    if(c=='s') sc=1;		/* set the soft error bit */
    if(c=='h') 			/* print usage */
      fprintf(stderr,"Usage: %s -hvrmsnf [block size]\n%s%s%s%s%s%s%s",argv[0],
    "\t-h   : print usage,\n",
	"\t-b # : set fixed block mode with size #,\n",
	"\t-v   : set variable block mode,\n",
	"\t-m   : do a mode sense command and report the results,\n",
	"\t-r   : do a request sense command and report the results,\n",	        	
	"\t-s   : set the soft error bit, (not valid on exabyte)\n",
	"\t-f   : use device named.\n");
    }

printf("Using tape drive: %s\n",tape_name);

  /* open /dev/rxt0 */
  if((tape=open(tape_name,O_RDWR,777))==0)
    {
    fprintf(stderr,"Unable to open %s\n",*tape_name);
    exit(1);
    }

  if(sv)
    {
    if(!sf)
      set_var_blk();
    else
      {
      fprintf(stderr,"Can't set to both fixed and variable block mode\n");
      problem();
      }
    }
  if(sf) set_fix_blk(sf);
  if(ms) mode_sense(VERBOSE);
  if(rs) request_sense();
  if(sc) set_sec();

  /* close tape */
  close (tape);
  exit(0);
}

problem()
{
  /* close tape */
  close (tape);
  exit(-1);
}

mode_sense(verbose)
int verbose;
{
  /* do a mode sense ioctl */
  msp.msp_bcount=17; /*  think this is correct */
  if(ioctl(tape,MTIOCMODSEN,&msp))
    {
      perror("mode sense ioctl failed\n");
      exit(1); 
    }
  if(!verbose)
    return;
  /* print out the returned data */
  fprintf(stdout,"mode sense data length  = %d\n",(int)msp.msp_data.msd_header.msh_sd_length_0);
  fprintf(stdout,"media type              = %d\n",(int)msp.msp_data.msd_header.msh_med_type);
  if(msp.msp_data.msd_header.msh_wp)
    fprintf(stdout,"tape is                 = write protected\n");
  else
    fprintf(stdout,"tape is                 = writeable\n");
   
  fprintf(stdout,"buffered mode           = %d\n",(int)msp.msp_data.msd_header.msh_bufmode);
  fprintf(stdout,"speed                   = %d\n",(int)msp.msp_data.msd_header.msh_speed);
  fprintf(stdout,"block descriptor length = %d\n",(int)msp.msp_data.msd_header.msh_bd_length);
  fprintf(stdout,"density code            = %d\n",(int)msp.msp_data.msd_blockdescript.msbd_density);
  fprintf(stdout,"number of blocks        = %d\n",(int)msp.msp_data.msd_blockdescript.msbd_numblocks);
  fprintf(stdout,"block length            = %d\n",(int)msp.msp_data.msd_blockdescript.msbd_blocklength);
  fprintf(stdout,"vendor unique byte[0]   = %d\n",(int)msp.msp_data.msd_vudata[0]);
  fprintf(stdout,"vendor unique byte[1]   = %d\n",(int)msp.msp_data.msd_vudata[1]);
  fprintf(stdout,"vendor unique byte[2]   = %d\n",(int)msp.msp_data.msd_vudata[2]);
  fprintf(stdout,"vendor unique byte[3]   = %d\n",(int)msp.msp_data.msd_vudata[3]);
  fprintf(stdout,"vendor unique byte[4]   = %d\n",(int)msp.msp_data.msd_vudata[4]);
}

mode_slct()
{
  /* this routine assumes that the msp structure has already been */
  /* initialized, a mode_sense is the best way to do this */

  /* do a mode select ioctl */
  if(ioctl(tape,MTIOCMODSEL,&msp))
    {
      perror("mode select ioctl failed\n");
      return 1; 
    }
}

set_sec()
{

  mode_sense(QUIET);				/* do a mode sense */
  msp.msp_data.msd_vudata[0]|=SEC;	/* set the SEC bit */
  fprintf(stdout,"setting no report for soft errors\n");
  mode_slct();				/* do a mode select */
}

set_fix_blk(blocksize)
int blocksize;
{

  if(ioctl(tape,MTIOCFIXBLK,&blocksize))
    {
    perror("fixed block ioctl failed\n");
    return 1; 
    }
/* The following section added to set the drive to be the same as */
/* the driver.  sgb */
  msp.msp_data.msd_blockdescript.msbd_blocklength=blocksize;
  fprintf(stdout,"tape is set for fixed blocks of %i\n",blocksize);

  mode_slct();
}


set_var_blk()
{

  if(ioctl(tape,MTIOCVARBLK))
    {
    perror("variable block ioctl failed\n");
    return 1; 
    }
/* The following section added to set the drive to be the same as */
/* the driver.  sgb */
 fprintf(stdout,"tape is set for variable blocks\n");
 msp.msp_data.msd_blockdescript.msbd_blocklength=0;
 mode_slct();

}

request_sense()
{
  /* set up sr */
  bzero(&sr, sizeof(sr));
  sr.sr_dma_dir=SR_DMA_RD;
  sr.sr_dma_max=sizeof(sr.sr_esense);
  sr.sr_addr=(caddr_t)&sr.sr_esense;
  sr.sr_ioto=2;
  sr.sr_cdb.cdb_c6.c6_opcode=C6OP_REQSENSE;
  sr.sr_cdb.cdb_c6.c6_len=sizeof(sr.sr_esense);

  /* execute the request sense */
  if(ioctl(tape,MTIOCSRQ,&sr))
    {
    perror("request sense ioctl failed\n");
    return 1; 
    }

  /* print the answers */
  fprintf(stdout,"io status               = %d\n",(int)sr.sr_io_status);
  fprintf(stdout,"scsi status             = %d\n",(int)sr.sr_scsi_status);
  fprintf(stdout,"bytes dma'd             = %d\n",(int)sr.sr_dma_xfr);
  fprintf(stdout,"sense info bytes are    =");
  if(sr.sr_esense.er_ibvalid)
    fprintf(stdout,"valid\n");
  else
    fprintf(stdout,"not valid\n");
  fprintf(stdout,"error class             = %d\n",(int)sr.sr_esense.er_class);
  fprintf(stdout,"error code              = %d\n",(int)sr.sr_esense.er_code);
  fprintf(stdout,"segment number          = %d\n",(int)sr.sr_esense.er_segment);
  fprintf(stdout,"file mark found         = ");
  if(sr.sr_esense.er_filemark)
    fprintf(stdout,"yes\n");
  else
    fprintf(stdout,"no\n");
  fprintf(stdout,"end of medium           = ");
  if(sr.sr_esense.er_endofmedium)
    fprintf(stdout,"yes\n");
  else
    fprintf(stdout,"no\n");
  fprintf(stdout,"incorect length         = ");
  if(sr.sr_esense.er_badlen)
    fprintf(stdout,"yes\n");
  else
    fprintf(stdout,"no\n");
  fprintf(stdout,"sense key               = %d\n",(int)sr.sr_esense.er_sensekey);
  fprintf(stdout,"residue length          = %d\n",(int)sr.sr_esense.er_info+((int)sr.sr_esense.er_infomsb<<24));
  fprintf(stdout,"additional sense length = %d\n",(int)sr.sr_esense.er_addsenselen);
  fprintf(stdout,"additional sense code   = %d\n",(int)sr.sr_esense.er_addsensecode);
  fprintf(stdout,"sense code qualifier    = %d\n",(int)sr.sr_esense.er_qualifier);
  fprintf(stdout,"status byte 13          = %d\n",(int)sr.sr_esense.er_stat_13);
  fprintf(stdout,"status byte 14          = %d\n",(int)sr.sr_esense.er_stat_14);
  fprintf(stdout,"status byte 15          = %d\n",(int)sr.sr_esense.er_stat_15);
  fprintf(stdout,"recoverable errors      = %d\n",(int)sr.sr_esense.er_err_count);
}

/*			Additional Credits:*/
/*	 nigelm@ohm.york.ac.uk (Nigel Metheringham)*/
/*	 	bug in -f setting*/
/*		consisting in printing what drive is being used.*/

	

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