Easyhyum
Easyhyum

Reputation: 359

Linux scsi ata cmd write or read sometimes work and sometimes didn't work when transfer length is over 1345

My code is as follows:

unsigned char cmd[16];
cmd[0] = WRITE_16;
//lba is start address
cmd[2] = (lba >> 54) & 0xFF;
cmd[3] = (lba >> 48) & 0xFF;
cmd[4] = (lba >> 40) & 0xFF;
cmd[5] = (lba >> 32) & 0xFF;
cmd[6] = (lba >> 24) & 0xFF;
cmd[7] = (lba >> 16) & 0xFF;
cmd[8] = (lba >> 8) & 0xFF;
cmd[9] = lba & 0xFF;
//len is transfer length
cmd[10] = (len >> 24) & 0xFF;
cmd[11] = (len >> 16) & 0xFF;
cmd[12] = (len >> 8) & 0xFF;
cmd[13] = len & 0xFF;

void* buffer;
buffer = malloc(len*512);
__u64 buffer_len = 512*len;
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof(cmd);
io_hdr.mx.sb_len = sizeof(sense);
io_hdr.dxfer_direction = SG_DXFER_TO_FROM_DEV;
io_hdr.dxfer_len = buffer_len;
io_hdr.dxferp = buffer;
io_hdr.cmdp = cmd;
io_hdr.sbp = sense;
io_hdr.timeout = 30000;
ioctl(fd, SG_IO, &io_hdr);

If I send cmd transfer length over 1345, it sometimes work and sometimes it doesn't work. If thetransfer length grows up, the portion that doesn't work goes up too. There's no uart log or kernel log when cmd doesn't work.

ps. If cmd doesn't work, errno says 22(invalid argument)

Upvotes: 1

Views: 184

Answers (1)

Mike Andrews
Mike Andrews

Reputation: 3205

You're not initializing the bytes in the SCSI CDB to zero, so sometimes there's trash in cmd[1], cmd[14], and cmd[15]. Add a call to memset up at the top, or initialize the array with = { };.

Also, I know a bunch of examples use this technique for initializing the command structure, but man, it's really going to drive you nuts. I recommend defining an __attribute__ ((packed)) structure for the CDB that uses bitfields.

Lastly, the line cmd[2] = (lba >> 54) & 0xFF; should shift lba by 56 bits, not 54 bits.

Upvotes: 0

Related Questions