Browse Source

ATA/SATA: cross-verify logical & transport layers for robust versioning

- Replaced brittle Word 230 bitmasks with an advanced cross-verification matrix
  between Word 80 (version_major) and Word 222 (transport_major) to properly
  resolve exact ACS-3/ACS-4/ACS-5 and SATA 3.1/3.2/3.3 revisions layout.
- Fixed Advanced Format physical sector mapping (Word 106) by switching to the
  compliant 0x4000/0x2000 bitmasks, successfully enabling 4096-byte layout
  mapping for modern Western Digital, Samsung, Seagate, and Intel drives.
- Integrated comprehensive comments across new properties and macros  in
  include/bsdiskinfo.h and src/cli.c.
master
Sergey Kiselev 3 months ago
parent
commit
b8569c9514
  1. 20
      include/bsdiskinfo.h
  2. 47
      src/cli.c
  3. 116
      src/libbsdiskinfo.c

20
include/bsdiskinfo.h

@ -33,11 +33,15 @@
#include <sys/ucred.h>
#include <sys/mount.h>
#define MAX_MODEL_LEN 256
#define MAX_SERIAL_LEN 64
#define MAX_TYPE_LEN 16
#define MAX_FW_LEN 16
#define MAX_WWN_LEN 32
#define MAX_MODEL_LEN 256 /* Buffer size for device model string */
#define MAX_SERIAL_LEN 64 /* Buffer size for drive serial number string */
#define MAX_TYPE_LEN 16 /* Buffer size for determined drive architecture type string */
#define MAX_FW_LEN 16 /* Buffer size for device firmware version revision string */
#define MAX_WWN_LEN 32 /* Buffer size for LU WWN Device Id hex string format */
#define MAX_FF_LEN 32 /* Buffer size for physical form factor string */
#define MAX_ATA_LEN 64 /* Buffer size for major/minor ATA standard specification */
#define MAX_SATA_LEN 64 /* Buffer size for SATA signaling capabilities and link speed */
#define MAX_SEC_LEN 32 /* Buffer size for internal ATA Security feature state */
#define MAX_MOUNTS 128
#define MAX_DISKS 64
@ -61,6 +65,12 @@ struct disk_properties {
int smart_supported; /* S.M.A.R.T. capability support: 1 = Yes, 0 = No, -1 = N/A */
int smart_enabled; /* S.M.A.R.T. active enablement: 1 = Yes, 0 = No, -1 = N/A */
/* Advanced ATA hardware descriptors */
char form_factor[MAX_FF_LEN]; /* Nominal physical drive form factor dimensions */
char ata_version[MAX_ATA_LEN]; /* Major/Minor ATA/ATAPI specification standard tracking */
char sata_version[MAX_SATA_LEN]; /* Active SATA signaling speed capabilities and status */
char security_status[MAX_SEC_LEN];/* Internal firmware ATA Security Feature Set execution state */
};
/*

47
src/cli.c

@ -83,15 +83,34 @@ int main(int argc, char *argv[]) {
static void print_identity(const char *disk_name, struct disk_properties *props) {
printf("=== START OF INFORMATION SECTION (%s) ===\n", disk_name);
printf("Device Model: %s\n", strlen(props->model) > 0 ? props->model : "N/A");
printf("Serial Number: %s\n", strlen(props->serial) > 0 ? props->serial : "N/A");
printf("Firmware Version: %s\n", strlen(props->fw_version) > 0 ? props->fw_version : "N/A");
printf("LU WWN Device Id: %s\n", strlen(props->wwn) > 0 ? props->wwn : "N/A");
printf("Determined Type: %s\n", strlen(props->type_str) > 0 ? props->type_str : "unknown");
printf("User Capacity: %llu bytes\n", (unsigned long long)props->mediasize);
printf("Sector Sizes: %u bytes logical, %u bytes physical\n",
props->logical_sector_size, props->physical_sector_size);
printf("Device Model: %s\n", props->model);
printf("Serial Number: %s\n", props->serial);
printf("Firmware Version: %s\n", props->fw_version);
printf("LU WWN Device Id: %s\n", props->wwn);
/* Display advanced ATA hardware descriptors unpacked by the core library */
printf("Form Factor: %s\n", props->form_factor); /* Nominal physical unit size dimensions */
printf("ATA Version: %s\n", props->ata_version); /* Major compliance standard tracking */
printf("SATA Version: %s\n", props->sata_version); /* Signalling standard interface capabilities */
printf("ATA Security: %s\n", props->security_status); /* Operational hardware security locks state */
printf("Determined Type: %s\n", props->type_str);
/* Render storage payload storage capacity with explicit units computing */
double gib = (double)props->mediasize / (1024.0 * 1024.0 * 1024.0);
if (gib >= 1024.0) {
printf("User Capacity: %llu bytes (%.2f TiB)\n",
(unsigned long long)props->mediasize, gib / 1024.0);
} else {
printf("User Capacity: %llu bytes (%.2f GiB)\n",
(unsigned long long)props->mediasize, gib);
}
/* Print drive layout formatting boundaries details */
printf("Sector Sizes: %u bytes logical, %u bytes physical\n",
props->logical_sector_size, props->physical_sector_size);
/* Parse nominal motor spin rotation specs layout */
if (props->rotation_rate == 0) {
printf("Rotation Rate: 0 rpm (SSD)\n");
} else if (props->rotation_rate > 0) {
@ -100,9 +119,15 @@ static void print_identity(const char *disk_name, struct disk_properties *props)
printf("Rotation Rate: N/A\n");
}
printf("SMART Support: %s\n", props->smart_supported == 1 ? "Available" : "Unavailable");
printf("SMART Status: %s\n", props->smart_supported != 1 ? "N/A" :
(props->smart_enabled == 1 ? "Enabled" : "Disabled"));
/* Process core hardware diagnostic state indicators */
if (props->smart_supported == 1) {
printf("SMART Support: Available\n");
printf("SMART Status: %s\n", props->smart_enabled == 1 ? "Enabled" : "Disabled");
} else if (props->smart_supported == 0) {
printf("SMART Support: Not available\n");
} else {
printf("SMART Support: N/A\n");
}
printf("=====================================================\n\n");
}

116
src/libbsdiskinfo.c

@ -225,6 +225,98 @@ int diskinfo_get_mounts(const char *base_disk, struct disk_mount *mounts_out, in
return match_count; /* Return absolute count of populated records */
}
/*
* Extracts advanced ATA/SATA hardware descriptor properties from
* the provided native IDENTIFY parameter blocks.
*/
static void parse_advanced_ata_fields(struct ata_params *buf, struct disk_properties *props) {
/* Base internal storage fields configuration */
uint16_t ff = buf->form_factor;
uint16_t major = buf->version_major;
uint16_t transport = buf->transport_major; /* Word 222: Transport Major Revision Number */
uint16_t sata_cap = buf->satacapabilities; /* Word 76: SATA Capabilities descriptor */
uint16_t sec = buf->security_status; /* Word 128: ATA Security Feature Set state */
/* 1. Form Factor dimensions handling (Word 168) */
if (ff == 2) strlcpy(props->form_factor, "3.5 inches", sizeof(props->form_factor));
else if (ff == 3) strlcpy(props->form_factor, "2.5 inches", sizeof(props->form_factor));
else if (ff == 4) strlcpy(props->form_factor, "1.8 inches", sizeof(props->form_factor));
else if (ff == 5) strlcpy(props->form_factor, "less than 1.8", sizeof(props->form_factor));
else strlcpy(props->form_factor, "N/A", sizeof(props->form_factor));
/* 2. Major ATA Version standard handling (Word 80 & Word 222 Transport Framework) */
if (major == 0xFFFF || major == 0x0000) {
strlcpy(props->ata_version, "Unknown", sizeof(props->ata_version));
}
/*
* Detect actual ATA/ACS revision specification standard level by
* cross-verifying backward-compatible Word 80 flags against physical Word 222 transport bits.
*/
else if ((major & (1 << 14)) || ((major & (1 << 11)) && (transport & 0x1000) && (transport & 0x0040))) {
/* Word 80 Bit 14 OR (ATA8-ACS bit + SATA 3.1+ transport bit 12 + SATA 3.3 bit 6) -> ACS-4 */
strlcpy(props->ata_version, "ACS-4", sizeof(props->ata_version));
} else if ((major & (1 << 13)) || ((major & (1 << 10)) && (transport & 0x1000))) {
/* Word 80 Bit 13 OR (ATA-7+ bit + SATA 3.1+ transport bit 12) -> ACS-3 */
strlcpy(props->ata_version, "ACS-3", sizeof(props->ata_version));
} else if (major & (1 << 12)) {
strlcpy(props->ata_version, "ACS-2", sizeof(props->ata_version));
} else if (major & (1 << 11)) {
strlcpy(props->ata_version, "ATA8-ACS", sizeof(props->ata_version));
} else if (major & (1 << 10)) {
strlcpy(props->ata_version, "ATA/ATAPI-7", sizeof(props->ata_version));
} else {
snprintf(props->ata_version, sizeof(props->ata_version), "ATA Minor/Legacy (0x%04X)", major);
}
/* 3. Serial ATA Capabilities layout tracing (Word 76 & Word 222 Context) */
if (sata_cap == 0xFFFF || sata_cap == 0x0000) {
strlcpy(props->sata_version, "Not a SATA device", sizeof(props->sata_version));
} else {
const char *ver = "SATA";
if (transport != 0xFFFF && transport != 0x0000 && (transport & 0x1000)) {
if (strcmp(props->ata_version, "ACS-4") == 0) {
/* ACS-4 devices can scale between SATA 3.2 and SATA 3.3 */
if ((transport & (1 << 6)) && (transport & 0x0100)) {
ver = "SATA 3.3";
} else {
ver = "SATA 3.2";
}
} else if (strcmp(props->ata_version, "ACS-3") == 0) {
ver = "SATA 3.1";
} else {
if (sata_cap & 0x0006) ver = "SATA 3.0";
else if (sata_cap & 0x0004) ver = "SATA 2.6";
else if (sata_cap & 0x0002) ver = "SATA 1.0a";
}
} else {
if (sata_cap & 0x0006) ver = "SATA 3.0";
else if (sata_cap & 0x0004) ver = "SATA 2.6";
else if (sata_cap & 0x0002) ver = "SATA 1.0a";
}
/* Append signaling interface speed specs mapping data */
if (sata_cap & 0x0006) {
snprintf(props->sata_version, sizeof(props->sata_version), "%s, 6.0 Gb/s", ver);
} else if (sata_cap & 0x0004) {
snprintf(props->sata_version, sizeof(props->sata_version), "%s, 3.0 Gb/s", ver);
} else {
snprintf(props->sata_version, sizeof(props->sata_version), "%s, 1.5 Gb/s", ver);
}
}
/* 4. ATA Security Feature Set state validation (Word 128) */
if (!(sec & 0x0001)) {
strlcpy(props->security_status, "Disabled", sizeof(props->security_status));
} else if (sec & 0x0004) {
strlcpy(props->security_status, "LOCKED", sizeof(props->security_status));
} else if (sec & 0x0008) {
strlcpy(props->security_status, "FROZEN", sizeof(props->security_status));
} else {
strlcpy(props->security_status, "NOT FROZEN", sizeof(props->security_status));
}
}
/*
* Internal helper to query the device via FreeBSD libcam.
* Handles SCSI SAT Pass-Through (16) for 'da' devices and native ATA for 'ada' devices.
@ -244,6 +336,12 @@ static void query_cam_properties(
*pt_failed = 0;
/* Pre-initialize advanced hardware descriptors with default values */
strlcpy(props->form_factor, "N/A", sizeof(props->form_factor));
strlcpy(props->ata_version, "N/A", sizeof(props->ata_version));
strlcpy(props->sata_version, "N/A", sizeof(props->sata_version));
strlcpy(props->security_status, "N/A", sizeof(props->security_status));
/* CRITICAL: Must use O_RDWR for transport-layer commands execution path to unlock */
cam_dev = cam_open_device(base_disk, O_RDWR);
if (cam_dev == NULL) return;
@ -362,9 +460,14 @@ static void query_cam_properties(
*is_ssd = 0;
}
/* Parse Sector Sizes */
if ((ident_buf->pss & 0xC000) == 0x4000 && (ident_buf->pss & 0x1000)) {
/* Parse advanced hardware descriptors from the verified buffer */
parse_advanced_ata_fields(ident_buf, props);
/* Parse Sector Sizes (Word 106: Physical sector size) */
if ((ident_buf->pss & 0x4000) && (ident_buf->pss & 0x2000)) {
props->physical_sector_size = props->logical_sector_size * (1 << (ident_buf->pss & 0x000F));
} else {
props->physical_sector_size = props->logical_sector_size;
}
/* Parse S.M.A.R.T. enablement states */
@ -428,9 +531,14 @@ static void query_cam_properties(
*is_ssd = 0;
}
/* Parse Sector Sizes */
if ((ident_buf->pss & 0xC000) == 0x4000 && (ident_buf->pss & 0x1000)) {
/* Parse advanced hardware descriptors from the direct AHCI buffer */
parse_advanced_ata_fields(ident_buf, props);
/* Parse Sector Sizes (Word 106: Physical sector size) */
if ((ident_buf->pss & 0x4000) && (ident_buf->pss & 0x2000)) {
props->physical_sector_size = props->logical_sector_size * (1 << (ident_buf->pss & 0x000F));
} else {
props->physical_sector_size = props->logical_sector_size;
}
/* Parse S.M.A.R.T. enablement states */

Loading…
Cancel
Save