Files
2026-02-21 12:34:38 +01:00

545 lines
14 KiB
Plaintext

seti $printhelp = $printhelp
seti $help = $help
if $help != 0
echo 'This will scan the drive using the read verify command.'
echo 'Reads are done in blocks (clusters) of 256 sectors.'
echo 'This means that all warnings and errors show the position'
echo ' of the first sector of the block, NOT the actual problem sector.'
echo 'If the required variables below are not set on the command line,'
echo ' then you will be propted to enter them.'
echo 'This requires the number variable startsector to be set.'
echo 'This requires the number variable endsector to be set.'
echo 'If endsector is set to 0, it will default to the last addressable sector.'
echo 'This uses the identify device command to determine the last sector.'
echo 'This requires the number variable threshold to be set.'
echo 'Threshold is time in milliseconds.'
echo 'If a read exceeds the threshold, a warning will be given.'
echo 'If threshold is set to 0, it will default to 150ms.'
echo 'This requires the number variable softtimeout to be set.'
echo 'Softtimeout is the time in milliseconds to wait before giving up on a command.'
echo 'If softtimeout is set to 0, it will default to 10000ms.'
echo 'This requires the number variable hardtimeout to be set.'
echo 'Hardtimeout is the time to wait after a softreset before doing a hardreset.'
echo 'If hardtimeout is set to 0, it will default to 10000ms.'
echo 'This requires the string variable logfile to be set.'
echo 'Logfile will capture all the warnings and errors.'
echo 'This requires the string variable rateslog to be set.'
echo 'Rateslog will capture timing info that can be ploted.'
echo 'Rateslog captures the low, high, and average over 256 block reads.'
echo 'If logfile and/or ratesfile are blank no log will be produced.'
echo 'Example using defaults:'
echo 'opensuperclone --tool -t /dev/sda -f ata_scan_device threshold=0 softtimeout=0 startsector=0 endsector=0 logfile=="" rateslog==""'
if $printhelp = 1
exit 0
endif
echo 'Hit ENTER to continue...'
userinput $choicestring
previousscript
endif
include good_subroutines.osc
sets $null = ""
seti $using_menu = $using_menu
seti $ask = 0
while 1 = 1
variablecheck $startsector
if $error_level < 16
seti $ask = 1
elseif $using_menu = 1
seti $ask = 1
endif
if $ask = 1
echo "Enter start sector, or leave blank for first:"
userinput $choicestring
if $choicestring != $null
seti $startsector = $choicestring 0
break
else
seti $startsector = 0
break
endif
else
break
endif
done
seti $ask = 0
while 1 = 1
variablecheck $endsector
if $error_level < 16
seti $ask = 1
elseif $using_menu = 1
seti $ask = 1
endif
if $ask = 1
echo "Enter end sector, or leave blank for last:"
userinput $choicestring
if $choicestring != $null
seti $endsector = $choicestring 0
break
else
seti $endsector = 0
break
endif
else
break
endif
done
seti $ask = 0
while 1 = 1
variablecheck $threshold
if $error_level < 16
seti $ask = 1
elseif $using_menu = 1
seti $ask = 1
endif
if $ask = 1
echo "Enter warning threshold in ms, or leave blank for default(150):"
userinput $choicestring
if $choicestring != $null
seti $threshold = $choicestring 0
break
else
seti $threshold = 150
break
endif
else
break
endif
done
if $threshold = 0
seti $threshold = 150
endif
seti $threshold = $threshold * 1000
seti $ask = 0
while 1 = 1
variablecheck $softtimeout
if $error_level < 16
seti $ask = 1
elseif $using_menu = 1
seti $ask = 1
endif
if $ask = 1
echo "Enter softtimeout in ms, or leave blank for default(10000ms):"
userinput $choicestring
if $choicestring != $null
seti $softtimeout = $choicestring 0
break
else
seti $softtimeout = 10000
break
endif
else
break
endif
done
if $softtimeout = 0
seti $softtimeout = 10000
endif
seti $softtimeout = $softtimeout * 1000
softtimeout $softtimeout
seti $ask = 0
while 1 = 1
variablecheck $hardtimeout
if $error_level < 16
seti $ask = 1
elseif $using_menu = 1
seti $ask = 1
endif
if $ask = 1
echo "Enter hardtimeout in ms, or leave blank for default(10000ms):"
userinput $choicestring
if $choicestring != $null
seti $hardtimeout = $choicestring 0
break
else
seti $hardtimeout = 10000
break
endif
else
break
endif
done
if $hardtimeout = 0
seti $hardtimeout = 10000
endif
seti $hardtimeout = $hardtimeout * 1000
hardtimeout $hardtimeout
seti $ask = 0
variablecheck $logfile
if $error_level < 16
seti $ask = 1
elseif $using_menu = 1
seti $ask = 1
endif
if $ask = 1
echo "Enter logfile name, or leave blank for no log:"
userinput $choicestring
sets $logfile = $choicestring
endif
seti $ask = 0
variablecheck $rateslog
if $error_level < 16
seti $ask = 1
elseif $using_menu = 1
seti $ask = 1
endif
if $ask = 1
echo "Enter optional rates logfile name, or leave blank for no log:"
userinput $choicestring
sets $rateslog = $choicestring
endif
# get the size of the drive using identify device command
buffersize 512
setreadpio
ata28cmd 0 0 0 0 0 0xa0 0xec
# check if command failed
seti $command_failed = 0
gosub check_command_status
if $command_failed = 1
echo "Identify device command failed!"
gosub show_sense_data
gosub show_ata_return_status
previousscript
endif
# check if drive supports extended commands
seti $tempnum = buffer 167
seti $extended = $tempnum & 4
# total addressable sectors
if $extended > 0
seti $addressable = buffer 200 qw
else
seti $addressable = buffer 120 dw
endif
if $endsector = 0
seti $endsector = $addressable
endif
buffersize 0
setreadpio
seti $blocksize = 256
seti $logchunk = 256
seti $currentposition = $startsector
seti $previousposition = $currentposition
seti $blockposition = $currentposition
seti $processedsectors = 0
seti $totalsectors = $endsector - $startsector
seti $logcounter = 0
seti $accumulatedtime = 0
seti $1ms = 0
seti $3ms = 0
seti $10ms = 0
seti $30ms = 0
seti $100ms = 0
seti $300ms = 0
seti $over300ms = 0
seti $errorcount = 0
seti $highvalue = 0
seti $lowvalue = 1000000000
if $logfile != $null
deletefile $logfile
sets $line = "# warning log " $date
writelog $logfile $line
sets $line = "# cluster size is " $blocksize
writelog $logfile $line
endif
if $rateslog != $null
deletefile $rateslog
sets $line = "# position low high avg"
writelog $rateslog $line
endif
gettime
seti $displaytime = $time
seti $redodisplay = 1
echo " "
echo " "
echo " "
echo " "
echo " "
echo " "
echo " "
echo " "
echo " "
echo " "
echo " "
echo " "
echo " "
echo " "
gettime
seti $programstart = $time
while $currentposition < $endsector
seti $sector = $currentposition
if $extended > 0
seti $features = 0
seti $count = $blocksize
seti $LBAlow = $sector & 0xffff
seti $temp = $sector > 16
seti $LBAmid = $temp & 0xffff
seti $temp = $sector > 32
seti $LBAhigh = $temp & 0xffff
seti $device = 0xe0
seti $command = 0x42
gettime
seti $startreadtime = $time
ata48cmd $features $count $LBAhigh $LBAmid $LBAlow $device $command
gettime
seti $endreadtime = $time
else
seti $features = 0
seti $count = $blocksize & 0xff
seti $LBAlow = $sector & 0xff
seti $temp = $sector > 8
seti $LBAmid = $temp & 0xff
seti $temp = $sector > 16
seti $LBAhigh = $temp & 0xff
seti $temp = $sector > 24
seti $LBAdevice = $temp & 0x0f
seti $device = 0xe0
seti $device = $device | $LBAdevice
seti $command = 0x40
gettime
seti $startreadtime = $time
ata28cmd $features $count $LBAlow $LBAmid $LBAhigh $device $command
gettime
seti $endreadtime = $time
endif
# check if command failed
seti $command_failed = 0
gosub check_command_status
if $command_failed = 1
seti $devicefault = $ata_return_status & 0x20
endif
seti $readtime = $endreadtime - $startreadtime
if $command_failed = 1
seti $errorcount = $errorcount + 1
elseif $readtime > 300000
seti $over300ms = $over300ms + 1
elseif $readtime > 100000
seti $300ms = $300ms + 1
elseif $readtime > 30000
seti $100ms = $100ms + 1
elseif $readtime > 10000
seti $30ms = $30ms + 1
elseif $readtime > 3000
seti $10ms = $10ms + 1
elseif $readtime > 1000
seti $3ms = $3ms + 1
else
seti $1ms = $1ms + 1
endif
if $readtime < $lowvalue
seti $lowvalue = $readtime
endif
if $readtime > $highvalue
seti $highvalue = $readtime
endif
seti $showerror = 0
if $command_failed = 1
seti $showerror = 1
elseif $readtime > $threshold
seti $showerror = 1
endif
if $showerror > 0
upline
upline
upline
upline
upline
upline
upline
upline
upline
upline
upline
upline
upline
seti $adjustedtime = $readtime / 1000
if $command_failed = 1
hex
sets $errorstring = "e=0x" $ata_return_error " s=0x" $ata_return_status
decimal
if $direct_mode = 1
seti $command_status = $command_status & 0xfff0
if $command_status = 0x20
sets $status = "BUSY"
elseif $command_status = 0x30
sets $status = "TIMEOUT/RESET"
elseif $command_status = 0x40
sets $status = "TIMEOUT/RESET/BUSY"
elseif $command_status = 0x50
sets $status = "TIMEOUT"
elseif $command_status = 0x60
sets $status = "NO DRQ"
elseif $command_status = 0x70
sets $status = "WRONG DEVICE"
elseif $command_status > 0x7f
hex
sets $status = "OTHER/0x" $command_status
decimal
else
sets $status = ""
endif
else
sets $status = ""
endif
sets $outputline = "ERROR " $status " " $currentposition " " $adjustedtime "ms " $errorstring
else
sets $outputline = "WARNING " $currentposition " " $adjustedtime "ms "
endif
echo $outputline
echo $null
echo $null
echo $null
echo $null
echo $null
echo $null
echo $null
echo $null
echo $null
echo $null
echo $null
echo $null
echo $null
seti $redodisplay = 1
if $logfile != $null
writelog $logfile $outputline
endif
endif
seti $elapsedtime = $endreadtime - $displaytime
if $elapsedtime > 1000000
seti $redodisplay = 1
endif
if $redodisplay = 1
seti $sectorstransferred = $currentposition - $previousposition
seti $previousposition = $currentposition
seti $bytestransferred = $sectorstransferred * 512
seti $adjustedbytes = $bytestransferred * 1000000
seti $currentspeed = $adjustedbytes / $elapsedtime
seti $currentspeed = $currentspeed / 1000
gosub displayoutput
seti $displaytime = $endreadtime
endif
seti $redodisplay = 0
seti $accumulatedtime = $accumulatedtime + $readtime
seti $logcounter = $logcounter + 1
if $logcounter = $logchunk
seti $average = $accumulatedtime / $logchunk
if $rateslog != $null
sets $line = $blockposition " " $lowvalue " " $highvalue " " $average
writelog $rateslog $line
else
#echo "low=" $lowvalue " high=" $highvalue " average=" $average
endif
seti $highvalue = 0
seti $lowvalue = 1000000000
seti $accumulatedtime = 0
seti $logcounter = 0
seti $blockposition = $currentposition + $blocksize
endif
if $devicefault > 0
echo "Device fault detected!"
echo "Current position= " $currentposition
gosub show_ata_return_status
seti $devicefault = 0
echo "Power cycle the drive and hit enter to continue"
userinput $dummy
# do a hard reset to set the drive back up for access
hardreset
endif
seti $currentposition = $currentposition + $blocksize
seti $processedsectors = $processedsectors + $blocksize
# check if last read is less than blocksize
seti $partial = $currentposition + $blocksize
if $partial > $endsector
if $currentposition < $endsector
seti $blocksize = $endsector - $currentposition
endif
endif
done
if $devicefault = 0
gosub displayoutput
endif
previousscript
end
subroutine displayoutput
upline
upline
upline
upline
upline
upline
upline
upline
upline
upline
upline
upline
upline
echo " "
gettime
seti $totaltime = $time - $programstart
seti $totalseconds = $totaltime / 1000000
seti $remainder = $totaltime % 1000000
seti $totalminutes = $totalseconds / 60
seti $seconds = $totalseconds % 60
seti $hours = $totalminutes / 60
seti $minutes = $totalminutes % 60
echo "scantime h:m:s = " $hours ":" $minutes ":" $seconds "." $remainder
seti $positionpercent = $processedsectors * 100
seti $percentcomplete = $positionpercent / $totalsectors
seti $remainder = $positionpercent % $totalsectors
seti $remainder = $remainder * 100
seti $percentremainder = $remainder / $totalsectors
if $percentremainder < 10
echo $percentcomplete ".0" $percentremainder "% complete "
else
echo $percentcomplete "." $percentremainder "% complete "
endif
echo "position= " $currentposition " "
echo "speed= " $currentspeed " kB/s "
echo "<1ms=" $1ms " "
echo "1-3ms=" $3ms " "
echo "3-10ms=" $10ms " "
echo "10-30ms=" $30ms " "
echo "30-100ms=" $100ms " "
echo "100-300ms=" $300ms " "
echo ">300ms=" $over300ms " "
echo "errors=" $errorcount " "
endsubroutine