/* * smartdump.c - FreeBSD CLI utility for querying and decoding * disk hardware S.M.A.R.T. records directly via the CAM subsystem. * * Can output raw binary stream for piping or human-readable decoded matrix. * * cc -O2 -Wall smartdump.c -lcam -o smartdump */ #include #include #include #include #include #include #include #include #include /* FreeBSD CAM Library Interface Headers */ #include #include /* Import local shared SMART layout matrix definitions */ #include "../src/smart.h" /* Cross-vendor SMART buffer decoder and normalizer */ static void decode_smart(struct smart_values *smart_buf) { printf("ID# ATTRIBUTE_NAME VALUE WORST RAW_VALUE\n"); printf("==================================================================\n"); for (int i = 0; i < 30; i++) { struct smart_attribute *a = &smart_buf->attr[i]; if (a->id == 0) continue; uint64_t raw_val = 0; /* Enforce custom cross-vendor temperature extraction rule */ if (a->id == 194 || a->id == 190) { raw_val = parse_smart_temperature(a); } else { /* Assemble clean 48-bit metric integer for standard counters */ for (int b = 0; b < 6; b++) { raw_val |= ((uint64_t)a->raw[b]) << (b * 8); } } printf("%3d %-23s %3d %3d %llu\n", a->id, get_attr_name(a->id), a->current, a->worst, (unsigned long long)raw_val); } } int main(int argc, char **argv) { int ch; int mode_decode = 0; /* Parse configuration operational runtime flag args */ while ((ch = getopt(argc, argv, "dr")) != -1) { switch (ch) { case 'd': mode_decode = 1; break; case 'r': mode_decode = 0; break; default: fprintf(stderr, "Usage: %s [-d|-r] \n", argv[0]); return 1; } } argc -= optind; argv += optind; if (argc < 1) { fprintf(stderr, "Usage: %s [-d|-r] (e.g. ada1 or da0)\n", argv[-optind]); return 1; } const char *disk = argv[0]; struct cam_device *cam_dev = NULL; union ccb *ccb = NULL; struct smart_values *smart_buf = NULL; /* Open device via O_RDWR to unlock transport-layer CCB execution paths */ cam_dev = cam_open_device(disk, O_RDWR); if (cam_dev == NULL) { fprintf(stderr, "Error: cam_open_device failed for '%s'. Check permissions.\n", disk); return 1; } ccb = cam_getccb(cam_dev); if (ccb == NULL) { fprintf(stderr, "Error: Failed to allocate CCB block\n"); cam_close_device(cam_dev); return 1; } smart_buf = calloc(1, sizeof(struct smart_values)); if (smart_buf == NULL) { fprintf(stderr, "Error: Memory allocation failed\n"); cam_freeccb(ccb); cam_close_device(cam_dev); return 1; } /* --- PROTOCOL BRANCH 1: Native SATA/ATA Devices (ada) --- */ if (strncmp(disk, "ada", 3) == 0) { cam_fill_ataio(&ccb->ataio, 2, NULL, CAM_DIR_IN, CAM_TAG_ACTION_NONE, (uint8_t *)smart_buf, sizeof(struct smart_values), 5000); ccb->ataio.cmd.command = 0xB0; /* ATA SMART Command Opcode */ ccb->ataio.cmd.features = 0xD0; /* SMART READ DATA Command Feature Code */ ccb->ataio.cmd.lba_mid = 0x4F; /* Subsystem Spec Signature Marker */ ccb->ataio.cmd.lba_high = 0xC2; /* Subsystem Spec Signature Marker */ if (cam_send_ccb(cam_dev, ccb) != 0 || (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { fprintf(stderr, "Error: ATA SMART command failed (CAM Status: 0x%X)\n", ccb->ccb_h.status); free(smart_buf); cam_freeccb(ccb); cam_close_device(cam_dev); return 1; } } /* --- PROTOCOL BRANCH 2: USB / SCSI Bridges (da) --- */ else if (strncmp(disk, "da", 2) == 0) { memset(&ccb->csio, 0, sizeof(struct ccb_scsiio)); cam_fill_csio(&ccb->csio, 2, NULL, CAM_DIR_IN, CAM_TAG_ACTION_NONE, (uint8_t *)smart_buf, sizeof(struct smart_values), SSD_FULL_SIZE, 16, 5000); uint8_t *cdb = ccb->csio.cdb_io.cdb_bytes; cdb[0] = 0x85; /* SCSI Opcode: ATA PASS-THROUGH (16) */ cdb[1] = 4 << 1; /* Protocol: PIO Data-In */ cdb[2] = 0x08 | 0x02; /* T_DIR = 1 (Data-In), ByteBlock = 1 (Sectors mode) */ cdb[4] = 0xD0; /* Features (lower) -> SMART READ DATA */ cdb[6] = 1; /* Sector Count = 1 sector (512 bytes) */ cdb[8] = 0x4F; /* LBA Mid -> SMART Signature Mid */ cdb[10] = 0xC2; /* LBA High -> SMART Signature High */ cdb[14] = 0xB0; /* ATA Command -> SMART Command Opcode */ if (cam_send_ccb(cam_dev, ccb) != 0 || (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { fprintf(stderr, "Error: SCSI SAT SMART command failed (CAM Status: 0x%X)\n", ccb->ccb_h.status); free(smart_buf); cam_freeccb(ccb); cam_close_device(cam_dev); return 1; } } else { fprintf(stderr, "Error: Unsupported device driver type target routing path.\n"); free(smart_buf); cam_freeccb(ccb); cam_close_device(cam_dev); return 1; } /* Route output generation maps according to active selection flag switches */ if (mode_decode) { decode_smart(smart_buf); } else { fwrite(smart_buf, 1, 512, stdout); } free(smart_buf); cam_freeccb(ccb); cam_close_device(cam_dev); return 0; }