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.