ftp.nice.ch/pub/next/unix/disk/reasb.s.tar.gz#/reasb/reasb.c

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

/*	Copyright (c) 1991 NeXT Computer, Inc.  All rights reserved. 
 *
 * reasb - reassign logical SCSI block.
 */
 
#include <sys/types.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <nextdev/scsireg.h>
#include <errno.h>
#include <fcntl.h>

/* 
 * reassign block command data format
 */
 
struct rb_defect_list {		/* for one defect only */
	u_short rdl_spare;
	u_short rdl_length;	/* will always be 4 */
	u_int   rdl_bad_block;	/* logical block to be reassigned */
};

#define RDL_LENGTH		4	/* for rdl_length */
#define RDL_DMA_LENGTH		8	/* DMA length */
#define RECOVER_ATTEMPTS	20	/* # of times to read bad sector */
/*
 * values for 'silent' argument for do_ioc()
 */
#define SILENT_FALSE	0
#define SILENT_TRUE	1

int 	saved_sect_valid=0;
u_char	saved_sect[DEV_BSIZE];
int 	fd;
int 	recover_flag=0;
u_int 	bad_block;		/* to be reassigned */

main(int argc, char **argv) {

	int arg;
	struct scsi_req sr;	
	struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6;
	
	if(argc<3)
		usage(argv);
	bad_block = atoi(argv[2]);
	if(bad_block < 0)
		usage(argv);
	for(arg=3; arg<argc; arg++) {
		if(argv[arg][1] == 'r')
			recover_flag++;
	}
	if ((fd = open (argv[1], O_RDWR)) <= 0) {
		printf("\nCould not open %s\n",argv[1]);
		perror("open()");
		exit(-1);
	}
	
	/*
	 * request sense - just to be clean
	 */
	if(do_request_sense(fd))
		exit(1);
	
	if(recover_flag) {
		/* 
		 * try to read the sector we want.
		 */
		int attempt;
		u_char inch;
		
		printf("...Trying to recover block %d(d)\n",bad_block);
		for(attempt=0; attempt<RECOVER_ATTEMPTS; attempt++) {
		    if(do_read(fd, bad_block, 1, saved_sect, 
		    		SILENT_TRUE) == 0) {
			/* ah hah! */
			printf("...block %d(d) recovered after %d attempts\n",
			    bad_block, attempt+1);
			saved_sect_valid++;
			break;
		    }
		}
		if(!saved_sect_valid) {
			printf("...Could not recover block %d(d) after %d "
				"attempts.\n", bad_block,attempt);
			printf("Reassign anyway (y/anything)? ");
			inch = getchar();
			if(inch != 'y')
				exit(1);
		}
	} /* recovering bad block */
	
	printf("...Reassigning block %d(d)\n",bad_block);
	if(do_reassign(fd,bad_block))	/* do it */
		exit(1);
	printf("...Block %d(d) reassigned\n",bad_block);
	if(saved_sect_valid) {
		/*
		 * OK, restore the block's data to the new location 
		 */
		 if(do_write(fd, bad_block, 1, saved_sect, SILENT_FALSE)) {
		 	printf("***COULD NOT RESTORE DATA TO BLOCK %d(d)\n",
				bad_block);
			exit(1);
		 }
		printf("...Block %d(d) data restored\n",bad_block);
	}
	exit(0);
	
} /* main() */

usage(char **argv) {
	printf("\nusage: %s raw_device SCSI_block_number [-r]\n", argv[0]);
	exit(1);
}

/*	
 *	standard I/O routines
 */
 
do_request_sense(int fd) {

	struct scsi_req sr;	
	struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6;
	int rtn;
	u_char sbuf[0x40];
	
	cdb_clr(cdbp);
	cdbp->c6_opcode = C6OP_REQSENSE;
	cdbp->c6_len	= 0x40;
	sr.sr_dma_dir	= SR_DMA_RD;
	sr.sr_addr	= (caddr_t)sbuf;
	sr.sr_dma_max	= 0x40;
	sr.sr_ioto	= 10;
	rtn = do_ioc(fd, &sr, SILENT_FALSE);
	if(rtn)
		printf("\n***REQUEST SENSE COMMAND FAILED\n");
	return(rtn);

} /* do_request_sense() */

do_read(int fd, int lba, int block_count, u_char *bp, int silent) {

	/* read block_count blocks starting at lba. Data goes to *bp. */
	
	struct scsi_req sr;	
	struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6;
	int rtn;
	
	cdb_clr(cdbp);
	cdbp->c6_opcode = C6OP_READ;
	cdbp->c6_lun    = 0;
	cdbp->c6_lba	= lba;
	cdbp->c6_len	= block_count;
	sr.sr_dma_dir	= SR_DMA_RD;
	sr.sr_addr	= (char *)bp;
	sr.sr_dma_max	= block_count * DEV_BSIZE;
	sr.sr_ioto	= 10;
	rtn = do_ioc(fd, &sr, silent);
	if(rtn && !silent)
		printf("\n***READ COMMAND FAILED\n");
	return(rtn);

} /* gs_read() */

do_write(int fd, int lba, int block_count, u_char *bp) {

	/* write block_count blocks starting at lba. Data comes from *bp. */

	struct scsi_req sr;	
	struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6;
	int rtn;
	
	cdb_clr(cdbp);
	cdbp->c6_opcode = C6OP_WRITE;
	cdbp->c6_lun    = 0;
	cdbp->c6_lba	= lba;
	cdbp->c6_len	= block_count;
	sr.sr_dma_dir	= SR_DMA_WR;
	sr.sr_addr	= (char *)bp;
	sr.sr_dma_max	= block_count * DEV_BSIZE;
	sr.sr_ioto	= 10;
	rtn = do_ioc(fd, &sr, SILENT_FALSE);
	if(rtn)
		printf("\n***WRITE COMMAND FAILED\n");
	return(rtn);

} /* gs_write() */

do_reassign(int fd, u_int bad_block) {

	struct scsi_req sr;	
	struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6;
	struct rb_defect_list rdl, *rdlp;
	int rtn;
	
	rdlp = &rdl;
	cdb_clr(cdbp);
	cdbp->c6_opcode = C6OP_REASSIGNBLK;
	sr.sr_dma_dir	= SR_DMA_WR;
	sr.sr_addr	= (caddr_t)rdlp;
	sr.sr_dma_max	= RDL_DMA_LENGTH;
	sr.sr_ioto	= 100;
	/*
	 * set up the defect list 
	 */
	rdlp->rdl_spare     = 0;
	rdlp->rdl_length    = RDL_LENGTH;
	rdlp->rdl_bad_block = bad_block;
	rtn = do_ioc(fd, &sr, SILENT_FALSE);
	if(rtn)
		printf("\n***REASSIGN BLOCK COMMAND FAILED\n");
	return(rtn);

} /* do_reassign() */


cdb_clr(cdbp)
union cdb *cdbp;
{
	int i;
	char *p;
	
	p = (char *)cdbp;
	for(i=0; i<sizeof(union cdb); i++)
		*p++ = 0;
}

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

/* end of reasb.c */

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