Added initial Macintosh source.
10
README.md
|
@ -11,9 +11,6 @@ This tool is meant for Macintosh computers with a SCSI port, which
|
|||
range from the Macintosh Plus, released in 1986, through the "Beige"
|
||||
Power Macintosh G3, released in 1997.
|
||||
|
||||
If you have consulting work, particular contract work pertaining
|
||||
to vintage computers, please hit me via my GitHub account!
|
||||
|
||||
Disclaimer
|
||||
----------
|
||||
|
||||
|
@ -30,6 +27,12 @@ Right now the port is in early testing, so I am not releasing any
|
|||
compiled binaries. There is always a risk of data loss with a tool like
|
||||
this, so please contact me directly if you want to beta test.
|
||||
|
||||
Got projects?
|
||||
-------------
|
||||
|
||||
If you have consulting work, particular contract work pertaining
|
||||
to vintage computers or THREE.js, please hit me via my [GitHub account]!
|
||||
|
||||
About the code
|
||||
--------------
|
||||
|
||||
|
@ -59,6 +62,7 @@ his code in this repository with his permission.
|
|||
|
||||
</details>
|
||||
|
||||
[GitHub account]: https://github.com/marciot
|
||||
[mac-screenshot1]: https://github.com/marciot/mac-tip/raw/main/images/mac-tip1.png "TIP"
|
||||
[win-screenshot1]: https://github.com/marciot/mac-tip/raw/main/images/win-tip1.gif "TIP"
|
||||
[win-screenshot2]: https://github.com/marciot/mac-tip/raw/main/images/win-tip2.gif "TIP"
|
||||
|
|
After Width: | Height: | Size: 410 B |
After Width: | Height: | Size: 10 KiB |
|
@ -0,0 +1,176 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <SIOUX.h>
|
||||
|
||||
#include "tip.h"
|
||||
#include "mac_vol.h"
|
||||
#include "mac_scsi.h"
|
||||
#include "iomega_cmds.h"
|
||||
|
||||
bool process_command();
|
||||
void printn( unsigned char *c, int n );
|
||||
void print_help();
|
||||
void scan_bus();
|
||||
void dev_info( int id );
|
||||
void show_spares( int id );
|
||||
|
||||
void main() {
|
||||
SIOUXSettings.autocloseonquit = TRUE;
|
||||
SIOUXSettings.asktosaveonclose = FALSE;
|
||||
SIOUXSettings.standalone = FALSE;
|
||||
|
||||
printf( "SCSI and Iomega Zip/Jaz Toolkit V0.1\n" );
|
||||
printf( "(c) 2021 Marcio Teixeira\n\n" );
|
||||
printf( "TIP based on source code provided by Steve Gibson (http://grc.com)\n" );
|
||||
|
||||
SIOUXSetTitle("\pCommand Console");
|
||||
|
||||
print_help();
|
||||
|
||||
do {
|
||||
EventRecord event;
|
||||
if (WaitNextEvent(everyEvent, &event, GetCaretTime(), NULL))
|
||||
SIOUXHandleOneEvent(&event);
|
||||
|
||||
} while (process_command());
|
||||
|
||||
printf( "Goodbye.\n" );
|
||||
}
|
||||
|
||||
bool process_command() {
|
||||
short int arg_val = 0;
|
||||
char cmd[80];
|
||||
printf( "\n> " );
|
||||
gets( cmd );
|
||||
printf("\n");
|
||||
|
||||
char *arg_str = strchr(cmd, ' ');
|
||||
if(arg_str) arg_val = atoi(arg_str);
|
||||
|
||||
switch( tolower(cmd[0]) ) {
|
||||
case 'h': print_help(); break;
|
||||
case 'l': scan_bus(); break;
|
||||
case 's': iomega_spin_up_cartridge(arg_val); break;
|
||||
case 'r': scsi_reset(); break;
|
||||
case 'e': iomega_eject_cartridge(arg_val); break;
|
||||
case 'i': dev_info(arg_val); break;
|
||||
case 'v': mac_list_volumes(); break;
|
||||
case 'u': mac_unmount(arg_val); break;
|
||||
case 't': run_tip(); break;
|
||||
case 'q': return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void print_help() {
|
||||
printf(
|
||||
"\nGeneral commands:\n"
|
||||
" help : print this help\n"
|
||||
" quit : quit the program\n"
|
||||
|
||||
"\nMacintosh commands (please unmount Zip prior to testing):\n"
|
||||
" volumes : list Mac volumes\n"
|
||||
" unmount [n] : unmount a volume\n"
|
||||
|
||||
"\nGeneral SCSI operations:\n"
|
||||
" reset : reset the SCSI bus\n"
|
||||
" list : list devices on the SCSI bus\n"
|
||||
" info [n] : display SCSI inquiry\n"
|
||||
|
||||
"\nIomega device operations on SCSI device:\n"
|
||||
" spin [n] : spin up a cartridge\n"
|
||||
" eject [n] : eject cartridge\n"
|
||||
" tip [n] : run Steve Gibson's TIP 2.1\n"
|
||||
);
|
||||
}
|
||||
|
||||
void scan_bus() {
|
||||
short err, id;
|
||||
scsi_inq_reply reply;
|
||||
|
||||
for( id=0; id<8; id++ ) {
|
||||
err = scsi_inquiry( id, 0, &reply);
|
||||
if( err != 0 ) {
|
||||
printf( " %hd: (Not installed)\n", id );
|
||||
} else {
|
||||
printf( " %hd: ", id );
|
||||
printn( reply.prod, 16 );
|
||||
printf( " " );
|
||||
printn( reply.vend, 8 );
|
||||
printf( " " );
|
||||
printn( reply.rvsn, 4 );
|
||||
putchar( '\n' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dev_info( int id ) {
|
||||
short err, lun;
|
||||
scsi_inq_reply reply;
|
||||
|
||||
for( lun = 0; lun < 8; lun++ ) {
|
||||
err = scsi_inquiry( id, lun, &reply);
|
||||
if( err ) {
|
||||
printf( "Device not installed\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
printf( " LUN %hd: ", lun );
|
||||
switch( (reply.inf1 & 0xE0) >> 5 ) {
|
||||
case 0x00: printf( "supported and connected\n" ); break;
|
||||
case 0x01: printf( "not connected\n" ); continue;
|
||||
case 0x03: printf( "not supported\n" ); continue;
|
||||
}
|
||||
|
||||
printf( " Device class (%02X): ", reply.inf1 & 0x1F );
|
||||
switch( reply.inf1 & 0x1F ) {
|
||||
case 0x00: printf( "Disk drive\n" ); break;
|
||||
case 0x01: printf( "Tape drive\n" ); break;
|
||||
case 0x02: printf( "Printer\n" ); break;
|
||||
case 0x03: printf( "Processor device\n" ); break;
|
||||
case 0x04: printf( "WORM drive\n" ); break;
|
||||
case 0x05: printf( "CD-ROM drive\n" ); break;
|
||||
case 0x06: printf( "Scanner\n" ); break;
|
||||
case 0x07: printf( "Optical disk\n" ); break;
|
||||
case 0x08: printf( "Media changer\n" ); break;
|
||||
case 0x09: printf( "Communication device\n" ); break;
|
||||
case 0x1F: printf( "Unknown device\n" ); break;
|
||||
default: printf( "Reserved\n" );
|
||||
}
|
||||
|
||||
printf( " ANSI version (%02X): ", reply.vers & 0x07 );
|
||||
switch( reply.vers & 0x07 ) {
|
||||
case 0x00: printf( "SCSI-1\n" ); break;
|
||||
case 0x01: printf( "SCSI-1 w/ CCS\n" ); break;
|
||||
case 0x02: printf( "SCSI-2\n" ); break;
|
||||
default: printf( "???\n" );
|
||||
}
|
||||
printf( " ISO version (%02X)\n", reply.vers & 0xC0 >> 6 );
|
||||
printf( " ECMA version (%02X)\n", reply.vers & 0x78 >> 3 );
|
||||
|
||||
printf( " Flags: " );
|
||||
if( reply.flg1 & 0x80 ) printf( "rmb " );
|
||||
if( reply.flg2 & 0x80 ) printf( "rel " );
|
||||
if( reply.flg2 & 0x40 ) printf( "w32 " );
|
||||
if( reply.flg2 & 0x20 ) printf( "w16 " );
|
||||
if( reply.flg2 & 0x10 ) printf( "syn " );
|
||||
if( reply.flg2 & 0x08 ) printf( "lnk " );
|
||||
if( reply.flg2 & 0x04 ) printf( "??? " );
|
||||
if( reply.flg2 & 0x02 ) printf( "que " );
|
||||
if( reply.flg2 & 0x01 ) printf( "sfR " );
|
||||
if( reply.inf2 & 0x80 ) printf( "aen " );
|
||||
if( reply.inf2 & 0x40 ) printf( "tio " );
|
||||
printf( "\n" );
|
||||
}
|
||||
}
|
||||
|
||||
void printn( unsigned char *c, int n ) {
|
||||
while( n-- ) {
|
||||
putchar( isprint(*c) ? *c : '.' );
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 410 B |
After Width: | Height: | Size: 410 B |
|
@ -0,0 +1,38 @@
|
|||
#include <stdio.h>
|
||||
#include <Files.h>
|
||||
#include "mac_vol.h"
|
||||
|
||||
void mac_list_volumes() {
|
||||
HParamBlockRec paramBlock;
|
||||
Str255 volName;
|
||||
|
||||
paramBlock.volumeParam.ioCompletion = 0;
|
||||
paramBlock.volumeParam.ioNamePtr = volName;
|
||||
paramBlock.volumeParam.ioVRefNum = 0;
|
||||
paramBlock.volumeParam.ioVolIndex = 0;
|
||||
for (;;) {
|
||||
OSErr err = PBHGetVInfo(¶mBlock, false);
|
||||
if (err == nsvErr) break;
|
||||
printf(" %d: %#s\n", paramBlock.volumeParam.ioVolIndex, paramBlock.volumeParam.ioNamePtr);
|
||||
paramBlock.volumeParam.ioVolIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
void mac_unmount(int id) {
|
||||
HParamBlockRec paramBlock;
|
||||
paramBlock.volumeParam.ioCompletion = 0;
|
||||
paramBlock.volumeParam.ioNamePtr = 0;
|
||||
paramBlock.volumeParam.ioVRefNum = 0;
|
||||
paramBlock.volumeParam.ioVolIndex = id;
|
||||
OSErr err = PBHGetVInfo(¶mBlock, false);
|
||||
if (err == nsvErr) {
|
||||
printf("No such volume\n");
|
||||
return;
|
||||
}
|
||||
err = UnmountVol(0, paramBlock.volumeParam.ioVRefNum);
|
||||
switch (err) {
|
||||
case noErr: printf("Okay\n"); break;
|
||||
case fBsyErr: printf("One or more files are open\n"); break;
|
||||
default: printf("Failed %d\n", err);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
void mac_list_volumes();
|
||||
void mac_unmount(int id);
|
After Width: | Height: | Size: 410 B |
After Width: | Height: | Size: 410 B |
After Width: | Height: | Size: 410 B |
After Width: | Height: | Size: 410 B |
|
@ -0,0 +1,50 @@
|
|||
#include "mac_scsi.h"
|
||||
#include "iomega_cmds.h"
|
||||
|
||||
// Iomega commands
|
||||
|
||||
OSErr iomega_spin_up_cartridge( int id ) {
|
||||
// issue an Asynchronous START command to induce spinup
|
||||
char cmd[6] = {
|
||||
SCSI_Cmd_StartStopUnit,
|
||||
1, // set the IMMED bit for offline
|
||||
0,
|
||||
0,
|
||||
1, // start the disk spinning
|
||||
0
|
||||
};
|
||||
return scsi_cmd(id, cmd, sizeof(cmd), 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
OSErr iomega_spin_down_and_eject( int id ) {
|
||||
// issue an Asynchronous STOP command to induce spindown and ejection
|
||||
char cmd[6] = {
|
||||
SCSI_Cmd_StartStopUnit,
|
||||
1, // set the IMMED bit for offline
|
||||
0,
|
||||
0,
|
||||
2, // eject a Jaz disk after stopping
|
||||
0
|
||||
};
|
||||
return scsi_cmd(id, cmd, sizeof(cmd), 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
OSErr iomega_set_prevent_removal( int id, bool lock) {
|
||||
OSErr err;
|
||||
char cmd[6] = {
|
||||
SCSI_Cmd_PreventAllow,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
lock ? 1 : 0,
|
||||
0
|
||||
};
|
||||
return scsi_cmd(id, cmd, sizeof(cmd), 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
OSErr iomega_eject_cartridge( int id ) {
|
||||
OSErr err;
|
||||
err = iomega_set_prevent_removal(id, false);
|
||||
if (err != noErr) return err;
|
||||
return iomega_spin_down_and_eject(id);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <scsi.h>
|
||||
|
||||
typedef Boolean bool;
|
||||
|
||||
OSErr iomega_spin_up_cartridge(int id);
|
||||
OSErr iomega_spin_down_and_eject(int id);
|
||||
OSErr iomega_set_prevent_removal(int id, bool lock);
|
||||
OSErr iomega_eject_cartridge(int id);
|
|
@ -0,0 +1,116 @@
|
|||
#include <scsi.h>
|
||||
#include "mac_scsi.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define READ_TIMEOUT 300 /* 300 ticks = 5 seconds */
|
||||
|
||||
OSErr scsi_reset() {
|
||||
return SCSIReset();
|
||||
}
|
||||
|
||||
OSErr scsi_cmd(int id, void *cmd, size_t clen, void *buff, size_t siz, size_t cnt, int flags, char *status) {
|
||||
SCSIInstr TIB[3]; /* Transfer instruction block */
|
||||
OSErr err;
|
||||
|
||||
/* Set up the TIB (used by Macintosh SCSI Manager) */
|
||||
|
||||
if( cnt != 0 ) {
|
||||
/* Transfer cnt continguous blocks of size siz, one at a time. */
|
||||
/* Use this sort of transfer when doing blind transfers to a */
|
||||
/* disk drive, in order to force the SCSI to poll the bus */
|
||||
/* between each block [Inside Macintosh: Devices, 3-22] */
|
||||
|
||||
TIB[0].scOpcode = scInc;
|
||||
TIB[0].scParam1 = (long) buff;
|
||||
TIB[0].scParam2 = siz;
|
||||
TIB[1].scOpcode = scLoop;
|
||||
TIB[1].scParam1 = -10;
|
||||
TIB[1].scParam2 = cnt;
|
||||
TIB[2].scOpcode = scStop;
|
||||
TIB[2].scParam1 = 0;
|
||||
TIB[2].scParam2 = 0;
|
||||
} else {
|
||||
/* Transfer siz bytes in one fell swoop. */
|
||||
|
||||
TIB[0].scOpcode = scInc;
|
||||
TIB[0].scParam1 = (long) buff;
|
||||
TIB[0].scParam2 = siz;
|
||||
TIB[1].scOpcode = scStop;
|
||||
TIB[1].scParam1 = 0;
|
||||
TIB[1].scParam2 = 0;
|
||||
}
|
||||
|
||||
/* Arbitrate for the bus and select the device. */
|
||||
err = SCSIGet();
|
||||
if (err != noErr) {printf("SCSIGet Error: %d\n", err); return err;}
|
||||
|
||||
err = SCSISelect(id);
|
||||
if (err != noErr) {/*printf("SCSISelect Error: %d\n", err);*/ return err;}
|
||||
|
||||
/* Send the command to the SCSI device and perform the requested I/O */
|
||||
err = SCSICmd( (Ptr) cmd, clen );
|
||||
if (err == noErr) {
|
||||
switch(flags) {
|
||||
case SCSI_WRITE | SCSI_BLIND: err = SCSIWBlind( (Ptr) TIB ); break;
|
||||
case SCSI_READ | SCSI_BLIND: err = SCSIRBlind( (Ptr) TIB ); break;
|
||||
case SCSI_WRITE: err = SCSIWrite( (Ptr) TIB ); break;
|
||||
case SCSI_READ: err = SCSIRead( (Ptr) TIB ); break;
|
||||
default: break;
|
||||
}
|
||||
if (err != noErr) {
|
||||
printf("SCSI Read/Write Error: %d\n", err);
|
||||
}
|
||||
} else {
|
||||
printf("SCSICmd Error: %d", err);
|
||||
}
|
||||
|
||||
/* Complete the transaction and release the bus */
|
||||
short cstat, cmsg;
|
||||
OSErr comperr = SCSIComplete( &cstat, &cmsg, READ_TIMEOUT );
|
||||
if (comperr != noErr) {printf("SCSIComplete Error: %d\n", err); return err;}
|
||||
if(status) *status = cstat;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
OSErr scsi_inquiry(int id, int lun, scsi_inq_reply *reply) {
|
||||
short err;
|
||||
unsigned char cmd[6] = { SCSI_Cmd_Inquiry, lun << 5, 0x00, 0x00, 0x05, 0x00 };
|
||||
|
||||
memset(reply, 0, sizeof(scsi_inq_reply));
|
||||
|
||||
/* First we issue a dummy command to get the additional data field, then */
|
||||
/* we use that number to issue a second command with the corrected length. */
|
||||
|
||||
if( (err = scsi_cmd(id, cmd, sizeof(cmd), reply, cmd[4], 0, SCSI_READ)) != noErr) {
|
||||
return err;
|
||||
}
|
||||
cmd[4] += reply->alen;
|
||||
return scsi_cmd(id, cmd, sizeof(cmd), reply, cmd[4], 0, SCSI_READ);
|
||||
}
|
||||
|
||||
OSErr scsi_request_sense_data(int id, scsi_sense_reply *reply) {
|
||||
short err;
|
||||
unsigned char cmd[6] = { SCSI_Cmd_RequestSense, 0x00, 0x00, 0x00, 0x08, 0x00 };
|
||||
|
||||
memset(reply, 0, sizeof(scsi_sense_reply));
|
||||
|
||||
/* First we issue a dummy command to get the additional data field, then */
|
||||
/* we use that number to issue a second command with the corrected length. */
|
||||
|
||||
if( (err = scsi_cmd(id, cmd, sizeof(cmd), reply, cmd[4], 0, SCSI_READ)) != noErr) {
|
||||
return err;
|
||||
}
|
||||
cmd[4] += reply->alen;
|
||||
return scsi_cmd(id, cmd, sizeof(cmd), reply, cmd[4], 0, SCSI_READ);
|
||||
}
|
||||
|
||||
OSErr scsi_get_class(int id, int lun, int &dev ) {
|
||||
scsi_inq_reply reply;
|
||||
OSErr err = scsi_inquiry(id, lun, &reply );
|
||||
dev = reply.inf1 & 0x1F;
|
||||
return err;
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
#include <stdio.h>
|
||||
|
||||
typedef Boolean bool;
|
||||
|
||||
enum {
|
||||
SCSI_Cmd_RequestSense = 0x03,
|
||||
SCSI_Cmd_FormatUnit = 0x04,
|
||||
SCSI_Cmd_NonSenseData = 0x06,
|
||||
SCSI_Cmd_Read = 0x08,
|
||||
SCSI_Cmd_Write = 0x0a,
|
||||
SCSI_Cmd_CartProtect = 0x0c,
|
||||
SCSI_Cmd_Inquiry = 0x12,
|
||||
SCSI_Cmd_ModeSelect = 0x15,
|
||||
SCSI_Cmd_ModeSense = 0x1a,
|
||||
SCSI_Cmd_StartStopUnit = 0x1b,
|
||||
SCSI_Cmd_SendDiagnostic = 0x1d,
|
||||
SCSI_Cmd_PreventAllow = 0x1e,
|
||||
SCSI_Cmd_TranslateLBA = 0x22,
|
||||
SCSI_Cmd_FormatTest = 0x24,
|
||||
SCSI_Cmd_ReadMany = 0x28,
|
||||
SCSI_Cmd_WriteMany = 0x2a,
|
||||
SCSI_Cmd_Verify = 0x2f,
|
||||
SCSI_Cmd_ReadDefectData = 0x37,
|
||||
SCSI_Cmd_ReadLong = 0x3e,
|
||||
SCSI_Cmd_WriteLong = 0x3f
|
||||
};
|
||||
|
||||
enum {
|
||||
SCSI_DISK = 0x00,
|
||||
SCSI_TAPE = 0x01,
|
||||
SCSI_PRINTER = 0x02,
|
||||
SCSI_CPU_DEVICE = 0x03,
|
||||
SCSI_WORM = 0x04,
|
||||
SCSI_CDROM = 0x05,
|
||||
SCSI_SCANNER = 0x06,
|
||||
SCSI_OPTICAL = 0x07,
|
||||
SCSI_MEDIA_CHANGER = 0x08,
|
||||
SCSI_COM = 0x09,
|
||||
SCSI_UNKNOWN = 0x1F
|
||||
};
|
||||
|
||||
typedef struct { /* | 7 6 5 4 3 2 1 0 | */
|
||||
unsigned char inf1; /* 0 | qualifier | device class | */
|
||||
unsigned char flg1; /* 1 |RMB| reserved | */
|
||||
unsigned char vers; /* 2 | ISO | ECMA | ANSI | */
|
||||
unsigned char inf2; /* 3 |AEN|TIO| rsv | data format | */
|
||||
unsigned char alen; /* 4 | additional length | */
|
||||
unsigned char rsv1[2]; /* 5 | reserved | */
|
||||
unsigned char flg2; /* 7 |rel|W32|W16|Syn|Lnk|Rsv|Que|SRs| */
|
||||
unsigned char vend[8]; /* 8 | manufacturer | */
|
||||
unsigned char prod[16]; /* 16 | product | */
|
||||
unsigned char rvsn[4]; /* 32 | revision | */
|
||||
unsigned char rsv2[20]; /* 36 | vendor unique | */
|
||||
unsigned char rsv3[40]; /* 56 | reserved | */
|
||||
unsigned char rsv4[160]; /* 96 | vendor unique | */
|
||||
} scsi_inq_reply;
|
||||
|
||||
// Reference: https://docs.oracle.com/en/storage/tape-storage/storagetek-sl150-modular-tape-library/slorm/request-sense-03h.html#GUID-9309F2C0-ABF8-470E-AE25-E9535C821B39
|
||||
|
||||
typedef struct { /* | 7 6 5 4 3 2 1 0 | */
|
||||
unsigned char err; /* 0 |OK | error code | */
|
||||
unsigned char seg; /* 1 | segment number | */
|
||||
unsigned char key; /* 2 | reserved | sense key | */
|
||||
unsigned char inf1[4]; /* 3 | information | */
|
||||
unsigned char alen; /* 7 | additional length | */
|
||||
unsigned char inf2[4]; /* 8 | command specific information | */
|
||||
unsigned char asc; /* 12 | additional sense code | */
|
||||
unsigned char ascq; /* 13 | asc qualifier | */
|
||||
unsigned char fruc; /* 14 | field replaceable unit code | */
|
||||
unsigned char flg1; /* 15 |SKV|C/D| Rsv |bpv| bit ptr | */
|
||||
unsigned char fp[2]; /* 16 | field pointer | */
|
||||
unsigned char rsv[2]; /* 18 | reserved | */
|
||||
} scsi_sense_reply;
|
||||
|
||||
/* Flags for scsi_cmd */
|
||||
|
||||
#define SCSI_READ 0x0001
|
||||
#define SCSI_WRITE 0x0002
|
||||
#define SCSI_BLIND 0x0004
|
||||
|
||||
OSErr scsi_reset();
|
||||
OSErr scsi_cmd(int id, void *cmd, size_t clen, void *buff, size_t siz, size_t cnt, int flags, char *status = 0);
|
||||
OSErr scsi_inquiry(int id, int lun, scsi_inq_reply *buff);
|
||||
OSErr scsi_request_sense_data(int id, scsi_sense_reply *buff);
|
||||
OSErr scsi_get_class(int id, int lun, int &dev );
|
||||
|
||||
|
After Width: | Height: | Size: 410 B |
After Width: | Height: | Size: 410 B |
After Width: | Height: | Size: 410 B |
After Width: | Height: | Size: 410 B |
After Width: | Height: | Size: 410 B |
|
@ -0,0 +1,383 @@
|
|||
/*******************************************************************************
|
||||
* TIP.CPP TROUBLE IN PARADISE 05/22/98 *
|
||||
******************************************************************************/
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tip.h"
|
||||
|
||||
// ----------------------- Test Monitor Panel Definitions -------------------
|
||||
#define SET_RECT(LEFT, TOP, RIGHT, BOTTOM) {TOP, LEFT, BOTTOM, RIGHT}
|
||||
|
||||
Rect CS_Stat = SET_RECT(114, 8, 242, 28);
|
||||
Rect TP_Perc = SET_RECT( 12, 56, 409, 72);
|
||||
Rect SS_Jaz = SET_RECT( 12, 94, 409, 126);
|
||||
Rect SS_Sid0 = SET_RECT( 12, 94, 409, 110);
|
||||
Rect TL_Sect = SET_RECT( 75, 154, 203, 170);
|
||||
Rect ES_Read = SET_RECT(346, 154, 409, 170);
|
||||
Rect SE_Rect = SET_RECT(222, 154, 255, 221);
|
||||
|
||||
/*******************************************************************************
|
||||
* WndProc
|
||||
*
|
||||
* This is the system's main window procedure
|
||||
*/
|
||||
void WndProc(long iMessage, long wParam) {
|
||||
// -------------------------------------------------------------------------
|
||||
// WM_PAINT
|
||||
// -------------------------------------------------------------------------
|
||||
if (iMessage == WM_PAINT) {
|
||||
// Draw the Lower Horz Button Divider
|
||||
|
||||
SetColor(GRAY_COLOR);
|
||||
MoveTo(15, 289);
|
||||
LineTo(446, 289);
|
||||
SetColor(WHITE_COLOR);
|
||||
LineTo(446, 290);
|
||||
LineTo(14, 290);
|
||||
|
||||
// Paint the Copyright Notice
|
||||
SetColor(GRAY_COLOR);
|
||||
TextOut(15, 298, szCopyright_1);
|
||||
TextOut(15, 311, szCopyright_2);
|
||||
}
|
||||
// -------------------------------------------------------------------------
|
||||
// WM_COMMAND : a button was pressed
|
||||
// -------------------------------------------------------------------------
|
||||
else if (iMessage == WM_COMMAND) {
|
||||
switch(wParam) {
|
||||
case IDB_QUIT:
|
||||
if (TestingPhase < TESTING_STARTUP) {
|
||||
PostQuitMessage();
|
||||
}
|
||||
break;
|
||||
case IDB_TEST:
|
||||
switch(CartridgeStatus) {
|
||||
case DISK_SPUN_DOWN:
|
||||
SpinUpIomegaCartridge(CurrentDevice);
|
||||
break;
|
||||
case DISK_AT_SPEED:
|
||||
printf("Testing the disk\n");
|
||||
if(TestingPhase != READY_TO_TEST) {
|
||||
PrepareToBeginTesting();
|
||||
}
|
||||
TestTheDisk();
|
||||
printf("Test finished\n");
|
||||
break;
|
||||
case DISK_TEST_UNDERWAY:
|
||||
UserInterrupt = 1;
|
||||
break;
|
||||
case DISK_Z_TRACK_FAILURE:
|
||||
case DISK_TEST_FAILURE:
|
||||
case DISK_PROTECTED:
|
||||
//EjectIomegaCartridge();
|
||||
break;
|
||||
case DISK_LOW_SPARES:
|
||||
PrepareToBeginTesting();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BtnList tipBtns[] = {
|
||||
{IDB_TEST, szPressToStart, 200, 301, 160, 24, true}, // Added by MLT
|
||||
{IDB_BACK, szBack, 185-28, 301, 80, 24, false},
|
||||
{IDB_NEXT, szNext, 264-28, 301, 80, 24, false},
|
||||
{IDB_QUIT, szQuit, 367+35, 301, 45, 24, true},
|
||||
{0, 0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* SUNKEN FIELDS
|
||||
*******************************************************************************/
|
||||
void SunkenFields(Rect *pFirstRect, long count, long yspacing) {
|
||||
Rect drawRect;
|
||||
drawRect = *pFirstRect; // make a local copy
|
||||
do {
|
||||
DrawEdge(&drawRect, BDR_SUNKENOUTER, BF_RECT);
|
||||
drawRect.top += yspacing;
|
||||
drawRect.bottom += yspacing;
|
||||
} while(--count);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PAINT TEXT ARRAY
|
||||
*******************************************************************************/
|
||||
void PaintTextArray(TextList *list, long color) {
|
||||
SetColor(color);
|
||||
for(int i = 0; list[i].str; i++) {
|
||||
TextOut(list[i].x, list[i].y, list[i].str);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PAINT TEST PHASE
|
||||
*******************************************************************************/
|
||||
void PaintTestPhase() {
|
||||
DrawLed(320, 5, TestingPhase == READING_DATA ? GREEN_COLOR : BACK_COLOR);
|
||||
DrawLed(336, 5, TestingPhase == WRITING_PATT ? RED_COLOR : BACK_COLOR);
|
||||
DrawLed(336, 21, TestingPhase == READING_PATT ? GREEN_COLOR : BACK_COLOR);
|
||||
DrawLed(320, 21, TestingPhase == WRITING_DATA ? RED_COLOR : BACK_COLOR);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PAINT CART STATUS
|
||||
*
|
||||
* Paints the textual cartridge status window
|
||||
*******************************************************************************/
|
||||
void PaintCartStatus() {
|
||||
// blank out any previous status display
|
||||
SetColor(BACK_COLOR);
|
||||
Rectangle(115, 9, 241, 27);
|
||||
// display the new cartridge status
|
||||
long eax = CartridgeStatus - 1;
|
||||
if(eax < 0 || eax >= LAST_CART_STATUS) {
|
||||
eax = 0;
|
||||
}
|
||||
// pickup the pointer to the string
|
||||
const char *esi;
|
||||
//if (DriveCount) {
|
||||
esi = CartStatStrings[eax];
|
||||
//} else {
|
||||
// esi = szNoIomegaDrives;
|
||||
//}
|
||||
SetColor(BLACK_COLOR);
|
||||
TextOutCentered(115, 9, 241 - 115, 27 - 9, esi);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PAINT BAR GRAPH
|
||||
*******************************************************************************/
|
||||
void PaintBarGraph(int Xleft, int Ytop, int XWidth, int YHeight, long BarColor, long BarValue, char *pRightText, bool Active) {
|
||||
// fill the entire rectangle with background gray
|
||||
SetColor(BACK_COLOR);
|
||||
Rectangle(Xleft, Ytop, Xleft + XWidth, Ytop + YHeight);
|
||||
if (Active) { // now fleshout the bar ONLY IF we're active
|
||||
// if RightText string is non-null, paint it in darker gray
|
||||
if(pRightText) {
|
||||
SetColor(GRAY_COLOR);
|
||||
TextOutCentered(Xleft, Ytop, XWidth, YHeight, pRightText);
|
||||
}
|
||||
// now paint the active portion
|
||||
const long AbsoluteBarWidth = XWidth * BarValue / 100;
|
||||
SetColor(BarColor, BLACK_COLOR);
|
||||
Rectangle(Xleft, Ytop, Xleft + AbsoluteBarWidth, Ytop + YHeight);
|
||||
// now place the floating percentage into the middle (if it fits there)
|
||||
if(BarValue) {
|
||||
char PercentString[8];
|
||||
sprintf(PercentString, szBarChartPercent, BarValue);
|
||||
SetColor(WHITE_COLOR);
|
||||
TextOutCentered(Xleft, Ytop, AbsoluteBarWidth, YHeight, PercentString);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PAINT THE BAR GRAPHS
|
||||
*
|
||||
* This paints the two or three bar graphs on the test monitor window.
|
||||
*******************************************************************************/
|
||||
void PaintTheBarGraphs(bool Active) {
|
||||
long ebx, ecx;
|
||||
PaintBarGraph(13, 57, 395, 14, BLUE_COLOR, PercentComplete, NULL, Active);
|
||||
if(JazDrive) {
|
||||
ebx = Side_0_SparesCount;
|
||||
ecx = MAXIMUM_JAZ_SPARES;
|
||||
if(ebx > ecx) { // if Spares > MAXIMUM
|
||||
ebx = ecx; // clip Spares down to MAX
|
||||
}
|
||||
PaintBarGraph(13, 95, 395, 30, RED_COLOR, ebx*100/ecx, NULL, Active);
|
||||
} else {
|
||||
ebx = Side_0_SparesCount;
|
||||
ecx = MAXIMUM_ZIP_SPARES;
|
||||
PaintBarGraph(13, 95, 395, 14, RED_COLOR, ebx*100/ecx, "Side 0", Active);
|
||||
ebx = Side_1_SparesCount;
|
||||
ecx = MAXIMUM_ZIP_SPARES;
|
||||
PaintBarGraph(13, 111, 395, 14, RED_COLOR, ebx*100/ecx, "Side 1", Active);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PAINT CENTERED STRING
|
||||
*
|
||||
* Paubts a string int a rectangular region
|
||||
*******************************************************************************/
|
||||
void PaintCenteredString(int Xleft, int Ytop, int XWidth, int YHeight, const char *pText, bool Active) {
|
||||
// fill the entire rectangle with background gray
|
||||
SetColor(BACK_COLOR);
|
||||
Rectangle(Xleft, Ytop, Xleft + XWidth, Ytop + YHeight);
|
||||
// now fleshout the bitmap ONLY IF we're active
|
||||
if(Active) {
|
||||
SetColor(BLACK_COLOR);
|
||||
TextOutCentered(Xleft, Ytop, XWidth, YHeight, pText);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PAINT CENTERED VALUE
|
||||
*
|
||||
* Paints a decimal-value into a rectangular region
|
||||
*******************************************************************************/
|
||||
void PaintCenteredValue(int Xleft, int Ytop, int XWidth, int YHeight, long value, bool Active) {
|
||||
char szString[40];
|
||||
// convert our value into a string
|
||||
sprintf(szString, szCenteredDecimal, value);
|
||||
// and paint it's value
|
||||
PaintCenteredString(Xleft, Ytop, XWidth, YHeight, szString, Active);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PAINT TEST STATISTICS
|
||||
*
|
||||
* This paints the two columns of testing statistics on the test minitor window.
|
||||
*******************************************************************************/
|
||||
void PaintTestStatistics(bool Active) {
|
||||
char szString[40];
|
||||
// assemble and paint the sector testing range
|
||||
long eax = SingleTransferLBA;
|
||||
if (eax) {
|
||||
sprintf(szString, szCenteredDecimal, eax);
|
||||
} else {
|
||||
eax = FirstLBASector;
|
||||
if (!TestingPhase) {
|
||||
eax = 0;
|
||||
}
|
||||
sprintf(szString, szCenteredDecimal, eax);
|
||||
strcat(szString, szSpaceDashSpace);
|
||||
eax = FirstLBASector + NumberOfLBAs;
|
||||
if (TestingPhase == READY_TO_TEST) {
|
||||
eax = LastLBAOnCartridge;
|
||||
}
|
||||
sprintf(szString + strlen(szString), szCenteredDecimal, eax);
|
||||
}
|
||||
PaintCenteredString(76, 155, 126, 14, szString, Active);
|
||||
|
||||
// show the LastError
|
||||
char *errStr = 0;
|
||||
for (int i = 0; errorTypeList[i].str; i++) {
|
||||
errStr = errorTypeList[i].str;
|
||||
if (errorTypeList[i].code == LastError) break;
|
||||
}
|
||||
PaintCenteredString(76, 172, 126, 14, errStr, Active);
|
||||
|
||||
// show the elapsed time
|
||||
CvrtSecondsToHMSstring(szString, SecondsElapsed);
|
||||
PaintCenteredString(76, 189, 126, 14, szString, Active);
|
||||
|
||||
// see if it's time for us to estimate...
|
||||
if(SecondsElapsed - ElapsedTimeOfLastEstimate > 15 && PercentComplete > 0) {
|
||||
// assemble the remaining time
|
||||
ElapsedTimeOfLastEstimate = SecondsElapsed;
|
||||
CurrentTotalTimeEstimate = SecondsElapsed * 100 / PercentComplete;
|
||||
}
|
||||
|
||||
// given the current estimate time, show the remaining time!
|
||||
eax = CurrentTotalTimeEstimate;
|
||||
if(eax) {
|
||||
eax -= SecondsElapsed;
|
||||
if(eax < 0) eax = 0;
|
||||
CvrtSecondsToHMSstring(szString, eax);
|
||||
} else {
|
||||
strcpy(szString, szEstimating);
|
||||
}
|
||||
PaintCenteredString(76, 206, 126, 14, szString, Active);
|
||||
|
||||
// now show the error accumulations...
|
||||
long TotalErrors = SoftErrors + FirmErrors + HardErrors;
|
||||
PaintCenteredValue(347, 155, 61, 14, SoftErrors, Active);
|
||||
PaintCenteredValue(347, 172, 61, 14, FirmErrors, Active);
|
||||
PaintCenteredValue(347, 189, 61, 14, HardErrors, Active);
|
||||
PaintCenteredValue(347, 206, 61, 14, TotalErrors, Active);
|
||||
}
|
||||
|
||||
void CvrtSecondsToHMSstring(char *szString, long seconds) {
|
||||
const long h = (seconds / 3600);
|
||||
const long m = (seconds / 60) % 60;
|
||||
const long s = (seconds % 60);
|
||||
sprintf(szString, szHoursMinsSecs, h, m, s);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* TEST MONITOR WND PROC
|
||||
*******************************************************************************/
|
||||
void TestMonitorWndProc() {
|
||||
long eax;
|
||||
SetColor(BLACK_COLOR);
|
||||
TextOut(12, 9, szCartStatus);
|
||||
DrawEdge(&CS_Stat, BDR_SUNKENOUTER, BF_RECT);
|
||||
PaintCartStatus();
|
||||
|
||||
// draw the sunken rectangles
|
||||
DrawEdge(&TP_Perc, BDR_SUNKENOUTER, BF_RECT);
|
||||
DrawEdge(&SE_Rect, BDR_SUNKENOUTER, BF_RECT);
|
||||
SunkenFields(&TL_Sect, 4, 17);
|
||||
SunkenFields(&ES_Read, 4, 17);
|
||||
if(JazDrive) { // draw a single LARGE rectangle
|
||||
DrawEdge(&SS_Jaz, BDR_SUNKENOUTER, BF_RECT);
|
||||
} else { // draw a pair of smaller rectangles
|
||||
SunkenFields(&SS_Sid0, 2, 16);
|
||||
}
|
||||
if((CartridgeStatus == DISK_AT_SPEED) || (CartridgeStatus == DISK_SPUN_DOWN) || (CartridgeStatus >= DISK_LOW_SPARES)) {
|
||||
PaintTheBarGraphs(true);
|
||||
PaintTestStatistics(true);
|
||||
eax = BLACK_COLOR;
|
||||
} else {
|
||||
PaintTheBarGraphs(false);
|
||||
PaintTestStatistics(false);
|
||||
eax = GRAY_COLOR;
|
||||
}
|
||||
PaintTextArray(TestBlackText, eax);
|
||||
PaintTextArray(TestGrayText, GRAY_COLOR);
|
||||
PaintTestPhase();
|
||||
|
||||
// TODO: paint the little speaker icon
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* UPDATE RUN TIME DISPLAY
|
||||
*******************************************************************************/
|
||||
|
||||
void UpdateRunTimeDisplay() {
|
||||
GetDC(hTestMonitor);
|
||||
PaintTestPhase();
|
||||
PaintTheBarGraphs(true);
|
||||
PaintTestStatistics(true);
|
||||
PaintCartStatus();// Added by MLT
|
||||
ReleaseDC(hTestMonitor);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* UPDATE CURRENT SECTOR
|
||||
*******************************************************************************/
|
||||
|
||||
void UpdateCurrentSector() {
|
||||
GetDC(hTestMonitor);
|
||||
char szString[40];
|
||||
sprintf(szString, szCenteredDecimal, SingleTransferLBA);
|
||||
PaintCenteredString(76, 155, 126, 14, szString, true);
|
||||
ReleaseDC(hTestMonitor);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* UPDATE RUN PHASE DISPLAY
|
||||
*******************************************************************************/
|
||||
|
||||
void UpdateRunPhaseDisplay() {
|
||||
GetDC(hTestMonitor);
|
||||
PaintTestPhase();
|
||||
ReleaseDC(hTestMonitor);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* ERROR SOUND
|
||||
*******************************************************************************/
|
||||
|
||||
void ErrorSound() {
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
|
||||
typedef Boolean bool;
|
||||
|
||||
extern WindowPtr tipWindow;
|
||||
|
||||
void run_tip();
|
||||
|
||||
#define MINIMUM_JAZ_SPARES 500
|
||||
#define MAXIMUM_JAZ_SPARES 2557
|
||||
#define MINIMUM_ZIP_SPARES 50
|
||||
#define MAXIMUM_ZIP_SPARES 126
|
||||
|
||||
extern long CurrentDevice;
|
||||
extern bool JazDrive; // true if the current drive
|
||||
extern long CartridgeStatus;
|
||||
extern long LastLBAOnCartridge;
|
||||
extern unsigned long StartingInstant;
|
||||
extern long NumberOfLBAs;
|
||||
extern long Side_0_SparesCount; // JAZ has only one count
|
||||
extern long Side_1_SparesCount; // ZIP has counts for both sides
|
||||
extern long Initial_Side_0_Spares;
|
||||
extern long Initial_Side_1_Spares;
|
||||
extern long TestingPhase; // 0 = not testing, no data ...
|
||||
extern long PercentComplete;
|
||||
extern long FirstLBASector;
|
||||
extern long NumberOfLBAs;
|
||||
extern long SecondsElapsed;
|
||||
extern long SoftErrors;
|
||||
extern long FirmErrors;
|
||||
extern long HardErrors;
|
||||
extern long ElapsedTimeOfLastEstimate;
|
||||
extern long CurrentTotalTimeEstimate;
|
||||
extern bool UserInterrupt;
|
||||
extern long LastError;
|
||||
extern long SingleTransferLBA;
|
||||
|
||||
// ----------------------- Macintosh Compatibility -----------------------
|
||||
|
||||
enum {
|
||||
BACK_COLOR = -1,
|
||||
BLACK_COLOR = 0x000000,
|
||||
LTGRAY_COLOR = 0xc0c0c0,
|
||||
GRAY_COLOR = 0x808080,
|
||||
WHITE_COLOR = 0xffffff,
|
||||
BLUE_COLOR = 0x0000ff,
|
||||
RED_COLOR = 0xff0000,
|
||||
GREEN_COLOR = 0x00ff00,
|
||||
};
|
||||
|
||||
#define BDR_SUNKENOUTER 1
|
||||
#define BF_RECT 1
|
||||
#define WM_PAINT 1
|
||||
#define WM_COMMAND 2
|
||||
|
||||
void SetColor(long color);
|
||||
void SetColor(long color, long monoColor);
|
||||
void DrawLed(int x, int y, long color);
|
||||
void StrToPascal(Str255 pStr, const char *str);
|
||||
long GetTextExtent(const char *str, unsigned long len);
|
||||
void TextOut(int x, int y, Str255 str);
|
||||
void TextOut(int x, int y, const char *str);
|
||||
void TextOutCentered(int x, int y, int w, int h, const char *str);
|
||||
void SetButtonText(const char *str);
|
||||
void Rectangle(int left, int top, int right, int bottom);
|
||||
void DrawEdge(Rect *qrc, int edge, int grfFlags);
|
||||
void PostQuitMessage();
|
||||
unsigned long GetSystemTime();
|
||||
|
||||
#define hTestMonitor -20, -10
|
||||
#define hMainWnd 0, 40
|
||||
|
||||
#define GetDC(h) {GrafPtr oldPort; \
|
||||
GetPort(&oldPort); \
|
||||
SetPort(tipWindow); \
|
||||
SetOrigin(h);
|
||||
|
||||
#define ReleaseDC(h) SetOrigin(0,0); \
|
||||
SetPort(oldPort);}
|
||||
|
||||
|
||||
// ------------------------------ Cartridge Status -------------------------------
|
||||
|
||||
enum {
|
||||
DISK_STATUS_UNKNOWN = 1,
|
||||
DISK_AT_SPEED = 2,
|
||||
DISK_SPINNING_UP = 3,
|
||||
DISK_NOT_PRESENT = 4,
|
||||
DISK_SPUN_DOWN = 5,
|
||||
DISK_STALLED = 6,
|
||||
DISK_Z_TRACK_FAILURE = 7,
|
||||
DISK_PROTECTED = 8,
|
||||
DISK_LOW_SPARES = 9,
|
||||
DISK_TEST_UNDERWAY = 10,
|
||||
DISK_TEST_FAILURE = 11,
|
||||
|
||||
LAST_CART_STATUS = 11
|
||||
};
|
||||
|
||||
// ---------------------------- Testing Phase Status -----------------------------
|
||||
|
||||
enum {
|
||||
UNTESTED = 0,
|
||||
READY_TO_TEST = 1,
|
||||
TESTING_STARTUP = 2,
|
||||
READING_DATA = 3,
|
||||
WRITING_PATT = 4,
|
||||
READING_PATT = 5,
|
||||
WRITING_DATA = 6
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* STRINGS
|
||||
*******************************************************************************/
|
||||
|
||||
extern const char *szWindowTitle;
|
||||
extern const char *szCopyright_1;
|
||||
extern const char *szCopyright_2;
|
||||
extern const char *szSide0;
|
||||
extern const char *szSide1;
|
||||
extern const char *szSpaceDashSpace;
|
||||
extern const char *szBarChartPercent;
|
||||
extern const char *szCenteredDecimal;
|
||||
extern const char *szCenteredHex;
|
||||
extern const char *szHoursMinsSecs;
|
||||
extern const char *szCartStatus;
|
||||
extern const char *szEstimating;
|
||||
extern const char *szOneMoment;
|
||||
extern const char *szPressToStart;
|
||||
extern const char *szPressToStop;
|
||||
extern const char *szPressToSpin;
|
||||
extern const char *szPressToEject;
|
||||
extern const char *szPressToProceed;
|
||||
|
||||
/************* Cartridge Status Text *************/
|
||||
|
||||
typedef struct {long code; char *str;} ErrorTypeList;
|
||||
typedef struct {int x, y; char *str;} TextList;
|
||||
|
||||
extern const char *szUnknownStat;
|
||||
extern const char *szAtSpeedStat;
|
||||
extern const char *szSpinningUp;
|
||||
extern const char *szNotPresent;
|
||||
extern const char *szSpunDown;
|
||||
extern const char *szStalledStat;
|
||||
extern const char *szZtrackFailure;
|
||||
extern const char *szDiskLocked;
|
||||
extern const char *szLowSpares;
|
||||
extern const char *szTestUnderway;
|
||||
extern const char *DriveUnderTest;
|
||||
extern const char *szTestFailure;
|
||||
extern const char *szNoIomegaDrives;
|
||||
|
||||
extern const char *CartStatStrings[];
|
||||
|
||||
extern ErrorTypeList errorTypeList[];
|
||||
extern TextList TestBlackText[];
|
||||
extern TextList TestGrayText[];
|
||||
|
||||
/************* Window Creation Data **************/
|
||||
|
||||
extern const char *szBack;
|
||||
extern const char *szNext;
|
||||
extern const char *szQuit;
|
||||
|
||||
#define IDB_BACK 0xFF00
|
||||
#define IDB_NEXT 0xFF01
|
||||
#define IDB_QUIT 0xFF02
|
||||
#define IDB_TEST 0xFF03
|
||||
|
||||
typedef struct {long id; const char *name; int x; int y; int w; int h; bool visible;} BtnList;
|
||||
extern BtnList tipBtns[];
|
||||
|
||||
/*******************************************************************************
|
||||
* FUNCTION PROTOTYPES
|
||||
*******************************************************************************/
|
||||
|
||||
void PaintCenteredString(int Xleft, int Ytop, int XWidth, int YHeight, const char *pText, bool Active);
|
||||
void PaintCenteredValue(int Xleft, int Ytop, int XWidth, int YHeight, long value, bool Active);
|
||||
void SunkenFields(Rect *pFirstRect, long count, long yspacing);
|
||||
void PaintCartStatus();
|
||||
void PaintTextArray(TextList *list, long color);
|
||||
void PaintBarGraph(int Xleft, int Ytop, int XWidth, int YHeight, long BarColor, long BarValue, char *pRightText, bool Active);
|
||||
void PaintTestPhase();
|
||||
void PaintTheBarGraphs(bool Active);
|
||||
void PaintTestStatistics(bool Active);
|
||||
void CvrtSecondsToHMSstring(char *szString, long seconds);
|
||||
|
||||
void UpdateCurrentSector();
|
||||
void UpdateRunTimeDisplay();
|
||||
void UpdateRunPhaseDisplay();
|
||||
void ErrorSound();
|
||||
void ProcessPendingMessages();
|
||||
void WndProc(long iMessage, long wParam);
|
||||
void TestMonitorWndProc();
|
||||
void TestButtonClicked();
|
||||
|
||||
void GetCommandDetails(char command, char &cmd_flags, char &cmd_length);
|
||||
long SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, short IoBufLen);
|
||||
long GetModePage(short Device, short PageToGet, void *pBuffer, short BufLen);
|
||||
long SetModePage(short Device, void *pBuffer);
|
||||
void ModifyModePage(char *PageBuff, char eec, char retries);
|
||||
void SetErrorRecovery(bool Retries, bool ECC, bool Testing);
|
||||
long GetNonSenseData(short Device, short DataPage, void *Buffer, short BufLen);
|
||||
long LockCurrentDrive();
|
||||
long UnlockCurrentDrive();
|
||||
long SpinUpIomegaCartridge(short Device);
|
||||
void GetSpareSectorCounts(bool);
|
||||
long PerformRegionTransfer(short XferCmd, void *pBuffer);
|
||||
long TestTheDisk();
|
||||
long GetElapsedTimeInSeconds();
|
||||
void PrepareToBeginTesting();
|
||||
void BumpErrorCounts(long ErrorCode);
|
|
@ -0,0 +1,684 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "mac_scsi.h"
|
||||
#include "tip.h"
|
||||
|
||||
//#define DEMO
|
||||
|
||||
#define BYTE_AT(a) *((char*)&(a))
|
||||
#define WORD_AT(a) *((short*)&(a))
|
||||
#define DWORD_AT(a) *((long*)&(a))
|
||||
|
||||
#define MAKE_LITTLE_ENDIAN(a) a // Don't do anything on 68000
|
||||
#define MAKE_BIG_ENDIAN(a) a // Don't do anything on 68000
|
||||
|
||||
// offsets to the various sector data images
|
||||
|
||||
#define ZIP_100_PART 0x0000
|
||||
#define ZIP_100_BOOT 0x0200
|
||||
#define ZIP_250_PART 0x0400
|
||||
#define ZIP_250_BOOT 0x0600
|
||||
#define JAZ_1GB_PART 0x0800
|
||||
#define JAZ_1GB_BOOT 0x0A00
|
||||
#define JAZ_2GB_PART 0x0C00
|
||||
#define JAZ_2GB_BOOT 0x0E00
|
||||
|
||||
struct DEFECT_LIST_HEADER {
|
||||
char DLH_reserved; // (00h)
|
||||
char DLH_BitFlags; // [000] [P] [G] [xxx - defect list format]
|
||||
char DLH_DefectListLength;
|
||||
};
|
||||
|
||||
//-------------------------- Drive Array Status Flags ---------------------------
|
||||
|
||||
#define JAZ_DRIVE 0x00010000
|
||||
#define MEDIA_CHANGED 0x00020000
|
||||
#define DISK_EJECTING 0x00040000 // we've asked for eject and waiting ...
|
||||
#define ODD_BYTE_COMPENSATION 0x00080000 // special handling for ODD length PSWD
|
||||
#define MAX_DRIVE_COUNT 16 // we can handle up to 16 Zip/Jaz drives
|
||||
|
||||
#define ERROR_RECOVERY_PAGE 1 // From disassembly
|
||||
#define FORMAT_STATUS_PAGE 1
|
||||
#define DISK_STATUS_PAGE 2
|
||||
|
||||
#define NEW_DISK_STATUS_OFFSET 3 // newer offset of the Disk Status Byte
|
||||
#define OLD_DISK_STATUS_OFFSET 1 // older offset of the Disk Status Byte
|
||||
|
||||
#define JAZ_SPARES_COUNT_OFFSET 68 // offsets into DiskStat tbl
|
||||
#define NEW_ZIP_SIDE_0_SPARES_COUNT_OFFSET 13
|
||||
#define NEW_ZIP_SIDE_1_SPARES_COUNT_OFFSET 17
|
||||
#define OLD_ZIP_SIDE_0_SPARES_COUNT_OFFSET 11
|
||||
#define OLD_ZIP_SIDE_1_SPARES_COUNT_OFFSET 15
|
||||
#define JAZ_PROTECT_MODE_OFFSET 21
|
||||
#define NEW_ZIP_PROTECT_MODE_OFFSET 21
|
||||
#define OLD_ZIP_PROTECT_MODE_OFFSET 19
|
||||
#define JAZ_LAST_LBA_OFFSET 5
|
||||
#define NEW_ZIP_LAST_LBA_OFFSET 5
|
||||
#define OLD_ZIP_LAST_LBA_OFFSET 3
|
||||
|
||||
#define DRIVE_A_SUPPORT_BIAS 32 // reduce total by 32 for DRIVE A support
|
||||
|
||||
#define BYTES_PER_SECTOR 512
|
||||
#define MAX_SECTORS_PER_TEST 20
|
||||
|
||||
#define BADNESS_THRESHOLD 10
|
||||
|
||||
#define SS_ERR 0x00000004 // From disassembly
|
||||
#define BUFFER_TOO_BIG 0x00FFFFE6 // From disassembly
|
||||
#define LBA_TOO_LARGE 0x00210005 // From disassembly
|
||||
#define INCOMPATIBLE_MEDIA 0x00300002 // From disassembly
|
||||
#define MEDIA_NOT_PRESENT 0x003a0002 // From disassembly
|
||||
#define DEFECT_LIST_READ_ERROR 0x001c0003 // From disassembly
|
||||
|
||||
#define CHECK_CONDITION 0x02
|
||||
|
||||
enum {
|
||||
szBadResult,
|
||||
szInterrupted,
|
||||
szExplainResult,
|
||||
szPerfectResult
|
||||
};
|
||||
|
||||
long CurrentDevice = 0;
|
||||
|
||||
bool JazDrive; // true if the current drive
|
||||
long CartridgeStatus = /*DISK_NOT_PRESENT*/ DISK_AT_SPEED;
|
||||
|
||||
unsigned long StartingInstant;
|
||||
|
||||
// ----------------------------- Run Time Variables ------------------------------
|
||||
|
||||
long Side_0_SparesCount; // JAZ has only one count
|
||||
long Side_1_SparesCount; // ZIP has counts for both sides
|
||||
long Initial_Side_0_Spares;
|
||||
long Initial_Side_1_Spares;
|
||||
|
||||
long TestingPhase; // 0 = not testing, no data ...
|
||||
long PercentComplete;
|
||||
long FirstLBASector;
|
||||
long NumberOfLBAs;
|
||||
long LastLBAOnCartridge;
|
||||
long SecondsElapsed;
|
||||
long SoftErrors;
|
||||
long FirmErrors;
|
||||
long HardErrors;
|
||||
long ElapsedTimeOfLastEstimate;
|
||||
long CurrentTotalTimeEstimate;
|
||||
bool UserInterrupt;
|
||||
long LastError;
|
||||
long SingleTransferLBA;
|
||||
|
||||
/*******************************************************************************
|
||||
* GET COMMAND DETAILS
|
||||
*
|
||||
* Given a SCSI command byte, this returns the command
|
||||
* block length in AL and the Command Flags in AH
|
||||
*******************************************************************************/
|
||||
|
||||
#define TEN_BYTE_CMDS 0x1F
|
||||
#define SRB_DIR_IN SCSI_READ
|
||||
#define SRB_DIR_OUT SCSI_WRITE
|
||||
|
||||
void GetCommandDetails(char command, char &cmd_flags, char &cmd_length) {
|
||||
char CommandDetailsTable[] = {
|
||||
SCSI_Cmd_RequestSense, SRB_DIR_IN, // 03 IN == get from drive
|
||||
SCSI_Cmd_FormatUnit, 0, // 04 OUT == send to drive
|
||||
SCSI_Cmd_NonSenseData, SRB_DIR_IN, // 06
|
||||
SCSI_Cmd_Read, SRB_DIR_IN, // 08
|
||||
SCSI_Cmd_Write, SRB_DIR_OUT, // 0A
|
||||
SCSI_Cmd_CartProtect, SRB_DIR_OUT, // 0C
|
||||
SCSI_Cmd_Inquiry, SRB_DIR_IN, // 12
|
||||
SCSI_Cmd_ModeSelect, SRB_DIR_OUT, // 15
|
||||
SCSI_Cmd_ModeSense, SRB_DIR_IN, // 1A
|
||||
SCSI_Cmd_StartStopUnit, 0, // 1B
|
||||
SCSI_Cmd_SendDiagnostic, 0, // 1D
|
||||
SCSI_Cmd_PreventAllow, 0, // 1E
|
||||
SCSI_Cmd_TranslateLBA, SRB_DIR_IN, // 22
|
||||
SCSI_Cmd_FormatTest, 0, // 24
|
||||
SCSI_Cmd_ReadMany, SRB_DIR_IN, // 28
|
||||
SCSI_Cmd_WriteMany, SRB_DIR_OUT, // 2A
|
||||
SCSI_Cmd_Verify, 0, // 2F
|
||||
SCSI_Cmd_ReadDefectData, SRB_DIR_IN, // 37
|
||||
SCSI_Cmd_ReadLong, SRB_DIR_IN, // 3E
|
||||
SCSI_Cmd_WriteLong, SRB_DIR_OUT // 3F
|
||||
};
|
||||
cmd_flags = 0; // ; if we don't locate it ... return ZERO
|
||||
// search the table for the command entry
|
||||
for(int i = 0; i < sizeof(CommandDetailsTable); i += 2) {
|
||||
if(CommandDetailsTable[i] == command) { // if we match we're done
|
||||
cmd_flags = CommandDetailsTable[i+1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
cmd_length = 6; // presume a short (6 byte) command
|
||||
if(command > TEN_BYTE_CMDS) // but if it's a LONG one ....
|
||||
cmd_length = 10;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* SCSI COMMAND
|
||||
*
|
||||
* This executes a SCSI command through the interface. It receives a
|
||||
* pointer to a standard SCSI command block (SCB) and a pointer and
|
||||
* length to an IoBuffer for the command. It returns the complete
|
||||
* three-byte sense code from the command.
|
||||
*******************************************************************************/
|
||||
long SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, short IoBufLen) {
|
||||
char cmd_length, cmd_flags, cmd_status;
|
||||
GetCommandDetails(lpCmdBlk[0], cmd_flags, cmd_length);
|
||||
// call the SCSI interface to forward the command to the device
|
||||
OSErr err = scsi_cmd(Device, lpCmdBlk, cmd_length, lpIoBuf, IoBufLen, 0, cmd_flags, &cmd_status);
|
||||
if(err != noErr) {
|
||||
return SS_ERR;
|
||||
}
|
||||
if(cmd_status == 0) {
|
||||
printf("SCSI OK\n");
|
||||
// if the command did not generate any Sense Data, just return NULL
|
||||
return 0;
|
||||
}
|
||||
else if(cmd_status == 2) { // Check Condition
|
||||
printf("SCSI CHK CONDITION\n");
|
||||
// Request sense data
|
||||
scsi_sense_reply sense_data;
|
||||
scsi_request_sense_data(Device, &sense_data);
|
||||
// okay, we have an SS_ERR condition, let's check the SENSE DATA
|
||||
// assemble [00 ASC ASCQ SenseKey]
|
||||
return (sense_data.asc << 16) ||
|
||||
(sense_data.ascq << 8) ||
|
||||
sense_data.key;
|
||||
}
|
||||
else {
|
||||
// else, if it's *NOT* a "Sense Data" error (SS_ERR)
|
||||
return cmd_status | 0x00FFFF00; // [00 FF FF er]
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* GET MODE PAGE
|
||||
*******************************************************************************/
|
||||
long GetModePage(short Device, short PageToGet, void *pBuffer, short BufLen) {
|
||||
char Scsi[6] = {0};
|
||||
Scsi[0] = SCSI_Cmd_ModeSense;
|
||||
Scsi[2] = PageToGet;
|
||||
Scsi[4] = BufLen;
|
||||
return SCSICommand(Device, Scsi, pBuffer, BufLen);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* SET MODE PAGE
|
||||
*******************************************************************************/
|
||||
long SetModePage(short Device, void *pBuffer) {
|
||||
char Scsi[6] = {0}; // init the SCSI parameter block
|
||||
char* ebx = (char*) pBuffer; // get a pointer to the top of buffer
|
||||
char ecx = ebx[0] + 1; // adjust it up by one
|
||||
Scsi[0] = SCSI_Cmd_ModeSelect; // set the command
|
||||
Scsi[1] = 0x10; // set the Page Format bit
|
||||
Scsi[4] = ecx; // set the parameter list length
|
||||
return SCSICommand(Device, Scsi, pBuffer, ecx);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* SET ERROR RECOVERY
|
||||
*******************************************************************************/
|
||||
void ModifyModePage(char *PageBuff, char ecc, char retries) {
|
||||
long eax = PageBuff[3]; // get the Block Descriptor Length
|
||||
|
||||
char *ebx = PageBuff + 4; // get just past the header address
|
||||
// form ebx == the offset to the top of the page we've read ...
|
||||
ebx += eax;
|
||||
|
||||
ebx[0] &= ~0x80; // always turn off the PS bit (parameters savable)
|
||||
ebx[2] = 0xC0 | ecc; // set the ECC fields
|
||||
ebx[3] = retries; // set the common retry count
|
||||
if(ebx[1] > 6) // if we have a large format page...
|
||||
ebx[8] = retries; // then set the write count too
|
||||
}
|
||||
|
||||
void SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
|
||||
char PageBuff[40];
|
||||
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, sizeof(PageBuff));
|
||||
|
||||
#define EARLY_RECOVERY 0x08
|
||||
#define PER 0x04
|
||||
#define SUPPRESS_ECC 0x01
|
||||
|
||||
// set the ECC fields
|
||||
char ecc = SUPPRESS_ECC; // presume ECC suppression
|
||||
if(ECC) {
|
||||
ecc = EARLY_RECOVERY; // enable ECC and Early Recovery
|
||||
if(Testing) {
|
||||
ecc = EARLY_RECOVERY | PER; // we're testing, so EER & PER
|
||||
}
|
||||
}
|
||||
|
||||
// set the retry counts
|
||||
char retries = 0x16; // set retries to 22 for Zip drive
|
||||
if(JazDrive)
|
||||
retries = 0x64; // and to 100 for Jaz drive
|
||||
if(!Retries) // But if we have no retries ...
|
||||
retries = 0;
|
||||
|
||||
ModifyModePage(PageBuff, ecc, retries);
|
||||
long eax = SetModePage(CurrentDevice, PageBuff);
|
||||
// if we had an invalid field in the CDB (the EER bit was on)
|
||||
if (eax == 0x00260005) {
|
||||
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, sizeof(PageBuff));
|
||||
ecc &= ~0x08; // same, *BUT*NOT* Early Recovery
|
||||
ModifyModePage(PageBuff, ecc, retries);
|
||||
SetModePage(CurrentDevice, PageBuff);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* GET NON-SENSE PAGE DATA
|
||||
*
|
||||
* Given Adapter, Device, DataPage, and a Buffer to receive the data, this
|
||||
* fills the buffer we're given and returns with the SCSI Completion Code
|
||||
*******************************************************************************/
|
||||
long GetNonSenseData(short Device, short DataPage, void *Buffer, short BufLen) {
|
||||
char Scsi[6] = {0};
|
||||
Scsi[0] = SCSI_Cmd_NonSenseData; // do a Non-Sense Data Read
|
||||
Scsi[2] = DataPage; // which page to read
|
||||
Scsi[4] = BufLen; // tell drive page is this long
|
||||
return SCSICommand(Device, Scsi, Buffer, BufLen);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* LOCK CURRENT DRIVE
|
||||
*******************************************************************************/
|
||||
long LockCurrentDrive() {
|
||||
char Scsi[6] = {0};
|
||||
Scsi[0] = SCSI_Cmd_PreventAllow;
|
||||
Scsi[4] = 1; // set to ONE to lock the drive
|
||||
return SCSICommand(CurrentDevice, Scsi, NULL, 0);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* UNLOCK CURRENT DRIVE
|
||||
*******************************************************************************/
|
||||
long UnlockCurrentDrive() {
|
||||
char Scsi[6] = {0};
|
||||
Scsi[0] = SCSI_Cmd_PreventAllow;
|
||||
return SCSICommand(CurrentDevice, Scsi, NULL, 0);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* SPIN UP IOMEGA CARTRIDGE
|
||||
*******************************************************************************/
|
||||
long SpinUpIomegaCartridge(short Device) {
|
||||
char Scsi[6] = {0};
|
||||
Scsi[0] = SCSI_Cmd_StartStopUnit;
|
||||
Scsi[1] = 1; // set the IMMED bit for offline
|
||||
Scsi[4] = 1; // start the disk spinning
|
||||
return SCSICommand(Device, Scsi, NULL, 0);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* GET SPARE SECTOR COUNTS
|
||||
*
|
||||
* This returns NON-ZERO if we have trouble and posted the error message
|
||||
* into the RichText control, else it sets the number of spares available
|
||||
*******************************************************************************/
|
||||
|
||||
void GetSpareSectorCounts(bool) {
|
||||
DEFECT_LIST_HEADER DefectHeader;
|
||||
long eax = 0, ebx, edx;
|
||||
short ch, cl;
|
||||
ListChk:
|
||||
// ask for the defect list to make sure we're able to read it
|
||||
char Scsi[10] = {0};
|
||||
Scsi[0] = SCSI_Cmd_ReadDefectData;
|
||||
Scsi[2] = 0x1e; // 0b00011110 defect format, G/P bits
|
||||
Scsi[8] = 4; // ask for only FOUR bytes
|
||||
eax = SCSICommand(CurrentDevice, Scsi, &DefectHeader, sizeof(DefectHeader));
|
||||
if ((!eax) || (eax == INCOMPATIBLE_MEDIA)) {
|
||||
// we could read its defect list ... so show it!
|
||||
// --------------------------------------------------------------------------
|
||||
// MLT: looks like on the Iomega Zip 100, the maximum size for DiskStat is 63
|
||||
// rather than 72; it looks like this code is causing a SCSI transfer error
|
||||
// here... might be better to conditionally check for Jaz drive
|
||||
char DiskStat[72];
|
||||
eax = GetNonSenseData(CurrentDevice, DISK_STATUS_PAGE, DiskStat, sizeof(DiskStat));
|
||||
if (!eax) /*goto ListChk;*/ return;
|
||||
// --------------------------------------------------------------------------
|
||||
ch = 0; // clear the DRIVE_A_SUPPORT
|
||||
if (JazDrive) {
|
||||
eax = WORD_AT(DiskStat[JAZ_SPARES_COUNT_OFFSET]);
|
||||
ebx = 0;
|
||||
cl = BYTE_AT(DiskStat[JAZ_PROTECT_MODE_OFFSET]);
|
||||
edx = DWORD_AT(DiskStat[JAZ_LAST_LBA_OFFSET]);
|
||||
} else {
|
||||
if (DiskStat[0] == DISK_STATUS_PAGE) {
|
||||
eax = WORD_AT(DiskStat[NEW_ZIP_SIDE_0_SPARES_COUNT_OFFSET]);
|
||||
ebx = WORD_AT(DiskStat[NEW_ZIP_SIDE_1_SPARES_COUNT_OFFSET]);
|
||||
cl = BYTE_AT(DiskStat[NEW_ZIP_PROTECT_MODE_OFFSET]);
|
||||
edx = DWORD_AT(DiskStat[NEW_ZIP_LAST_LBA_OFFSET]);
|
||||
ch--; // set the DRIVE_A_SUPPORT
|
||||
}
|
||||
else {
|
||||
eax = WORD_AT(DiskStat[OLD_ZIP_SIDE_0_SPARES_COUNT_OFFSET]);
|
||||
ebx = WORD_AT(DiskStat[OLD_ZIP_SIDE_1_SPARES_COUNT_OFFSET]);
|
||||
cl = BYTE_AT(DiskStat[OLD_ZIP_PROTECT_MODE_OFFSET]);
|
||||
edx = DWORD_AT(DiskStat[OLD_ZIP_LAST_LBA_OFFSET]);
|
||||
}
|
||||
if(ebx == 0) {
|
||||
CartridgeStatus = DISK_TEST_FAILURE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
//---------------------------
|
||||
// bswap edx; save the last LBA in any event
|
||||
//---------------------------
|
||||
if(ch) {
|
||||
edx -= DRIVE_A_SUPPORT_BIAS;
|
||||
}
|
||||
LastLBAOnCartridge = edx;
|
||||
MAKE_LITTLE_ENDIAN(eax); // make it little endian
|
||||
Side_0_SparesCount = eax;
|
||||
MAKE_LITTLE_ENDIAN(ebx); // make it little endian
|
||||
Side_1_SparesCount = ebx;
|
||||
// compute the number of troubles we encountered during the testing
|
||||
FirmErrors = Initial_Side_0_Spares - Side_0_SparesCount;
|
||||
FirmErrors += Initial_Side_1_Spares - Side_1_SparesCount;
|
||||
// check to see whether we have ANY spare sectors remaining
|
||||
if(!Side_0_SparesCount && !Side_1_SparesCount) {
|
||||
CartridgeStatus = DISK_TEST_FAILURE;
|
||||
return;
|
||||
}
|
||||
// MLT: The code for removing the ZIP protection has been omitted
|
||||
return; // return zero since no error
|
||||
}
|
||||
else {
|
||||
// trouble of some sort ... so suppress controls and
|
||||
// show the richedit control for the trouble
|
||||
if (eax == DEFECT_LIST_READ_ERROR) {
|
||||
CartridgeStatus = DISK_Z_TRACK_FAILURE;
|
||||
return;
|
||||
}
|
||||
else if (eax == MEDIA_NOT_PRESENT) {
|
||||
CartridgeStatus = MEDIA_NOT_PRESENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* GET ELAPSED TIME IN SECONDS
|
||||
*******************************************************************************/
|
||||
long GetElapsedTimeInSeconds() {
|
||||
return GetSystemTime() - StartingInstant;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PREPARE TO BEGIN TESTING
|
||||
*******************************************************************************/
|
||||
void PrepareToBeginTesting() {
|
||||
// Zero all of the testing variables
|
||||
TestingPhase = 0; // 0 = not testing, no data ...
|
||||
PercentComplete = 0;
|
||||
FirstLBASector = 0;
|
||||
NumberOfLBAs = 0;
|
||||
SoftErrors = 0;
|
||||
FirmErrors = 0;
|
||||
HardErrors = 0;
|
||||
UserInterrupt = 0;
|
||||
LastError = 0;
|
||||
#ifdef DEMO
|
||||
LastLBAOnCartridge = 99999;
|
||||
SoftErrors = 6;
|
||||
FirmErrors = 2;
|
||||
HardErrors = 1;
|
||||
UserInterrupt = 0;
|
||||
LastError = 0x0C8001;
|
||||
Side_0_SparesCount = 12;
|
||||
Side_1_SparesCount = 20;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* BUMP ERROR COUNTS
|
||||
*
|
||||
* See: https://en.wikipedia.org/wiki/Key_Code_Qualifier
|
||||
*******************************************************************************/
|
||||
void BumpErrorCounts(long ErrorCode) {
|
||||
long eax = ErrorCode;
|
||||
if (eax == BUFFER_TOO_BIG) { // if we got BUFFER TOO BIG, halt!
|
||||
UserInterrupt = 1;
|
||||
}
|
||||
long ebx = eax & 0x00FF00FF; // mask off the middle byte
|
||||
if (ebx == 0x00150004) // if it was one of the many seek
|
||||
eax = ebx; // errors, cvrt to seek error
|
||||
if (eax)
|
||||
LastError = eax;
|
||||
if (eax == 0x320003 || eax == 0x328F03)
|
||||
CartridgeStatus = DISK_LOW_SPARES;
|
||||
if (eax & 0xFF == 1) // recovered error
|
||||
SoftErrors++;
|
||||
else
|
||||
HardErrors++;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PERFORM REGION TRANSFER
|
||||
*******************************************************************************/
|
||||
long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
||||
return -1;
|
||||
char Scsi[10] = {0}; // clear out the SCSI CDB
|
||||
const long InitialHardErrors = HardErrors;
|
||||
|
||||
SetErrorRecovery(false, false, true); // disable Retries & ECC
|
||||
|
||||
Scsi[0] = XferCmd;
|
||||
DWORD_AT(Scsi[2]) = MAKE_BIG_ENDIAN(FirstLBASector); // WHICH LBA's to read, BIG endian
|
||||
WORD_AT(Scsi[7]) = MAKE_BIG_ENDIAN(NumberOfLBAs); // HOW MANY to read, BIG endian
|
||||
long eax = SCSICommand(CurrentDevice, Scsi, pBuffer, NumberOfLBAs * BYTES_PER_SECTOR);
|
||||
|
||||
return 1;
|
||||
// if we failed somewhere during our transfer ... let's zero in on it
|
||||
if (eax) {
|
||||
if ( eax == SS_ERR || // if it's a CONTROLLER ERROR, skip!
|
||||
eax == BUFFER_TOO_BIG ||
|
||||
eax == LBA_TOO_LARGE) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Save error and current Soft + Hard Error count to see if we do FIND the glitch ...
|
||||
const long GlitchError = eax; // save the error which stopped us!
|
||||
const long GlitchCount = SoftErrors + HardErrors;
|
||||
char *LocalBuffer = (char*) pBuffer;
|
||||
ErrorSound();
|
||||
|
||||
SingleTransferLBA = FirstLBASector;
|
||||
|
||||
// Perform transfer LBA block at a time
|
||||
for(long i = 0; i < NumberOfLBAs; ++i) {
|
||||
UpdateCurrentSector();
|
||||
|
||||
// setup for our series of transfer tests ...
|
||||
|
||||
// disable all recovery techniques
|
||||
SetErrorRecovery(false, false, true); // disable Retries & ECC
|
||||
|
||||
memset(Scsi, 0, sizeof(Scsi)); // clear out the SCSI CDB
|
||||
Scsi[0] = XferCmd;
|
||||
DWORD_AT(Scsi[2]) = MAKE_BIG_ENDIAN(SingleTransferLBA); // WHICH LBA to read, BIG endian
|
||||
WORD_AT(Scsi[7]) = MAKE_BIG_ENDIAN(1); // a single sector
|
||||
eax = SCSICommand(CurrentDevice, Scsi, LocalBuffer, BYTES_PER_SECTOR);
|
||||
|
||||
if (eax) {
|
||||
// some sort of problem encountered!
|
||||
if (eax == SS_ERR) goto Exit; // if it's a CONTROLLER ERROR, skip!
|
||||
if (eax & 0xFF == 1) goto PostTheError; // did we recover?
|
||||
|
||||
SetErrorRecovery(true, false, true); // enable retries
|
||||
eax = SCSICommand(CurrentDevice, Scsi, LocalBuffer, BYTES_PER_SECTOR);
|
||||
if (eax) {
|
||||
// failed with retries
|
||||
if (eax == SS_ERR) goto Exit; // if it's a CONTROLLER ERROR, skip!
|
||||
if (eax & 0xFF == 1) goto PostTheError; // did we recover?
|
||||
|
||||
SetErrorRecovery(true, true, true); // enable retries AND EEC
|
||||
eax = SCSICommand(CurrentDevice, Scsi, LocalBuffer, BYTES_PER_SECTOR);
|
||||
if (eax) {
|
||||
// failed with retries and EEC
|
||||
if (eax == SS_ERR) goto Exit; // if it's a CONTROLLER ERROR, skip!
|
||||
if (eax & 0xFF == 1) goto PostTheError; // did we recover?
|
||||
}
|
||||
else { // succeeded with ECC
|
||||
eax = 0x180101; // "ECC & Retries"
|
||||
}
|
||||
} // succeeded with retries
|
||||
else {
|
||||
eax = 0x170101; // "Read with Retries"
|
||||
if (XferCmd == SCSI_Cmd_WriteMany)
|
||||
eax = 0x0C8001; // "Wrote with Retries"
|
||||
}
|
||||
|
||||
PostTheError:
|
||||
BumpErrorCounts(eax); // given eax, count the errors
|
||||
GetSpareSectorCounts(false); // update the Cart's Condition
|
||||
UpdateRunTimeDisplay();
|
||||
|
||||
LocalBuffer += BYTES_PER_SECTOR;
|
||||
SingleTransferLBA++;
|
||||
if(UserInterrupt) break;
|
||||
}
|
||||
ProcessPendingMessages();
|
||||
}
|
||||
|
||||
// now see whether we *did* found something to complain about ...
|
||||
eax = SoftErrors + HardErrors;
|
||||
if (eax == GlitchCount) {
|
||||
// we missed it ... but SOMETHING happened! So let's report it ...
|
||||
const long SavedSoftErrors = SoftErrors; // save the existing counts
|
||||
const long SavedHardErrors = HardErrors;
|
||||
eax = GlitchError; // get the error that triggered our search
|
||||
long ebx = eax & 0x00FF00FF; // strip the ASCQ byte
|
||||
if(ebx == 0x00110003) // if we're about to say "unrecovered read"
|
||||
eax = 0x170101; // change it to: "Read with Retries"
|
||||
BumpErrorCounts(eax); // given eax, count the errors
|
||||
HardErrors = SavedHardErrors; // restore the counts
|
||||
SoftErrors = SavedSoftErrors;
|
||||
SoftErrors++;
|
||||
UpdateRunTimeDisplay();
|
||||
}
|
||||
SingleTransferLBA = 0;
|
||||
eax = 0; // now let's return happiness to our caller
|
||||
if (HardErrors != InitialHardErrors) // UNRECOVERABLE errors!
|
||||
eax = -1;
|
||||
}
|
||||
|
||||
Exit:
|
||||
SetErrorRecovery(true, true, false); // reenable Retries & ECC
|
||||
return eax;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* TEST THE DISK
|
||||
*******************************************************************************/
|
||||
|
||||
long TestTheDisk() {
|
||||
void *pPatternBuffer = malloc(MAX_SECTORS_PER_TEST * BYTES_PER_SECTOR);
|
||||
void *pUserDataBuffer = malloc(MAX_SECTORS_PER_TEST * BYTES_PER_SECTOR);
|
||||
|
||||
if(pPatternBuffer == NULL || pUserDataBuffer == NULL) {
|
||||
printf("Allocation error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
CartridgeStatus = DISK_TEST_UNDERWAY;
|
||||
TestingPhase = TESTING_STARTUP; // inhibit stopping now
|
||||
SetButtonText(szPressToStop);
|
||||
|
||||
LockCurrentDrive(); // prevent media removal
|
||||
|
||||
// Standard Testing Operation
|
||||
StartingInstant = GetSystemTime();
|
||||
|
||||
do {
|
||||
ProcessPendingMessages();
|
||||
|
||||
NumberOfLBAs = MAX_SECTORS_PER_TEST;
|
||||
|
||||
if(LastLBAOnCartridge) {
|
||||
if (FirstLBASector + NumberOfLBAs > LastLBAOnCartridge + 1) {
|
||||
NumberOfLBAs = LastLBAOnCartridge - FirstLBASector + 1;
|
||||
}
|
||||
// compute the percentage complete
|
||||
PercentComplete = FirstLBASector * 100 / LastLBAOnCartridge;
|
||||
}
|
||||
|
||||
if(NumberOfLBAs == 0) break;
|
||||
|
||||
// uppdate the elapsed time
|
||||
SecondsElapsed = GetElapsedTimeInSeconds();
|
||||
|
||||
// get a random pattern of data to write
|
||||
const long DataPattern = rand();
|
||||
memset(pPatternBuffer, DataPattern, sizeof(pPatternBuffer));
|
||||
|
||||
// update the cartridge's status
|
||||
GetSpareSectorCounts(false); // update the Cart's Condition
|
||||
|
||||
TestingPhase = READING_DATA;
|
||||
|
||||
UpdateRunTimeDisplay();
|
||||
|
||||
long eax = PerformRegionTransfer(SCSI_Cmd_ReadMany, pUserDataBuffer);
|
||||
|
||||
if(eax == 0) {
|
||||
// -------------------------------
|
||||
TestingPhase = WRITING_PATT;
|
||||
UpdateRunPhaseDisplay();
|
||||
PerformRegionTransfer(SCSI_Cmd_WriteMany, pPatternBuffer);
|
||||
// -------------------------------
|
||||
TestingPhase = READING_PATT;
|
||||
UpdateRunPhaseDisplay();
|
||||
PerformRegionTransfer(SCSI_Cmd_Verify, pPatternBuffer);
|
||||
// -------------------------------
|
||||
TestingPhase = WRITING_DATA;
|
||||
UpdateRunPhaseDisplay();
|
||||
PerformRegionTransfer(SCSI_Cmd_Verify, pUserDataBuffer);
|
||||
}
|
||||
else if (eax == LBA_TOO_LARGE) {
|
||||
// if we hit the end of the disk ... exit gracefully!
|
||||
goto GetOut;
|
||||
}
|
||||
if (CartridgeStatus != DISK_TEST_UNDERWAY) {
|
||||
break;
|
||||
}
|
||||
// bump the FirstLBASector up for the next transfer
|
||||
FirstLBASector += NumberOfLBAs;
|
||||
} while(!UserInterrupt);
|
||||
// show that we're post-test
|
||||
|
||||
GetOut:
|
||||
free(pPatternBuffer);
|
||||
free(pUserDataBuffer);
|
||||
|
||||
TestingPhase = UNTESTED;
|
||||
UnlockCurrentDrive();
|
||||
SetErrorRecovery(true, true, false); // reenable Retries & ECC
|
||||
SetButtonText(szPressToStart);
|
||||
CartridgeStatus = DISK_AT_SPEED;
|
||||
UpdateRunTimeDisplay(); // added by mlt
|
||||
|
||||
// compute the number of serious troubles
|
||||
long errors = FirmErrors + HardErrors;
|
||||
if (errors >= BADNESS_THRESHOLD) {
|
||||
return szBadResult;
|
||||
}
|
||||
else if (UserInterrupt) {
|
||||
return szInterrupted;
|
||||
}
|
||||
else {
|
||||
// it wasn't interrupted, nor seriously bad, was it perfect?
|
||||
errors += SoftErrors;
|
||||
if(errors) {
|
||||
return szExplainResult;
|
||||
} else {
|
||||
return szPerfectResult;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,370 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <SIOUX.h>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <Quickdraw.h>
|
||||
|
||||
#include "tip.h"
|
||||
|
||||
WindowPtr tipWindow;
|
||||
|
||||
static int gDone;
|
||||
static bool AllowColor;
|
||||
static ControlHandle actionBtn = 0;
|
||||
|
||||
void NewTipWindow();
|
||||
void DestroyTipWindow();
|
||||
void DoEvent(EventRecord &event, RgnHandle *cursorRgn);
|
||||
void DoUpdate(WindowPtr window);
|
||||
void DoMouseDown(EventRecord &event);
|
||||
void DoMouseMove(EventRecord &event, RgnHandle *cursorRegion);
|
||||
|
||||
void run_tip(void) {
|
||||
RgnHandle cursorRgn = NewRgn();
|
||||
|
||||
NewTipWindow();
|
||||
gDone = false;
|
||||
do {
|
||||
EventRecord event;
|
||||
if (WaitNextEvent(everyEvent, &event, GetCaretTime(), cursorRgn)) {
|
||||
DoEvent(event, &cursorRgn);
|
||||
}
|
||||
} while (!gDone);
|
||||
|
||||
DestroyTipWindow();
|
||||
DisposeRgn(cursorRgn);
|
||||
}
|
||||
|
||||
void NewTipWindow() {
|
||||
OSErr error;
|
||||
SysEnvRec theWorld;
|
||||
|
||||
error = SysEnvirons(1, &theWorld);
|
||||
AllowColor = theWorld.hasColorQD;
|
||||
|
||||
Rect rect = qd.screenBits.bounds;
|
||||
InsetRect(&rect, 50, 50);
|
||||
rect.bottom = rect.top + 336 - 35;
|
||||
rect.right = rect.left + 467;
|
||||
|
||||
Str255 title;
|
||||
StrToPascal(title, szWindowTitle);
|
||||
tipWindow = AllowColor ?
|
||||
NewCWindow(NULL,&rect, title, true, 0, 0, true, 0) :
|
||||
NewWindow(NULL,&rect, title, true, 0, 0, true, 0);
|
||||
|
||||
GetDC(hMainWnd);
|
||||
|
||||
if (AllowColor) {
|
||||
SetColor(BACK_COLOR);
|
||||
RGBColor bgColor;
|
||||
GetForeColor(&bgColor);
|
||||
RGBBackColor(&bgColor);
|
||||
}
|
||||
TextSize(10);
|
||||
|
||||
for(int i = 0; tipBtns[i].name; i++) {
|
||||
if (!tipBtns[i].visible) continue;
|
||||
SetRect(&rect,
|
||||
tipBtns[i].x,
|
||||
tipBtns[i].y,
|
||||
tipBtns[i].x + tipBtns[i].w,
|
||||
tipBtns[i].y + tipBtns[i].h
|
||||
);
|
||||
|
||||
StrToPascal(title, tipBtns[i].name);
|
||||
ControlHandle h = NewControl(tipWindow, &rect, title, true, 0, 0, 0, 0, tipBtns[i].id);
|
||||
if(tipBtns[i].id == IDB_TEST) {
|
||||
actionBtn = h;
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseDC(hMainWnd);
|
||||
}
|
||||
|
||||
void DestroyTipWindow() {
|
||||
DisposeWindow(tipWindow);
|
||||
}
|
||||
|
||||
void DoEvent(EventRecord &event, RgnHandle *cursorRgn) {
|
||||
if(!SIOUXHandleOneEvent(&event)) {
|
||||
// If SIOUX didn't handle the event, then handle it ourselves
|
||||
switch(event.what) {
|
||||
case mouseDown: DoMouseDown(event); break;
|
||||
case updateEvt: DoUpdate((WindowPtr)event.message); break;
|
||||
case osEvt: DoMouseMove(event, cursorRgn); break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DoUpdate(WindowPtr window) {
|
||||
BeginUpdate(window);
|
||||
SetPort(window);
|
||||
EraseRect(&window->portRect);
|
||||
|
||||
GetDC(hMainWnd);
|
||||
WndProc(WM_PAINT, 0);
|
||||
DrawControls(window);
|
||||
ReleaseDC(hMainWnd);
|
||||
|
||||
GetDC(hTestMonitor);
|
||||
TestMonitorWndProc();
|
||||
ReleaseDC(hTestMonitor);
|
||||
|
||||
EndUpdate(window);
|
||||
}
|
||||
|
||||
void DoMouseDown(EventRecord &event) {
|
||||
WindowPtr thisWindow;
|
||||
ControlHandle thisControl;
|
||||
int part = FindWindow(event.where, &thisWindow);
|
||||
switch(part) {
|
||||
case inSysWindow:
|
||||
SystemClick(&event, thisWindow);
|
||||
break;
|
||||
case inContent:
|
||||
if(thisWindow != FrontWindow()) {
|
||||
SelectWindow(thisWindow);
|
||||
}
|
||||
else if(thisWindow == tipWindow) {
|
||||
long id = 0;
|
||||
Point mouse = event.where;
|
||||
GetDC(hMainWnd);
|
||||
GlobalToLocal(&mouse);
|
||||
if(FindControl(mouse, thisWindow, &thisControl) == inButton) {
|
||||
if(TrackControl(thisControl, mouse, 0) == inButton) {
|
||||
id = GetControlReference(thisControl);
|
||||
}
|
||||
}
|
||||
ReleaseDC(hMainWnd);
|
||||
if(id) {
|
||||
WndProc(WM_COMMAND, id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case inDrag:
|
||||
DragWindow(thisWindow, event.where, &(*GetGrayRgn())->rgnBBox);
|
||||
break;
|
||||
case inGrow:
|
||||
//DoGrowWindow(thisWindow, event);
|
||||
break;
|
||||
case inGoAway:
|
||||
if (TrackGoAway(thisWindow, event.where)) {
|
||||
gDone = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DoMouseMove(EventRecord &event, RgnHandle *cursorRgn) {
|
||||
WindowPtr thisWindow;
|
||||
int part = FindWindow(event.where, &thisWindow);
|
||||
if (thisWindow == tipWindow) {
|
||||
InitCursor();
|
||||
// Set the cursorRegion to everything inside our window
|
||||
if(cursorRgn) {
|
||||
CopyRgn(((WindowPeek)tipWindow)->contRgn, *cursorRgn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StrToPascal(Str255 pStr, const char *str) {
|
||||
size_t len = strlen(str);
|
||||
pStr[0] = (len > 255) ? 255 : len;
|
||||
strncpy((char*)pStr + 1, str, 255);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* SET COLOR
|
||||
*******************************************************************************/
|
||||
|
||||
void SetColor(long color) {
|
||||
if (AllowColor) {
|
||||
if(color == BACK_COLOR) color = LTGRAY_COLOR;
|
||||
// Use colors when available
|
||||
RGBColor rgbColor;
|
||||
rgbColor.red = (color & 0xFF0000) >> 8;
|
||||
rgbColor.green = (color & 0x00FF00) >> 0;
|
||||
rgbColor.blue = (color & 0x0000FF) << 8;
|
||||
RGBForeColor(&rgbColor);
|
||||
} else {
|
||||
// Use patterns for B&W Macs
|
||||
TextMode(srcCopy);
|
||||
switch(color) {
|
||||
case BACK_COLOR:
|
||||
case WHITE_COLOR:
|
||||
PenPat(&qd.white);
|
||||
TextMode(srcBic);
|
||||
break;
|
||||
case BLACK_COLOR:
|
||||
case GRAY_COLOR:
|
||||
PenPat(&qd.black);
|
||||
break;
|
||||
case RED_COLOR:
|
||||
case BLUE_COLOR:
|
||||
PenPat(&qd.ltGray);
|
||||
break;
|
||||
case LTGRAY_COLOR:
|
||||
case GREEN_COLOR:
|
||||
PenPat(&qd.gray);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetColor(long color, long monoColor) {
|
||||
if (AllowColor) {
|
||||
SetColor(color);
|
||||
} else {
|
||||
SetColor(monoColor);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* DRAW LED
|
||||
*******************************************************************************/
|
||||
|
||||
void DrawLed(int x, int y, long color) {
|
||||
Rect ledRect;
|
||||
SetRect(&ledRect, x, y, x + 12, y + 12);
|
||||
// Draw the LED
|
||||
SetColor(color);
|
||||
PaintOval(&ledRect);
|
||||
if (AllowColor) {
|
||||
// Draw a recessed outline
|
||||
SetColor(BLACK_COLOR);
|
||||
FrameOval(&ledRect);
|
||||
SetColor(WHITE_COLOR);
|
||||
FrameArc(&ledRect,45,180);
|
||||
} else {
|
||||
// Draw a non-recessed outline
|
||||
SetColor(BLACK_COLOR);
|
||||
FrameOval(&ledRect);
|
||||
SetColor(WHITE_COLOR);
|
||||
}
|
||||
// Draw the reflection
|
||||
if(color != BACK_COLOR) {
|
||||
ledRect.left += 3;
|
||||
ledRect.top += 3;
|
||||
ledRect.right -= 7;
|
||||
ledRect.bottom -= 7;
|
||||
OffsetRect(&ledRect,0,1);
|
||||
PaintRect(&ledRect);
|
||||
OffsetRect(&ledRect,1,-1);
|
||||
PaintRect(&ledRect);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* DRAW EDGE
|
||||
*******************************************************************************/
|
||||
|
||||
void DrawEdge(Rect *qrc, int edge, int grfFlags) {
|
||||
if(edge == BDR_SUNKENOUTER && AllowColor) {
|
||||
// Draw a sunken rectangle
|
||||
SetColor(GRAY_COLOR);
|
||||
MoveTo(qrc->left,qrc->bottom-1);
|
||||
LineTo(qrc->left,qrc->top);
|
||||
LineTo(qrc->right-1,qrc->top);
|
||||
SetColor(WHITE_COLOR);
|
||||
MoveTo(qrc->left,qrc->bottom-1);
|
||||
LineTo(qrc->right-1,qrc->bottom-1);
|
||||
LineTo(qrc->right-1,qrc->top);
|
||||
} else {
|
||||
// Draw a non-recessed rectangle
|
||||
SetColor(LTGRAY_COLOR);
|
||||
FrameRect(qrc);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* RECTANGLE
|
||||
*******************************************************************************/
|
||||
|
||||
void Rectangle(int left, int top, int right, int bottom) {
|
||||
Rect rect;
|
||||
SetRect(&rect, left, top, right, bottom);
|
||||
PaintRect(&rect);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* TEXT OUT
|
||||
*******************************************************************************/
|
||||
|
||||
void TextOut(int x, int y, Str255 pStr) {
|
||||
FontInfo info;
|
||||
GetFontInfo(&info);
|
||||
MoveTo(x, y + info.ascent + info.descent);
|
||||
DrawString(pStr);
|
||||
}
|
||||
|
||||
void TextOut(int x, int y, const char *str) {
|
||||
Str255 pStr;
|
||||
StrToPascal(pStr, str);
|
||||
TextOut(x, y, pStr);
|
||||
}
|
||||
|
||||
void TextOutCentered(int x, int y, int w, int h, const char *str) {
|
||||
// convert to Pascal string
|
||||
Str255 pStr;
|
||||
StrToPascal(pStr, str);
|
||||
// now place the floating string in the middle
|
||||
const int width = TextWidth(pStr, 0, strlen(str));
|
||||
if(width < w) {
|
||||
TextOut(x + w/2 - width/2, y, pStr);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* GET TEXT EXTENT
|
||||
*******************************************************************************/
|
||||
long GetTextExtent(const char *str, unsigned long len) {
|
||||
// convert to Pascal string
|
||||
Str255 pStr;
|
||||
StrToPascal(pStr, str);
|
||||
// now place the floating string in the middle
|
||||
return TextWidth(pStr, 0, len);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* GET SYSTEM TIME
|
||||
*******************************************************************************/
|
||||
unsigned long GetSystemTime() {
|
||||
unsigned long time;
|
||||
GetDateTime (&time);
|
||||
return time;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* SET BUTTON TEXT
|
||||
*******************************************************************************/
|
||||
void SetButtonText(const char *str) {
|
||||
Str255 pStr;
|
||||
StrToPascal(pStr, str);
|
||||
if(actionBtn) {
|
||||
GetDC(hMainWnd);
|
||||
SetCTitle(actionBtn, pStr);
|
||||
ReleaseDC(hMainWnd);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* POST QUIT MESSAGE
|
||||
*******************************************************************************/
|
||||
void PostQuitMessage() {
|
||||
gDone = true;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PROCESS PENDING MESSAGES
|
||||
*******************************************************************************/
|
||||
void ProcessPendingMessages() {
|
||||
EventRecord event;
|
||||
if (GetNextEvent(everyEvent, &event)) {
|
||||
DoEvent(event,NULL);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
#include "tip.h"
|
||||
|
||||
const char *szWindowTitle = "TIP 2.1b -- Zip & Jaz Drive and Cartridge Testing System";
|
||||
const char *szCopyright_1 = "Copyright (c) 2006 by";
|
||||
const char *szCopyright_2 = "Gibson Research Corp.";
|
||||
|
||||
const char *szSide0 = "Side 0";
|
||||
const char *szSide1 = "Side 1";
|
||||
const char *szSpaceDashSpace = " - ";
|
||||
|
||||
const char *szBarChartPercent = " %ld%% ";
|
||||
const char *szCenteredDecimal = "%ld";
|
||||
const char *szCenteredHex = "ErrorCode: %06lX";
|
||||
const char *szHoursMinsSecs = "%ld:%02ld:%02ld";
|
||||
|
||||
const char *szCartStatus = "Cartridge Status:";
|
||||
const char *szEstimating = "Estimating ...";
|
||||
const char *szOneMoment = "--- --- ---";
|
||||
const char *szPressToStart = "Press to Begin";
|
||||
const char *szPressToStop = "Press to Stop";
|
||||
const char *szPressToSpin = "Press to Spin Up";
|
||||
const char *szPressToEject = "Press to Eject";
|
||||
const char *szPressToProceed = "Press to Proceed";
|
||||
|
||||
/************* Cartridge Status Text *************/
|
||||
|
||||
const char *szUnknownStat = "Ejecting Cartridge";
|
||||
const char *szAtSpeedStat = "Ready to Test";
|
||||
const char *szSpinningUp = "Spinning Up";
|
||||
const char *szNotPresent = "Awaiting Cartridge";
|
||||
const char *szSpunDown = "Not Spinning";
|
||||
const char *szStalledStat = "Stalled Error";
|
||||
const char *szZtrackFailure = "Z-Tracks Failure !!";
|
||||
const char *szDiskLocked = "Disk Protected";
|
||||
const char *szLowSpares = "Low Spares Count";
|
||||
const char *szTestUnderway = "Testing Drive ";
|
||||
const char *DriveUnderTest = "X: ...";
|
||||
const char *szTestFailure = "Testing Failed";
|
||||
const char *szNoIomegaDrives = "No Iomega Drives";
|
||||
|
||||
const char *CartStatStrings[] = {
|
||||
szUnknownStat, szAtSpeedStat, szSpinningUp,
|
||||
szNotPresent, szSpunDown, szStalledStat,
|
||||
szZtrackFailure, szDiskLocked, szLowSpares,
|
||||
szTestUnderway, szTestFailure
|
||||
};
|
||||
|
||||
ErrorTypeList errorTypeList[] = {
|
||||
0x00000000, "-- None So Far --",
|
||||
|
||||
0x001C0000, "Missing Defect List",
|
||||
|
||||
0x000C0101, "Wrote with Realloc",
|
||||
0x000C8001, "Wrote with Retries",
|
||||
0x000C8101, "Wrote with Off Track",
|
||||
0x000C8201, "Wrote w/o SectorMark",
|
||||
0x000C8301, "Wrote with ID skip",
|
||||
0x00170101, "Read with Retries",
|
||||
0x00170601, "Retried & Realloc",
|
||||
0x00180001, "Data Corrected",
|
||||
0x00180101, "ECC & Retries",
|
||||
0x00180201, "ECC & Realloc'd",
|
||||
0x001C8F01, "Defect List Recvr'd",
|
||||
|
||||
0x00040002, "Drive Not Ready",
|
||||
0x00040102, "Drive Going Ready",
|
||||
0x00040202, "Drive Not Ready #2",
|
||||
0x00040302, "Drive Needs Help",
|
||||
0x00040402, "Not Rdy - Formating",
|
||||
0x00300002, "Incompatible Media",
|
||||
0x003A0002, "Media Not Present",
|
||||
|
||||
0x00010003, "Missing Sector Mark",
|
||||
0x00030003, "Off Track Write",
|
||||
0x00100003, "Bad ID Checksum",
|
||||
0x00110003, "Unrecovered Read",
|
||||
0x00118003, "Unrecovered Read",
|
||||
0x00120003, "MissingID Sync",
|
||||
0x00130003, "Missing Addr Mark",
|
||||
0x00140003, "Sector Not Found",
|
||||
0x00160003, "Sync Mark Missing",
|
||||
0x001C0003, "Defect List Error",
|
||||
0x00310003, "Corrupt Media Format",
|
||||
0x00310103, "Format Command Fail",
|
||||
// 0x0031xx03, " -- failures --"
|
||||
0x00320003, "No Spare Sectors", // abort on this
|
||||
0x00328F03, "No Spare Tracks", // abort on this
|
||||
|
||||
0x00018104, "Missing Sector Pulse",
|
||||
0x00090004, "Track Follow Error",
|
||||
0x00150004, "Head Seek Failure",
|
||||
0x00220004, "Cartridge Sense Fail",
|
||||
// 0x0040xx04, "Self Test Failed",
|
||||
0x00470004, "Data Parity Error",
|
||||
// 0x00xx0004, "Vendor Specific Error",
|
||||
|
||||
0x00290006, "I/O Bus Reset Error",
|
||||
|
||||
0x0088010B, "Reassigned Blk Err",
|
||||
0x0088020B, "Side Switch Error",
|
||||
0x00FFFFE6, "Buffer Too Big",
|
||||
|
||||
0xFFFFFFFF, "-- Unknown Error --",
|
||||
|
||||
0, 0
|
||||
};
|
||||
|
||||
/****************** Control Text *****************/
|
||||
|
||||
const char *szBack = "< Back";
|
||||
const char *szNext = "Next >";
|
||||
const char *szQuit = "Exit";
|
||||
|
||||
/*******************************************************************************
|
||||
* PERFORM_TEST_PAGE
|
||||
*******************************************************************************/
|
||||
|
||||
TextList TestBlackText[] = {
|
||||
{250, 2, "Data Read"},
|
||||
{350, 2, "Patt Write"},
|
||||
{250, 18, "Data Write"},
|
||||
{350, 18, "Patt Read"},
|
||||
{11, 39, "0%"},
|
||||
{377, 39, "100%"},
|
||||
{ 11, 77, "0"},
|
||||
{377, 77, "100%"},
|
||||
{ 22, 154, "Sectors"},
|
||||
{ 10, 171, "Last Error"},
|
||||
{ 17, 188, "Elapsed"},
|
||||
{ 13, 205, "Time Left"},
|
||||
{278, 154, "Soft Errors"},
|
||||
{275, 171, "Firm Errors"},
|
||||
{272, 188, "Hard Errors"},
|
||||
{271, 205, "Total Errors"},
|
||||
{0,0,0}
|
||||
};
|
||||
|
||||
TextList TestGrayText[] = {
|
||||
{155, 39, "Testing Progress"},
|
||||
{129, 77, "Spare Sectors Consumed"},
|
||||
{61, 135, "Testing Location"},
|
||||
/*{219, 135, "Sound"},*/
|
||||
{297, 135, "Error Summary"},
|
||||
{0,0,0}
|
||||
};
|