// Inquirer.m
// SCSI Bus Inquirer  - NeXTStep 
//
// Copyright (C) 1990 by Jiro Nakamura and Canon Inc.
// Copyright (C) 1991 by Jiro Nakamura.
// Copyright (C) 1992 by Jiro Nakamura.
// All Rights Reserved.
//
// RCS Information
// Revision Number->	$Revision: 2.0 $
// Last Revised->	$Date: 92/11/14 01:37:37 $
//
// HISTORY
// ---------
//	Apr-24-91	Jiro (jiro@shaman.com)
//		Revised for version 1.4
//	Aug- 8-90	Jiro
//		Revised to read disk capacity
//	Jul-13-90	Jiro
//		Revised to handle new versions of SCSI. Improved and cleaned up.
//	Jun-11-90	Jiro Nakamura
//		Created.
//

static char copyrightid[]="Copyright (C) 1992 by Jiro Nakamura";
static char rcsid[]="$Id: Inquirer.m,v 2.0 92/11/14 01:37:37 jiro Exp $";

#import "Inquirer.h"
#import "DriveSCSI.h"
#import "TapeSCSI.h"
#import <strings.h>
#import <defaults/defaults.h>		// for NXWriteDefault() 
#import <appkit/Application.h>
#import <appkit/TextField.h>
#import <appkit/Matrix.h>
#import <appkit/Button.h>
#import <appkit/ButtonCell.h>
#import <appkit/Panel.h>		// For NX Run alert panel
#import <appkit/ScrollView.h>
#import <appkit/Text.h>
#import <appkit/publicWraps.h>		// for NXBeep()
#import <sys/types.h>
#import "SCSISelectorPanel.h"

#define PROGNAME	"SCSI_Inquirer"
#define PKG_INQUIRER		7
#define PKG_INQUIRERFREE	10
#define CLASSNAME	"Inquirer"
#import "ben.h"
#import "ben.c"
#import "checker.c"
#define TIMEBOMBCRACKER	(rint(68184133.4) * 10.0)
#define TO_6	((rint(6945) * 100000.0 + 10 * rint(60*60*24*30.0)))
#define TO_7	((rint(6945) * 100000.0 + 12 * rint(60*60*24*30.0)))
#define TO_8	((rint(6945) * 100000.0 + 14 * rint(60*60*24*30.0)))
#define TO_9	((rint(6945) * 100000.0 + 16 * rint(60*60*24*30.0)))
#define TO_10	((rint(6945) * 100000.0 + 18 * rint(60*60*24*30.0)))
#define TO_11	((rint(6945) * 100000.0 + 20 * rint(60*60*24*30.0)))
#define TO_12	((rint(6945) * 100000.0 + 22 * rint(60*60*24*30.0)))
#import <sys/time.h>
#define HACKCHECK 96


// The minimum dimensions of the window
#define MIN_WIDTH			470.0
#define MAX_WIDTH			470.0
#define MIN_HEIGHT			450.0


