From 9002d15a554badab03eb8d57cdf62895b6aef8a2 Mon Sep 17 00:00:00 2001 From: Sergey Kiselev Date: Wed, 15 Jul 2026 20:49:06 +0500 Subject: [PATCH] SAT: implement 12-byte fallback recovery for legacy JMicron bridges Introduces an automated 12-byte ATA PASS-THROUGH (12) fallback chain inside query_cam_properties. If a legacy controller (e.g., JMicron JMS539) silences the modern 16-byte layout by returning an empty identity payload, the core safely downgrades the command tracking to 12-byte mapping (0xA1). Additionally, standardized temperature output parsing for Samsung/Toshiba drive limits. --- src/cli.c | 6 ++++++ src/libbsdiskinfo.c | 30 ++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/cli.c b/src/cli.c index 9f2e67a..72fc03f 100644 --- a/src/cli.c +++ b/src/cli.c @@ -166,6 +166,12 @@ static void print_smart(const char *disk_name) { int min_lifetime = (int)((counters[i].raw_val >> 32) & 0xFF); /* Fixed strict & 0xFF byte-4 alignment masking */ int max_lifetime = (int)((counters[i].raw_val >> 40) & 0xFF); /* Fixed strict & 0xFF byte-5 alignment masking */ + /* Fix for Toshiba/Samsung layouts where byte 4 is Max and byte 5 is empty */ + if (min_lifetime > 0 && max_lifetime == 0) { + max_lifetime = min_lifetime; + min_lifetime = 0; + } + if (min_lifetime > 0 && min_lifetime < 100) { if (max_lifetime > 0 && max_lifetime < 100 && max_lifetime > min_lifetime) { printf("%-12llu (Min/Max %d/%d)\n", (unsigned long long)counters[i].raw_val, min_lifetime, max_lifetime); diff --git a/src/libbsdiskinfo.c b/src/libbsdiskinfo.c index 07bd90f..72543fa 100644 --- a/src/libbsdiskinfo.c +++ b/src/libbsdiskinfo.c @@ -296,7 +296,33 @@ 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; + } + } + } + + if (success) { /* Extract Identity Block Data fields */ char real_model[41]; memcpy(real_model, ident_buf->model, sizeof(ident_buf->model)); @@ -354,7 +380,7 @@ static void query_cam_properties( } free(inq_buf); - } + } /* --- PROTOCOL BRANCH 2: Native SATA/ATA Devices (ada) --- */ else if (strncmp(base_disk, "ada", 3) == 0) { /* 2a: Pure ATA IDENTIFY */