git: e139a49b5d8e - main - Revert "Vendor import of smart at 1.0.2"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 28 Apr 2026 19:04:00 UTC
The branch main has been updated by chuck:
URL: https://cgit.FreeBSD.org/src/commit/?id=e139a49b5d8e9385b4d42ea1ec3850bc80d7f989
commit e139a49b5d8e9385b4d42ea1ec3850bc80d7f989
Author: Chuck Tuffli <chuck@FreeBSD.org>
AuthorDate: 2026-04-28 18:49:22 +0000
Commit: Chuck Tuffli <chuck@FreeBSD.org>
CommitDate: 2026-04-28 19:03:38 +0000
Revert "Vendor import of smart at 1.0.2"
This reverts commit 68e5b71517e947b4e3f349c970af362b47b45f27.
---
contrib/smart/Changelog | 37 --
contrib/smart/LICENSE | 13 -
contrib/smart/Makefile | 26 -
contrib/smart/freebsd_dev.c | 828 -------------------------
contrib/smart/libsmart.c | 1359 -----------------------------------------
contrib/smart/libsmart.h | 174 ------
contrib/smart/libsmart_desc.c | 158 -----
contrib/smart/libsmart_dev.h | 60 --
contrib/smart/libsmart_priv.h | 83 ---
contrib/smart/smart.8 | 245 --------
contrib/smart/smart.c | 334 ----------
packages/Makefile | 1 -
packages/smart/Makefile | 4 -
packages/smart/smart.ucl | 30 -
usr.sbin/Makefile | 1 -
usr.sbin/smart/Makefile | 8 -
16 files changed, 3361 deletions(-)
diff --git a/contrib/smart/Changelog b/contrib/smart/Changelog
deleted file mode 100644
index 42b79bc34070..000000000000
--- a/contrib/smart/Changelog
+++ /dev/null
@@ -1,37 +0,0 @@
-This file documents changes for smart releases
-
-version 1.0.2
- - Bring man page up to snuff
- - Fix various complier warnings
-
-version 1.0.1
- - Fix don't print attribute ID with description
-
-version 1.0.0
- - Fix ATA threshold output (gh-10). This is a breaking change as it
- reduces the output from 4 fields to 3 (drops the "reserved" byte
- from threshold).
- - Fix the ATA raw output. This is a breaking change as it increase the
- output from 6 bytes to 7 (i.e., includes the "reserved" byte). Note
- that while some attributes use this byte, most do not.
- - Fix direct debug output (--debug) to standard error
- - Use POSIX memcpy and memset instead of older bXXX equivalents
-
-version 0.4.2
- - Update README contents
-
-version 0.4.1
- - Allow a comma-separated list of attributes
- - Code refactor + update code comments
-
-version 0.3.0
-
- - Reclaim the -d option from debug
- - Change field separator from spaces to tab
- - Add textual descriptions of attribute IDs for ATA, NVMe, and SCSI
- - Add a manual page
- - Fixes
- * libxo structure for attribute and attributes
- * simplify LIBXO ifdef sprawl
- * display of threshold values
- * display of long values
diff --git a/contrib/smart/LICENSE b/contrib/smart/LICENSE
deleted file mode 100644
index 8b0a0bf6a4a6..000000000000
--- a/contrib/smart/LICENSE
+++ /dev/null
@@ -1,13 +0,0 @@
-Copyright (c) 2016-2026 Chuck Tuffli <chuck@tuffli.net>
-
-Permission to use, copy, modify, and distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/contrib/smart/Makefile b/contrib/smart/Makefile
deleted file mode 100644
index 64cab720e08f..000000000000
--- a/contrib/smart/Makefile
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# Copyright (c) 2016-2021 Chuck Tuffli <chuck@tuffli.net>
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-PROG= smart
-SRCS= smart.c libsmart.c libsmart_desc.c
-SRCS+= freebsd_dev.c
-LIBADD= cam xo
-MAN=smart.8
-MLINKS= smart.8 diskhealth.8
-#CFLAGS+= -ggdb -O0
-CFLAGS+= -DLIBXO
-LINKS= ${BINDIR}/smart ${BINDIR}/diskhealth
-
-.include <bsd.prog.mk>
diff --git a/contrib/smart/freebsd_dev.c b/contrib/smart/freebsd_dev.c
deleted file mode 100644
index d1dda2289742..000000000000
--- a/contrib/smart/freebsd_dev.c
+++ /dev/null
@@ -1,828 +0,0 @@
-/*
- * Copyright (c) 2016-2021 Chuck Tuffli <chuck@tuffli.net>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <string.h>
-#include <err.h>
-#include <errno.h>
-#include <camlib.h>
-#include <cam/scsi/scsi_message.h>
-
-#include "libsmart.h"
-#include "libsmart_priv.h"
-#include "libsmart_dev.h"
-
-/* Provide compatibility for FreeBSD 11.0 */
-#if (__FreeBSD_version < 1101000)
-
-struct scsi_log_informational_exceptions {
- struct scsi_log_param_header hdr;
-#define SLP_IE_GEN 0x0000
- uint8_t ie_asc;
- uint8_t ie_ascq;
- uint8_t temperature;
-};
-
-#endif
-
-struct fbsd_smart {
- smart_t common;
- struct cam_device *camdev;
-};
-
-static smart_protocol_e __device_get_proto(struct fbsd_smart *);
-static bool __device_proto_tunneled(struct fbsd_smart *);
-static int32_t __device_get_info(struct fbsd_smart *);
-
-smart_h
-device_open(smart_protocol_e protocol, char *devname)
-{
- struct fbsd_smart *h = NULL;
-
- h = malloc(sizeof(struct fbsd_smart));
- if (h == NULL)
- return NULL;
-
- memset(h, 0, sizeof(struct fbsd_smart));
-
- h->common.protocol = SMART_PROTO_MAX;
- h->camdev = cam_open_device(devname, O_RDWR);
- if (h->camdev == NULL) {
- printf("%s: error opening %s - %s\n",
- __func__, devname,
- cam_errbuf);
- free(h);
- h = NULL;
- } else {
- smart_protocol_e proto = __device_get_proto(h);
-
- if ((protocol == SMART_PROTO_AUTO) ||
- (protocol == proto)) {
- h->common.protocol = proto;
- } else {
- printf("%s: protocol mismatch %d vs %d\n",
- __func__, protocol, proto);
- }
-
- if (proto == SMART_PROTO_SCSI) {
- if (__device_proto_tunneled(h)) {
- h->common.protocol = SMART_PROTO_ATA;
- h->common.info.tunneled = 1;
- }
- }
-
- __device_get_info(h);
- }
-
- return h;
-}
-
-void
-device_close(smart_h h)
-{
- struct fbsd_smart *fsmart = h;
-
- if (fsmart != NULL) {
- if (fsmart->camdev != NULL) {
- cam_close_device(fsmart->camdev);
- }
-
- free(fsmart);
- }
-}
-
-static const uint8_t smart_read_data[] = {
- 0xb0, 0xd0, 0x00, 0x4f, 0xc2, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static const uint8_t smart_return_status[] = {
- 0xb0, 0xda, 0x00, 0x4f, 0xc2, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static int32_t
-__device_read_ata(smart_h h, uint32_t page, void *buf, size_t bsize, union ccb *ccb)
-{
- struct fbsd_smart *fsmart = h;
- const uint8_t *smart_fis;
- uint32_t smart_fis_size = 0;
- uint32_t cam_flags = 0;
- uint16_t sector_count = 0;
- uint8_t protocol = 0;
-
- switch (page) {
- case PAGE_ID_ATA_SMART_READ_DATA: /* Support SMART READ DATA */
- smart_fis = smart_read_data;
- smart_fis_size = sizeof(smart_read_data);
- cam_flags = CAM_DIR_IN;
- sector_count = 1;
- protocol = AP_PROTO_PIO_IN;
- break;
- case PAGE_ID_ATA_SMART_RET_STATUS: /* Support SMART RETURN STATUS */
- smart_fis = smart_return_status;
- smart_fis_size = sizeof(smart_return_status);
- /* Command has no data but uses the return status */
- cam_flags = CAM_DIR_NONE;
- protocol = AP_PROTO_NON_DATA;
- bsize = 0;
- break;
- default:
- return EINVAL;
- }
-
- if (fsmart->common.info.tunneled) {
- struct ata_pass_16 *cdb;
- uint8_t cdb_flags;
-
- if (bsize > 0) {
- cdb_flags = AP_FLAG_TDIR_FROM_DEV |
- AP_FLAG_BYT_BLOK_BLOCKS |
- AP_FLAG_TLEN_SECT_CNT;
- } else {
- cdb_flags = AP_FLAG_CHK_COND |
- AP_FLAG_TDIR_FROM_DEV |
- AP_FLAG_BYT_BLOK_BLOCKS;
- }
-
- cdb = (struct ata_pass_16 *)ccb->csio.cdb_io.cdb_bytes;
- memset(cdb, 0, sizeof(*cdb));
-
- scsi_ata_pass_16(&ccb->csio,
- /*retries*/ 1,
- /*cbfcnp*/ NULL,
- /*flags*/ cam_flags,
- /*tag_action*/ MSG_SIMPLE_Q_TAG,
- /*protocol*/ protocol,
- /*ata_flags*/ cdb_flags,
- /*features*/ page,
- /*sector_count*/sector_count,
- /*lba*/ 0,
- /*command*/ ATA_SMART_CMD,
- /*control*/ 0,
- /*data_ptr*/ buf,
- /*dxfer_len*/ bsize,
- /*sense_len*/ SSD_FULL_SIZE,
- /*timeout*/ 5000
- );
- cdb->lba_mid = 0x4f;
- cdb->lba_high = 0xc2;
- cdb->device = 0; /* scsi_ata_pass_16() sets this */
- } else {
- memcpy(&ccb->ataio.cmd.command, smart_fis, smart_fis_size);
-
- cam_fill_ataio(&ccb->ataio,
- /* retries */1,
- /* cbfcnp */NULL,
- /* flags */cam_flags,
- /* tag_action */0,
- /* data_ptr */buf,
- /* dxfer_len */bsize,
- /* timeout */5000);
- ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT;
- ccb->ataio.cmd.control = 0;
- }
-
- return 0;
-}
-
-static int32_t
-__device_read_scsi(__attribute__((unused)) smart_h h, uint32_t page, void *buf, size_t bsize, union ccb *ccb)
-{
-
- scsi_log_sense(&ccb->csio,
- /* retries */1,
- /* cbfcnp */NULL,
- /* tag_action */0,
- /* page_code */SLS_PAGE_CTRL_CUMULATIVE,
- /* page */page,
- /* save_pages */0,
- /* ppc */0,
- /* paramptr */0,
- /* param_buf */buf,
- /* param_len */bsize,
- /* sense_len */0,
- /* timeout */5000);
-
- return 0;
-}
-
-static int32_t
-__device_read_nvme(__attribute__((unused)) smart_h h, uint32_t page, void *buf, size_t bsize, union ccb *ccb)
-{
- struct ccb_nvmeio *nvmeio = &ccb->nvmeio;
- uint32_t numd = 0; /* number of dwords */
-
- /*
- * NVME CAM passthru
- * 1200000 > version > 1101510 uses nvmeio->cmd.opc
- * 1200059 > version > 1200038 uses nvmeio->cmd.opc
- * 1200081 > version > 1200058 uses nvmeio->cmd.opc_fuse
- * > 1200080 uses nvmeio->cmd.opc
- * This code doesn't support the brief 'opc_fuse' period.
- */
-#if ((__FreeBSD_version > 1200038) || ((__FreeBSD_version > 1101510) && (__FreeBSD_version < 1200000)))
- switch (page) {
- case NVME_LOG_HEALTH_INFORMATION:
- numd = (sizeof(struct nvme_health_information_page) / sizeof(uint32_t));
- break;
- default:
- /* Unsupported log page */
- return EINVAL;
- }
-
- /* Subtract 1 because NUMD is a zero based value */
- numd--;
-
- nvmeio->cmd.opc = NVME_OPC_GET_LOG_PAGE;
- nvmeio->cmd.nsid = NVME_GLOBAL_NAMESPACE_TAG;
- nvmeio->cmd.cdw10 = page | (numd << 16);
-
- cam_fill_nvmeadmin(&ccb->nvmeio,
- /* retries */1,
- /* cbfcnp */NULL,
- /* flags */CAM_DIR_IN,
- /* data_ptr */buf,
- /* dxfer_len */bsize,
- /* timeout */5000);
-#endif
- return 0;
-}
-
-/*
- * Retrieve the SMART RETURN STATUS
- *
- * SMART RETURN STATUS provides the reliability status of the
- * device and can be used as a high-level indication of health.
- */
-static int32_t
-__device_status_ata(smart_h h, union ccb *ccb)
-{
- struct fbsd_smart *fsmart = h;
- uint8_t *buf = NULL;
- uint32_t page = 0;
- uint8_t lba_high = 0, lba_mid = 0, device = 0, status = 0;
-
- if (fsmart->common.info.tunneled) {
- struct ata_res_pass16 {
- u_int16_t reserved[5];
- u_int8_t flags;
- u_int8_t error;
- u_int8_t sector_count_exp;
- u_int8_t sector_count;
- u_int8_t lba_low_exp;
- u_int8_t lba_low;
- u_int8_t lba_mid_exp;
- u_int8_t lba_mid;
- u_int8_t lba_high_exp;
- u_int8_t lba_high;
- u_int8_t device;
- u_int8_t status;
- } *res_pass16 = (struct ata_res_pass16 *)(uintptr_t)
- &ccb->csio.sense_data;
-
- buf = ccb->csio.data_ptr;
- page = ((struct ata_pass_16 *)ccb->csio.cdb_io.cdb_bytes)->features;
- lba_high = res_pass16->lba_high;
- lba_mid = res_pass16->lba_mid;
- device = res_pass16->device;
- status = res_pass16->status;
-
- /*
- * Note that this generates an expected CHECK CONDITION.
- * Mask it so the outer function doesn't print an error
- * message.
- */
- ccb->ccb_h.status &= ~CAM_STATUS_MASK;
- ccb->ccb_h.status |= CAM_REQ_CMP;
- } else {
- struct ccb_ataio *ataio = (struct ccb_ataio *)&ccb->ataio;
-
- buf = ataio->data_ptr;
- page = ataio->cmd.features;
- lba_high = ataio->res.lba_high;
- lba_mid = ataio->res.lba_mid;
- device = ataio->res.device;
- status = ataio->res.status;
- }
-
- switch (page) {
- case PAGE_ID_ATA_SMART_RET_STATUS:
- /*
- * Typically, SMART related log pages return data, but this
- * command is different in that the data is encoded in the
- * result registers.
- *
- * Handle this in a UNIX-like way by writing a 0 (no errors)
- * or 1 (threshold exceeded condition) to the output buffer.
- */
- dprintf("SMART_RET_STATUS: lba mid=%#x high=%#x device=%#x status=%#x\n",
- lba_mid,
- lba_high,
- device,
- status);
- if ((lba_high == 0x2c) && (lba_mid == 0xf4)) {
- buf[0] = 1;
- } else if ((lba_high == 0xc2) && (lba_mid == 0x4f)) {
- buf[0] = 0;
- } else {
- /* Ruh-roh ... */
- buf[0] = 255;
- }
- break;
- default:
- ;
- }
-
- return 0;
-}
-
-int32_t
-device_read_log(smart_h h, uint32_t page, void *buf, size_t bsize)
-{
- struct fbsd_smart *fsmart = h;
- union ccb *ccb = NULL;
- int rc = 0;
-
- if (fsmart == NULL)
- return EINVAL;
-
- dprintf("read log page %#x\n", page);
-
- ccb = cam_getccb(fsmart->camdev);
- if (ccb == NULL)
- return ENOMEM;
-
- CCB_CLEAR_ALL_EXCEPT_HDR(ccb);
-
- switch (fsmart->common.protocol) {
- case SMART_PROTO_ATA:
- rc = __device_read_ata(h, page, buf, bsize, ccb);
- break;
- case SMART_PROTO_SCSI:
- rc = __device_read_scsi(h, page, buf, bsize, ccb);
- break;
- case SMART_PROTO_NVME:
- rc = __device_read_nvme(h, page, buf, bsize, ccb);
- break;
- default:
- warnx("unsupported protocol %d", fsmart->common.protocol);
- cam_freeccb(ccb);
- return ENODEV;
- }
-
- if (rc) {
- if (rc == EINVAL)
- warnx("unsupported page %#x", page);
-
- return rc;
- }
-
- if (((rc = cam_send_ccb(fsmart->camdev, ccb)) < 0)
- || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
- if (rc < 0)
- warn("error sending command");
- }
-
- /*
- * Most commands don't need any post-processing. But then there's
- * ATA. It's why we can't have nice things :(
- */
- switch (fsmart->common.protocol) {
- case SMART_PROTO_ATA:
- __device_status_ata(h, ccb);
- break;
- default:
- ;
- }
-
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
- cam_error_print(fsmart->camdev, ccb, CAM_ESF_ALL,
- CAM_EPF_ALL, stderr);
- }
-
- cam_freeccb(ccb);
-
- return 0;
-}
-
-/*
- * The SCSI / ATA Translation (SAT) requires devices to support the ATA
- * Information VPD Page (T10/2126-D Revision 04). Use the existence of
- * this page to identify tunneled devices.
- */
-static bool
-__device_proto_tunneled(struct fbsd_smart *fsmart)
-{
- union ccb *ccb = NULL;
- struct scsi_vpd_supported_page_list supportedp;
- uint32_t i;
- bool is_tunneled = false;
-
- if (fsmart->common.protocol != SMART_PROTO_SCSI) {
- return false;
- }
-
- ccb = cam_getccb(fsmart->camdev);
- if (!ccb) {
- warn("Allocation failure ccb=%p", ccb);
- goto __device_proto_tunneled_out;
- }
-
- scsi_inquiry(&ccb->csio,
- 3, // retries
- NULL, // callback function
- MSG_SIMPLE_Q_TAG, // tag action
- (uint8_t *)&supportedp,
- sizeof(struct scsi_vpd_supported_page_list),
- 1, // EVPD
- SVPD_SUPPORTED_PAGE_LIST, // page code
- SSD_FULL_SIZE, // sense length
- 5000); // timeout
-
- ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
-
- if ((cam_send_ccb(fsmart->camdev, ccb) >= 0) &&
- ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)) {
- dprintf("Looking for page %#x (total = %u):\n", SVPD_ATA_INFORMATION,
- supportedp.length);
- for (i = 0; i < supportedp.length; i++) {
- dprintf("\t[%u] = %#x\n", i, supportedp.list[i]);
- if (supportedp.list[i] == SVPD_ATA_INFORMATION) {
- is_tunneled = true;
- break;
- }
- }
- }
-
- cam_freeccb(ccb);
-
-__device_proto_tunneled_out:
- return is_tunneled;
-}
-
-/**
- * Retrieve the device protocol type via the transport settings
- *
- * @return protocol type or SMART_PROTO_MAX on error
- */
-static smart_protocol_e
-__device_get_proto(struct fbsd_smart *fsmart)
-{
- smart_protocol_e proto = SMART_PROTO_MAX;
- union ccb *ccb;
-
- if (!fsmart || !fsmart->camdev) {
- warn("Bad handle %p", fsmart);
- return proto;
- }
-
- ccb = cam_getccb(fsmart->camdev);
- if (ccb != NULL) {
- CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->cts);
-
- ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
- ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS;
-
- if (cam_send_ccb(fsmart->camdev, ccb) >= 0) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
- struct ccb_trans_settings *cts = &ccb->cts;
-
- switch (cts->protocol) {
- case PROTO_ATA:
- proto = SMART_PROTO_ATA;
- break;
- case PROTO_SCSI:
- proto = SMART_PROTO_SCSI;
- break;
- case PROTO_NVME:
- proto = SMART_PROTO_NVME;
- break;
- default:
- printf("%s: unknown protocol %d\n",
- __func__,
- cts->protocol);
- }
- }
- }
-
- cam_freeccb(ccb);
- }
-
- return proto;
-}
-
-static int32_t
-__device_info_ata(struct fbsd_smart *fsmart, struct ccb_getdev *cgd)
-{
- smart_info_t *sinfo = NULL;
-
- if (!fsmart || !cgd) {
- return -1;
- }
-
- sinfo = &fsmart->common.info;
-
- sinfo->supported = cgd->ident_data.support.command1 &
- ATA_SUPPORT_SMART;
-
- dprintf("ATA command1 = %#x\n", cgd->ident_data.support.command1);
-
- cam_strvis((uint8_t *)sinfo->device, cgd->ident_data.model,
- sizeof(cgd->ident_data.model),
- sizeof(sinfo->device));
- cam_strvis((uint8_t *)sinfo->rev, cgd->ident_data.revision,
- sizeof(cgd->ident_data.revision),
- sizeof(sinfo->rev));
- cam_strvis((uint8_t *)sinfo->serial, cgd->ident_data.serial,
- sizeof(cgd->ident_data.serial),
- sizeof(sinfo->serial));
-
- return 0;
-}
-
-static int32_t
-__device_info_scsi(struct fbsd_smart *fsmart, struct ccb_getdev *cgd)
-{
- smart_info_t *sinfo = NULL;
- union ccb *ccb = NULL;
- struct scsi_vpd_unit_serial_number *snum = NULL;
- struct scsi_log_informational_exceptions ie = {0};
-
- if (!fsmart || !cgd) {
- return -1;
- }
-
- sinfo = &fsmart->common.info;
-
- cam_strvis((uint8_t *)sinfo->vendor, (uint8_t *)cgd->inq_data.vendor,
- sizeof(cgd->inq_data.vendor),
- sizeof(sinfo->vendor));
- cam_strvis((uint8_t *)sinfo->device, (uint8_t *)cgd->inq_data.product,
- sizeof(cgd->inq_data.product),
- sizeof(sinfo->device));
- cam_strvis((uint8_t *)sinfo->rev, (uint8_t *)cgd->inq_data.revision,
- sizeof(cgd->inq_data.revision),
- sizeof(sinfo->rev));
-
- ccb = cam_getccb(fsmart->camdev);
- snum = malloc(sizeof(struct scsi_vpd_unit_serial_number));
- if (!ccb || !snum) {
- warn("Allocation failure ccb=%p snum=%p", ccb, snum);
- goto __device_info_scsi_out;
- }
-
- /* Get the serial number */
- CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
-
- scsi_inquiry(&ccb->csio,
- 3, // retries
- NULL, // callback function
- MSG_SIMPLE_Q_TAG, // tag action
- (uint8_t *)snum,
- sizeof(struct scsi_vpd_unit_serial_number),
- 1, // EVPD
- SVPD_UNIT_SERIAL_NUMBER, // page code
- SSD_FULL_SIZE, // sense length
- 5000); // timeout
-
- ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
-
- if ((cam_send_ccb(fsmart->camdev, ccb) >= 0) &&
- ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)) {
- cam_strvis((uint8_t *)sinfo->serial, snum->serial_num,
- snum->length,
- sizeof(sinfo->serial));
- sinfo->serial[sizeof(sinfo->serial) - 1] = '\0';
- }
-
- memset(ccb, 0, sizeof(*ccb));
-
- scsi_log_sense(&ccb->csio,
- /* retries */1,
- /* cbfcnp */NULL,
- /* tag_action */0,
- /* page_code */SLS_PAGE_CTRL_CUMULATIVE,
- /* page */SLS_IE_PAGE,
- /* save_pages */0,
- /* ppc */0,
- /* paramptr */0,
- /* param_buf */(uint8_t *)&ie,
- /* param_len */sizeof(ie),
- /* sense_len */0,
- /* timeout */5000);
-
- /*
- * Note: The existance of the Informational Exceptions (IE) log page
- * appears to be the litmus test for SMART support in SCSI
- * devices. Confusingly, smartctl will report SMART health
- * status as 'OK' if the device doesn't support the IE page.
- * For now, just report the facts.
- */
- if ((cam_send_ccb(fsmart->camdev, ccb) >= 0) &&
- ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)) {
- if ((ie.hdr.param_len < 4) || ie.ie_asc || ie.ie_ascq) {
- printf("Log Sense, Informational Exceptions failed "
- "(length=%u asc=%#x ascq=%#x)\n",
- ie.hdr.param_len, ie.ie_asc, ie.ie_ascq);
- } else {
- sinfo->supported = true;
- }
- }
-
-__device_info_scsi_out:
- free(snum);
- if (ccb)
- cam_freeccb(ccb);
-
- return 0;
-}
-
-static int32_t
-__device_info_nvme(struct fbsd_smart *fsmart, struct ccb_getdev *cgd)
-{
- union ccb *ccb;
- smart_info_t *sinfo = NULL;
- struct nvme_controller_data cd;
-
- if (!fsmart || !cgd) {
- return -1;
- }
-
- sinfo = &fsmart->common.info;
-
- sinfo->supported = true;
-
- ccb = cam_getccb(fsmart->camdev);
- if (ccb != NULL) {
- struct ccb_dev_advinfo *cdai = &ccb->cdai;
-
- CCB_CLEAR_ALL_EXCEPT_HDR(cdai);
-
- cdai->ccb_h.func_code = XPT_DEV_ADVINFO;
- cdai->ccb_h.flags = CAM_DIR_IN;
- cdai->flags = CDAI_FLAG_NONE;
-#ifdef CDAI_TYPE_NVME_CNTRL
- cdai->buftype = CDAI_TYPE_NVME_CNTRL;
-#else
- cdai->buftype = 6;
-#endif
- cdai->bufsiz = sizeof(struct nvme_controller_data);
- cdai->buf = (uint8_t *)&cd;
-
- if (cam_send_ccb(fsmart->camdev, ccb) >= 0) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
- cam_strvis((uint8_t *)sinfo->device, cd.mn,
- sizeof(cd.mn),
- sizeof(sinfo->device));
- cam_strvis((uint8_t *)sinfo->rev, cd.fr,
- sizeof(cd.fr),
- sizeof(sinfo->rev));
- cam_strvis((uint8_t *)sinfo->serial, cd.sn,
- sizeof(cd.sn),
- sizeof(sinfo->serial));
- }
- }
-
- cam_freeccb(ccb);
- }
-
- return 0;
-}
-
-static int32_t
-__device_info_tunneled_ata(struct fbsd_smart *fsmart)
-{
- struct ata_params ident_data;
- union ccb *ccb = NULL;
- struct ata_pass_16 *ata_pass_16;
- struct ata_cmd ata_cmd;
- int32_t rc = -1;
-
- ccb = cam_getccb(fsmart->camdev);
- if (ccb == NULL) {
- goto __device_info_tunneled_ata_out;
- }
-
- memset(&ident_data, 0, sizeof(struct ata_params));
-
- CCB_CLEAR_ALL_EXCEPT_HDR(ccb);
-
- scsi_ata_pass_16(&ccb->csio,
- /*retries*/ 1,
- /*cbfcnp*/ NULL,
- /*flags*/ CAM_DIR_IN,
- /*tag_action*/ MSG_SIMPLE_Q_TAG,
- /*protocol*/ AP_PROTO_PIO_IN,
- /*ata_flags*/ AP_FLAG_TLEN_SECT_CNT |
- AP_FLAG_BYT_BLOK_BLOCKS |
- AP_FLAG_TDIR_FROM_DEV,
- /*features*/ 0,
- /*sector_count*/sizeof(struct ata_params),
- /*lba*/ 0,
- /*command*/ ATA_ATA_IDENTIFY,
- /*control*/ 0,
- /*data_ptr*/ (uint8_t *)&ident_data,
- /*dxfer_len*/ sizeof(struct ata_params),
- /*sense_len*/ SSD_FULL_SIZE,
- /*timeout*/ 5000
- );
-
- ata_pass_16 = (struct ata_pass_16 *)ccb->csio.cdb_io.cdb_bytes;
- ata_cmd.command = ata_pass_16->command;
- ata_cmd.control = ata_pass_16->control;
- ata_cmd.features = ata_pass_16->features;
-
- rc = cam_send_ccb(fsmart->camdev, ccb);
- if (rc != 0) {
- warnx("%s: scsi_ata_pass_16() failed (programmer error?)",
- __func__);
- goto __device_info_tunneled_ata_out;
- }
-
- fsmart->common.info.supported = ident_data.support.command1 &
- ATA_SUPPORT_SMART;
-
- dprintf("ATA command1 = %#x\n", ident_data.support.command1);
-
-__device_info_tunneled_ata_out:
- if (ccb) {
- cam_freeccb(ccb);
- }
-
- return rc;
-}
-
-/**
- * Retrieve the device information and use to populate the info structure
- */
-static int32_t
-__device_get_info(struct fbsd_smart *fsmart)
-{
- union ccb *ccb;
- int32_t rc = -1;
-
- if (!fsmart || !fsmart->camdev) {
- warn("Bad handle %p", fsmart);
- return -1;
- }
-
- ccb = cam_getccb(fsmart->camdev);
- if (ccb != NULL) {
- struct ccb_getdev *cgd = &ccb->cgd;
-
- CCB_CLEAR_ALL_EXCEPT_HDR(cgd);
-
- /*
- * GDEV_TYPE doesn't support NVMe. What we do get is:
- * - device (ata/model, scsi/product)
- * - revision (ata, scsi)
- * - serial (ata)
- * - vendor (scsi)
- * - supported (ata)
- *
- * Serial # for all proto via ccb_dev_advinfo (buftype CDAI_TYPE_SERIAL_NUM)
- */
- ccb->ccb_h.func_code = XPT_GDEV_TYPE;
-
- if (cam_send_ccb(fsmart->camdev, ccb) >= 0) {
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
- switch (cgd->protocol) {
- case PROTO_ATA:
- rc = __device_info_ata(fsmart, cgd);
- break;
- case PROTO_SCSI:
- rc = __device_info_scsi(fsmart, cgd);
- if (!rc && fsmart->common.protocol == SMART_PROTO_ATA) {
- rc = __device_info_tunneled_ata(fsmart);
- }
- break;
- case PROTO_NVME:
- rc = __device_info_nvme(fsmart, cgd);
- break;
- default:
- printf("%s: unsupported protocol %d\n",
- __func__, cgd->protocol);
- }
- }
- }
-
- cam_freeccb(ccb);
- }
-
- return rc;
-}
diff --git a/contrib/smart/libsmart.c b/contrib/smart/libsmart.c
deleted file mode 100644
index a1732de09ed9..000000000000
--- a/contrib/smart/libsmart.c
+++ /dev/null
@@ -1,1359 +0,0 @@
-/*
- * Copyright (c) 2016-2026 Chuck Tuffli <chuck@tuffli.net>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <assert.h>
-#include <err.h>
*** 2512 LINES SKIPPED ***