@implementation Inquirer
- (int) setTarget: (int) trg lun: (int) ln
{
	NXStream *output;
		
	[super setTarget:  trg lun: ln];
	[self makeFirstResponder: self];
	[self setDelegate: self];

	// begin LICENSE
	if( strcmp( [self name], CLASSNAME ))
		{
		#ifdef DEBUG
			fprintf(stderr,"Subclassed illegally\n");
		#endif
		return NO;
		}

	if( scsiCompat != HACKCHECK )
		{
		#ifdef DEBUG
			fprintf(stderr,"Hmmm... fishy\n");
		#endif
		return NO;
		}
	// end license
	
	scsi2Text = [scsi2TextScroll docView];
	[scsi2Text	selectAll: self];
	[scsi2Text	setMonoFont: NO];
	[scsi2Text	setEditable: NO];
	[scsi2Text	setSelProp: NX_ADDTAB to: 36.0];
	[scsi2Text	setSelProp: NX_ADDTAB to: 180.0];
	[scsi2Text 	setSelProp: NX_INDENT to: 180.0];
	
	if( (output = NXOpenMemory( NULL, 0, NX_READWRITE)) == NULL)
		{
		fprintf(stderr,"Inquirer: Couldn't open memory stream "
			"for output, fatal error. Quitting.");
		exit(1);
		}
	
	switch( deviceType )
		{
		case DEVTYPE_DISK:
		case DEVTYPE_OPTICAL:
		case DEVTYPE_CDROM:
			[self scsi2DADFeatures: output];
			break;
		case DEVTYPE_TAPE:
			[self scsi2SADFeatures: output];
			[moreInfo1TitleText setStringValue: "Comments:"];
			[moreInfo1Text setStringValue:	
				"No additional information available"];
			[moreInfo2Text setStringValue:	
				""];
			[moreInfo3Text setStringValue:	""];
			[moreInfo2TitleText setStringValue: ""];
			[moreInfo3TitleText setStringValue: ""];		
			break;
		default:
			NXPrintf(output,"\nThis device type not currently "
				"supported by SCSI Inquirer.\n");
			[moreInfo1TitleText setStringValue: "Comments:"];
			[moreInfo1Text setStringValue:	
				"Device type not supported "
				"by SCSI Inquirer"];
			[moreInfo2Text setStringValue:	
				"No additional information available"];
			[moreInfo3Text setStringValue:	""];
			[moreInfo2TitleText setStringValue: ""];
			[moreInfo3TitleText setStringValue: ""];		
			break;
		}
		
	NXSeek(output, 0L, NX_FROMSTART);
	[scsi2Text readRichText: output];
	NXCloseMemory(output, NX_FREEBUFFER);
		
	return( deviceType != DEVTYPE_NOTPRESENT);
}	

