|
|
|
@ -30,6 +30,7 @@ |
|
|
|
|
|
|
|
#define _GNU_SOURCE /* For strcasestr support */ |
|
|
|
|
|
|
|
#include <errno.h> |
|
|
|
#include <sys/param.h> |
|
|
|
#include <sys/ucred.h> |
|
|
|
#include <sys/mount.h> |
|
|
|
@ -246,24 +247,25 @@ static void parse_advanced_ata_fields(struct ata_params *buf, struct disk_proper |
|
|
|
|
|
|
|
/* 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)); |
|
|
|
fprintf(stderr, "[WARNING] ATA Version unreadable: Word 80 reports invalid boundary (0x%04X)\n", major); |
|
|
|
strlcpy(props->ata_version, "Unknown (Invalid Word 80)", 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)) { |
|
|
|
} else if ((major & (1 << 11)) || (major & (1 << 8))) { |
|
|
|
strlcpy(props->ata_version, "ATA8-ACS", sizeof(props->ata_version)); |
|
|
|
} else if (major & (1 << 10)) { |
|
|
|
} else if (major & (1 << 7)) { |
|
|
|
strlcpy(props->ata_version, "ATA/ATAPI-7", sizeof(props->ata_version)); |
|
|
|
} else if (major & (1 << 6)) { |
|
|
|
strlcpy(props->ata_version, "ATA/ATAPI-6", sizeof(props->ata_version)); |
|
|
|
} else { |
|
|
|
snprintf(props->ata_version, sizeof(props->ata_version), "ATA Minor/Legacy (0x%04X)", major); |
|
|
|
} |
|
|
|
@ -276,7 +278,6 @@ static void parse_advanced_ata_fields(struct ata_params *buf, struct disk_proper |
|
|
|
|
|
|
|
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 { |
|
|
|
@ -295,7 +296,6 @@ static void parse_advanced_ata_fields(struct ata_params *buf, struct disk_proper |
|
|
|
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) { |
|
|
|
@ -342,6 +342,17 @@ static void query_cam_properties( |
|
|
|
strlcpy(props->sata_version, "N/A", sizeof(props->sata_version)); |
|
|
|
strlcpy(props->security_status, "N/A", sizeof(props->security_status)); |
|
|
|
|
|
|
|
/* CRITICAL Check: Permissions routing validation */ |
|
|
|
cam_dev = cam_open_device(base_disk, O_RDWR); |
|
|
|
if (cam_dev == NULL) { |
|
|
|
if (errno == EACCES || errno == EPERM) { |
|
|
|
fprintf(stderr, "[ERROR] %s: Permission denied. Accessing libcam transport layers requires root privileges (run with sudo).\n", base_disk); |
|
|
|
} else { |
|
|
|
fprintf(stderr, "[ERROR] %s: Failed to open CAM device node (errno: %d)\n", base_disk, errno); |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
/* 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; |
|
|
|
@ -418,6 +429,11 @@ static void query_cam_properties( |
|
|
|
success = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* Filter out fake success on SAT(12) loop as well */ |
|
|
|
if (success && ident_buf->model[0] == 0) { |
|
|
|
success = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (success) { |
|
|
|
@ -463,7 +479,7 @@ static void query_cam_properties( |
|
|
|
/* Parse advanced hardware descriptors from the verified buffer */ |
|
|
|
parse_advanced_ata_fields(ident_buf, props); |
|
|
|
|
|
|
|
/* Parse Sector Sizes (Word 106: Physical sector size) */ |
|
|
|
/* Parse Sector Sizes (Word 106: Physical sector size / Advanced Format) */ |
|
|
|
if ((ident_buf->pss & 0x4000) && (ident_buf->pss & 0x2000)) { |
|
|
|
props->physical_sector_size = props->logical_sector_size * (1 << (ident_buf->pss & 0x000F)); |
|
|
|
} else { |
|
|
|
@ -478,6 +494,7 @@ static void query_cam_properties( |
|
|
|
props->smart_supported = 0; props->smart_enabled = 0; |
|
|
|
} |
|
|
|
} else { |
|
|
|
fprintf(stderr, "[ERROR] %s: ATA Pass-Through rejected or returned empty payload (hardware timeout/fault)\n", base_disk); |
|
|
|
*pt_failed = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -493,6 +510,9 @@ static void query_cam_properties( |
|
|
|
ccb->ataio.cmd.command = 0xEC; |
|
|
|
|
|
|
|
if (cam_send_ccb(cam_dev, ccb) == 0 && (ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { |
|
|
|
if (ident_buf->model[0] == 0) { |
|
|
|
fprintf(stderr, "[ERROR] %s: IDENTIFY DEVICE returned empty payload (hardware fault)\n", base_disk); |
|
|
|
} else { |
|
|
|
char real_model[41]; |
|
|
|
memcpy(real_model, ident_buf->model, sizeof(ident_buf->model)); |
|
|
|
real_model[sizeof(ident_buf->model)] = '\0'; |
|
|
|
@ -534,7 +554,7 @@ static void query_cam_properties( |
|
|
|
/* Parse advanced hardware descriptors from the direct AHCI buffer */ |
|
|
|
parse_advanced_ata_fields(ident_buf, props); |
|
|
|
|
|
|
|
/* Parse Sector Sizes (Word 106: Physical sector size) */ |
|
|
|
/* Parse Sector Sizes (Word 106: Physical sector size / Advanced Format) */ |
|
|
|
if ((ident_buf->pss & 0x4000) && (ident_buf->pss & 0x2000)) { |
|
|
|
props->physical_sector_size = props->logical_sector_size * (1 << (ident_buf->pss & 0x000F)); |
|
|
|
} else { |
|
|
|
@ -549,6 +569,9 @@ static void query_cam_properties( |
|
|
|
props->smart_supported = 0; props->smart_enabled = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
fprintf(stderr, "[ERROR] %s: Native ATA IDENTIFY command rejected by the controller\n", base_disk); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* Clean up allocated heap memory buffers */ |
|
|
|
|