Naraeon SSD Tools internals – 6. Identify SATA devices

Necessity

Last time, I introduced ATAPI command standard, ACS-3. I said about some definitions and introduced how we can issue a command to SATA devices.

In this time, we would see implementation to issue identify device command in Naraeon SSD Tools.

Identify (Identify device)

In fourth, I said about Identify command like this.

BIOS and device manager shows model name, firmware version, capacity using this command. We need this to get them.

In Naraeon SSD Tools, to know what the device is, issuing this command is mandatory. I said only four things above, but almost every information about device can be get with this command.

It is super easy to issue this command. Empty PreviousTaskFile and data buffer, and set other like next list. (N/A also means 0)

  • AtaFlags of Passthrough structure: ATA_FLAGS_DATA_IN
  • CurrentTaskFile[0]: N/A
  • CurrentTaskFile[1]: N/A
  • CurrentTaskFile[2]: N/A
  • CurrentTaskFile[3]: N/A
  • CurrentTaskFile[4]: N/A
  • CurrentTaskFile[5]: N/A
  • CurrentTaskFile[6]: 0xEC
  • CurrentTaskFile[7]: N/A

If it is sent successfully, data buffer would have result. As I said in fifth, though most of the things come out in little endian word unit, be careful with byte order of string. The result has so many things so I can’t explain all of them one by one. You can refer Table 45 of ACS-3. There’s 20 pages of explanation about the result. If you see earlier version than that, you wouldn’t found negotiated SATA speed part.

In Naraeon SSD Tools, issuing Identify device command is implemented in SetBufferAndIdentifyDevice function of TATACommandSet. Details are explained above, so I wouldn’t repeat in code part.

procedure TATACommandSet.SetBufferAndIdentifyDevice;
begin
  SetInnerBufferToIdentifyDevice;
  SetOSBufferByInnerBuffer;
  IoControl(TIoControlCode.ATAPassThroughDirect, IoOSBuffer);
end;

Interpretation is done in BufferToIdentifyDeviceResult of TATABufferInterpreter.

function TATABufferInterpreter.BufferToIdentifyDeviceResult(
  const Buffer: TSmallBuffer): TIdentifyDeviceResult;
begin
  BufferInterpreting := Buffer;
  result.Model := GetModelFromBuffer;
  result.Firmware := GetFirmwareFromBuffer;
  result.Serial := GetSerialFromBuffer;
  result.UserSizeInKB := GetUserSizeInKBFromBuffer;
  result.SATASpeed := GetSATASpeedFromBuffer;
  result.LBASize := GetLBASizeFromBuffer;
  result.RotationRate := GetRotationRateFromBuffer;
end;

Interpretation in normal little endian word is done like this.

function TATABufferInterpreter.GetUserSizeInKBFromBuffer: UInt64;
const
  UserSizeStart = 100;
  UserSizeEnd = 103;
var
  CurrentWord: Integer;
begin
  result := 0;
  for CurrentWord := UserSizeStart to UserSizeEnd do
  begin
    result :=
      result +
      BufferInterpreting[CurrentWord * 2] shl
        (((CurrentWord - UserSizeStart) * 2) * 8) +
      BufferInterpreting[CurrentWord * 2 + 1]  shl
        ((((CurrentWord - UserSizeStart) * 2) + 1) * 8);
  end;
  result := result div 2;
end;

But as ATA string has different byte order, we need another example.

function TATABufferInterpreter.GetModelFromBuffer: String;
const
  ModelStart = 27;
  ModelEnd = 46;
var
  CurrentWord: Integer;
begin
  result := '';
  for CurrentWord := ModelStart to ModelEnd do
    result :=
      result +
      Chr(BufferInterpreting[CurrentWord * 2 + 1]) +
      Chr(BufferInterpreting[CurrentWord * 2]);
  result := Trim(result);
end;

We went through how to get basic information from SATA storages. I would talk about getting diagnostic information(SMART) next time.

Leave a Reply

Your email address will not be published. Required fields are marked *