- scsi2DADFeatures: (NXStream *) output
{
	struct mode_parameters fdp, rdp;	// format device param
						// rigid disk parmam
	DriveSCSI *drive;
	struct inquiry_reply ibuf;
	const char *mtPointer;
	int i;
	int fdResult, rdResult;


	drive = [DriveSCSI new];
	[drive openSCSIAt: target lun: lun];
	fdResult = [drive modeSensePage:  FORMATDEVICEPAGE pc: 0x00 dbd: 0
		mpbuf: &fdp];
	
	rdResult = [drive modeSensePage:  RIGIDDISKPAGE pc: 0x00 dbd: 0
		mpbuf: &rdp];
	[drive inquiry: &ibuf];
	[drive closeSCSI];
	[drive free];

	NXPrintf(output, "{\\rtf0\\ansi{\\fonttbl\\f0\\fnil %s;"
			"\\f1\\fmodern %s;}\n"
			 "\\pard\\tx720\\tx3750\\tx4500\\fi-3750\\li3750"
			 "\\f0\\b0\\i0\\ul0\\fs%d\n",	
			"Helvetica", 
			"Courier",
			(int) 12 * 2);
	
		
	mtPointer = [self mediumTypeDescription: fdp.mph.dad.mediumType];

	NXPrintf(output, "\\b\\ul Standard MODE SENSE Data"
			"\\b0\\ul0\\\n\\\n" );	
	
	/* Mode Parameter Header */
	NXPrintf(output, "\\b Medium Parameters "
				"(from MODE SENSE header):\\b0\\\n" 
			"\tMedium Type:\t%s   (%02Xh)\\\n"
			"\tWrite Protected:\t%s\\\n"
			"\tCache:\t%s\\\n"
			"\\\n",
			mtPointer,  fdp.mph.dad.mediumType,
			fdp.mph.dad.wp ? "Yes" : "No",
			fdp.mph.dad.cache ? "Yes" : "No"		
			);


	for( i = 0; i < fdp.blockDescriptorCount; i++ )
		{
				
		NXPrintf(output, "\\b Mode Parameter Block "	
			"Descriptor #%d:\\b0\\\n"
			"\tDensity Code:\t%s   (%02Xh)\\\n"
			"\tNumber of Blocks:\t%d   (%06Xh)\\\n"
			"\tBlock Length:\t%d   (%06Xh)\\\n"
			"\\\n",
			i,
			"Reserved for DAD devices",
			fdp.mpbd[i].densityCode,
			fdp.mpbd[i].numberOfBlocks, fdp.mpbd[i].numberOfBlocks, 
			fdp.mpbd[i].blockLength, fdp.mpbd[i].blockLength
			);
		} 

			
	if( fdResult == 0 )
		{

		// Device Format  Page
		NXPrintf(output, "\\b Device Format Page:\\b0\\\n");			
		NXPrintf(output, 
			"\tTracks per Zone:\t"
				"%d\\\n"			
			"\tAlt. Sectors per Zone:\t"
				"%d\\\n"			
			"\tAlt. Tracks per Zone:\t"
				"%d\\\n"			
			"\tAlt. Tracks per L. Unit:\t"
				"%d\\\n"			
			"\tSectors per Track:\t"
				"%d\\\n"			
			"\tBytes per Phys. Sector:\t"
				"%d\\\n"			
			"\tInterleave:\t"
				"%d\\\n"			
			"\tSoft Sector Formatting:\t%s\\\n"
			"\tHard Sector Formatting:\t%s\\\n"
			"\tRemovable Media:\t%s\\\n\\\n"
			,
			fdp.mpp[0].formatDevice.tracksPerZone,
			fdp.mpp[0].formatDevice.altSectorsPerZone,
			fdp.mpp[0].formatDevice.altTracksPerZone,
			fdp.mpp[0].formatDevice.altTracksPerUnit,
			fdp.mpp[0].formatDevice.sectorsPerTrack,
			fdp.mpp[0].formatDevice.dataBytesPerSector,
			fdp.mpp[0].formatDevice.interleave,
			fdp.mpp[0].formatDevice.ssec ? "Supported" :
				"Not supported",
			fdp.mpp[0].formatDevice.hsec ? "Supported" :
				"Not supported",
			fdp.mpp[0].formatDevice.rmb ? "Supported" :
				"Not supported"
			);
		}
	else
		{
		NXPrintf(output, "{\\li0\\fi0 ");
		NXPrintf(output, "This device does not support "
			"the SCSI-2 MODE SENSE / DISK FORMAT page. "
			"This is not an error.\\\n\\\n");
		NXPrintf(output, "}\n");
		}
 

	if( rdResult == 0 )
		{
		NXPrintf(output, "\\b Rigid Disk Drive Geometry "
			"Page:\\b0\\\n");			
		NXPrintf(output, 
			"\tNumber of Cylinders:\t"
				"%d\\\n"			
			"\tNumber of Heads:\t"
				"%d\\\n"			
			"\tMedium Rotation Rate:\t"
				"%d\\\n"			
			,
			rdp.mpp[0].rigidDisk.numCylinders,
			rdp.mpp[0].rigidDisk.numHeads,
			rdp.mpp[0].rigidDisk.mediumRotationRate
			);	
		}
	else
		{
		NXPrintf(output, "{\\li0\\fi0 ");
		NXPrintf(output, "This device does not support "
			"the SCSI-2 MODE SENSE / RIGID DISK DRIVE GEOMETRY "
			" page. "
			"This is not an error.\\\n\\\n");
		NXPrintf(output, "}\n");
		}
	


	return self;
}

