

echo 'Western Digital ROYL patch module 0x02 using vendor specific commands.'
echo 'This is to resolve a common WD slow issue, where the drive reads slow.'
echo 'Definition of the "slow responding issue":'
echo ' - The drive is reading very slow, but all reads are GOOD.'
echo 'This may not help any if the reads are bad due to a weak or bad head.'
echo 'WARNING: THIS IS DANGEROUS AND COULD KILL THE DRIVE!!!'
echo 'USE AT YOUR OWN RISK!!!'

seti $printhelp = $printhelp
seti $help = $help
if $help = 1
  echo 'WD patch module 02 to perform the slow fix, alternate method.'
  echo 'WARNING! Do NOT run the fast ram patch before running this patch!'
  echo 'If you have ran the fast ram patch, power cycle the drive to clear it.'
  echo 'This patches the module in RAM and uses a trick to write it.'
  echo 'This will set and remove a password on the drive.'
  echo 'The password will be "password" in case drive ends up locked.'
  echo 'You must power cycle the drive for the patch to take effect.'

  if $printhelp = 1
    exit 0
  endif
  echo 'Hit ENTER to continue...'
  userinput $choicestring
  previousscript
endif
echo ""

include good_subroutines

# set a blank string variable to compare with user input
# make sure not to set this anyplace else
sets $null = ""

# set this to itself for use with the menu system
# make sure not to set this anyplace else
# if it was not previously set it will = 0
seti $using_menu = $using_menu


echo "You should have already tried the regular mod02 patch."
echo "Did you already try the regular patch and it failed to apply?"
echo 'Type "YES" to continue:'
userinput $choicestring
sets $safety = "YES"
if $choicestring != $safety
  echo "You chose not to continue"
  previousscript
endif

echo "WARNING! You are about to write to the service area of the drive."
echo "There is NO UNDO with this script! This operation could be permanent!"
echo "You are on your own if something goes wrong."
echo 'Type "DANGEROUS" to continue:'
userinput $choicestring
sets $safety = "DANGEROUS"
if $choicestring != $safety
  echo "You chose not to continue"
  previousscript
endif

echo "You must NOT have ran the fast ram patch before running this patch."
echo "Are you sure you did not run the fast ram patch since the drive was powered up?"
echo 'Type "YES" to continue:'
userinput $choicestring
sets $safety = "YES"
if $choicestring != $safety
  echo "You chose not to continue"
  previousscript
endif


# set these for later, and to make it easy to change if needed
seti $ram_read_block_size = 65536

seti $ram_start = 0x8000000
seti $ram_size = 0x40000
seti $max_ram_size = 0x2000000

if $ram_size < $ram_read_block_size
  seti $ram_read_block_size = $ram_size
endif
seti $divide_check = $ram_read_block_size % 512
if $divide_check != 0
  echo "ram_read_block_size is not dividable by 512"
  previousscript
endif

seti $patch_successful = 0
seti $not_erased_check = 0

gosub idle_drive

gosub identify_device

gosub find_ram_size

gosub dump_ram

if $patch_successful = 1
  gosub set_password
  gosub remove_password
  echo "if password commands completed without errors,"
  echo "then the drive should now be patched."
endif


previousscript
end





subroutine identify_device
  # set the base filenames
  sets $basefilename = "mod02original.bin"
  sets $basepatchname = "mod02patched.bin"
  echo "Performing identify device command"
  buffersize 512
  setreadpio
  ata28cmd 0 0 0 0 0 0xa0 0xec
  # check if command failed
  gosub status_check
  # extract model and serial and trim leading and trailing spaces
  sets $model = "null"
  sets $serial = "null"
  wordflipbuffer 0 512
  seti $count = 0
  seti $start_offset = 54
  while $count < 40
    seti $byte = buffer $start_offset
    if $byte > 0x20
      break
    endif
    seti $start_offset = $start_offset + 1
    seti $count = $count + 1
  done
  seti $count = 0
  seti $end_offset = 93
  while $count < 40
    seti $byte = buffer $end_offset
    if $byte > 0x20
      break
    endif
    seti $end_offset = $end_offset - 1
    seti $count = $count + 1
  done
  seti $end_offset = $end_offset + 1
  seti $size = $end_offset - $start_offset
  if $size > 0
    sets $model = buffer $start_offset $size
  endif
  # find out if it is a WD drive
  sets $wdcheck = buffer $start_offset 3
  sets $wdcompare = "WDC"
  if $wdcheck != $wdcompare
    echo "Model: " $model
    echo "Drive is not WD, exiting
    previousscript
  endif

  seti $count = 0
  seti $start_offset = 20
  while $count < 20
    seti $byte = buffer $start_offset
    if $byte > 0x20
      break
    endif
    seti $start_offset = $start_offset + 1
    seti $count = $count + 1
  done
  seti $count = 0
  seti $end_offset = 39
  while $count < 20
    seti $byte = buffer $end_offset
    if $byte > 0x20
      break
    endif
    seti $end_offset = $end_offset - 1
    seti $count = $count + 1
  done
  seti $end_offset = $end_offset + 1
  seti $size = $end_offset - $start_offset
  if $size > 0
    sets $serial = buffer $start_offset $size
  endif

  echo "Model: " $model
  echo "Serial: " $serial

  # create a directory named with model and serial
  sets $directory = $model "__" $serial
  sets $wdcommand = 'mkdir -p "' $directory '"'
  callcommand $wdcommand

  # set filename for backup dump file
  gettime
  sets $backup_filename = $directory "/" $date "__" $basefilename
  sets $backup_patchname = $directory "/" $date "__" $basepatchname

  sets $firmware = buffer 46 8
  echo "Firmware revision= " $firmware
  wordflipbuffer 0 512

# show if drive supports extended commands
seti $tempnum = buffer 167
seti $extended = $tempnum & 4
seti $extended = $extended > 2
#echo "supports 48 bit commands = " $extended

# total addressable sectors
if $extended = 1
  seti $addressable = buffer 200 qw
  echo "total addressable sectors= " $addressable
else
  seti $addressable = buffer 120 dw
  echo "total addressable sectors= " $addressable
endif

# words per logical sector
seti $wordsps = buffer 234 w
#echo "words per logical sector= " $wordsps

# size
if $wordsps = 0
  seti $sectorsize = 512
else
  seti $sectorsize = $wordsps * 2
endif
seti $sizeb = $addressable * $sectorsize
seti $sizemb = $sizeb / 1048576
echo "Size in bytes= " $sizeb
#echo "Size in MiB= " $sizemb

# show drive security status
seti $tempnum = buffer 257
seti $security_level = $tempnum & 1
seti $tempnum = buffer 256
seti $enhanced_security_erase_supported = $tempnum & 32
seti $enhanced_security_erase_supported = $enhanced_security_erase_supported > 5
seti $security_count_expired = $tempnum & 16
seti $security_count_expired = $security_count_expired > 4
seti $security_frozen = $tempnum & 8
seti $security_frozen = $security_frozen > 3
seti $security_locked = $tempnum & 4
seti $security_locked = $security_locked > 2
seti $security_enabled = $tempnum & 2
seti $security_enabled = $security_enabled > 1
seti $security_supported = $tempnum & 1
#echo "enhanced_security_erase_supported= " $enhanced_security_erase_supported
#echo "security_count_expired= " $security_count_expired
#echo "security_frozen= " $security_frozen
echo "security_locked= " $security_locked
echo "security_enabled= " $security_enabled
#echo "security_supported= " $security_supported

if $security_enabled != 0
  echo "The drive currently has a password set."
  echo "This patch will not work with an existing password."
  previousscript
endif
endsubroutine





subroutine find_ram_size
  gosub enable_vsc

  seti $find_ram_read_size = 0x200
  scratchpadsize $find_ram_read_size
  seti $position = $ram_start
  seti $remainder = $find_ram_read_size
  if $remainder != 0
    seti $write_offset = 0
    seti $read_size = $remainder
    hex
    echo "position=0x" $position "  rsize=0x" $read_size
    decimal
    # vsc to prepare for ram read
    #echo "prepare to read ram"
    buffersize 0x200
    clearbuffer
    seti $offsetl = $position & 0xff
    seti $offsetm1 = $position > 8
    seti $offsetm1 = $offsetm1 & 0xff
    seti $offsetm2 = $position > 16
    seti $offsetm2 = $offsetm2 & 0xff
    seti $offseth = $position > 24
    seti $offseth = $offseth & 0xff
    seti $sizel = $read_size & 0xff
    seti $sizem1 = $read_size > 8
    seti $sizem1 = $sizem1 & 0xff
    seti $sizem2 = $read_size > 16
    seti $sizem2 = $sizem2 & 0xff
    seti $sizeh = $read_size > 24
    seti $sizeh = $sizeh & 0xff
    setbuffer 0
      13 00 01 00 $offsetl $offsetm1 $offsetm2 $offseth $sizel $sizem1 $sizem2 $sizeh
    endbuffer
    setwritepio
    ata28cmd 0xd6 0x01 0xbe 0x4f 0xc2 0xa0 0xb0
    # check if command failed
    gosub status_check
    # vsc to get the ram
    seti $sectors = $read_size / 512
    buffersize $read_size
    clearbuffer
    setreadpio
    #echo "reading ram"
    ata28cmd 0xd5 $sectors 0xbf 0x4f 0xc2 0xa0 0xb0
    # check if command failed
    gosub status_check
    # copy the buffer to the scratchpad
    copybuffertoscratchpad 0 $write_offset $read_size
  endif

  #printscratchpad 0 512

  seti $read_size = $find_ram_read_size
  while 1 = 1
    seti $position = $ram_start + $ram_size
    hex
    echo "position=0x" $position "  size=0x" $read_size
    decimal
    # vsc to prepare for ram read
    #echo "prepare to read ram"
    buffersize 0x200
    clearbuffer
    seti $offsetl = $position & 0xff
    seti $offsetm1 = $position > 8
    seti $offsetm1 = $offsetm1 & 0xff
    seti $offsetm2 = $position > 16
    seti $offsetm2 = $offsetm2 & 0xff
    seti $offseth = $position > 24
    seti $offseth = $offseth & 0xff
    seti $sizel = $read_size & 0xff
    seti $sizem1 = $read_size > 8
    seti $sizem1 = $sizem1 & 0xff
    seti $sizem2 = $read_size > 16
    seti $sizem2 = $sizem2 & 0xff
    seti $sizeh = $read_size > 24
    seti $sizeh = $sizeh & 0xff
    setbuffer 0
      13 00 01 00 $offsetl $offsetm1 $offsetm2 $offseth $sizel $sizem1 $sizem2 $sizeh
    endbuffer
    hex
    #echo "keysector= 13 00 01 00 " $offsetl " " $offsetm1 " " $offsetm2 " " $offseth " " $sizel " " $sizem1 " " $sizem2 " " $sizeh
    setwritepio
    ata28cmd 0xd6 0x01 0xbe 0x4f 0xc2 0xa0 0xb0
    # check if command failed
    gosub status_check

    # vsc to get the ram
    seti $sectors = $read_size / 512
    buffersize $read_size
    clearbuffer
    setreadpio
    #echo "reading ram"
    ata28cmd 0xd5 $sectors 0xbf 0x4f 0xc2 0xa0 0xb0
    hex
    #echo "command= d5 " $sectors " bf 4f c2 a0 b0"
    decimal
    # check if command failed
    gosub status_check

    seti $comparedata = 0
    seti $found_match = 1
    while $comparedata < 512
      seti $cmp = buffer $comparedata qw
      seti $check = scratchpad $comparedata qw
      if $cmp != $check
        seti $found_match = 0
        break
      endif
      seti $comparedata = $comparedata + 8
    done
    if $found_match = 1
      hex
      echo "ram size is 0x" $ram_size
      decimal
      break
    endif

    seti $ram_size = $ram_size * 2
    if $ram_size > $max_ram_size
      hex
      echo "ram size not found, using default maximum size of 0x" $max_ram_size
      decimal
      seti $ram_size = $max_ram_size
      break
    endif
  done

  gosub disable_vsc
endsubroutine





