Prx
Prx

Reputation: 11

Sending ATA command "Read native max address (0x27 , 0xF8) not reponding over SAS controller using SAT(SCSI ATA translate)

i want to find out native max address of an HDD over SAS interface. i am using SAT ( scsi ata translation) with SCSI_PASS_THROUGH.

but unable to find out any buffer or valid senseinfo of SCSI_PASS_THROUGH with IOCTL_SCSI_PASS_THROUGH from drive. cdb value of SCSI_PASS_THROUGH =

sptwb.Spt.CdbLength = 12;
        sptwb.Spt.Cdb[0] = 0xA1;//ATA PASS THROUGH(12) OPERATION CODE(A1h)
        sptwb.Spt.Cdb[1] = (4 << 1) | 0; 
        sptwb.Spt.Cdb[2] = (1 << 3) | (1 << 2) | 2;
        sptwb.Spt.Cdb[3] = 0xe0;
        sptwb.Spt.Cdb[4] = 0x00;
        sptwb.Spt.Cdb[5] = 0x00;
        sptwb.Spt.Cdb[6] = 0x00;
        sptwb.Spt.Cdb[7] = 0x00;
        sptwb.Spt.Cdb[8] = (UCHAR)0x40;//(UCHAR)head;
        sptwb.Spt.Cdb[9] = 0x27;//COMMAND

But not return any buffer. Please provide exact cdb parameters to read native max address on SAS machine.

Upvotes: 0

Views: 1676

Answers (3)

Zibri
Zibri

Reputation: 9857

I think this is what you want:
This works under cygwin or native linux having "sg3_utils" installed.

#!/bin/bash
dev=$1
sz=$(sg_raw 2>/dev/null -r 40 $dev 9e 10 00 00 00 00 00 00 00 00 00 00 00 0c 00 00 -b|xxd -p)
nb=$((0x${sz:0:16}+1))
bs=$((0x${sz:16:8}))
pbs=$((bs*2**0x${sz:24:4}))
echo Real number of blocks: $nb
echo Real HDD Size: $((nb*bs))
echo Logical Block Size: $bs
echo Physical Block Size: $pbs
p=$((0x$(sg_raw 2>/dev/null $dev -r 512 85 08 0e 00 00 00 01 00 00 00 00 00 00 00 ec 00 -o -|xxd -c 0 -ps|while read -N1 a;do read -N1 b;echo -n $b$a;done|cut -c 401-416|rev)))
echo User Addressable blocks: $p
echo User Addressable size: $(($p*bs))
./gethdsize.sh PD2 (device obtained with sg_scan)  

output:

Real number of blocks: 27344764928
Real HDD Size: 14000519643136
Logical Block Size: 512
Physical Block Size: 4096
User Addressable blocks: 27344750581
User Addressable size: 14000512297472

after resetting drive to max lba:

Real number of blocks: 27344764928
Real HDD Size: 14000519643136
Logical Block Size: 512
Physical Block Size: 4096
User Addressable blocks: 27344764928
User Addressable size: 14000519643136

Upvotes: 0

mattypiper
mattypiper

Reputation: 1232

The command you're trying to implement, 0xF8 (Read Native Max Address) is not a SCSI command, it's an ATA command.

CDB code 0xA1 does indeed work with with the IOCTL_SCSI_PASS_THROUGH API to get SCSI/ATAPI commands to a device. But that's not what you want.

Try IOCTL_ATA_PASSTHROUGH instead.

Example and discussion here: Sending ATA commands directly to device in Windows?

Upvotes: 0

Andrew Falanga
Andrew Falanga

Reputation: 2484

I don't have all relevant SCSI Specs in front of me. Therefore, I'm assuming you're building the SATL (SCSI ATA Translation Layer) CDB correctly. The first thing to check for is whether the ioctl completed. That is, check the return code of DeviceIoControl() for True or False and then check GetLastError() to determine what went wrong (if applicable). If the ioctl was fine, check the SCSI_PASS_THROUGH_DIRECT structure member .ScsiStatus. If this is 0, then the command completed just fine. If the status was 0, this may well be the reason for no valid sense info.

I was actually researching this very command when I stumbled onto this thread. The most recent ATA Command Spec, ACS-3 (dated October 28, 2013) shows that the Read Native Max Address and Read Native Max Address Ext commands are now obsolete. I found their definition in ACS-2. The most recent draft, dated August 3, 2009, shows that the output of this command won't be a buffer. Rather, the output will be in the LBA field of the returned Device-To-Host FIS.


Addendum The verbiage of the original post lead me to believe this was being done in Windows. I should have included that the process will be the same for Linux, if that is what you're using. However, don't use GetLastError() to determine what went wrong. In Linux, the return code from ioctl() will be the code you need.

If in Linux, you're most likely using the sg driver and the sg_io_hdr_t structure. This structure also has a .status member which contains the SCSI Status code. Whether in Linux or Windows, you should always check this code because assuming the command succeeded because the ioctl did is a fallacy. There are other pass through drivers available in Linux, e.g. the LSI MPT interface. The process is still the same if this is what you're using.

Upvotes: 0

Related Questions