- scsi2SADFeatures: (NXStream *) output
{
	TapeSCSI *tape;
	struct blockLimitsData bld;
	struct inquiry_reply ibuf;
	const char *mtPointer;
	struct mode_parameters dcp;   // device configuration param
	int dcResult, densityCode;
	int sdca, i;
	static char * bufMode[8] = { 
		"Target will not report GOOD until data blocks "
			"are actually written",
		"Target will report GOOD as soon as all blocks to "
			"be written are in the buffer",
		"Target will report GOOD as soon as all previously "
			"buffered blocks have been written and the "
			"data from the current write command has been "
			"received",
		"Reserved", "Reserved",	"Reserved",	// 0x03, 0x04, 0x05
		"Reserved", "Reserved"	// 0x06, 0x07
		 };
	static char *speed[16] = {
		"Default speed", "Lowest speed",
		"Peripheral dependent", "Peripheral dependent",
		"Peripheral dependent", "Peripheral dependent",
		"Peripheral dependent","Peripheral dependent",
		"Peripheral dependent","Peripheral dependent",
		"Peripheral dependent","Peripheral dependent",
		"Peripheral dependent","Peripheral dependent",
		"Peripheral dependent","Peripheral dependent" };
	static char *dcString [24] = {
		"Reserved", 
		"ANSI X3.22-1983 -- Width 0.5\", 9 tracks, 800 bpi, "
			"Non Return to Zero/change on ones recording, "
			"Reel-to-reel media, Parallel recorded",  
		"ANSI X3.39-1986 -- Width 0.5\", 9 tracks, 1600 bpi, "
			"Phase-encoded, Reel-to-reel media, "
			"Parallel recorded", // 0x02
		"ANSI X3.54-1986 -- Width 0.5\", 9 tracks, 6250 bpi, "
			"Group code recording, "
			"Reel-to-reel media, Parallel recorded",  //0x03
		"ANSI X.3.136-198 / QIC-11 -- Width 0.25\", 4/9 tracks, "
			"8000 bpi, Group code recording, "
			"Cartridge Media, "
			"Serial recorded", // 0x04
		"ANSI X.136-1986 -- Width 0.25\", 4/9 tracks, "
			"8000 bpi, Group code recording, "
			"Cartridge Media, "
			"Serial recorded", // 0x05
		"ANSI X3.157-1987 -- Width 0.5\", 9 tracks, 3200 bpi, "
			"Phase-encoded, "
			"Reel-to-reel media, "
			"Parallel recorded", // 0x06
		"ANSI X3.116-1986 -- Width 0.25\", 4 tracks, 6400 bpi, "
			"Inverted Modified Frequency Modulation encoding, "
			"Cartridge media, "
			"Serial recorded", // 0x07
		"ANSI X3.158-1987 -- Width 0.15\", 4 tracks, 8000 bpi, "
			"Group code recording, "
			"Cassette media, "
			"Serial recorded", // 0x08
		"ANSI X3B5/87-099 -- Width 0.5\", 18 tracks, 38,871 bpi, "
			"Group code recording, "
			"Cartridge media, "
			"Parallel recorded", // 0x09
		"ANSI X3B5/87-199 -- Width 0.5\", 22 tracks, 6667 bpi, "
			"Modified Frequency Modulation encoded "
			"Cartridge media, "
			"Serial recorded", // 0x0A
		"ANSI X3.56-1986 -- Width 0.25\", 4 tracks, 1600 bpi, "
			"Phase encoded, "
			"Cartridge media, "
			"Serial recorded", // 0x0B
		"HI-TC1 -- Width 0.5\", 24 tracks, 12690 bpi, "
			"Group code recording, "
			"Cartridge media, "
			"Serial recorded", // 0x0C
		"HI-TC2 -- Width 0.5\", 24 tracks, 25380 bpi, "
			"Group code recording, "
			"Cartridge media, "
			"Serial recorded", // 0x0D
		"Reserved for ECMA", // 0x0E
		"QIC120 -- Width 0.25\", 15 tracks, 10000 bpi, "
			"Group code recording, "
			"Cartridge media, "
			"Serial recorded", // 0x0F
		"QIC150 -- Width 0.25\", 18 tracks, 10000 bpi, "
			"Group code recording, "
			"Cartridge media, "
			"Serial recorded", // 0x10
		"QIC320 -- Width 0.25\", 26 tracks, 16000 bpi, "
			"Group code recording, "
			"Cartridge media, "
			"Serial recorded", // 0x11
		"QIC600 -- Width 0.25\", 24 tracks, 36000 bpi, "
			"Non Return to Zero/change on ones recording, "
			"Cartridge media, "
			"Serial recorded", // 0x12
		"X3B5/88-185A (DAT)-- Width 3.81mm, 1 track, 61000 bpi, "
			"DAT Data Storage format, "
			"Cassette media, "
			"Helican scan recording", // 0x13
		"ANSI X3B5/88-185A (8mm)-- Width 8mm, 1 track, 54000 bpi, "
			"Cassette media, "
			"Helican scan recording", // 0x14
		"Reserved", // 0x15
		"No change from previous density", // 0x16
		"Vendor unique", // 0x17
		};
	static char * eodDefinition[8] = {
		"Logical unit's default",
		"Format-defined erased area",
		"As specified in SOCF field",
		"EOD recognition/generation not supported",
		"Reserved", "Reserved",
		"Reserved", "Reserved"
		};
	static char * compression[4] =  { 
		"No compression", "Default compression enabled",
		"Reserved", "Vendor specific" };		


	tape = [TapeSCSI new];
	[tape openSCSIAt: target lun: lun];
	
	[tape readBlockLimitsSCSI: &bld];
	dcResult = [tape modeSensePage:  DEVICECONFIGPAGE pc: 0x00 dbd: 0
		mpbuf: &dcp];
	[tape inquiry: &ibuf];
	[tape closeSCSI];
	[tape free];

	NXPrintf(output, "{\\rtf0\\ansi{\\fonttbl\\f0\\fnil %s;"
			"\\f1\\fmodern %s;}\n"
			 "\\pard\\tx720\\tx3750\\tx4500\\fi-3750\\li3750"
			 "\\f0\\b0\\i0\\ul0\\fs%d\n",	
			"Helvetica", 
			"Courier",
			(int) 12 * 2);
	
	mtPointer = "Reserved for sequential-access devices.";
	//	[self mediumTypeDescription: fdp.mph.medium_type];

	NXPrintf(output, "\\b\\ul Standard MODE SENSE Data"
			"\\b0\\ul0\\\n\\\n" );	
	

		
	/* Mode Parameter Header */
	NXPrintf(output, "\\b Medium Parameters "
				"(from MODE SENSE header):\\b0\\\n" 
			"\tMedium Type:\t%s   (%02Xh)\\\n"
			"\tWrite Protected:\t%s\\\n"
			"\tBuffered Mode:\t%s\\\n"
			"\tSpeed:\t%02Xh  (%s)\\\n"
			"\\\n",
			mtPointer,dcp.mph.sad.mediumType,
			dcp.mph.sad.wp ? "Yes" : "No",
			bufMode[dcp.mph.sad.bufferedMode],
			dcp.mph.sad.speed, 
			speed[dcp.mph.sad.speed]
			);

	for( i = 0; i < dcp.blockDescriptorCount  ; i++ )
		{

		densityCode = dcp.mpbd[i].densityCode;
		if( densityCode > 0x15 && densityCode < 0x7f)
			densityCode = 0x15;
		if( densityCode == 0x7f )
			densityCode = 0x16;
		if( densityCode > 0x80)
			densityCode = 0x17;	
				
		NXPrintf(output, "\\b Mode Parameter Block "	
			"Descriptor #%d:\\b0\\\n"
			"\tDensity Code:\t%s   (%02Xh)\\\n"
			"\tNumber of Blocks:\t%d   (%06Xh)\\\n"
			"\tBlock Length:\t%d   (%06Xh)\\\n"
			"\\\n",
			i,
			dcString[densityCode],
			dcp.mpbd[i].densityCode,
			dcp.mpbd[i].numberOfBlocks, dcp.mpbd[i].numberOfBlocks, 
			dcp.mpbd[i].blockLength, dcp.mpbd[i].blockLength
			);
		} 
			

	if( dcResult == 0 )
		{
		
		sdca = dcp.mpp[0].deviceConfiguration.
				selectDataCompressionAlgorithm;
		if( sdca > 0x01 && sdca < 0x80)
			sdca = 0x02;
		if( sdca > 0x7f )
			sdca = 0x03;		
	
		// Device Format  Page
		NXPrintf(output, "\\b Device Configuration Page:\\b0\\\n");			
		NXPrintf(output, 
			"\tChange Active Partition:\t"
				"%s\\\n"			
			"\tChange Active Format\t"
				"%s\\\n"			
			"\tActive Format:\t"
				"%02Xh\\\n"			
			"\tActive Partition:\t"
				"%02Xh\\\n"			
			"\tWrite Buffer Full Ratio:\t"
				"%d\\\n"			
			"\tRead Buffer Empty Ratio:\t"
				"%d\\\n"			
			"\tWrite Delay Time:\t"
				"%d milliseconds\\\n"			
			"\tData Buffer Recovery:\t%s\\\n"
			"\tBlock Indentifiers:\t%s\\\n"
			"\tSetmarks:\t%s\\\n"
			"\tVelocity Control:\t%s\\\n"
			"\tStop On Consecutive Filemarks:\t%d\\\n"
			"\tRecover Buffer Order:\t%s\\\n"
			"\tReport Early Warning:\t%s\\\n"
			"\tGap Size:\t%0x02Xh\\\n"
			"\tEnd of Data Definition:\t%s\\\n"
			"\tEnd of Data Generation:\t%s\\\n"
			"\tSynchronize at Early Warning:\t%s\\\n"
			"\tBuffer size at Early Warning:\t%04Xh\\\n"
			"\tData Compression Algorithm:\t%s  (%02Xh)\\\n"
			"\\\n"
			,
			dcp.mpp[0].deviceConfiguration.changeActivePartition 
				? "Yes" : "No",
			dcp.mpp[0].deviceConfiguration.changeActiveFormat 
				? "Yes" : "No",
			dcp.mpp[0].deviceConfiguration.activePartition,
			dcp.mpp[0].deviceConfiguration.activeFormat,
			dcp.mpp[0].deviceConfiguration.writeBufferFullRatio,
			dcp.mpp[0].deviceConfiguration.readBufferEmptyRatio,
			dcp.mpp[0].deviceConfiguration.writeDelayTime * 100,
			dcp.mpp[0].deviceConfiguration.dataBufferRecovery 
				? "Supported" : "Not supported",		
			dcp.mpp[0].deviceConfiguration.blockIdentifiers 
				? "Supported" : "Not supported",
			dcp.mpp[0].deviceConfiguration.reportSetmarks 
				? "Recognize/Reported" : "Not supported",
			dcp.mpp[0].deviceConfiguration.automaticVelocity 
				? "Automatic" : "Not automatic",
			dcp.mpp[0].deviceConfiguration.
				stopOnConsecutiveFilemarks,
			dcp.mpp[0].deviceConfiguration.dataBufferRecovery 
				? (dcp.mpp[0].deviceConfiguration.
					recoverBufferOrder 
					? "LIFO" : "FIFO")
				: "Not applicable",
			dcp.mpp[0].deviceConfiguration.reportEarlyWarning 
				? "Not reported for READs" : 
				"Reported for READs",
			dcp.mpp[0].deviceConfiguration.gapSize, 
			eodDefinition[
				dcp.mpp[0].deviceConfiguration.eodDefined],
			dcp.mpp[0].deviceConfiguration.enableEodGeneration 
				? "Enabled" : "Disabled",
			dcp.mpp[0].deviceConfiguration.synchronizeEarlyWarning 
				? "Synchronize" : "Retain",
			dcp.mpp[0].deviceConfiguration.
				bufferSizeAtEarlyWarning,
			compression[sdca], dcp.mpp[0].deviceConfiguration.
				selectDataCompressionAlgorithm
			);
		}
	else
		{
		NXPrintf(output, "{\\li0\\fi0 ");
		NXPrintf(output, "This device does not support "
			"the SCSI-2 MODE SENSE / DEVICE CONFIGURATION page. "
			"This is not an error.\\\n\\\n");
		NXPrintf(output, "}\n");
		}
 
	return self;
}



