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:
Marcio T 2022-02-13 17:34:14 -07:00
parent dcfa0958a6
commit c719c8d7dd
7 changed files with 132 additions and 27 deletions

View File

@ -47,6 +47,7 @@ bool process_command() {
case 'h': print_help(); break; case 'h': print_help(); break;
case 'l': scan_bus(); break; case 'l': scan_bus(); break;
case 's': iomega_spin_up_cartridge(arg_val); 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 'r': scsi_reset(); break;
case 'e': mac_eject(arg_val); break; case 'e': mac_eject(arg_val); break;
case 'i': dev_info(arg_val); break; case 'i': dev_info(arg_val); break;
@ -83,6 +84,7 @@ void print_help() {
"\nIomega device operations on SCSI device:\n" "\nIomega device operations on SCSI device:\n"
" spin [n] : spin up a cartridge\n" " spin [n] : spin up a cartridge\n"
" pause [n] : spin down a cartridge\n"
); );
} }

View File

@ -29,6 +29,19 @@ OSErr iomega_spin_down_and_eject( int id ) {
return scsi_cmd(id, cmd, sizeof(cmd), 0, 0, 0, 0); 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 iomega_set_prevent_removal( int id, bool lock) {
OSErr err; OSErr err;
char cmd[6] = { char cmd[6] = {

View File

@ -4,5 +4,6 @@ typedef Boolean bool;
OSErr iomega_spin_up_cartridge(int id); OSErr iomega_spin_up_cartridge(int id);
OSErr iomega_spin_down_and_eject(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_set_prevent_removal(int id, bool lock);
OSErr iomega_eject_cartridge(int id); OSErr iomega_eject_cartridge(int id);

View File

@ -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; case SCSI_READ: io_err = SCSIRead( (Ptr) TIB ); break;
default: break; default: break;
} }
if (io_err != noErr) { if (io_err == scPhaseErr && flags & SCSI_READ) {
printf("SCSI Read/Write Error: %d\n", io_err); 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 { } else {
printf("SCSICmd Error: %d\n", err); printf("SCSICmd Error: %d\n", err);

View File

@ -161,7 +161,7 @@ void WndProc(long iMessage, uint16_t wParam) {
SpinUpIomegaCartridge(CurrentDevice); SpinUpIomegaCartridge(CurrentDevice);
break; break;
case DISK_AT_SPEED: case DISK_AT_SPEED:
printf("Testing the disk\n"); printf("\nTesting the disk\n");
if(TestingPhase != READY_TO_TEST) { if(TestingPhase != READY_TO_TEST) {
PrepareToBeginTesting(); 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. * 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) { void PaintTestStatistics(bool Active) {
char szString[40]; char szString[40];
// assemble and paint the sector testing range // assemble and paint the sector testing range
@ -361,12 +370,7 @@ void PaintTestStatistics(bool Active) {
PaintCenteredString(76, 155, 126, 14, szString, Active); PaintCenteredString(76, 155, 126, 14, szString, Active);
// show the LastError // show the LastError
char *errStr = 0; PaintCenteredString(76, 172, 126, 14, FindErrorString(LastError), Active);
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 // show the elapsed time
CvrtSecondsToHMSstring(szString, SecondsElapsed); CvrtSecondsToHMSstring(szString, SecondsElapsed);

View File

@ -282,6 +282,8 @@ void PaintTheBarGraphs(bool Active);
void PaintTestStatistics(bool Active); void PaintTestStatistics(bool Active);
void CvrtSecondsToHMSstring(char *szString, long seconds); void CvrtSecondsToHMSstring(char *szString, long seconds);
char *FindErrorString(long error);
void UpdateCurrentSector(); void UpdateCurrentSector();
void UpdateRunTimeDisplay(); void UpdateRunTimeDisplay();
void UpdateRunPhaseDisplay(); 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 SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, size_t IoBufLen);
long EnumerateIomegaDevices(uint8_t *DrivesSkipped); long EnumerateIomegaDevices(uint8_t *DrivesSkipped);
long GetModePage(short Device, short PageToGet, void *pBuffer, short BufLen); 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 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 GetNonSenseData(short Device, short DataPage, void *Buffer, short BufLen);
long LockCurrentDrive(); long LockCurrentDrive();
long UnlockCurrentDrive(); long UnlockCurrentDrive();

View File

@ -6,8 +6,28 @@
#include "tip.h" #include "tip.h"
//#define DEMO //#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 #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_LITTLE_ENDIAN(a) a // Don't do anything on 68000
#define MAKE_BIG_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 JazDrive = 0; // true if the current drive
long CartridgeStatus = DISK_NOT_PRESENT; long CartridgeStatus = DISK_NOT_PRESENT;
#ifdef SUPRESS_ER_ERRORS
Boolean SupressEarlyRecovery = false;
#endif
#ifdef SUPPRESS_DEFECTS_ERROR
Boolean SupressDefectsError = false;
#endif
unsigned long StartingInstant; unsigned long StartingInstant;
// ----------------------------- Run Time Variables ------------------------------ // ----------------------------- 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.ascq) << 8) |
(long(sense_data.key) ); (long(sense_data.key) );
if(res == MEDIA_CHANGE_CODE) { if(res == MEDIA_CHANGE_CODE) {
printf("Media change signalled. Most recent error can be ignored\n\n");
int index = GetDriveEntryOffset(Device); int index = GetDriveEntryOffset(Device);
DriveArray[index].flags |= MEDIA_CHANGED; DriveArray[index].flags |= MEDIA_CHANGED;
return 0; return 0;
@ -312,13 +340,18 @@ long GetModePage(short Device, short PageToGet, void *pBuffer, short BufLen) {
/******************************************************************************* /*******************************************************************************
* SET MODE PAGE * SET MODE PAGE
*******************************************************************************/ *******************************************************************************/
long SetModePage(short Device, void *pBuffer) { long SetModePage(short Device, void *pBuffer, short BufLen) {
char* ebx = (char*) pBuffer; // get a pointer to the top of buffer unsigned char* ebx = (unsigned char*) pBuffer; // get a pointer to the top of buffer
char ecx = ebx[0] + 1; // adjust it up by one unsigned char ecx = ebx[0] + 1; // adjust it up by one
ebx[0] = 0; // now clear the two reserved bytes ebx[0] = 0; // now clear the two reserved bytes
ebx[2] = 0; 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 char Scsi[6] = {0}; // init the SCSI parameter block
Scsi[0] = SCSI_Cmd_ModeSelect; // set the command Scsi[0] = SCSI_Cmd_ModeSelect; // set the command
Scsi[1] = 0x10; // set the Page Format bit 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 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]; char PageBuff[40];
#ifdef NO_EXCESS_READS #ifdef NO_EXCESS_READS
// Limit reads to 20 bytes on Zip to prevent controller errors // Limit reads to 20 bytes on Zip (24 bytes on Jaz) to prevent controller errors
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, JazDrive ? sizeof(PageBuff) : 20); const short pageBuffLen = JazDrive ? 24 : 20;
#else #else
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, sizeof(PageBuff)); const short pageBuffLen = sizeof(PageBuff);
#endif #endif
long eax = GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, pageBuffLen);
if(eax) {
printf("SetErrorRecovery failed\n");
return eax;
}
#define EARLY_RECOVERY 0x08 #define EARLY_RECOVERY 0x08
#define PER 0x04 #define PER 0x04
#define SUPPRESS_ECC 0x01 #define SUPPRESS_ECC 0x01
@ -360,6 +398,9 @@ void SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
// set the ECC fields // set the ECC fields
char ecc = SUPPRESS_ECC; // presume ECC suppression char ecc = SUPPRESS_ECC; // presume ECC suppression
if(ECC) { if(ECC) {
#ifdef SUPRESS_ER_ERRORS
if(!SupressEarlyRecovery)
#endif
ecc = EARLY_RECOVERY; // enable ECC and Early Recovery ecc = EARLY_RECOVERY; // enable ECC and Early Recovery
if(Testing) { if(Testing) {
ecc = EARLY_RECOVERY | PER; // we're testing, so EER & PER ecc = EARLY_RECOVERY | PER; // we're testing, so EER & PER
@ -374,14 +415,22 @@ void SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
retries = 0; retries = 0;
ModifyModePage(PageBuff, ecc, retries); 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 we had an invalid field in the CDB (the EER bit was on)
if (eax == 0x00260005) { if (eax == 0x00260005) {
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, sizeof(PageBuff)); GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, pageBuffLen);
ecc &= ~0x08; // same, *BUT*NOT* Early Recovery ecc &= ~EARLY_RECOVERY; // same, *BUT*NOT* Early Recovery
ModifyModePage(PageBuff, ecc, retries); 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[0] = SCSI_Cmd_ReadDefectData;
Scsi[2] = 0x1e; // 0b00011110 defect format, G/P bits Scsi[2] = 0x1e; // 0b00011110 defect format, G/P bits
Scsi[8] = 4; // ask for only FOUR bytes 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)); 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)) { if ((!eax) || (eax == INCOMPATIBLE_MEDIA)) {
// we could read its defect list ... so show it! // we could read its defect list ... so show it!
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -635,7 +695,7 @@ uint8_t GetCartridgeStatus(long Device, uint8_t flags) {
long eax; long eax;
char DiskStat[72]; char DiskStat[72];
#ifdef NO_EXCESS_READS #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; if (eax) return DISK_STATUS_UNKNOWN;
#else #else
eax = GetNonSenseData(Device, DISK_STATUS_PAGE, DiskStat, sizeof(DiskStat)); eax = GetNonSenseData(Device, DISK_STATUS_PAGE, DiskStat, sizeof(DiskStat));
@ -674,6 +734,7 @@ void SetCartridgeStatusToEAX(long eax, uint8_t flags) {
SetRichEditText(szNotRunning); SetRichEditText(szNotRunning);
goto DisableActions; goto DisableActions;
case DISK_AT_SPEED: case DISK_AT_SPEED:
printf("Disk at speed\n");
eax = GetSpareSectorCounts(true); // update the Cart Condition eax = GetSpareSectorCounts(true); // update the Cart Condition
if(eax == MEDIA_NOT_PRESENT) { if(eax == MEDIA_NOT_PRESENT) {
goto DisableActions; goto DisableActions;
@ -686,10 +747,14 @@ void SetCartridgeStatusToEAX(long eax, uint8_t flags) {
FirmErrors = 0; FirmErrors = 0;
// check to see if we have enough spares to start // check to see if we have enough spares to start
if(JazDrive) { if(JazDrive) {
printf("Spare Sectors: %ld/%d\n", Side_0_SparesCount, MAXIMUM_JAZ_SPARES);
if(Side_0_SparesCount < MINIMUM_JAZ_SPARES) if(Side_0_SparesCount < MINIMUM_JAZ_SPARES)
goto InsufficientSpares; goto InsufficientSpares;
} }
else { 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) { if(Side_0_SparesCount < MINIMUM_ZIP_SPARES) {
goto InsufficientSpares; goto InsufficientSpares;
} }
@ -761,6 +826,12 @@ void PrepareToBeginTesting() {
HardErrors = 0; HardErrors = 0;
UserInterrupt = 0; UserInterrupt = 0;
LastError = 0; LastError = 0;
#ifdef SUPRESS_ER_ERRORS
SupressEarlyRecovery = false;
#endif
#ifdef SUPPRESS_DEFECTS_ERROR
SupressDefectsError = false;
#endif
#ifdef DEMO #ifdef DEMO
LastLBAOnCartridge = 99999; LastLBAOnCartridge = 99999;
SoftErrors = 6; SoftErrors = 6;
@ -820,12 +891,12 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
char Scsi[10] = {0}; // clear out the SCSI CDB char Scsi[10] = {0}; // clear out the SCSI CDB
const long InitialHardErrors = HardErrors; const long InitialHardErrors = HardErrors;
SetErrorRecovery(false, false, true); // disable Retries & ECC long eax = SetErrorRecovery(false, false, true); // disable Retries & ECC
Scsi[0] = XferCmd; Scsi[0] = XferCmd;
SET_DWORD_AT(Scsi, 2, MAKE_BIG_ENDIAN(FirstLBASector)); // WHICH LBA's to read, BIG endian 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 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 we failed somewhere during our transfer ... let's zero in on it
if (eax) { if (eax) {
if ( eax == SS_ERR || // if it's a CONTROLLER ERROR, skip! if ( eax == SS_ERR || // if it's a CONTROLLER ERROR, skip!
@ -834,6 +905,8 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
goto Exit; goto Exit;
} }
printf("Starting detailed search...\n");
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Save error and current Soft + Hard Error count to see if we do FIND the glitch ... // 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 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 == SS_ERR) goto Exit; // if it's a CONTROLLER ERROR, skip!
if (eax & 0xFF == 1) goto PostTheError; // did we recover? if (eax & 0xFF == 1) goto PostTheError; // did we recover?
printf(" Found error, retesting with retries\n");
SetErrorRecovery(true, false, true); // enable retries SetErrorRecovery(true, false, true); // enable retries
eax = SCSICommand(CurrentDevice, Scsi, LocalBuffer, BYTES_PER_SECTOR); eax = SCSICommand(CurrentDevice, Scsi, LocalBuffer, BYTES_PER_SECTOR);
if (eax) { 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 == SS_ERR) goto Exit; // if it's a CONTROLLER ERROR, skip!
if (eax & 0xFF == 1) goto PostTheError; // did we recover? 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); eax = SCSICommand(CurrentDevice, Scsi, LocalBuffer, BYTES_PER_SECTOR);
if (eax) { if (eax) {
// failed with retries and EEC // failed with retries and EEC
@ -888,6 +963,8 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
} }
PostTheError: PostTheError:
printf(" %s (Sector %ld)\n", FindErrorString(eax), SingleTransferLBA);
printf("--------------------------------------------\n");
BumpErrorCounts(eax); // given eax, count the errors BumpErrorCounts(eax); // given eax, count the errors
GetSpareSectorCounts(false); // update the Cart's Condition GetSpareSectorCounts(false); // update the Cart's Condition
UpdateRunTimeDisplay(); UpdateRunTimeDisplay();
@ -897,6 +974,7 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
ProcessPendingMessages(); ProcessPendingMessages();
} }
printf("... detailed search finished\n");
// now see whether we *did* found something to complain about ... // now see whether we *did* found something to complain about ...
eax = SoftErrors + HardErrors; eax = SoftErrors + HardErrors;
if (eax == GlitchCount) { if (eax == GlitchCount) {
@ -907,6 +985,7 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
long ebx = eax & 0x00FF00FF; // strip the ASCQ byte long ebx = eax & 0x00FF00FF; // strip the ASCQ byte
if(ebx == 0x00110003) // if we're about to say "unrecovered read" if(ebx == 0x00110003) // if we're about to say "unrecovered read"
eax = 0x170101; // change it to: "Read with Retries" eax = 0x170101; // change it to: "Read with Retries"
printf("%s\n", FindErrorString(eax));
BumpErrorCounts(eax); // given eax, count the errors BumpErrorCounts(eax); // given eax, count the errors
HardErrors = SavedHardErrors; // restore the counts HardErrors = SavedHardErrors; // restore the counts
SoftErrors = SavedSoftErrors; SoftErrors = SavedSoftErrors;
@ -917,6 +996,7 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
eax = 0; // now let's return happiness to our caller eax = 0; // now let's return happiness to our caller
if (HardErrors != InitialHardErrors) // UNRECOVERABLE errors! if (HardErrors != InitialHardErrors) // UNRECOVERABLE errors!
eax = -1; eax = -1;
printf("\n");
} }
Exit: Exit: