X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=dev_interface.cpp;h=a09799038aba2c142cce09343cc3d8b96ef83122;hb=HEAD;hp=71bf8bcd35cf2fe30e0a2a0947649c5785da0afa;hpb=ee38a438aafef7a04b7df628ca5ad38810a1d63e;p=mirror_smartmontools-debian.git diff --git a/dev_interface.cpp b/dev_interface.cpp index 71bf8bc..a097990 100644 --- a/dev_interface.cpp +++ b/dev_interface.cpp @@ -1,25 +1,20 @@ /* * dev_interface.cpp * - * Home page of code is: http://smartmontools.sourceforge.net + * Home page of code is: http://www.smartmontools.org * - * Copyright (C) 2008-13 Christian Franke - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * You should have received a copy of the GNU General Public License - * (for example COPYING); If not, see . + * Copyright (C) 2008-18 Christian Franke * + * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" -#include "int64.h" + #include "dev_interface.h" +#include "dev_intelliprop.h" #include "dev_tunnelled.h" #include "atacmds.h" // ATA_SMART_CMD/STATUS +#include "scsicmds.h" // scsi_cmnd_io #include "utility.h" #include @@ -32,27 +27,31 @@ #include #endif -const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 3741 2013-01-02 17:06:54Z chrfranke $" +const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 4848 2018-12-05 18:30:46Z chrfranke $" DEV_INTERFACE_H_CVSID; ///////////////////////////////////////////////////////////////////////////// // smart_device +int smart_device::s_num_objects = 0; + smart_device::smart_device(smart_interface * intf, const char * dev_name, const char * dev_type, const char * req_type) : m_intf(intf), m_info(dev_name, dev_type, req_type), - m_ata_ptr(0), m_scsi_ptr(0) + m_ata_ptr(0), m_scsi_ptr(0), m_nvme_ptr(0) { + s_num_objects++; } smart_device::smart_device(do_not_use_in_implementation_classes) -: m_intf(0), m_ata_ptr(0), m_scsi_ptr(0) +: m_intf(0), m_ata_ptr(0), m_scsi_ptr(0), m_nvme_ptr(0) { throw std::logic_error("smart_device: wrong constructor called in implementation class"); } smart_device::~smart_device() throw() { + s_num_objects--; } bool smart_device::is_syscall_unsup() const @@ -88,6 +87,11 @@ smart_device * smart_device::autodetect_open() return this; } +bool smart_device::is_powered_down() +{ + return false; +} + bool smart_device::owns(const smart_device * /*dev*/) const { return false; @@ -193,6 +197,52 @@ bool ata_device::ata_identify_is_cached() const return false; } +///////////////////////////////////////////////////////////////////////////// +// scsi_device + +bool scsi_device::scsi_pass_through_and_check(scsi_cmnd_io * iop, + const char * msg) +{ + // Provide sense buffer + unsigned char sense[32] = {0, }; + iop->sensep = sense; + iop->max_sense_len = sizeof(sense); + iop->timeout = SCSI_TIMEOUT_DEFAULT; + + // Run cmd + if (!scsi_pass_through(iop)) { + if (scsi_debugmode > 0) + pout("%sscsi_pass_through() failed, errno=%d [%s]\n", + msg, get_errno(), get_errmsg()); + return false; + } + + // Check sense + scsi_sense_disect sinfo; + scsi_do_sense_disect(iop, &sinfo); + int err = scsiSimpleSenseFilter(&sinfo); + if (err) { + if (scsi_debugmode > 0) + pout("%sscsi error: %s\n", msg, scsiErrString(err)); + return set_err(EIO, "scsi error %s", scsiErrString(err)); + } + + return true; +} + +///////////////////////////////////////////////////////////////////////////// +// nvme_device + +bool nvme_device::set_nvme_err(nvme_cmd_out & out, unsigned status, const char * msg /* = 0 */) +{ + if (!status) + throw std::logic_error("nvme_device: set_nvme_err() called with status=0"); + + out.status = status; + out.status_valid = true; + return set_err(EIO, "%sNVMe Status 0x%02x", (msg ? msg : ""), status); +} + ///////////////////////////////////////////////////////////////////////////// // tunnelled_device_base @@ -258,7 +308,9 @@ std::string smart_interface::get_valid_dev_types_str() { // default std::string s = - "ata, scsi, sat[,auto][,N][+TYPE], usbcypress[,X], usbjmicron[,p][,x][,N], usbsunplus"; + "ata, scsi[+TYPE], nvme[,NSID], sat[,auto][,N][+TYPE], usbcypress[,X], " + "usbjmicron[,p][,x][,N], usbprolific, usbsunplus, sntjmicron[,NSID], " + "intelliprop,N[+TYPE]"; // append custom std::string s2 = get_valid_custom_dev_types_str(); if (!s2.empty()) { @@ -364,8 +416,20 @@ smart_device * smart_interface::get_smart_device(const char * name, const char * else if (!strcmp(type, "scsi")) dev = get_scsi_device(name, type); - else if ( ((!strncmp(type, "sat", 3) && (!type[3] || strchr(",+", type[3]))) - || (!strncmp(type, "usb", 3)))) { + else if (str_starts_with(type, "nvme")) { + int n1 = -1, n2 = -1, len = strlen(type); + unsigned nsid = 0; // invalid namespace id -> use default + sscanf(type, "nvme%n,0x%x%n", &n1, &nsid, &n2); + if (!(n1 == len || n2 == len)) { + set_err(EINVAL, "Invalid NVMe namespace id in '%s'", type); + return 0; + } + dev = get_nvme_device(name, type, nsid); + } + + else if ( (str_starts_with(type, "sat") && (!type[3] || strchr(",+", type[3]))) + || str_starts_with(type, "scsi+") + || str_starts_with(type, "usb") ) { // Split "sat...+base..." -> ("sat...", "base...") unsigned satlen = strcspn(type, "+"); std::string sattype(type, satlen); @@ -384,11 +448,42 @@ smart_device * smart_interface::get_smart_device(const char * name, const char * return 0; } // Attach SAT tunnel - ata_device * satdev = get_sat_device(sattype.c_str(), basedev->to_scsi()); - if (!satdev) + return get_sat_device(sattype.c_str(), basedev.release()->to_scsi()); + } + + else if (str_starts_with(type, "snt")) { + smart_device_auto_ptr basedev( get_smart_device(name, "scsi") ); + if (!basedev) { + set_err(EINVAL, "Type '%s': %s", type, get_errmsg()); + return 0; + } + + return get_snt_device(type, basedev.release()->to_scsi()); + } + + else if (str_starts_with(type, "intelliprop")) { + // Parse "intelliprop,N[+base...]" + unsigned phydrive = ~0; int n = -1; char c = 0; + sscanf(type, "intelliprop,%u%n%c", &phydrive, &n, &c); + if (!((n == (int)strlen(type) || c == '+') && phydrive <= 3)) { + set_err(EINVAL, "Option '-d intelliprop,N' requires N between 0 and 3"); + return 0; + } + const char * basetype = (type[n] ? type + n + 1 : ""); + // Recurse to allocate base device, default is standard ATA + if (!*basetype) + basetype = "ata"; + smart_device_auto_ptr basedev( get_smart_device(name, basetype) ); + if (!basedev) { + set_err(EINVAL, "Type '%s': %s", type, get_errmsg()); return 0; - basedev.release(); - return satdev; + } + // Result must be ATA + if (!basedev->is_ata()) { + set_err(EINVAL, "Type '%s': Device type '%s' is not ATA", type, basetype); + return 0; + } + return get_intelliprop_device(this, phydrive, basedev.release()->to_ata()); } else { @@ -400,6 +495,37 @@ smart_device * smart_interface::get_smart_device(const char * name, const char * return dev; } +bool smart_interface::scan_smart_devices(smart_device_list & /*devlist*/, + const char * /*type*/, const char * /*pattern*/ /* = 0 */) +{ + return set_err(ENOSYS); +} + +bool smart_interface::scan_smart_devices(smart_device_list & devlist, + const smart_devtype_list & types, const char * pattern /* = 0 */) +{ + unsigned n = types.size(); + if (n == 0) + return scan_smart_devices(devlist, (const char *)0, pattern); + if (n == 1) + return scan_smart_devices(devlist, types.front().c_str(), pattern); + + for (unsigned i = 0; i < n; i++) { + smart_device_list tmplist; + if (!scan_smart_devices(tmplist, types[i].c_str(), pattern)) + return false; + devlist.append(tmplist); + } + + return true; +} + +nvme_device * smart_interface::get_nvme_device(const char * /*name*/, const char * /*type*/, unsigned /*nsid*/) +{ + set_err(ENOSYS, "NVMe devices are not supported in this version of smartmontools"); + return 0; +} + smart_device * smart_interface::get_custom_smart_device(const char * /*name*/, const char * /*type*/) { return 0; @@ -409,3 +535,12 @@ std::string smart_interface::get_valid_custom_dev_types_str() { return ""; } + +smart_device * smart_interface::get_scsi_passthrough_device(const char * type, scsi_device * scsidev) +{ + if (!strncmp(type, "snt", 3)) { + return get_snt_device(type, scsidev); + } + + return get_sat_device(type, scsidev); +}