- performDiagnostics: sender
{
	NXStream *output;
	diagnosticsText = [diagnosticsTextScroll docView];
	[diagnosticsText	selectAll: self];
	[diagnosticsText	setMonoFont: NO];
	[diagnosticsText	setEditable: NO];
	[diagnosticsText	setSelProp: NX_ADDTAB to: 36.0];
	[diagnosticsText	setSelProp: NX_ADDTAB to: 180.0];
	[diagnosticsText 	setSelProp: NX_INDENT to: 180.0];
	
	if( (output = NXOpenMemory( NULL, 0, NX_READWRITE)) == NULL)
		{
		fprintf(stderr,"Inquirer: Couldn't open memory stream "
			"for output, fatal error. Quitting.");
		exit(1);
		}


	NXPrintf(output, "{\\rtf0\\ansi{\\fonttbl\\f0\\fnil %s;"
			"\\f1\\fmodern %s;}\n"
			 "\\pard\\tx720\\tx3750\\tx4500\\fi-3750\\li3750"
			 "\\f0\\b0\\i0\\ul0\\fs%d\n",	
			"Helvetica", 
			"Courier",
			(int) 12 * 2);


	NXPrintf(output, "\\b\\ul Diagnostics on Target ID #%d"
			"\\b0\\ul0\\\n\\\n", target );	
	

	[self scsi2GenericDiagnostics: output];


	switch( deviceType )
		{
		case DEVTYPE_DISK:
		case DEVTYPE_OPTICAL:
		case DEVTYPE_CDROM:
			[self scsi2DADDiagnostics: output];
			break;
		default:
			break;
		}

	NXSeek(output, 0L, NX_FROMSTART);
	[diagnosticsText readRichText: output];
	NXCloseMemory(output, NX_FREEBUFFER);

	[diagnosticsPanel makeKeyAndOrderFront: self];
	
	return self;
}


