diff --git a/README.md b/README.md index a6f76b7..79fe958 100644 --- a/README.md +++ b/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. +[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" diff --git a/mac-cpp-source/.finf/Iomega Zip Tester.cpp b/mac-cpp-source/.finf/Iomega Zip Tester.cpp new file mode 100644 index 0000000..4da4961 Binary files /dev/null and b/mac-cpp-source/.finf/Iomega Zip Tester.cpp differ diff --git a/mac-cpp-source/.finf/Iomega Zip Tester.µ b/mac-cpp-source/.finf/Iomega Zip Tester.µ new file mode 100644 index 0000000..24195bc Binary files /dev/null and b/mac-cpp-source/.finf/Iomega Zip Tester.µ differ diff --git a/mac-cpp-source/.finf/macos b/mac-cpp-source/.finf/macos new file mode 100644 index 0000000..fbd64cf Binary files /dev/null and b/mac-cpp-source/.finf/macos differ diff --git a/mac-cpp-source/.finf/scsi b/mac-cpp-source/.finf/scsi new file mode 100644 index 0000000..c1566d8 Binary files /dev/null and b/mac-cpp-source/.finf/scsi differ diff --git a/mac-cpp-source/.finf/tip b/mac-cpp-source/.finf/tip new file mode 100644 index 0000000..3973766 Binary files /dev/null and b/mac-cpp-source/.finf/tip differ diff --git a/mac-cpp-source/.rsrc/Iomega Zip Tester.cpp b/mac-cpp-source/.rsrc/Iomega Zip Tester.cpp new file mode 100644 index 0000000..eb2b58d Binary files /dev/null and b/mac-cpp-source/.rsrc/Iomega Zip Tester.cpp differ diff --git a/mac-cpp-source/.rsrc/Iomega Zip Tester.µ b/mac-cpp-source/.rsrc/Iomega Zip Tester.µ new file mode 100644 index 0000000..651e6f0 Binary files /dev/null and b/mac-cpp-source/.rsrc/Iomega Zip Tester.µ differ diff --git a/mac-cpp-source/Iomega Zip Tester.cpp b/mac-cpp-source/Iomega Zip Tester.cpp new file mode 100644 index 0000000..87b8b25 --- /dev/null +++ b/mac-cpp-source/Iomega Zip Tester.cpp @@ -0,0 +1,176 @@ +#include +#include +#include +#include +#include + +#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++; + } +} + + diff --git a/mac-cpp-source/Iomega Zip Tester.µ b/mac-cpp-source/Iomega Zip Tester.µ new file mode 100644 index 0000000..f13a045 Binary files /dev/null and b/mac-cpp-source/Iomega Zip Tester.µ differ diff --git a/mac-cpp-source/macos/.finf/mac_vol.cpp b/mac-cpp-source/macos/.finf/mac_vol.cpp new file mode 100644 index 0000000..a222493 Binary files /dev/null and b/mac-cpp-source/macos/.finf/mac_vol.cpp differ diff --git a/mac-cpp-source/macos/.finf/mac_vol.h b/mac-cpp-source/macos/.finf/mac_vol.h new file mode 100644 index 0000000..dc3e112 Binary files /dev/null and b/mac-cpp-source/macos/.finf/mac_vol.h differ diff --git a/mac-cpp-source/macos/.rsrc/mac_vol.cpp b/mac-cpp-source/macos/.rsrc/mac_vol.cpp new file mode 100644 index 0000000..e19724d Binary files /dev/null and b/mac-cpp-source/macos/.rsrc/mac_vol.cpp differ diff --git a/mac-cpp-source/macos/.rsrc/mac_vol.h b/mac-cpp-source/macos/.rsrc/mac_vol.h new file mode 100644 index 0000000..c77a274 Binary files /dev/null and b/mac-cpp-source/macos/.rsrc/mac_vol.h differ diff --git a/mac-cpp-source/macos/mac_vol.cpp b/mac-cpp-source/macos/mac_vol.cpp new file mode 100644 index 0000000..aab2209 --- /dev/null +++ b/mac-cpp-source/macos/mac_vol.cpp @@ -0,0 +1,38 @@ +#include +#include +#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); + } +} \ No newline at end of file diff --git a/mac-cpp-source/macos/mac_vol.h b/mac-cpp-source/macos/mac_vol.h new file mode 100644 index 0000000..a861572 --- /dev/null +++ b/mac-cpp-source/macos/mac_vol.h @@ -0,0 +1,2 @@ +void mac_list_volumes(); +void mac_unmount(int id); \ No newline at end of file diff --git a/mac-cpp-source/scsi/.finf/iomega_cmds.cpp b/mac-cpp-source/scsi/.finf/iomega_cmds.cpp new file mode 100644 index 0000000..204eae6 Binary files /dev/null and b/mac-cpp-source/scsi/.finf/iomega_cmds.cpp differ diff --git a/mac-cpp-source/scsi/.finf/iomega_cmds.h b/mac-cpp-source/scsi/.finf/iomega_cmds.h new file mode 100644 index 0000000..2a5cd65 Binary files /dev/null and b/mac-cpp-source/scsi/.finf/iomega_cmds.h differ diff --git a/mac-cpp-source/scsi/.finf/mac_scsi.cpp b/mac-cpp-source/scsi/.finf/mac_scsi.cpp new file mode 100644 index 0000000..9e40976 Binary files /dev/null and b/mac-cpp-source/scsi/.finf/mac_scsi.cpp differ diff --git a/mac-cpp-source/scsi/.finf/mac_scsi.h b/mac-cpp-source/scsi/.finf/mac_scsi.h new file mode 100644 index 0000000..a222493 Binary files /dev/null and b/mac-cpp-source/scsi/.finf/mac_scsi.h differ diff --git a/mac-cpp-source/scsi/.rsrc/iomega_cmds.cpp b/mac-cpp-source/scsi/.rsrc/iomega_cmds.cpp new file mode 100644 index 0000000..a55ec9c Binary files /dev/null and b/mac-cpp-source/scsi/.rsrc/iomega_cmds.cpp differ diff --git a/mac-cpp-source/scsi/.rsrc/iomega_cmds.h b/mac-cpp-source/scsi/.rsrc/iomega_cmds.h new file mode 100644 index 0000000..f2af8c7 Binary files /dev/null and b/mac-cpp-source/scsi/.rsrc/iomega_cmds.h differ diff --git a/mac-cpp-source/scsi/.rsrc/mac_scsi.cpp b/mac-cpp-source/scsi/.rsrc/mac_scsi.cpp new file mode 100644 index 0000000..67b81eb Binary files /dev/null and b/mac-cpp-source/scsi/.rsrc/mac_scsi.cpp differ diff --git a/mac-cpp-source/scsi/.rsrc/mac_scsi.h b/mac-cpp-source/scsi/.rsrc/mac_scsi.h new file mode 100644 index 0000000..c3c6d3c Binary files /dev/null and b/mac-cpp-source/scsi/.rsrc/mac_scsi.h differ diff --git a/mac-cpp-source/scsi/iomega_cmds.cpp b/mac-cpp-source/scsi/iomega_cmds.cpp new file mode 100644 index 0000000..a7ff3c0 --- /dev/null +++ b/mac-cpp-source/scsi/iomega_cmds.cpp @@ -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); +} \ No newline at end of file diff --git a/mac-cpp-source/scsi/iomega_cmds.h b/mac-cpp-source/scsi/iomega_cmds.h new file mode 100644 index 0000000..8083bb9 --- /dev/null +++ b/mac-cpp-source/scsi/iomega_cmds.h @@ -0,0 +1,8 @@ +#include + +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); \ No newline at end of file diff --git a/mac-cpp-source/scsi/mac_scsi.cpp b/mac-cpp-source/scsi/mac_scsi.cpp new file mode 100644 index 0000000..6771e68 --- /dev/null +++ b/mac-cpp-source/scsi/mac_scsi.cpp @@ -0,0 +1,116 @@ +#include +#include "mac_scsi.h" + +#include +#include +#include + +#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; +} diff --git a/mac-cpp-source/scsi/mac_scsi.h b/mac-cpp-source/scsi/mac_scsi.h new file mode 100644 index 0000000..88f8ad2 --- /dev/null +++ b/mac-cpp-source/scsi/mac_scsi.h @@ -0,0 +1,87 @@ +#include + +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 ); + + diff --git a/mac-cpp-source/tip/.finf/tip.cpp b/mac-cpp-source/tip/.finf/tip.cpp new file mode 100644 index 0000000..42eba35 Binary files /dev/null and b/mac-cpp-source/tip/.finf/tip.cpp differ diff --git a/mac-cpp-source/tip/.finf/tip.h b/mac-cpp-source/tip/.finf/tip.h new file mode 100644 index 0000000..dc3e112 Binary files /dev/null and b/mac-cpp-source/tip/.finf/tip.h differ diff --git a/mac-cpp-source/tip/.finf/tip_aspi.cpp b/mac-cpp-source/tip/.finf/tip_aspi.cpp new file mode 100644 index 0000000..e5d9e40 Binary files /dev/null and b/mac-cpp-source/tip/.finf/tip_aspi.cpp differ diff --git a/mac-cpp-source/tip/.finf/tip_main.cpp b/mac-cpp-source/tip/.finf/tip_main.cpp new file mode 100644 index 0000000..5ea3eeb Binary files /dev/null and b/mac-cpp-source/tip/.finf/tip_main.cpp differ diff --git a/mac-cpp-source/tip/.finf/tip_text.cpp b/mac-cpp-source/tip/.finf/tip_text.cpp new file mode 100644 index 0000000..cca4b0c Binary files /dev/null and b/mac-cpp-source/tip/.finf/tip_text.cpp differ diff --git a/mac-cpp-source/tip/.rsrc/tip.cpp b/mac-cpp-source/tip/.rsrc/tip.cpp new file mode 100644 index 0000000..3b8ad69 Binary files /dev/null and b/mac-cpp-source/tip/.rsrc/tip.cpp differ diff --git a/mac-cpp-source/tip/.rsrc/tip.h b/mac-cpp-source/tip/.rsrc/tip.h new file mode 100644 index 0000000..2e1d236 Binary files /dev/null and b/mac-cpp-source/tip/.rsrc/tip.h differ diff --git a/mac-cpp-source/tip/.rsrc/tip_aspi.cpp b/mac-cpp-source/tip/.rsrc/tip_aspi.cpp new file mode 100644 index 0000000..36a6019 Binary files /dev/null and b/mac-cpp-source/tip/.rsrc/tip_aspi.cpp differ diff --git a/mac-cpp-source/tip/.rsrc/tip_main.cpp b/mac-cpp-source/tip/.rsrc/tip_main.cpp new file mode 100644 index 0000000..d367229 Binary files /dev/null and b/mac-cpp-source/tip/.rsrc/tip_main.cpp differ diff --git a/mac-cpp-source/tip/.rsrc/tip_text.cpp b/mac-cpp-source/tip/.rsrc/tip_text.cpp new file mode 100644 index 0000000..f1b3961 Binary files /dev/null and b/mac-cpp-source/tip/.rsrc/tip_text.cpp differ diff --git a/mac-cpp-source/tip/tip.cpp b/mac-cpp-source/tip/tip.cpp new file mode 100644 index 0000000..03795cf --- /dev/null +++ b/mac-cpp-source/tip/tip.cpp @@ -0,0 +1,383 @@ +/******************************************************************************* + * TIP.CPP TROUBLE IN PARADISE 05/22/98 * + ******************************************************************************/ + +#include +#include +#include + +#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() { +} \ No newline at end of file diff --git a/mac-cpp-source/tip/tip.h b/mac-cpp-source/tip/tip.h new file mode 100644 index 0000000..c3e3df2 --- /dev/null +++ b/mac-cpp-source/tip/tip.h @@ -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); \ No newline at end of file diff --git a/mac-cpp-source/tip/tip_aspi.cpp b/mac-cpp-source/tip/tip_aspi.cpp new file mode 100644 index 0000000..e010da6 --- /dev/null +++ b/mac-cpp-source/tip/tip_aspi.cpp @@ -0,0 +1,684 @@ +#include +#include +#include +#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; + } + } +} diff --git a/mac-cpp-source/tip/tip_main.cpp b/mac-cpp-source/tip/tip_main.cpp new file mode 100644 index 0000000..6a3b2d5 --- /dev/null +++ b/mac-cpp-source/tip/tip_main.cpp @@ -0,0 +1,370 @@ +#include +#include +#include +#include +#include + +#include +#include + +#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); + } +} \ No newline at end of file diff --git a/mac-cpp-source/tip/tip_text.cpp b/mac-cpp-source/tip/tip_text.cpp new file mode 100644 index 0000000..a65a1d4 --- /dev/null +++ b/mac-cpp-source/tip/tip_text.cpp @@ -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} +};