From: carl@SOL1.GPS.CALTECH.EDU (Carl J Lydick)
Newsgroups: comp.os.vms
Subject: Re: Question about RMS and MSCP-pair
Date: 9 Jan 1993 11:54:59 GMT
Organization: HST Wide Field/Planetary Camera
Distribution: world
Reply-To: carl@SOL1.GPS.CALTECH.EDU
NNTP-Posting-Host: sol1.gps.caltech.edu

In article <9301051405.AA16112@uu3.psi.com>, leichter@lrw.com (Jerry Leichter) writes:
>Some of this is already in ANALYZE/DISK/READ_CHECK.  The rest is in the old
>BAD utility (ANALYZE/MEDIA), though that will refuse to run on DSA disks.
>However, that utility won't run on DSA disks, reporting "Unable to analyze
><disk>, due to revector caching".  You really need diagnosic-level code
>(which has its own specialized disk drivers) to do this properly on a DSA
>disk.

Not really.  All you really want to do is make sure that the blocks currently
on the logical disk (including those that've been included by revectoring) are
OK.  I've got a program to do that (we once bought a *WHOLE LOT* of magneto
optical disks at a good price;  seems that one reason for the price was that
the manufacturer hadn't bothered to do much quality control.  Result:  Lots of
disks with a few bad sectors on each;  of course, the drive we were using was
DSA, so we couldn't use ANAL/MEDIA/EXERCISE to force revectoring, and I wrote a
simple exerciser.  Since the code's not all that long (OK, it's 255 lines, and
6.5 kbytes or so), here it is (by the way, one of the features of this program
is that it's pretty safe to run on a disk that already contains useful data: 
After running the program, the disk has exactly the same information it started
with, with the possible exception of the data in bad blocks;  why doesn't BAD
do the same thing, I wonder?):


#include ssdef
#include dvidef
#include IODEF
#include descrip

#define MAXBLK 128
#define MAXBYTE (MAXBLK * 512)
#define RMSMAXBLK 32
#define RMSMAXBYTE (RMSMAXBLK * 512)
long STAT;
#define ckstat(x) if(((STAT = x) & 7) != 1) SYS$EXIT(STAT);
#define $DESCRIPTOR_D(x) struct dsc$descriptor_d x = \
	{ 0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0 }

char olddata[MAXBYTE], testdata[MAXBYTE], pattern_0[MAXBYTE],
	pattern_1[MAXBYTE], temp[16];
unsigned short chan;

struct IOSB
{	unsigned short stat;
	unsigned long count;
	unsigned short not_used;
} iosb;

findbad()
{	$DESCRIPTOR(prompt,"Disk to test: ");
	$DESCRIPTOR_D(dev);
	$DESCRIPTOR_D(temp);
	$DESCRIPTOR_D(prmpt);
	$DESCRIPTOR(mountstr, "Device must be mounted /FOREIGN");
	$DESCRIPTOR(loprompt, "Lowest block to check [0]: ");
	$DESCRIPTOR(hiprompt, "Highest block to check [!UL]: ");
	$DESCRIPTOR(msgdsc, "Testing blocks !UL-!UL");
	unsigned long blocks, mount, foreign, loblk, hiblk, i, tmp;
	struct ITEM_LIST_3
	{   	unsigned short buflen, itmcod;
		unsigned char *bufadr;
		unsigned short *lenadr;
	} itmlst[] =
	{	{ 4, DVI$_MAXBLOCK, &blocks, 0 },
		{ 4, DVI$_MNT, &mount, 0 },
		{ 4, DVI$_FOR, &foreign, 0 },
		{ 0, 0, 0, 0 }
	};

	ckstat(LIB$GET_INPUT(&dev, &prompt, 0));
	for(i = 0; i < MAXBYTE-RMSMAXBYTE; i += RMSMAXBYTE)
	{	ckstat(LIB$MOVC5(&0, 0, &0x55, &16384, pattern_0 + i));
		ckstat(LIB$MOVC5(&0, 0, &0xAA, &16384, pattern_1 + i));
	}
	tmp = MAXBYTE - i;
	ckstat(LIB$MOVC5(&0, 0, &0x55, &tmp, pattern_0 + i));
	ckstat(LIB$MOVC5(&0, 0, &0x55, &tmp, pattern_1 + i));
	ckstat(SYS$ASSIGN(&dev, &chan, 0, 0));
	ckstat(SYS$GETDVIW(0, chan, 0, itmlst, &iosb, 0, 0, 0));
	ckstat(iosb.stat);
	if((((mount & 1) == 1) && ((foreign & 1) != 1)) || ((mount & 1) == 0))
	{	LIB$PUT_OUTPUT(&mountstr);
		SYS$EXIT(1);
	}
	blocks--;
	LIB$GET_INPUT(&temp, &loprompt);
	loblk = dtol(&temp);
	LIB$SYS_FAO(&hiprompt,0,&prmpt,blocks);
	LIB$GET_INPUT(&temp,&prmpt);
	if (temp.dsc$w_length == 0)
		hiblk = blocks;
	else
		hiblk = dtol(&temp);
	LIB$SYS_FAO(&msgdsc,0,&temp, loblk, hiblk);
	LIB$PUT_OUTPUT(&temp);
	for(blocks = loblk; blocks <= hiblk - MAXBLK; blocks += MAXBLK)
		test_00(blocks, MAXBLK);
	if(blocks <= hiblk)
		test_00(blocks, hiblk - blocks + 1);
	SYS$EXIT(1);
}

