From a3efbe51f6b00bc7703adbe1a49b7006b37fa892 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 23 Feb 2022 16:57:28 +0000 Subject: [PATCH] scsi: Add a simple plugin to enumerate SCSI hardware We might want this to tag insecure or broken SAS drives, cough. --- contrib/ci/build_windows.sh | 1 + contrib/fwupd.spec.in | 1 + meson_options.txt | 1 + plugins/meson.build | 1 + plugins/scsi/README.md | 22 ++++++ plugins/scsi/fu-plugin-scsi.c | 25 ++++++ plugins/scsi/fu-scsi-device.c | 139 ++++++++++++++++++++++++++++++++++ plugins/scsi/fu-scsi-device.h | 12 +++ plugins/scsi/meson.build | 38 ++++++++++ plugins/scsi/scsi.quirk | 24 ++++++ 10 files changed, 264 insertions(+) create mode 100644 plugins/scsi/README.md create mode 100644 plugins/scsi/fu-plugin-scsi.c create mode 100644 plugins/scsi/fu-scsi-device.c create mode 100644 plugins/scsi/fu-scsi-device.h create mode 100644 plugins/scsi/meson.build create mode 100644 plugins/scsi/scsi.quirk diff --git a/contrib/ci/build_windows.sh b/contrib/ci/build_windows.sh index 8d273295d..c09b9cdc0 100755 --- a/contrib/ci/build_windows.sh +++ b/contrib/ci/build_windows.sh @@ -47,6 +47,7 @@ meson .. \ -Dplugin_mtd=false \ -Dintrospection=false \ -Dplugin_thunderbolt=false \ + -Dplugin_scsi=false \ -Dplugin_synaptics_mst=false \ -Dplugin_synaptics_rmi=false \ -Dplugin_upower=false \ diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 23696e77e..4d3a3dd16 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -464,6 +464,7 @@ done %{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_redfish.so %{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_rts54hid.so %{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_rts54hub.so +%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_scsi.so %{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_steelseries.so %{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_superio.so %if 0%{?have_dell} diff --git a/meson_options.txt b/meson_options.txt index d53fe067b..c1b483cb2 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -31,6 +31,7 @@ option('plugin_pixart_rf', type : 'boolean', value : true, description : 'enable option('plugin_realtek_mst', type : 'boolean', value : true, description : 'enable Realtek MST hub support') option('plugin_synaptics_mst', type: 'boolean', value: true, description : 'enable Synaptics MST hub support') option('plugin_synaptics_rmi', type: 'boolean', value: true, description : 'enable Synaptics RMI support') +option('plugin_scsi', type: 'boolean', value: true, description : 'enable SCSI support') option('plugin_tpm', type : 'boolean', value : true, description : 'enable TPM support') option('plugin_thunderbolt', type : 'boolean', value : true, description : 'enable Thunderbolt support') option('plugin_redfish', type : 'boolean', value : true, description : 'enable Redfish support') diff --git a/plugins/meson.build b/plugins/meson.build index df1c7fbef..fb9832ed9 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -57,6 +57,7 @@ subdir('redfish') subdir('rts54hid') subdir('rts54hub') subdir('steelseries') +subdir('scsi') subdir('superio') subdir('synaptics-cape') subdir('synaptics-cxaudio') diff --git a/plugins/scsi/README.md b/plugins/scsi/README.md new file mode 100644 index 000000000..e431b70f2 --- /dev/null +++ b/plugins/scsi/README.md @@ -0,0 +1,22 @@ +# SCSI + +## Introduction + +This plugin adds support for SCSI storage hardware. Devices are only enumerated +and are not updatable. + +## GUID Generation + +These device use the SCSI DeviceInstanceId values, e.g. + +* `SCSI\VEN_HP&DEV_EG0900JETKB&REV_HPD4` +* `SCSI\VEN_HP&DEV_EG0900JETKB` +* `SCSI\VEN_HP` + +## Vendor ID Security + +The vendor ID is set from the vendor, for example set to `SCSI:HP` + +## External Interface Access + +This plugin requires only reading from sysfs. diff --git a/plugins/scsi/fu-plugin-scsi.c b/plugins/scsi/fu-plugin-scsi.c new file mode 100644 index 000000000..2558d9570 --- /dev/null +++ b/plugins/scsi/fu-plugin-scsi.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2022 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-scsi-device.h" + +static void +fu_plugin_scsi_init(FuPlugin *plugin) +{ + fu_plugin_add_udev_subsystem(plugin, "scsi"); + fu_plugin_add_device_gtype(plugin, FU_TYPE_SCSI_DEVICE); +} + +void +fu_plugin_init_vfuncs(FuPluginVfuncs *vfuncs) +{ + vfuncs->build_hash = FU_BUILD_HASH; + vfuncs->init = fu_plugin_scsi_init; +} diff --git a/plugins/scsi/fu-scsi-device.c b/plugins/scsi/fu-scsi-device.c new file mode 100644 index 000000000..bd360ea2c --- /dev/null +++ b/plugins/scsi/fu-scsi-device.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2022 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-scsi-device.h" + +struct _FuScsiDevice { + FuUdevDevice parent_instance; +}; + +G_DEFINE_TYPE(FuScsiDevice, fu_scsi_device, FU_TYPE_UDEV_DEVICE) + +static gboolean +fu_scsi_device_probe(FuDevice *device, GError **error) +{ + const gchar *name; + const gchar *vendor; + const gchar *version; + g_autofree gchar *name_safe = NULL; + g_autofree gchar *subsystem = NULL; + g_autofree gchar *vendor_safe = NULL; + g_autofree gchar *version_safe = NULL; + g_autoptr(GPtrArray) block_devs = NULL; + + /* ignore */ + if (g_strcmp0(fu_udev_device_get_devtype(FU_UDEV_DEVICE(device)), "scsi_target") == 0) { + g_set_error_literal(error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "targets are not supported"); + return FALSE; + } + + /* vendor */ + vendor = fu_udev_device_get_sysfs_attr(FU_UDEV_DEVICE(device), "vendor", NULL); + vendor_safe = fu_common_instance_id_strsafe(vendor); + if (vendor_safe == NULL || g_strcmp0(vendor_safe, "ATA") == 0) { + g_set_error_literal(error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no assigned vendor"); + return FALSE; + } + fu_device_set_vendor(device, vendor); + + /* name */ + name = fu_udev_device_get_sysfs_attr(FU_UDEV_DEVICE(device), "model", NULL); + name_safe = fu_common_instance_id_strsafe(name); + if (name_safe == NULL) { + g_set_error_literal(error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no assigned name"); + return FALSE; + } + fu_device_set_name(device, name); + + /* version */ + version = fu_udev_device_get_sysfs_attr(FU_UDEV_DEVICE(device), "rev", NULL); + version_safe = fu_common_instance_id_strsafe(version); + if (version_safe == NULL) { + g_set_error_literal(error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "no assigned version"); + return FALSE; + } + fu_device_set_version(device, version); + + /* add GUIDs */ + subsystem = g_utf8_strup(fu_udev_device_get_subsystem(FU_UDEV_DEVICE(device)), -1); + if (subsystem != NULL && vendor_safe != NULL && name_safe != NULL && version_safe != NULL) { + g_autofree gchar *devid = NULL; + devid = g_strdup_printf("%s\\VEN_%s&DEV_%s&REV_%s", + subsystem, + vendor_safe, + name_safe, + version_safe); + fu_device_add_instance_id(device, devid); + } + if (subsystem != NULL && vendor_safe != NULL && name_safe != NULL) { + g_autofree gchar *devid = NULL; + devid = g_strdup_printf("%s\\VEN_%s&DEV_%s", subsystem, vendor_safe, name_safe); + fu_device_add_instance_id(device, devid); + } + if (subsystem != NULL && vendor_safe != NULL) { + g_autofree gchar *devid = NULL; + devid = g_strdup_printf("%s\\VEN_%s", subsystem, vendor_safe); + fu_device_add_instance_id_full(device, devid, FU_DEVICE_INSTANCE_FLAG_ONLY_QUIRKS); + } + if (vendor_safe != NULL) { + g_autofree gchar *vendor_id = NULL; + vendor_id = g_strdup_printf("SCSI:%s", vendor_safe); + fu_device_add_vendor_id(device, vendor_id); + } + + /* check all block devices, although there should only be one */ + block_devs = fu_udev_device_get_children_with_subsystem(FU_UDEV_DEVICE(device), "block"); + for (guint i = 0; i < block_devs->len; i++) { + FuUdevDevice *block_dev = g_ptr_array_index(block_devs, i); + guint64 value = 0; + if (!fu_udev_device_get_sysfs_attr_uint64(block_dev, "removable", &value, NULL)) + continue; + if (value == 0x0) { + fu_device_add_flag(device, FWUPD_DEVICE_FLAG_INTERNAL); + break; + } + } + + /* set the physical ID */ + return fu_udev_device_set_physical_id(FU_UDEV_DEVICE(device), "scsi", error); +} + +static void +fu_scsi_device_init(FuScsiDevice *self) +{ + fu_device_add_icon(FU_DEVICE(self), "drive-harddisk"); + fu_device_set_version_format(FU_DEVICE(self), FWUPD_VERSION_FORMAT_PLAIN); + fu_device_set_summary(FU_DEVICE(self), "SCSI device"); +} + +static void +fu_scsi_device_finalize(GObject *object) +{ + G_OBJECT_CLASS(fu_scsi_device_parent_class)->finalize(object); +} + +static void +fu_scsi_device_class_init(FuScsiDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass); + object_class->finalize = fu_scsi_device_finalize; + klass_device->probe = fu_scsi_device_probe; +} diff --git a/plugins/scsi/fu-scsi-device.h b/plugins/scsi/fu-scsi-device.h new file mode 100644 index 000000000..c6c488ee7 --- /dev/null +++ b/plugins/scsi/fu-scsi-device.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2022 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_SCSI_DEVICE (fu_scsi_device_get_type()) +G_DECLARE_FINAL_TYPE(FuScsiDevice, fu_scsi_device, FU, SCSI_DEVICE, FuUdevDevice) diff --git a/plugins/scsi/meson.build b/plugins/scsi/meson.build new file mode 100644 index 000000000..7f06f35f8 --- /dev/null +++ b/plugins/scsi/meson.build @@ -0,0 +1,38 @@ +if get_option('plugin_scsi') +if not get_option('gudev') + error('gudev is required for plugin_scsi') +endif +cargs = ['-DG_LOG_DOMAIN="FuPluginScsi"'] + +install_data([ + 'scsi.quirk', + ], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_scsi', + fu_hash, + sources : [ + 'fu-plugin-scsi.c', + 'fu-scsi-device.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + c_args : [ + cargs, + '-DLOCALSTATEDIR="' + localstatedir + '"', + ], + link_with : [ + fwupd, + fwupdplugin, + ], + dependencies : [ + plugin_deps, + ], +) +endif diff --git a/plugins/scsi/scsi.quirk b/plugins/scsi/scsi.quirk new file mode 100644 index 000000000..199075fe0 --- /dev/null +++ b/plugins/scsi/scsi.quirk @@ -0,0 +1,24 @@ +[SCSI] +Plugin = scsi + +[SCSI\VEN_LSI&DEV_VirtualSES] +Flags = no-probe +[SCSI\VEN_Marvell&DEV_Console] +Flags = no-probe + +[SCSI\VEN_HP&DEV_EK0800JVYPN&REV_HPD5] +Issue = MTX-6f54e8621f4c490a918defdab6 +[SCSI\VEN_HP&DEV_EK0800JVYPN&REV_HPD6] +Issue = MTX-6f54e8621f4c490a918defdab6 +[SCSI\VEN_HP&DEV_EO1600JVYPP&REV_HPD5] +Issue = MTX-6f54e8621f4c490a918defdab6 +[SCSI\VEN_HP&DEV_EO1600JVYPP&REV_HPD6] +Issue = MTX-6f54e8621f4c490a918defdab6 +[SCSI\VEN_HP&DEV_MK0800JVYPQ&REV_HPD5] +Issue = MTX-6f54e8621f4c490a918defdab6 +[SCSI\VEN_HP&DEV_MK0800JVYPQ&REV_HPD6] +Issue = MTX-6f54e8621f4c490a918defdab6 +[SCSI\VEN_HP&DEV_MO1600JVYPR&REV_HPD5] +Issue = MTX-6f54e8621f4c490a918defdab6 +[SCSI\VEN_HP&DEV_MO1600JVYPR&REV_HPD6] +Issue = MTX-6f54e8621f4c490a918defdab6