subroutine dump_ram
  gosub enable_vsc

  scratchpadsize $ram_size
  seti $position = $ram_start
  seti $read_size = $ram_read_block_size
  seti $block_count = $ram_size / $ram_read_block_size
  seti $search_position = 0
  seti $count = 0
  while $count < $block_count
    hex
    echo "position=0x" $position "  size=0x" $read_size
    decimal
    # vsc to prepare for ram read
    #echo "prepare to read ram"
    buffersize 0x200
    clearbuffer
    seti $offsetl = $position & 0xff
    seti $offsetm1 = $position > 8
    seti $offsetm1 = $offsetm1 & 0xff
    seti $offsetm2 = $position > 16
    seti $offsetm2 = $offsetm2 & 0xff
    seti $offseth = $position > 24
    seti $offseth = $offseth & 0xff
    seti $sizel = $read_size & 0xff
    seti $sizem1 = $read_size > 8
    seti $sizem1 = $sizem1 & 0xff
    seti $sizem2 = $read_size > 16
    seti $sizem2 = $sizem2 & 0xff
    seti $sizeh = $read_size > 24
    seti $sizeh = $sizeh & 0xff
    setbuffer 0
      13 00 01 00 $offsetl $offsetm1 $offsetm2 $offseth $sizel $sizem1 $sizem2 $sizeh
    endbuffer
    setwritepio
    ata28cmd 0xd6 0x01 0xbe 0x4f 0xc2 0xa0 0xb0
    # check if command failed
    gosub status_check
    # send again
    ata28cmd 0xd6 0x01 0xbe 0x4f 0xc2 0xa0 0xb0
    # check if command failed
    gosub status_check

    # vsc to get the ram
    seti $sectors = $read_size / 512
    buffersize $read_size
    clearbuffer
    setreadpio
    #echo "reading ram"
    ata28cmd 0xd5 $sectors 0xbf 0x4f 0xc2 0xa0 0xb0
    # check if command failed
    gosub status_check
    seti $write_offset = $count * $read_size
    # copy the buffer to the scratchpad
    copybuffertoscratchpad 0 $write_offset $read_size

    gosub process_ram

    seti $count = $count + 1
    seti $position = $position + $ram_read_block_size
  done

  gosub disable_vsc
  echo "ram processing finished"
  if $patch_successful = 1
    echo "ram patch successful"
  else
    echo "ram patch failed"
  endif
endsubroutine





subroutine process_ram
  #echo "processing ram"
  sets $header_check = "ROYL"
  seti $search_end = $search_position + $ram_read_block_size
  seti $search_end = $search_end - 4096
  while $search_position < $search_end
    sets $header = scratchpad $search_position 4
    if $header = $header_check
      # process the module
      seti $working_offset = $search_position
      #echo "Header:"
      #printscratchpad $working_offset 4
      seti $working_offset = $search_position + 8
      seti $mod_id = scratchpad $working_offset w
      hex
      #echo "Module ID = 0x" $mod_id

      if $mod_id = 2
        # find how many sectors the module contains
        seti $working_offset = $search_position + 0xa
        seti $mod_length_sectors = scratchpad $working_offset
        seti $working_offset = $search_position + 0xb
        seti $tempnum = scratchpad $working_offset
        seti $tempnum = $tempnum > 8
        seti $mod_length_sectors = $mod_length_sectors + $tempnum

        #echo "Size in sectors = 0x" $mod_length_sectors
        seti $working_offset = $search_position + 0xc
        seti $checksum = scratchpad $working_offset dw
        #echo "32 bit checksum = 0x" $checksum
        seti $working_offset = $search_position + 0x10
        #echo "Mod version:"
        #printscratchpad $working_offset 8
        decimal

        seti $module_size = $mod_length_sectors * 512
        seti $calculated_checksum = 0
        seti $check_count = 0
        while $check_count < $module_size
          seti $working_offset = $search_position + $check_count
          if $working_offset > $search_end
            echo "end of module is past end of rom"
            break
          endif
          seti $dword = scratchpad $working_offset dw
          seti $calculated_checksum = $calculated_checksum + $dword
          seti $check_count = $check_count + 4
          # skip the actual checksum bytes
          if $check_count = 0xc
            seti $check_count = $check_count + 4
          endif
        done
        seti $calculated_checksum = $calculated_checksum & 0xffffffff
        seti $calculated_checksum = 0xffffffff - $calculated_checksum
        seti $calculated_checksum = $calculated_checksum + 1

        hex
        if $checksum = $calculated_checksum
          sets $checkstring = " calulated=0x" $calculated_checksum " (good)"
          echo "pos=0x" $search_position " ModID=0x" $mod_id " size=0x" $mod_length_sectors $checkstring
          seti $module_position = $search_position
          seti $module_length = $mod_length_sectors * 512
          gosub patch_module
        else
          sets $checkstring = " calulated=0x" $calculated_checksum " (bad)"
        endif
        decimal
      endif
    endif
    seti $search_position = $search_position + 512
  done
endsubroutine





