Using linux to upgrade firmware for sony dw-u18a

vbimport

#1

This is how I updated an old sony dvd writer, model DVD RW DW-U18A, firmware
version UYS1, to CG5M firmware using linux.

omnipatcher-2.6.2, EEPROM_Utility-6.0.1 and Flash_Utility-5.0.0 would not
run under wine 0.9.25. I was running as root. I added frogaspi, but that had
no effect.

I replaced wine 0.9.25 with wine 1.1.9. wine 1.1.9 is from 2008, and is not
the newest version of wine. I deleted /root/.wine and frogaspi.

omnipatcher-2.6.2 ran under wine 1.1.9. I applied recommended tweaks and
autobitsetting, then then saved as *.BIN.

Flash_Utility-5.0.0 ran under wine 1.1.9. I flashed the firmware, then read
the firmware back to a new file. I compared the two firmware files. The
files did not match, which means flashing the firmware had failed. But then
I flashed the firmware again, and read the firmware back to a file again,
and this time the two firmware files matched. I do not know why it did not
work the first time.

EEPROM_Utility-6.0.1 ran under wine 1.1.9. I copied the eeprom to a file.
Then I clicked clear media learn. EEPROM_Utility-6.0.1 said clearing media
learn failed. Then I tried to change the region. EEPROM_Utility-6.0.1 said
current setting is RPC2, new setting is RPC1. I clicked set. wine said
fixme: aspi:ASPI_ExecScsiCmd Program wants to do DVD Region switching, but
fails (non compliant DVD drive). Ignoring… EEPROM_Utility-6.0.1 said
Sorry, the Region Control for this drive could not be set to RPC1. I added
frogaspi and tried again, but that made no difference, the same errors
occurred again.

I rebooted to DOS and used ltnrpcdos to disable region codes. I rebooted to
linux and ran EEPROM_Utility-6.0.1 again. EEPROM_Utility-6.0.1 said the
current region setting was still RPC2. ltnrpcdos had unset the region code
instead of changing RPC2 to RPC1.

In other messages, codeking has said that to run the utilities under linux,
you need to upgrade wine, add frogaspi to wine, and run as root. My
experience is that frogaspi is not needed, and has no effect.

It is easy send commands to the drive from linux. If you know the commands
to read and write the firmware and eeprom, then it would be easy to create
linux utilities to flash the firmware, etc. For example, here is a linux
program to identify a drive:
<code>
#!/bin/sh
sg_raw --request=96 --outfile=/tmp/scsi_inquiry_response /dev/sg0 12 00 00 00 60 00
echo vendor: $(cut --bytes=9-16 /tmp/scsi_inquiry_response)
echo product: $(cut --bytes=17-32 /tmp/scsi_inquiry_response)
echo revision: $(cut --bytes=33-36 /tmp/scsi_inquiry_response)
echo other information: $(cut --bytes=37-56 /tmp/scsi_inquiry_response)
rm /tmp/scsi_inquiry_response
</code>

sg_raw is part of sg3_utils.
Your drive may be /dev/sg1, /dev/sg2, etc, instead of /dev/sg0.
12 00 00 00 60 00 is the 6 byte scsi INQUIRY command in hexadecimal.
There is also a windows version of sg3_utils, which may be useful for
someone without linux who wants to do something to a cd or dvd drive.


#2

Here is another way to send commands to a cd/dvd drive from linux. This does
not need sg utils.

<code>
#!/usr/bin/perl -w

use Fcntl;
use integer;
$Debug = 0; # set $Debug to 1 for debug output