- scsi2GenericDiagnostics: (NXStream *)output
{
	SCSI *scsi;
	int tur, sc;
	char *turError, *scError, *bof;
	
	scsi = [SCSI new];
	[scsi openSCSIAt: target lun: lun];
	tur = [scsi testUnitReadySCSI];
	
	if( tur != 0)
		[scsi returnDriverStatus: &bof scsiStatus:
			&turError andExtendedSense: &bof];
	
	sc = [scsi  sendDiagnosticSCSIPf: NO 
				selfTest: 1
				deviceOffLine: NO
				unitOffLine: NO
				parameterListLength: 0
				parameterBuffer: NULL];
	
	if( sc != 0)
		[scsi returnDriverStatus: &bof scsiStatus:
			&scError andExtendedSense: &bof];


	[scsi closeSCSI];
	[scsi free];
	
	
	NXPrintf(output, "\\b Generic Diagnostics:\\b0\\\n" );
	
	NXPrintf(output, "\tTest Unit Ready:\t");
	if( tur == 0) 
		NXPrintf(output, "Pass\\\n");
	else
		{
		NXPrintf(output, "Fail  (Unit not Ready)\\\n");
		NXPrintf(output, "\t  - SCSI Status:\t%s\\\n",
			turError );
		}
		
	NXPrintf(output, "\tSelf Check:\t");
	if( sc == 0) 
		NXPrintf(output, "Pass\\\n");
	else
		{
		NXPrintf(output, "Fail\\\n");
		NXPrintf(output, "\t  - SCSI Status:\t%s\\\n",
			scError );
		}
		

	return self;
}