test_00(base, blocks)
long base, blocks;
{	long tmp;
	$DESCRIPTOR(fmt, "Testing blocks !UL-!UL");
	$DESCRIPTOR_D(msg);

	LIB$SYS_FAO(&fmt, 0, &msg, base, base + blocks - 1);
	LIB$PUT_OUTPUT(&msg);
	if(blocks == 0)
		return;
	if(qio(olddata, 512 * blocks, base, IO$_READLBLK) != 1)
	{	if(blocks > 1)
		{	tmp = blocks / 2;
			test_00(base, tmp);
			test_00(base + tmp, blocks - tmp);
		}
	}
	else
		test_01(base, blocks);
}

test_01(base, blocks)
long base, blocks;
{	long tmp;

	if(qio(pattern_0, 512 * blocks, base, IO$_WRITELBLK) !=1)
	{	restore(base, blocks);
		if(blocks > 1)
		{	tmp = blocks / 2;
			test_00(base, tmp);
			test_00(base + tmp, blocks - tmp);
		}
	}
	else
		test_02(base, blocks);
}

test_02(base, blocks)
long base, blocks;
{	long tmp;

	if(qio(testdata, 512 * blocks, base, IO$_READLBLK) != 1)
	{	restore(base, blocks);
		if(blocks > 1)
		{	tmp = blocks / 2;
		 	test_00(base, tmp);
			test_00(base + tmp, blocks - tmp);
		}
	}
	else
		test_03(base, blocks);
}

test_03(base, blocks)
long base, blocks;
{	long tmp;

	compare(testdata, pattern_0, base, blocks);
	test_04(base, blocks);
}

test_04(base, blocks)
long base, blocks;
{	long tmp;

	if(qio(pattern_1, 512 * blocks, base, IO$_WRITELBLK) != 1)
	{	restore(base, blocks);
		if(blocks > 1)
		{	tmp = blocks / 2;
			test_00(base, tmp);
		 	test_00(base + tmp, blocks - tmp);
		}
	}
	else
		test_05(base, blocks);
}

test_05(base, blocks)
long base, blocks;
{	long tmp;

	if(blocks == 0)
		return;
	if(qio(testdata, 512 * blocks, base, IO$_READLBLK) != 1)
	{	restore(base, blocks);
		if(blocks > 1)
		{	tmp = blocks / 2;
			test_00(base, tmp);
			test_00(base + tmp, blocks - tmp);
		}
	}
	else
		test_06(base, blocks);
}

test_06(base, blocks)
long base, blocks;
{	long tmp;

	compare(testdata, pattern_1, base, blocks);
	restore(base, blocks);
}

qio(buff, siz, start, func)
char *buff;
long siz, start, func;
{	$DESCRIPTOR(fmt,
		"!AS FAILED ON BLOCKS !UL-!UL; STAT = !04XW; COUNT = !UL");
	$DESCRIPTOR(str_0, "READ");
	$DESCRIPTOR(str_1, "WRITE");
	$DESCRIPTOR_D(msg);
	$DESCRIPTOR(volinv, "VOLUME HAS DISAPPEARED.  QUITTING.");
	ckstat(SYS$QIOW(0, chan, func, &iosb, 0, 0, buff, siz, start, 0, 0, 0));
	if((iosb.stat & 7) != 1)
	{	LIB$SYS_FAO(&fmt, 0, &msg, func == IO$_READLBLK ? &str_0 :
			&str_1, start, start + (siz / 512) - 1, iosb.stat,
			iosb.count);
		LIB$PUT_OUTPUT(&msg);
		if(iosb.stat == SS$_VOLINV)
		{	LIB$PUT_OUTPUT(&volinv);
			SYS$EXIT(1);
		}
	}
	return iosb.stat & 7;
}

dtol(desc)
struct dsc$descriptor *desc;
{	int i, j;
	char c;
           
	for(i = j = 0; j < desc->dsc$w_length && desc->dsc$a_pointer[j] >= '0'
		&& desc->dsc$a_pointer[j] <= '9'; ++j)
		i = 10 * i + desc->dsc$a_pointer[j] - '0';
	return i;
}

restore(base, blocks)
long base, blocks;
{	long tmp;

	if(blocks == 0)
		return;
	if((qio(olddata, 512 * blocks, base, IO$_WRITELBLK) & 7) != 1)
	{	if(blocks > 1)
		{	tmp = blocks / 2;
			restore(base, tmp);
			restore(base + tmp, blocks - tmp);
		}
		else
			for(tmp = 0; ((qio(olddata, 512, base, IO$_WRITELBLK) &
				7) != 1) && (tmp < 10); ++tmp);
		return;
	}
}

compare(str_1, str_2, base, blocks)
char *str_1, *str_2;
long base;
{	$DESCRIPTOR(dsc_1, str_1);
	$DESCRIPTOR(dsc_2, str_2);
	long i;
	$DESCRIPTOR_D(msg);
	$DESCRIPTOR(fmt, "Compare failed on block !UL");

	if(blocks == 0)
		return;
	dsc_1.dsc$w_length = dsc_2.dsc$w_length = 512;
	for(i = 0; i < blocks ; i ++)
	{	if(STR$COMPARE(&dsc_1, &dsc_2) != 0)
		{	LIB$SYS_FAO(&fmt, 0, &msg, base + i);
			LIB$PUT_OUTPUT(&msg);
		}
 		dsc_1.dsc$a_pointer += 512;
 	 	dsc_2.dsc$a_pointer += 512;
	}
}

--------------------------------------------------------------------------------
Carl J Lydick | INTERnet: CARL@SOL1.GPS.CALTECH.EDU | NSI/HEPnet: SOL1::CARL

Disclaimer:  Hey, I understand VAXen and VMS.  That's what I get paid for.  My
understanding of astronomy is purely at the amateur level (or below).  So
unless what I'm saying is directly related to VAX/VMS, don't hold me or my
organization responsible for it.  If it IS related to VAX/VMS, you can try to
hold me responsible for it, but my organization had nothing to do with it.