Hi,
I figured out some basics from documentation and code examples.
I'm now trying to read/write to specific sectors (512 bytes) in a SATA storage media(/dev/sda) using ioctl and some simple SCSI read/write commands. I'm having some problems with consistency and just getting it to work. Here's what I've tried:
Using read(10)/read(12), when I send the ioctl over to the device, instead of getting the 1st 512 bytes, I get some identification info instead. For example if the drive is a Toshiba drive I'd see the TOSHIBA and the model number, which is actually the ata ident information.
When I use read(6) and send the ioctl, this seems to work for my HDD despite read(6)'s transfer length field being only 8 bytes. I guess the ioctl's transfer length overrides the SCSI CDB's transfer length? I don't know. Despite this, on some HDDs the io_hdr.info and io_hdr.masked_status is non-zero, which indicates a possible error?
However, when I use read(6) to test on a USB memory stick, it gives me the ident information again instead of the 512byte sector.
As for writes, I've only tried write(6) so far, but whenever I send the ioctl out, it would just hang there forever until I close the shell. I'm wondering what I'm doing wrong?
My function (in this case reading a 512byte sector from LBA 0) is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
int read_sector(const char *device_name, unsigned char *data)
int fd, res;
const int t_length = 512; // 512 bytes transferred
unsigned char rdCmdBlk6[SCSI_CDB6_LEN] =
{ SCSI_READ6, // Command
0, 0, 0, 0, 0 };
unsigned char sense_b[SENSE_BUFF_LEN];
sg_io_hdr_t io_hdr;
// Open device
fd = open(device_name, O_RDONLY);
// Prepare SCSI READ (6) command
rdCmdBlk6[1] = 0x00; // LBA
rdCmdBlk6[2] = 0x00; // LBA
rdCmdBlk6[3] = 0x00; // LBA
rdCmdBlk6[4] = t_length; // transfer length
// Prepare the sg_io_hdr_t structure
memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
io_hdr.interface_id = 'S'; // Always set to 'S' for sg driver
io_hdr.cmd_len = sizeof(rdCmdBlk6); // Size of SCSI command
io_hdr.mx_sb_len = sizeof(sense_b); // Max sense buffer size(for error)
io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; // Data transfer direction(no data)
io_hdr.dxfer_len = t_length; // Data transfer length(512)
io_hdr.dxferp = data; // Data transfer buffer(none)
io_hdr.cmdp = rdCmdBlk6; // SCSI command buffer
io_hdr.sbp = sense_b; // Sense buffer
io_hdr.timeout = 5000; // Timeout(5s)
// Sends the command to device
if ((res = ioctl(fd, SG_IO, &io_hdr)) < 0) {
close(fd);
return -1;
}
// Error processing
if ( ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) || // check info
(io_hdr.masked_status != 0x00) || // check status(0 if ioctl success)
(io_hdr.msg_status != 0x00) || // check message status
(io_hdr.host_status != 0x00) || // check host status
(io_hdr.driver_status != 0x00) ) // check driver status
{
close(fd);
return -1;
} else
{
close(fd);
return 0;
}
}
|
The write_sector() code is similar except for appropriate changes in io_hdr and wrCmdBlk[].
Anyone knows what's going on?
Thanks!