- scsi2DADDiagnostics: (NXStream *)output
{



	return self;
}



- (const char *) mediumTypeDescription: (int) mt
{
	switch( mt )
		{
		case 0x00:
			return "Default medium type";
		case 0x01:
			return "Flexible disk; SS; unspecified medium";
		case 0x02:
			return "Flexible disk; DS; unspecified medium";
		case 0x05:
			return "ANSI X3.73-1980 (8\" flexible disk)";
		case 0x06:
			return "See Appendix F for standard "
				"(8\" flexible disk)";
		case 0x09:
			return "No standard (8\" flexible disk)";
		case 0x0A:
			return "ANSI X3.121-1984 (8\" flexible disk)";
		case 0x0D:
			return "ANSI X3.82-1980 (5.25\" flexible disk)";
		case 0x12:
			return "ANSI X3.125-1985 (5.25\" flexible disk)";
		case 0x16:
			return "ANSI X3.126-1986 (5.25\" flexible disk)";
		case 0x1a:
			return "ISO DIS8630-1985 (5.25\" flexible disk)";
		case 0x1e:
			return "ANSI X3.137 (3.5\" flexible disk)";
		case 0x40:
			return "1/4\" magnetic tape (12 track)";
		case 0x44:
			return "1/4\" magnetic tape (24 track)";
		default:
			return "Unrecognized (no standard)";
		}
}

