@ -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>
@ -225,6 +226,125 @@ 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 using native libcam functions .
*/
static void parse_advanced_ata_fields ( struct ata_params * buf , struct disk_properties * props , float current_speed ) {
/* 1. Form Factor dimensions handling (Word 168) */
uint16_t ff = buf - > form_factor ;
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 using native ata_version() from libcam.so */
int version = ata_version ( buf - > version_major ) ;
if ( buf - > version_major = = 0xFFFF | | buf - > version_major = = 0x0000 | | version < 0 ) {
strlcpy ( props - > ata_version , " Unknown " , sizeof ( props - > ata_version ) ) ;
} else {
switch ( version ) {
case 0 :
strlcpy ( props - > ata_version , " ATA " , sizeof ( props - > ata_version ) ) ;
break ;
case 8 :
strlcpy ( props - > ata_version , " ATA8-ACS " , sizeof ( props - > ata_version ) ) ;
break ;
default :
if ( version < = 7 ) {
snprintf ( props - > ata_version , sizeof ( props - > ata_version ) , " ATA-%d " , version ) ;
} else {
snprintf ( props - > ata_version , sizeof ( props - > ata_version ) , " ACS-%d " , version - 7 ) ;
}
break ;
}
}
/* 3. Serial ATA Capabilities layout tracing limited by mapped ATA standard boundaries (Word 76 & Word 222) */
uint16_t sata_cap = buf - > satacapabilities ;
uint16_t transport = buf - > transport_major ;
if ( sata_cap = = 0xFFFF | | sata_cap = = 0x0000 ) {
strlcpy ( props - > sata_version , " Not a SATA device " , sizeof ( props - > sata_version ) ) ;
} else {
const char * ver = NULL ;
float cap_speed = 1.5 ;
/* Extract logical transport revision from Word 222 using explicit camcontrol bit boundaries */
if ( transport ! = 0xFFFF & & transport ! = 0x0000 & & ( transport & 0x1000 ) ) {
if ( transport & 0x0400 ) ver = " SATA 3.5 " ;
else if ( transport & 0x0200 ) ver = " SATA 3.4 " ;
else if ( transport & 0x0100 ) ver = " SATA 3.3 " ;
else if ( transport & 0x0080 ) ver = " SATA 3.2 " ;
else if ( transport & 0x0040 ) ver = " SATA 3.1 " ;
else if ( transport & 0x0020 ) ver = " SATA 3.0 " ;
else if ( transport & 0x0010 ) ver = " SATA 2.6 " ;
else if ( transport & 0x0008 ) ver = " SATA 2.5 " ;
}
/* Fallback to physical link generation signaling limits from Word 76 if transport is unmapped */
if ( ver = = NULL ) {
if ( strcmp ( props - > ata_version , " ATA-7 " ) = = 0 | | strncmp ( props - > ata_version , " ATA- " , 4 ) = = 0 ) {
ver = " SATA 1.x " ;
cap_speed = 1.5 ;
} else {
if ( sata_cap & 0x0006 ) {
ver = " SATA 3.x " ;
cap_speed = 6.0 ;
} else if ( sata_cap & 0x0004 ) {
ver = " SATA 2.x " ;
cap_speed = 3.0 ;
} else {
ver = " SATA 1.x " ;
cap_speed = 1.5 ;
}
}
} else {
/* Determine maximum capable speed rate from Word 76 capabilities for modern units */
if ( sata_cap & 0x0006 ) cap_speed = 6.0 ;
else if ( sata_cap & 0x0004 ) cap_speed = 3.0 ;
else cap_speed = 1.5 ;
/*
* Architectural ceiling check for backwards compatibility ( FreeBSD 11.4 legacy layers ) .
* If the drive is reporting legacy SATA 2.5 / 2.6 or if we are tracking older firmware lines ,
* override fake controller - injected Gen3 speed limits using drive ' s genuine Word 76 bits .
*/
if ( strncmp ( ver , " SATA 2. " , 7 ) = = 0 & & cap_speed > 3.0 ) {
if ( sata_cap & 0x0004 ) cap_speed = 3.0 ;
else cap_speed = 1.5 ;
}
/* If running on older FreeBSD 11.4 where Word 222 output fluctuates, sanitize down to 1.x */
if ( cap_speed = = 1.5 & & strncmp ( ver , " SATA 3. " , 7 ) ! = 0 ) {
ver = " SATA 1.x " ;
}
}
/* If CAM transport layout parsing returned empty/restricted, sync with capable speed */
if ( current_speed < = 0.0 ) {
current_speed = cap_speed ;
}
/* Generate final elegant string matches smartctl/camcontrol style */
snprintf ( props - > sata_version , sizeof ( props - > sata_version ) ,
" %s, %.1f Gb/s (current: %.1f Gb/s) " , ver , cap_speed , current_speed ) ;
}
/* 4. ATA Security Feature Set state validation (Word 128) */
uint16_t sec = buf - > security_status ;
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,12 +364,90 @@ static void query_cam_properties(
* pt_failed = 0 ;
/* CRITICAL: Must use O_RDWR for transport-layer commands execution path to unlock */
/* 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 Check: Permissions routing validation */
cam_dev = cam_open_device ( base_disk , O_RDWR ) ;
if ( cam_dev = = NULL ) return ;
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 ;
}
/* Extract current active signaling rate mirroring camcontrol.c camxferrate() flow exactly */
float current_speed = 0.0 ;
uint32_t speed = 0 ;
union ccb * ccb_cts = NULL ;
struct ccb_pathinq cpi ;
memset ( & cpi , 0 , sizeof ( struct ccb_pathinq ) ) ;
/* Step A: Fetch base speed path inquiry matching camcontrol get_cpi() */
union ccb * ccb_cpi = cam_getccb ( cam_dev ) ;
if ( ccb_cpi ! = NULL ) {
ccb_cpi - > ccb_h . func_code = XPT_PATH_INQ ;
ccb_cpi - > ccb_h . flags = CAM_DIR_NONE ;
ccb_cpi - > ccb_h . retry_count = 1 ;
ccb_cpi - > ccb_h . timeout = 1000 ;
if ( cam_send_ccb ( cam_dev , ccb_cpi ) = = 0 & & ( ccb_cpi - > ccb_h . status & CAM_STATUS_MASK ) = = CAM_REQ_CMP ) {
bcopy ( & ccb_cpi - > cpi , & cpi , sizeof ( struct ccb_pathinq ) ) ;
}
cam_freeccb ( ccb_cpi ) ;
}
/* Initialize baseline transfer speed value from Path Inquiry */
speed = cpi . base_transfer_speed ;
/* Step B: Query exact active transfer settings from the CAM layer */
ccb_cts = cam_getccb ( cam_dev ) ;
if ( ccb_cts ! = NULL ) {
ccb_cts - > ccb_h . func_code = XPT_GET_TRAN_SETTINGS ;
ccb_cts - > ccb_h . flags = CAM_DIR_NONE ;
ccb_cts - > ccb_h . retry_count = 1 ;
ccb_cts - > ccb_h . timeout = 1000 ;
ccb_cts - > ccb_h . target_id = cam_dev - > target_id ;
ccb_cts - > ccb_h . target_lun = cam_dev - > target_lun ;
ccb_cts - > cts . type = CTS_TYPE_CURRENT_SETTINGS ; /* Force runtime active link preference layout fetch */
if ( cam_send_ccb ( cam_dev , ccb_cts ) = = 0 & & ( ccb_cts - > ccb_h . status & CAM_STATUS_MASK ) = = CAM_REQ_CMP ) {
/* Execute exact transport specific branching copied from camcontrol.c source */
if ( ccb_cts - > cts . transport = = XPORT_ATA ) {
struct ccb_trans_settings_pata * pata = & ccb_cts - > cts . xport_specific . ata ;
if ( pata - > valid & CTS_ATA_VALID_MODE ) {
speed = ata_mode2speed ( pata - > mode ) ;
}
} else if ( ccb_cts - > cts . transport = = XPORT_SATA ) {
struct ccb_trans_settings_sata * sata = & ccb_cts - > cts . xport_specific . sata ;
if ( sata - > valid & CTS_SATA_VALID_REVISION ) {
speed = ata_revision2speed ( sata - > revision ) ;
}
} else if ( ccb_cts - > cts . transport = = XPORT_SAS ) {
struct ccb_trans_settings_sas * sas = & ccb_cts - > cts . xport_specific . sas ;
if ( sas - > valid & 0x01 ) { /* CTS_SAS_VALID_SPEED */
speed = sas - > bitrate ;
}
}
}
cam_freeccb ( ccb_cts ) ;
}
/* Map finalized speed KB/s calculation to human-readable Gb/s standard format */
uint32_t mb = speed / 1000 ;
if ( mb > = 550 ) current_speed = 6.0 ;
else if ( mb > = 280 ) current_speed = 3.0 ;
else if ( mb > = 140 ) current_speed = 1.5 ;
/* Allocate CCB structure for standard IDENTIFY command execution path below */
ccb = cam_getccb ( cam_dev ) ;
if ( ccb = = NULL ) {
fprintf ( stderr , " [ERROR] %s: Failed to allocate CAM CCB structure \n " , base_disk ) ;
cam_close_device ( cam_dev ) ;
return ;
}
@ -296,7 +494,38 @@ static void query_cam_properties(
uint8_t * cdb = ccb - > csio . cdb_io . cdb_bytes ;
cdb [ 0 ] = 0x85 ; cdb [ 1 ] = 4 < < 1 ; cdb [ 2 ] = 0x08 | 0x02 ; cdb [ 4 ] = 1 ; cdb [ 14 ] = 0xEC ;
if ( cam_send_ccb ( cam_dev , ccb ) = = 0 & & ( ccb - > ccb_h . status & CAM_STATUS_MASK ) = = CAM_REQ_CMP ) {
int success = ( cam_send_ccb ( cam_dev , ccb ) = = 0 & & ( ccb - > ccb_h . status & CAM_STATUS_MASK ) = = CAM_REQ_CMP ) ;
if ( success & & ident_buf - > model [ 0 ] = = 0 ) {
success = 0 ;
}
if ( ! success ) {
/*
* FALLBACK : 16 - byte frame returned an empty layout .
* Downgrade transport to 12 - byte ATA PASS - THROUGH ( 12 ) for legacy JMicron bridges .
*/
memset ( & ccb - > csio , 0 , sizeof ( struct ccb_scsiio ) ) ;
cam_fill_csio ( & ccb - > csio , 2 , NULL , CAM_DIR_IN , CAM_TAG_ACTION_NONE ,
( uint8_t * ) ident_buf , sizeof ( struct ata_params ) , SSD_FULL_SIZE , 12 , 5000 ) ;
uint8_t * cdb12 = ccb - > csio . cdb_io . cdb_bytes ;
cdb12 [ 0 ] = 0xA1 ; cdb12 [ 1 ] = 4 < < 1 ; cdb12 [ 2 ] = 0x2E ; cdb12 [ 4 ] = 1 ; cdb12 [ 9 ] = 0xEC ;
if ( cam_send_ccb ( cam_dev , ccb ) = = 0 ) {
uint32_t cam_status = ccb - > ccb_h . status & CAM_STATUS_MASK ;
if ( cam_status = = CAM_REQ_CMP | | cam_status = = CAM_SCSI_STATUS_ERROR ) {
success = 1 ;
}
}
/* Filter out fake success on SAT(12) loop as well */
if ( success & & ident_buf - > model [ 0 ] = = 0 ) {
success = 0 ;
}
}
if ( success ) {
/* Extract Identity Block Data fields */
char real_model [ 41 ] ;
memcpy ( real_model , ident_buf - > model , sizeof ( ident_buf - > model ) ) ;
@ -336,9 +565,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 , current_speed ) ;
/* 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 {
props - > physical_sector_size = props - > logical_sector_size ;
}
/* Parse S.M.A.R.T. enablement states */
@ -349,6 +583,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 ;
}
}
@ -364,56 +599,67 @@ 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 ) {
char real_model [ 41 ] ;
memcpy ( real_model , ident_buf - > model , sizeof ( ident_buf - > model ) ) ;
real_model [ sizeof ( ident_buf - > model ) ] = ' \0 ' ;
ata_str_fix ( real_model , sizeof ( real_model ) ) ;
if ( strlen ( real_model ) > 0 ) strlcpy ( props - > model , real_model , sizeof ( props - > model ) ) ;
char real_serial [ 21 ] ;
memcpy ( real_serial , ident_buf - > serial , sizeof ( ident_buf - > serial ) ) ;
real_serial [ sizeof ( ident_buf - > serial ) ] = ' \0 ' ;
ata_str_fix ( real_serial , sizeof ( real_serial ) ) ;
if ( strlen ( real_serial ) > 0 ) strlcpy ( props - > serial , real_serial , sizeof ( props - > serial ) ) ;
char real_fw [ 9 ] ;
memcpy ( real_fw , ident_buf - > revision , sizeof ( ident_buf - > revision ) ) ;
real_fw [ sizeof ( ident_buf - > revision ) ] = ' \0 ' ;
ata_str_fix ( real_fw , sizeof ( real_fw ) ) ;
if ( strlen ( real_fw ) > 0 ) strlcpy ( props - > fw_version , real_fw , sizeof ( props - > fw_version ) ) ;
/* Parse LU WWN Device ID */
uint64_t wwn_val = 0 ;
for ( int w = 0 ; w < 4 ; w + + ) {
wwn_val | = ( ( uint64_t ) ident_buf - > wwn [ w ] ) < < ( ( 3 - w ) * 16 ) ;
}
if ( wwn_val ! = 0 ) snprintf ( props - > wwn , sizeof ( props - > wwn ) , " %016llx " , ( unsigned long long ) wwn_val ) ;
else strlcpy ( props - > wwn , " N/A " , sizeof ( props - > wwn ) ) ;
/* Parse Rotation Rate and SSD state flags */
if ( ident_buf - > media_rotation_rate = = 1 ) {
props - > rotation_rate = 0 ;
* is_ssd = 1 ;
} else if ( ident_buf - > media_rotation_rate > 1 & & ident_buf - > media_rotation_rate < 0xFFFF ) {
props - > rotation_rate = ident_buf - > media_rotation_rate ;
* is_ssd = 0 ;
if ( ident_buf - > model [ 0 ] = = 0 ) {
fprintf ( stderr , " [ERROR] %s: IDENTIFY DEVICE returned empty payload (hardware fault) \n " , base_disk ) ;
} else {
props - > rotation_rate = - 1 ;
* is_ssd = 0 ;
}
char real_model [ 41 ] ;
memcpy ( real_model , ident_buf - > model , sizeof ( ident_buf - > model ) ) ;
real_model [ sizeof ( ident_buf - > model ) ] = ' \0 ' ;
ata_str_fix ( real_model , sizeof ( real_model ) ) ;
if ( strlen ( real_model ) > 0 ) strlcpy ( props - > model , real_model , sizeof ( props - > model ) ) ;
/* Parse Sector Sizes */
if ( ( ident_buf - > pss & 0xC000 ) = = 0x4000 & & ( ident_buf - > pss & 0x1000 ) ) {
props - > physical_sector_size = props - > logical_sector_size * ( 1 < < ( ident_buf - > pss & 0x000F ) ) ;
}
char real_serial [ 21 ] ;
memcpy ( real_serial , ident_buf - > serial , sizeof ( ident_buf - > serial ) ) ;
real_serial [ sizeof ( ident_buf - > serial ) ] = ' \0 ' ;
ata_str_fix ( real_serial , sizeof ( real_serial ) ) ;
if ( strlen ( real_serial ) > 0 ) strlcpy ( props - > serial , real_serial , sizeof ( props - > serial ) ) ;
/* Parse S.M.A.R.T. enablement states */
if ( ident_buf - > support . command1 & 0x0001 ) {
props - > smart_supported = 1 ;
props - > smart_enabled = ( ident_buf - > enabled . command1 & 0x0001 ) ? 1 : 0 ;
} else {
props - > smart_supported = 0 ; props - > smart_enabled = 0 ;
char real_fw [ 9 ] ;
memcpy ( real_fw , ident_buf - > revision , sizeof ( ident_buf - > revision ) ) ;
real_fw [ sizeof ( ident_buf - > revision ) ] = ' \0 ' ;
ata_str_fix ( real_fw , sizeof ( real_fw ) ) ;
if ( strlen ( real_fw ) > 0 ) strlcpy ( props - > fw_version , real_fw , sizeof ( props - > fw_version ) ) ;
/* Parse LU WWN Device ID */
uint64_t wwn_val = 0 ;
for ( int w = 0 ; w < 4 ; w + + ) {
wwn_val | = ( ( uint64_t ) ident_buf - > wwn [ w ] ) < < ( ( 3 - w ) * 16 ) ;
}
if ( wwn_val ! = 0 ) snprintf ( props - > wwn , sizeof ( props - > wwn ) , " %016llx " , ( unsigned long long ) wwn_val ) ;
else strlcpy ( props - > wwn , " N/A " , sizeof ( props - > wwn ) ) ;
/* Parse Rotation Rate and SSD state flags */
if ( ident_buf - > media_rotation_rate = = 1 ) {
props - > rotation_rate = 0 ;
* is_ssd = 1 ;
} else if ( ident_buf - > media_rotation_rate > 1 & & ident_buf - > media_rotation_rate < 0xFFFF ) {
props - > rotation_rate = ident_buf - > media_rotation_rate ;
* is_ssd = 0 ;
} else {
props - > rotation_rate = - 1 ;
* is_ssd = 0 ;
}
/* Parse advanced hardware descriptors from the direct AHCI buffer */
parse_advanced_ata_fields ( ident_buf , props , current_speed ) ;
/* 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 {
props - > physical_sector_size = props - > logical_sector_size ;
}
/* Parse S.M.A.R.T. enablement states */
if ( ident_buf - > support . command1 & 0x0001 ) {
props - > smart_supported = 1 ;
props - > smart_enabled = ( ident_buf - > enabled . command1 & 0x0001 ) ? 1 : 0 ;
} else {
props - > smart_supported = 0 ; props - > smart_enabled = 0 ;
}
}
} else {
fprintf ( stderr , " [ERROR] %s: Native ATA IDENTIFY command rejected by the controller \n " , base_disk ) ;
}
}