subroutine patch_module
  seti $wposition = $module_position
  seti $wposition = $wposition + 0x8000000
  seti $write_size = $module_length
  hex
  echo "wposition=0x" $wposition "  wsize=0x" $write_size
  decimal
  # vsc to prepare for ram write
  echo "prepare to write ram"
  buffersize 0x200
  clearbuffer
  seti $offsetl = $wposition & 0xff
  seti $offsetm1 = $wposition > 8
  seti $offsetm1 = $offsetm1 & 0xff
  seti $offsetm2 = $wposition > 16
  seti $offsetm2 = $offsetm2 & 0xff
  seti $offseth = $wposition > 24
  seti $offseth = $offseth & 0xff
  seti $sizel = $write_size & 0xff
  seti $sizem1 = $write_size > 8
  seti $sizem1 = $sizem1 & 0xff
  seti $sizem2 = $write_size > 16
  seti $sizem2 = $sizem2 & 0xff
  seti $sizeh = $write_size > 24
  seti $sizeh = $sizeh & 0xff
  setbuffer 0
    13 00 02 00 $offsetl $offsetm1 $offsetm2 $offseth $sizel $sizem1 $sizem2 $sizeh
  endbuffer
  hex
  #echo $offsetl " " $offsetm1 " " $offsetm2 " " $offseth "  " $sizel " " $sizem1 " " $sizem2 " " $sizeh
  decimal
  setwritepio
  ata28cmd 0xd6 0x01 0xbe 0x4f 0xc2 0xa0 0xb0
  # check if command failed
  gosub status_check
  # vsc to get the ram
  seti $sectors = $read_size / 512
  buffersize $module_length
  clearbuffer
  copyscratchpadtobuffer $module_position 0 $module_length
  #printbuffer 0 $module_length
  writebuffer $backup_filename 0 0 $module_length

  gosub process_mod02

  if $not_erased_check = 1
    # calculate new checksum and insert it
    seti $calculated_checksum = 0
    gosub calculate_checksum_buffer
    hex
    echo "Calculated Checksum = 0x" $calculated_checksum
    decimal
    seti $b1 = $calculated_checksum & 0xff
    seti $calculated_checksum = $calculated_checksum > 8
    seti $b2 = $calculated_checksum & 0xff
    seti $calculated_checksum = $calculated_checksum > 8
    seti $b3 = $calculated_checksum & 0xff
    seti $calculated_checksum = $calculated_checksum > 8
    seti $b4 = $calculated_checksum & 0xff
    setbuffer 0x0c
      $b1 $b2 $b3 $b4
    endbuffer

    writebuffer $backup_patchname 0 0 $module_length

    setwritepio
    echo "writing ram"
    ata28cmd 0xd6 $mod_length_sectors 0xbf 0x4f 0xc2 0xa0 0xb0
    # check if command failed
    gosub status_check

  else
    echo "Warning! Mod02 record 27 appears to have been erased in ram."
    echo "The patch will not be written."
    seti $patch_successful = 0
  endif

endsubroutine





subroutine process_mod02
  # process the module
  seti $total_records = buffer 0x30 w
  echo "Total records = " $total_records

  # process the data records
  seti $rcount = 0
  while $rcount < $total_records
    seti $offset = $rcount * 4
    seti $rcount = $rcount + 1
    seti $offset = $offset + 0x32
    seti $record_offset = buffer $offset w
    seti $offset = $offset + 2
    seti $record_size = buffer $offset w

    # process record 27 (slow fix)
    if $rcount = 27
      echo "Data record #" $rcount ":"
      printbuffer $record_offset $record_size

      seti $erased = 0
      seti $not_erased_check = 0
      while $erased < $record_size
        seti $erased_offset = $record_offset + $erased
        seti $check_byte = buffer $erased_offset b
        if $check_byte != 0
          seti $not_erased_check = 1
          break
        endif
        seti $erased = $erased + 1
      done

      seti $erase_offset = $record_offset + 2
      setbuffer $erase_offset
        00
      endbuffer
      echo "Data record #" $rcount " after patch:"
      printbuffer $record_offset $record_size
      seti $patch_successful = 1
    endif

  done
endsubroutine





subroutine calculate_checksum_buffer
  seti $calculated_checksum = 0
  seti $ccount = 0
  while $ccount < $module_length
    seti $dword = buffer $ccount dw
    seti $calculated_checksum = $calculated_checksum + $dword
    seti $ccount = $ccount + 4
    # skip the actual checksum bytes
    if $ccount = 0xc
      seti $ccount = $ccount + 4
    endif
  done
  seti $calculated_checksum = $calculated_checksum & 0xffffffff
  seti $calculated_checksum = 0xffffffff - $calculated_checksum
  seti $calculated_checksum = $calculated_checksum + 1