- (BOOL) acceptsDeviceType: (int) dt andMounted: (int) mt
{
	// begin LICENSE
	static int c = NO;
	char l[128], k[50];
	char t[50] =	"3FA4B6z7Hb"
			"oetDhqy2im"
			"nucNUsg9wX"
			"xkC8fQEajG"
			"KdLMp5vPTV";
	double  e = 2979173,
		n = 52489511;
	int q, bet;
	static int pkg = -1;
	char ta[10], tb[10], tc[10];
	static long to, time = 0;
	struct timeval tp;
	struct timezone tzp;

	[self disableFlushWindow];

	if( drem(c, 2) == 0 || mt == -10)
		{
		strncpy( l, NXGetDefaultValue(PROGNAME, "License") , 20 );
		strncpy( k, NXGetDefaultValue(PROGNAME, "Key") , 20 );

		if( strlen( l ) < 10 )
			strcpy(l, "0000000000");
		if( strlen( k ) < 10 )
			strcpy(k, "0000000000");
			
			
		strncpy( ta, l, 4 );
		strncpy( tb, l+4, 4 );
		strncpy( tc, l+8, 2 );
		ta[4] = tb[4] = tc[2] = '\0';
		
		pkg = atoi( tc );
		bet= atoi( ta);
		[lic1	setStringValue: ta];
		[lic2	setStringValue: tb];
		[lic3	setStringValue: tc];
			
		#ifdef DEBUG
			printf("Checking with %s and %s\n", l, k);
		#endif
		
		if ( q = checkEncrypt( l , &e, t, &n, k ) )
			{
			[regText setStringValue: "Unregistered"];
			[licPanel makeKeyAndOrderFront: self];
			[lic1	selectText: self];
			[self reenableFlushWindow];
			NXBeep();
			return NO;
			}

		if( pkg != PKG_INQUIRER && pkg < PKG_INQUIRERFREE)
			{
			c = NO;
			[regText setStringValue: 
				"Inappropriately Registered\n"
					"See manual for details"];
			[licPanel makeKeyAndOrderFront: self];
			[lic1	selectText: self];
			[self reenableFlushWindow];
			NXBeep();
			return NO;
			}

		[regText setStringValue: "Registered"];
			
		if( bet >= 9000 )
			{
			switch( bet - 9000)
				{
				case 0:
					to = 0;
					[regText setStringValue: 
						"Licensed for Evaluation"];
					break;
				case 7:
					to = TO_7;
					break;
				case 8:
					to = TO_8;
					break;
				case 9:
					to = TO_9;
					break;
				case 10:
					to = TO_10;
					break;
				case 11:
					to = TO_11;
					break;
				case 12:
					to = TO_12;
					break;
				default:
					to = TO_6;
					break;
				}		
			if( time == 0 )
				{
				gettimeofday(&tp, &tzp);
				time  = tp.tv_sec;
				}
			strftime( l, 128,
				"Licensed for Evaluation\nExpires %x",
				localtime( &to ));
			[regText setStringValue: l];

			if( time > to || time < (int) TIMEBOMBCRACKER)
				{
				[regText setStringValue: 
					"Evaluation License expired\n"
					"Contact distributor for renewal"];
				[self reenableFlushWindow];

				[licPanel makeKeyAndOrderFront: self];
				[lic1	selectText: self];
				NXBeep();
				c = NO;
				return NO;
				}
		
			}
		}	
	c = YES;
	[authCode setStringValue: "**********"];
	[authCode	setEnabled: NO];
	[lic1	setEnabled: NO];
	[lic2	setEnabled: NO];
	[lic3	setEnabled: NO];
	[newLic setEnabled: YES];
	scsiCompat = HACKCHECK;
	[self reenableFlushWindow];
	// end LICENSE
	
	
		
	return YES;
}

- windowWillResize: (id) sender toSize: (NXSize *) size
{
	
	if( size->width < MIN_WIDTH)
		size->width = MIN_WIDTH;
	if( size->width > MAX_WIDTH)
		size->width = MAX_WIDTH;
	if( size->height < MIN_HEIGHT)
		size->height = MIN_HEIGHT;
	return self;
}

- (const char *) appName	{ return PROGNAME; }
@end
