mirror of
https://github.com/marciot/mac-tip.git
synced 2024-12-26 13:32:25 +00:00
Major enhancements for Jaz drives
- Added command to spin down cartridges to command line - Improved console diagnostics - Report SCSI short reads - Report last error - Report media change - Report disk at speed - Report spare sectors - Report detailed testing steps - Supress unsuported commands on Jaz drive while: - Enabling early recovery - Reading defects list - Fix short reads on Jaz drives during: - Cartridge status - Set error recovery
This commit is contained in:
parent
dcfa0958a6
commit
c719c8d7dd
@ -47,6 +47,7 @@ bool process_command() {
|
||||
case 'h': print_help(); break;
|
||||
case 'l': scan_bus(); break;
|
||||
case 's': iomega_spin_up_cartridge(arg_val); break;
|
||||
case 'p': iomega_spin_down_cartridge(arg_val); break;
|
||||
case 'r': scsi_reset(); break;
|
||||
case 'e': mac_eject(arg_val); break;
|
||||
case 'i': dev_info(arg_val); break;
|
||||
@ -83,6 +84,7 @@ void print_help() {
|
||||
|
||||
"\nIomega device operations on SCSI device:\n"
|
||||
" spin [n] : spin up a cartridge\n"
|
||||
" pause [n] : spin down a cartridge\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,19 @@ OSErr iomega_spin_down_and_eject( int id ) {
|
||||
return scsi_cmd(id, cmd, sizeof(cmd), 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
OSErr iomega_spin_down_cartridge( int id ) {
|
||||
// issue an Asynchronous STOP command to induce spindown
|
||||
char cmd[6] = {
|
||||
SCSI_Cmd_StartStopUnit,
|
||||
1, // set the IMMED bit for offline
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
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] = {
|
||||
|
@ -4,5 +4,6 @@ typedef Boolean bool;
|
||||
|
||||
OSErr iomega_spin_up_cartridge(int id);
|
||||
OSErr iomega_spin_down_and_eject(int id);
|
||||
OSErr iomega_spin_down_cartridge(int id);
|
||||
OSErr iomega_set_prevent_removal(int id, bool lock);
|
||||
OSErr iomega_eject_cartridge(int id);
|
||||
|
@ -61,8 +61,11 @@ OSErr scsi_cmd(int id, void *cmd, size_t clen, void *buff, size_t siz, size_t cn
|
||||
case SCSI_READ: io_err = SCSIRead( (Ptr) TIB ); break;
|
||||
default: break;
|
||||
}
|
||||
if (io_err != noErr) {
|
||||
printf("SCSI Read/Write Error: %d\n", io_err);
|
||||
if (io_err == scPhaseErr && flags & SCSI_READ) {
|
||||
printf("\nSCSI phase error; less data delivered than requested\n");
|
||||
}
|
||||
else if (io_err != noErr) {
|
||||
printf("\nSCSI Read/Write Error: %d\n", io_err);
|
||||
}
|
||||
} else {
|
||||
printf("SCSICmd Error: %d\n", err);
|
||||
|
@ -161,7 +161,7 @@ void WndProc(long iMessage, uint16_t wParam) {
|
||||
SpinUpIomegaCartridge(CurrentDevice);
|
||||
break;
|
||||
case DISK_AT_SPEED:
|
||||
printf("Testing the disk\n");
|
||||
printf("\nTesting the disk\n");
|
||||
if(TestingPhase != READY_TO_TEST) {
|
||||
PrepareToBeginTesting();
|
||||
}
|
||||
@ -339,6 +339,15 @@ void PaintCenteredValue(int Xleft, int Ytop, int XWidth, int YHeight, long value
|
||||
*
|
||||
* This paints the two columns of testing statistics on the test minitor window.
|
||||
*******************************************************************************/
|
||||
char *FindErrorString(long error) {
|
||||
char *errStr = 0;
|
||||
for (int i = 0; errorTypeList[i].str; i++) {
|
||||
errStr = errorTypeList[i].str;
|
||||
if (errorTypeList[i].code == error) break;
|
||||
}
|
||||
return errStr;
|
||||
}
|
||||
|
||||
void PaintTestStatistics(bool Active) {
|
||||
char szString[40];
|
||||
// assemble and paint the sector testing range
|
||||
@ -361,12 +370,7 @@ void PaintTestStatistics(bool Active) {
|
||||
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);
|
||||
PaintCenteredString(76, 172, 126, 14, FindErrorString(LastError), Active);
|
||||
|
||||
// show the elapsed time
|
||||
CvrtSecondsToHMSstring(szString, SecondsElapsed);
|
||||
|
@ -282,6 +282,8 @@ void PaintTheBarGraphs(bool Active);
|
||||
void PaintTestStatistics(bool Active);
|
||||
void CvrtSecondsToHMSstring(char *szString, long seconds);
|
||||
|
||||
char *FindErrorString(long error);
|
||||
|
||||
void UpdateCurrentSector();
|
||||
void UpdateRunTimeDisplay();
|
||||
void UpdateRunPhaseDisplay();
|
||||
@ -301,9 +303,9 @@ void GetCommandDetails(char command, char &cmd_flags, char &cmd_length);
|
||||
long SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, size_t IoBufLen);
|
||||
long EnumerateIomegaDevices(uint8_t *DrivesSkipped);
|
||||
long GetModePage(short Device, short PageToGet, void *pBuffer, short BufLen);
|
||||
long SetModePage(short Device, void *pBuffer);
|
||||
long SetModePage(short Device, void *pBuffer, short BufLen);
|
||||
void ModifyModePage(char *PageBuff, char eec, char retries);
|
||||
void SetErrorRecovery(bool Retries, bool ECC, bool Testing);
|
||||
long SetErrorRecovery(bool Retries, bool ECC, bool Testing);
|
||||
long GetNonSenseData(short Device, short DataPage, void *Buffer, short BufLen);
|
||||
long LockCurrentDrive();
|
||||
long UnlockCurrentDrive();
|
||||
|
@ -6,8 +6,28 @@
|
||||
#include "tip.h"
|
||||
|
||||
//#define DEMO
|
||||
|
||||
/* The original TIP seems to request more data than is supplied by
|
||||
* certain commands. While this appears to be allowed, it causes
|
||||
* SCSI phase errors to be reported. Setting NO_EXCESS_READS will
|
||||
* adjust the reads to to the max size before such errors occur.
|
||||
*/
|
||||
#define NO_EXCESS_READS
|
||||
|
||||
/* The original TIP will always try to enable Early Recovery. This
|
||||
* fails on certain Jaz drives. While the original TIP will then
|
||||
* retry without Early Recovery, this will cause many errors to be
|
||||
* reported. Enable SUPRESS_ER_ERRORS to prevent this from problem
|
||||
* from happening as frequently
|
||||
*/
|
||||
#define SUPRESS_ER_ERRORS
|
||||
|
||||
/* The original TIP will always try to read the defects list, but
|
||||
* not all drives support this, causing many errors to be shown.
|
||||
* Setting SUPPRESS_DEFECTS_ERROR will silence these errors.
|
||||
*/
|
||||
#define SUPPRESS_DEFECTS_ERROR
|
||||
|
||||
#define MAKE_LITTLE_ENDIAN(a) a // Don't do anything on 68000
|
||||
#define MAKE_BIG_ENDIAN(a) a // Don't do anything on 68000
|
||||
|
||||
@ -96,6 +116,13 @@ long DriveCount = 0;
|
||||
long JazDrive = 0; // true if the current drive
|
||||
long CartridgeStatus = DISK_NOT_PRESENT;
|
||||
|
||||
#ifdef SUPRESS_ER_ERRORS
|
||||
Boolean SupressEarlyRecovery = false;
|
||||
#endif
|
||||
#ifdef SUPPRESS_DEFECTS_ERROR
|
||||
Boolean SupressDefectsError = false;
|
||||
#endif
|
||||
|
||||
unsigned long StartingInstant;
|
||||
|
||||
// ----------------------------- Run Time Variables ------------------------------
|
||||
@ -215,6 +242,7 @@ long SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, size_t IoBufLen) {
|
||||
(long(sense_data.ascq) << 8) |
|
||||
(long(sense_data.key) );
|
||||
if(res == MEDIA_CHANGE_CODE) {
|
||||
printf("Media change signalled. Most recent error can be ignored\n\n");
|
||||
int index = GetDriveEntryOffset(Device);
|
||||
DriveArray[index].flags |= MEDIA_CHANGED;
|
||||
return 0;
|
||||
@ -312,13 +340,18 @@ long GetModePage(short Device, short PageToGet, void *pBuffer, short BufLen) {
|
||||
/*******************************************************************************
|
||||
* SET MODE PAGE
|
||||
*******************************************************************************/
|
||||
long SetModePage(short Device, void *pBuffer) {
|
||||
char* ebx = (char*) pBuffer; // get a pointer to the top of buffer
|
||||
char ecx = ebx[0] + 1; // adjust it up by one
|
||||
long SetModePage(short Device, void *pBuffer, short BufLen) {
|
||||
unsigned char* ebx = (unsigned char*) pBuffer; // get a pointer to the top of buffer
|
||||
unsigned char ecx = ebx[0] + 1; // adjust it up by one
|
||||
|
||||
ebx[0] = 0; // now clear the two reserved bytes
|
||||
ebx[2] = 0;
|
||||
|
||||
if(ecx != BufLen) {
|
||||
printf("Length error in SetModePage %d != %d\n\n", BufLen, (int) ecx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char Scsi[6] = {0}; // init the SCSI parameter block
|
||||
Scsi[0] = SCSI_Cmd_ModeSelect; // set the command
|
||||
Scsi[1] = 0x10; // set the Page Format bit
|
||||
@ -343,16 +376,21 @@ void ModifyModePage(char *PageBuff, char ecc, char retries) {
|
||||
ebx[8] = retries; // then set the write count too
|
||||
}
|
||||
|
||||
void SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
|
||||
long SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
|
||||
char PageBuff[40];
|
||||
|
||||
#ifdef NO_EXCESS_READS
|
||||
// Limit reads to 20 bytes on Zip to prevent controller errors
|
||||
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, JazDrive ? sizeof(PageBuff) : 20);
|
||||
// Limit reads to 20 bytes on Zip (24 bytes on Jaz) to prevent controller errors
|
||||
const short pageBuffLen = JazDrive ? 24 : 20;
|
||||
#else
|
||||
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, sizeof(PageBuff));
|
||||
const short pageBuffLen = sizeof(PageBuff);
|
||||
#endif
|
||||
|
||||
long eax = GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, pageBuffLen);
|
||||
if(eax) {
|
||||
printf("SetErrorRecovery failed\n");
|
||||
return eax;
|
||||
}
|
||||
|
||||
#define EARLY_RECOVERY 0x08
|
||||
#define PER 0x04
|
||||
#define SUPPRESS_ECC 0x01
|
||||
@ -360,6 +398,9 @@ void SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
|
||||
// set the ECC fields
|
||||
char ecc = SUPPRESS_ECC; // presume ECC suppression
|
||||
if(ECC) {
|
||||
#ifdef SUPRESS_ER_ERRORS
|
||||
if(!SupressEarlyRecovery)
|
||||
#endif
|
||||
ecc = EARLY_RECOVERY; // enable ECC and Early Recovery
|
||||
if(Testing) {
|
||||
ecc = EARLY_RECOVERY | PER; // we're testing, so EER & PER
|
||||
@ -374,14 +415,22 @@ void SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
|
||||
retries = 0;
|
||||
|
||||
ModifyModePage(PageBuff, ecc, retries);
|
||||
const long eax = SetModePage(CurrentDevice, PageBuff);
|
||||
|
||||
eax = SetModePage(CurrentDevice, PageBuff, pageBuffLen);
|
||||
// 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
|
||||
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, pageBuffLen);
|
||||
ecc &= ~EARLY_RECOVERY; // same, *BUT*NOT* Early Recovery
|
||||
ModifyModePage(PageBuff, ecc, retries);
|
||||
SetModePage(CurrentDevice, PageBuff);
|
||||
eax = SetModePage(CurrentDevice, PageBuff, pageBuffLen);
|
||||
#ifdef SUPRESS_ER_ERRORS
|
||||
if(!eax) {
|
||||
printf(" Early recovery not supported on this drive. Ignoring.\n\n");
|
||||
SupressEarlyRecovery = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return eax;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@ -468,7 +517,18 @@ long GetSpareSectorCounts(char checkPassword) {
|
||||
Scsi[0] = SCSI_Cmd_ReadDefectData;
|
||||
Scsi[2] = 0x1e; // 0b00011110 defect format, G/P bits
|
||||
Scsi[8] = 4; // ask for only FOUR bytes
|
||||
#ifdef SUPPRESS_DEFECTS_ERROR
|
||||
if(SupressDefectsError)
|
||||
eax = INCOMPATIBLE_MEDIA;
|
||||
else
|
||||
#endif
|
||||
eax = SCSICommand(CurrentDevice, Scsi, &DefectHeader, sizeof(DefectHeader));
|
||||
#ifdef SUPPRESS_DEFECTS_ERROR
|
||||
if(!SupressDefectsError && eax == INCOMPATIBLE_MEDIA) {
|
||||
printf("Defects list not supported on this drive. Ignoring.\n\n");
|
||||
SupressDefectsError = true;
|
||||
}
|
||||
#endif
|
||||
if ((!eax) || (eax == INCOMPATIBLE_MEDIA)) {
|
||||
// we could read its defect list ... so show it!
|
||||
// --------------------------------------------------------------------------
|
||||
@ -635,7 +695,7 @@ uint8_t GetCartridgeStatus(long Device, uint8_t flags) {
|
||||
long eax;
|
||||
char DiskStat[72];
|
||||
#ifdef NO_EXCESS_READS
|
||||
eax = GetNonSenseData(Device, DISK_STATUS_PAGE, DiskStat, (flags & JAZ_DRIVE) ? sizeof(DiskStat) : 63);
|
||||
eax = GetNonSenseData(Device, DISK_STATUS_PAGE, DiskStat, 4);
|
||||
if (eax) return DISK_STATUS_UNKNOWN;
|
||||
#else
|
||||
eax = GetNonSenseData(Device, DISK_STATUS_PAGE, DiskStat, sizeof(DiskStat));
|
||||
@ -674,6 +734,7 @@ void SetCartridgeStatusToEAX(long eax, uint8_t flags) {
|
||||
SetRichEditText(szNotRunning);
|
||||
goto DisableActions;
|
||||
case DISK_AT_SPEED:
|
||||
printf("Disk at speed\n");
|
||||
eax = GetSpareSectorCounts(true); // update the Cart Condition
|
||||
if(eax == MEDIA_NOT_PRESENT) {
|
||||
goto DisableActions;
|
||||
@ -686,10 +747,14 @@ void SetCartridgeStatusToEAX(long eax, uint8_t flags) {
|
||||
FirmErrors = 0;
|
||||
// check to see if we have enough spares to start
|
||||
if(JazDrive) {
|
||||
printf("Spare Sectors: %ld/%d\n", Side_0_SparesCount, MAXIMUM_JAZ_SPARES);
|
||||
if(Side_0_SparesCount < MINIMUM_JAZ_SPARES)
|
||||
goto InsufficientSpares;
|
||||
}
|
||||
else {
|
||||
printf("Spare Sectors:\n");
|
||||
printf(" Side 1: %ld/%d\n", Side_0_SparesCount, MAXIMUM_ZIP_SPARES);
|
||||
printf(" Side 2: %ld/%d\n", Side_1_SparesCount, MAXIMUM_ZIP_SPARES);
|
||||
if(Side_0_SparesCount < MINIMUM_ZIP_SPARES) {
|
||||
goto InsufficientSpares;
|
||||
}
|
||||
@ -761,6 +826,12 @@ void PrepareToBeginTesting() {
|
||||
HardErrors = 0;
|
||||
UserInterrupt = 0;
|
||||
LastError = 0;
|
||||
#ifdef SUPRESS_ER_ERRORS
|
||||
SupressEarlyRecovery = false;
|
||||
#endif
|
||||
#ifdef SUPPRESS_DEFECTS_ERROR
|
||||
SupressDefectsError = false;
|
||||
#endif
|
||||
#ifdef DEMO
|
||||
LastLBAOnCartridge = 99999;
|
||||
SoftErrors = 6;
|
||||
@ -820,12 +891,12 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
||||
char Scsi[10] = {0}; // clear out the SCSI CDB
|
||||
const long InitialHardErrors = HardErrors;
|
||||
|
||||
SetErrorRecovery(false, false, true); // disable Retries & ECC
|
||||
long eax = SetErrorRecovery(false, false, true); // disable Retries & ECC
|
||||
|
||||
Scsi[0] = XferCmd;
|
||||
SET_DWORD_AT(Scsi, 2, MAKE_BIG_ENDIAN(FirstLBASector)); // WHICH LBA's to read, BIG endian
|
||||
SET_WORD_AT (Scsi, 7, MAKE_BIG_ENDIAN(NumberOfLBAs)); // HOW MANY to read, BIG endian
|
||||
long eax = SCSICommand(CurrentDevice, Scsi, pBuffer, NumberOfLBAs * BYTES_PER_SECTOR);
|
||||
eax = SCSICommand(CurrentDevice, Scsi, pBuffer, NumberOfLBAs * BYTES_PER_SECTOR);
|
||||
// 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!
|
||||
@ -834,6 +905,8 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
printf("Starting detailed search...\n");
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// 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!
|
||||
@ -863,6 +936,7 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
||||
if (eax == SS_ERR) goto Exit; // if it's a CONTROLLER ERROR, skip!
|
||||
if (eax & 0xFF == 1) goto PostTheError; // did we recover?
|
||||
|
||||
printf(" Found error, retesting with retries\n");
|
||||
SetErrorRecovery(true, false, true); // enable retries
|
||||
eax = SCSICommand(CurrentDevice, Scsi, LocalBuffer, BYTES_PER_SECTOR);
|
||||
if (eax) {
|
||||
@ -870,7 +944,8 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
||||
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
|
||||
printf(" Found error, retesting with retries & ECC\n");
|
||||
eax = SetErrorRecovery(true, true, true); // enable retries AND EEC
|
||||
eax = SCSICommand(CurrentDevice, Scsi, LocalBuffer, BYTES_PER_SECTOR);
|
||||
if (eax) {
|
||||
// failed with retries and EEC
|
||||
@ -888,6 +963,8 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
||||
}
|
||||
|
||||
PostTheError:
|
||||
printf(" %s (Sector %ld)\n", FindErrorString(eax), SingleTransferLBA);
|
||||
printf("--------------------------------------------\n");
|
||||
BumpErrorCounts(eax); // given eax, count the errors
|
||||
GetSpareSectorCounts(false); // update the Cart's Condition
|
||||
UpdateRunTimeDisplay();
|
||||
@ -897,6 +974,7 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
||||
ProcessPendingMessages();
|
||||
}
|
||||
|
||||
printf("... detailed search finished\n");
|
||||
// now see whether we *did* found something to complain about ...
|
||||
eax = SoftErrors + HardErrors;
|
||||
if (eax == GlitchCount) {
|
||||
@ -907,6 +985,7 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
||||
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"
|
||||
printf("%s\n", FindErrorString(eax));
|
||||
BumpErrorCounts(eax); // given eax, count the errors
|
||||
HardErrors = SavedHardErrors; // restore the counts
|
||||
SoftErrors = SavedSoftErrors;
|
||||
@ -917,6 +996,7 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
|
||||
eax = 0; // now let's return happiness to our caller
|
||||
if (HardErrors != InitialHardErrors) // UNRECOVERABLE errors!
|
||||
eax = -1;
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
Loading…
Reference in New Issue
Block a user