defined($ARGV[0]) or die(“which SCSI generic device?
”);
if ( $ARGV[0] =~ m/^\d{1,3}$/ ) { $SCSIdevice = “/dev/sg$ARGV[0]” }
else { $SCSIdevice = $ARGV[0] }
-e($SCSIdevice) or die("’$SCSIdevice’ does not exist
");
-w($SCSIdevice) or die(“you do not have permission to write to ‘$SCSIdevice’
”);
-c($SCSIdevice) or die("’$SCSIdevice’ is not a character device
");

if ( $Debug ) { print(“sending scsi INQUIRY command
”) }

the standard length of a reply to INQUIRY is 96 bytes, but that is a

suggestion, not a requirement. We don’t know what the actual size of the

reply will be. Request 255 bytes, because that is the largest size which

can be stored in one byte, and see what we get.

$InquiryReplyWithGarbage = &sendSCSIcommandUsingVersion1SGdriver(
pack(‘C6’,0x12,0,0,0,255,0,),
’’,
255);
if ( ! defined($StatusReturnedByScsiCommand) or $StatusReturnedByScsiCommand != 0 ) {
print(“scsi INQUIRY command failed
”);
print(“response code is $response_code
”);
print(“sense key is $sense_key”);
if ( $sense_key == 0 ) { print(’ (0 means no error)’) }
if ( $sense_key == 2 ) { print(’ (2 means NOT READY)’) }
if ( $sense_key == 4 ) { print(’ (4 means HARDWARE ERROR)’) }
if ( $sense_key == 5 ) { print(’ (5 means ILLEGAL REQUEST)’) }
print("
");
print(“additional sense code is $additional_sense_code
”);
print(“additional sense code qualifier is $additional_sense_code_qualifier
”) }

If the size of the reply is less then we requested, the scsi generic

driver adds random garbage data to the end. The fifth byte of the reply is

the “additional length”. We can use that to calculate the real size of the

reply, and then delete the garbage data from the end.

$ReplySize = unpack(‘C’,substr($InquiryReplyWithGarbage,4,1)) + 5;
if ( $Debug ) { print(“size of reply to INQUIRY is $ReplySize
”) }
$InquiryReply = substr($InquiryReplyWithGarbage,0,$ReplySize);
$device_type = unpack(‘C’,substr($InquiryReply,0,1)) & 31;
print(“type of scsi device is $device_type”);
if ( $device_type == 0 ) { print(’ (0 means hard disk)’) }
if ( $device_type == 5 ) { print(’ (5 means cd or dvd drive)’) }
print("
");
print('vendor: ',substr($InquiryReply,8,8),"
product: ",substr($InquiryReply,16,16),
"
revision: ",substr($InquiryReply,32,4),“
other information: “,substr($InquiryReply,36,20),”
”);

if ( $Debug ) { print(“sending scsi TEST UNIT READY command
”) }
&sendSCSIcommandUsingVersion1SGdriver(
pack(‘C6’,0,0,0,0,0,0,),
’’,
0);
if ( $sense_key == 2 and $additional_sense_code == 0x3a
and $additional_sense_code_qualifier == 0 )
{ print(“there is no disc or tape in the drive
”) }

sub sendSCSIcommandUsingVersion1SGdriver {

$[0] is binary string of CDB, $[1] is binary string of data,

$_[2] is expected number of bytes of data which will be returned

undef($StatusReturnedByScsiCommand);
@Sense_buffer = ();
undef($response_code);
undef($sense_key);
undef($additional_sense_code);
undef($additional_sense_code_qualifier);
if ( $Debug ) { print('command code is ',ord(substr($_[0],0,1)),"
") }

the header is 5 unsigned integers and 16 unsigned characters.

the header size depends on the size of integers.

on 32 bit systems, integers are 4 bytes, so the header is 36 bytes.

on 64 bit systems, integers are 8 bytes, so the header is 56 bytes.

my $IntegerSize = length(pack(‘I’,0));
my $SizeOf5Integers = 5 * $IntegerSize;
my $HeaderSize = $SizeOf5Integers + 16;
my $ReplySizeIncludingHeader = $HeaderSize + $[2];
if ( ord(substr($
[0],0,1)) > 191 and length($[0]) == 12 ) {
my $FifthInteger = 1;
if ( $Debug ) { print(“twelve byte vendor specific CDB
”) }
}
else {
$FifthInteger = 0;
if ( $Debug ) { print(“NOT a twelve byte vendor specific CDB
”) }
}
my $SG1header = pack(‘I5C16’,0,$ReplySizeIncludingHeader,0,0,$FifthInteger,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
sysopen(FH_scsi_device,$SCSIdevice,O_RDWR) or die(“can’t open ‘$SCSIdevice’
”);
if ( $Debug ) {
print(“writing to $SCSIdevice:
”);
&hexdump($SG1header . $
[0] . $[1]) }
syswrite(FH_scsi_device,$SG1header . $
[0] . $_[1]) or die(“write failed with error code $!
”);
if ( $Debug ) { print(“trying to read $ReplySizeIncludingHeader bytes from $SCSIdevice
”) }
my $NumberOfBytesRead = sysread(FH_scsi_device,my $BytesReadFromSCSIdevice,$ReplySizeIncludingHeader);
close(FH_scsi_device);
defined($NumberOfBytesRead) or die(“read failed with error code $!
”);
(my $pack_len,my $reply_len,my $pack_id,my $result,$FifthInteger) =
unpack(‘I5’,substr($BytesReadFromSCSIdevice,0,$SizeOf5Integers));
my $twelve_byte = $FifthInteger & 1;
my $target_status = ($FifthInteger >> 1) & 31;
$StatusReturnedByScsiCommand = $target_status;
my $host_status = ($FifthInteger >> 6) & 255;
my $driver_status = ($FifthInteger >> 14) & 255;
my $other_flags = ($FifthInteger >> 22);
my $Sense_buffer = substr($BytesReadFromSCSIdevice,$SizeOf5Integers,16);
@Sense_buffer = unpack(‘C16’,$Sense_buffer);
$response_code = $Sense_buffer[0] & 127;
$sense_key = $Sense_buffer[2] & 15;
$additional_sense_code = $Sense_buffer[12];
$additional_sense_code_qualifier = $Sense_buffer[13];
my $Data = substr($BytesReadFromSCSIdevice,$HeaderSize);
if ( $Debug ) {
print(“actually read $NumberOfBytesRead bytes
”);
print(“header minus sense buffer:
”);
&hexdump(substr($BytesReadFromSCSIdevice,0,$SizeOf5Integers));
print(“pack_len is $pack_len
”);
print(“reply_len is $reply_len
”);
print(“pack_id is $pack_id
”);
print(“result is $result
”);
print(“FifthInteger is $FifthInteger
”);
print(“twelve_byte is $twelve_byte
”);
print(“target_status is $target_status”);
if ( $target_status == 1 ) { print(’ (1 means CHECK CONDITION)’) }
if ( $target_status == 0 ) { print(’ (0 means OK)’) }
print("
");
print(“host_status is $host_status
”);
print(“driver_status is $driver_status
”);
print(“other_flags is $other_flags
”);
print(“sense buffer:
”);
&hexdump($Sense_buffer);
printf(“response code is $response_code (0x%02x)
”,$response_code);
printf(“sense key is $sense_key (0x%02x)”,$sense_key);
if ( $sense_key == 0 ) { print(’ (0 means no error)’) }
if ( $sense_key == 2 ) { print(’ (2 means NOT READY)’) }
if ( $sense_key == 4 ) { print(’ (4 means HARDWARE ERROR)’) }
if ( $sense_key == 5 ) { print(’ (5 means ILLEGAL REQUEST)’) }
print("
");
printf(“additional sense code is $additional_sense_code (0x%02x)
”,$additional_sense_code);
printf(“additional sense code qualifier is $additional_sense_code_qualifier (0x%02x)
”,$additional_sense_code_qualifier);
if ( length($Data) > 0 ) {
print(“data:
”);
&hexdump($Data) }
else { print(“there is no data
”) } }
return($Data);
}

sub hexdump {
my $Length = length($[0]);
my $LengthMinus16 = $Length - 16;
my $ByteNumber = 0;
while ( $LengthMinus16 >= $ByteNumber ) {
my $Line = substr($
[0],$ByteNumber,16);
my @LineSeperateAsciiNumbers = unpack(‘C16’,$Line);
my $LineWithoutNonTextCharacters = ‘’;
for ( @LineSeperateAsciiNumbers ) {
if ( $_ < 32 or $_ > 126 )
{ $LineWithoutNonTextCharacters = $LineWithoutNonTextCharacters . ‘.’; }
else { $LineWithoutNonTextCharacters = $LineWithoutNonTextCharacters . chr($); } }
printf("%08x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x $LineWithoutNonTextCharacters
",
$ByteNumber,@LineSeperateAsciiNumbers);
$ByteNumber = $ByteNumber + 16; }
if ( $Length == $ByteNumber ) { return }
$Line = substr($
[0],$ByteNumber);
my $LengthOfLastLine = length($Line);
my $HexadecimalPartOfLine = ‘’;
my $TextPartOfLine = ‘’;
for ( split(//,$Line) ) {
my $AsciiNumber = unpack(‘C’,$_);
$HexadecimalPartOfLine = $HexadecimalPartOfLine . sprintf(’ %02x’,$AsciiNumber);
if ( $AsciiNumber < 32 or $AsciiNumber > 126 )
{ $TextPartOfLine = $TextPartOfLine . ‘.’; }
else { $TextPartOfLine = $TextPartOfLine . chr($AsciiNumber); } }
while ( length($HexadecimalPartOfLine) < 48 )
{ $HexadecimalPartOfLine = $HexadecimalPartOfLine . ’ ’ }
my $FirstHexadecimalPart = substr($HexadecimalPartOfLine,0,24);
my $SecondHexadecimalPart = substr($HexadecimalPartOfLine,24);
printf("%08x $FirstHexadecimalPart $SecondHexadecimalPart $TextPartOfLine
",
$ByteNumber);
}
</code>