endsubroutine





subroutine set_password
echo "setting password"
# set the buffer size
buffersize 512
# clear the buffer to 0's
clearbuffer

seti $type = 0
seti $level = 0
sets $password = "password"

# put the type and level in the buffer
seti $byte0 = $type & 0x01
seti $byte1 = $level & 0x01
setbuffer 0
  $byte0 $byte1
endbuffer

# put the password (up to 32 characters) in the buffer
# if set this will overwrite part of all of the hex password
stringtobuffer 2 32 $password

# set the LBAs and count to 0
seti $count = 0
seti $LBAlow = 0
seti $LBAmid = 0
seti $LBAhigh = 0

# set some things for the ata command
setwritepio
# set features to 0
seti $features = 0
# set device bits 7(compatibility) 5(compatibility)
seti $device = 0xa0
# set the command for security set password pio data-out
seti $atacommand = 0xf1

# perform the command
ata28cmd $features $count $LBAlow $LBAmid $LBAhigh $device $atacommand

# check if command failed
seti $command_failed = 0
gosub check_command_status
if $command_failed = 1
  echo "Command failed!"
  gosub show_sense_data
  gosub show_ata_return_status
  previousscript
endif

echo "password set"
endsubroutine





subroutine remove_password
echo "removing password"
# set the buffer size
buffersize 512
# clear the buffer to 0's
clearbuffer

seti $type = 0
sets $password = "password"

# put the type in the buffer
seti $byte0 = $type & 0x01
setbuffer 0
  $byte0
endbuffer

# put the password (up to 32 characters) in the buffer
# if set this will overwrite part of all of the hex password
stringtobuffer 2 32 $password

# set the LBAs and count to 0
seti $count = 0
seti $LBAlow = 0
seti $LBAmid = 0
seti $LBAhigh = 0

# set some things for the ata command
setwritepio
# set features to 0
seti $features = 0
# set device bits 7(compatibility) 5(compatibility)
seti $device = 0xa0
# set the command for security disable password pio data-out
seti $atacommand = 0xf6

# perform the command
ata28cmd $features $count $LBAlow $LBAmid $LBAhigh $device $atacommand

# check if command failed
seti $command_failed = 0
gosub check_command_status
if $command_failed = 1
  echo "Command failed!"
  gosub show_sense_data
  gosub show_ata_return_status
  previousscript
endif

echo "password removed"
endsubroutine





subroutine idle_drive
  echo "attempting to idle drive"
  seti $idle_tries = 0
  while $idle_tries < 100
    seti $idle_tries = $idle_tries + 1
    echo "idle attempt " $idle_tries
    gettime
    seti $startreadtime = $time
    gosub idle
    gosub idle
    gettime
    seti $endreadtime = $time
    seti $elapsedtime = $endreadtime - $startreadtime
    if $elapsedtime < 100000
      break
    endif
  done
endsubroutine



subroutine idle
  buffersize 0
  setreadpio
  # set the count to 0
  seti $count = 0
  # set the LBA for the unload command
  seti $LBAlow = 0x4c
  seti $LBAmid = 0x4e
  seti $LBAhigh = 0x55
  # set features to unload
  seti $features = 0x44
  # set device bits 7(compatibility) 5(compatibility)
  seti $device = 0xa0
  # set the command for idle immediate
  seti $atacommand = 0xe1
  # perform the command
  ata28cmd $features $count $LBAlow $LBAmid $LBAhigh $device $atacommand
  gosub status_check
endsubroutine





subroutine status_check
  seti $command_failed = 0
  gosub check_command_status
  if $command_failed = 1
    echo "Command failed!"
    gosub show_sense_data
    gosub show_ata_return_status
    previousscript
  endif
endsubroutine



subroutine enable_vsc
  # enable vendor specific commands
  echo "enable vsc"
  buffersize 0
  setreadpio
  ata28cmd 0x45 0x0b 0x00 0x44 0x57 0xa0 0x80
  # check if command failed
  gosub status_check
endsubroutine



subroutine disable_vsc
  # disable vendor specific commands
  echo "disable vsc"
  buffersize 0
  setreadpio
  ata28cmd 0x44 0x0b 0x00 0x44 0x57 0xa0 0x80
  # check if command failed
  gosub status_check
endsubroutine



