From: Peter Jones Date: Wed, 6 Jun 2018 20:47:11 +0000 (-0400) Subject: Move SAS parsing to linux-sas.c X-Git-Tag: android-x86-8.1-r1~66 X-Git-Url: http://git.osdn.net/view?p=android-x86%2Fexternal-efivar.git;a=commitdiff_plain;h=b7de3bf1031ae60d3d6d716bcd48bd6bc8392d64 Move SAS parsing to linux-sas.c This won't actually *work* yet, because the infrastructure to use it (replacing "struct disk_info") won't land for a few more patches. Signed-off-by: Peter Jones --- diff --git a/src/linux-sas.c b/src/linux-sas.c new file mode 100644 index 0000000..4a11147 --- /dev/null +++ b/src/linux-sas.c @@ -0,0 +1,130 @@ +/* + * libefiboot - library for the manipulation of EFI boot variables + * Copyright 2012-2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * . + * + */ + +#include "fix_coverity.h" + +#include +#include +#include +#include +#include + +#include "efiboot.h" + +/* + * support for SAS devices + * + * /sys/dev/block/$major:$minor looks like: + * 8:32 -> ../../devices/pci0000:00/0000:00:01.0/0000:01:00.0/host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc + * 8:33 -> ../../devices/pci0000:00/0000:00:01.0/0000:01:00.0/host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc/sdc1 + * + * /sys/dev/block/8:32/device looks like: + * DUNNO. But I suspect it's: ../../../4:0:0:0 + * + * These things are also things in this case: + * /sys/class/scsi_host/host4/host_sas_address + * /sys/class/block/sdc/device/sas_address + * + * I'm not sure at the moment if they're the same or not. + */ +static ssize_t +parse_sas(struct device *dev, const char *current) +{ + struct stat statbuf = { 0, }; + int rc; + uint32_t scsi_host, scsi_bus, scsi_device, scsi_target; + uint64_t scsi_lun; + ssize_t pos; + uint8_t *filebuf = NULL; + uint64_t sas_address; + + debug(DEBUG, "entry"); + + pos = parse_scsi_link(current, &scsi_host, + &scsi_bus, &scsi_device, + &scsi_target, &scsi_lun); + /* + * If we can't parse the scsi data, it isn't a sas device, so return 0 + * not error. + */ + if (pos < 0) + return 0; + + /* + * Make sure it has the actual /SAS/ bits before we continue + * validating all this junk. + */ + rc = sysfs_stat(&statbuf, + "class/scsi_host/host%d/host_sas_address", + scsi_host); + /* + * If we can't parse the scsi data, it isn't a /SAS/ device, so return + * 0 not error. Later errors mean it is an ata device, but we can't + * parse it right, so they return -1. + */ + if (rc < 0) + return 0; + + /* + * we also need to get the actual sas_address from someplace... + */ + rc = read_sysfs_file(&filebuf, + "class/block/%s/device/sas_address", + dev->disk_name); + if (rc < 0 || filebuf == NULL) + return -1; + + rc = sscanf((char *)filebuf, "%"PRIx64, &sas_address); + if (rc != 1) + return -1; + + dev->sas_info.sas_address = sas_address; + + dev->scsi_info.scsi_bus = scsi_bus; + dev->scsi_info.scsi_device = scsi_device; + dev->scsi_info.scsi_target = scsi_target; + dev->scsi_info.scsi_lun = scsi_lun; + dev->interface_type = sas; + return pos; +} + +static ssize_t +dp_create_sas(struct device *dev, + uint8_t *buf, ssize_t size, ssize_t off) +{ + ssize_t sz; + + debug(DEBUG, "entry"); + + sz = efidp_make_sas(buf + off, size ? size - off : 0, + dev->sas_info.sas_address); + + return sz; +} + +enum interface_type sas_iftypes[] = { sas, unknown }; + +struct dev_probe HIDDEN sas_parser = { + .name = "sas", + .iftypes = sas_iftypes, + .flags = DEV_PROVIDES_HD, + .parse = parse_sas, + .create = dp_create_sas, +}; diff --git a/src/linux.c b/src/linux.c index 16c4680..97fcaf2 100644 --- a/src/linux.c +++ b/src/linux.c @@ -214,38 +214,6 @@ sysfs_test_pmem(const char *buf) return 0; } -static int -sysfs_test_sas(const char *buf, ssize_t size) -{ - int rc; - char *path; - struct stat statbuf = { 0, }; - char *newbuf; - - int host; - int sz; - - newbuf = strndupa(buf, size+1); - if (!newbuf) - return -1; - newbuf[size] = '\0'; - - errno = 0; - rc = sscanf(newbuf, "host%d/%n", &host, &sz); - if (rc < 1) - return (errno == 0) ? 0 : -1; - - rc = asprintfa(&path, "/sys/class/scsi_host/host%d/host_sas_address", - host); - if (rc < 0) - return -1; - - rc = stat(path, &statbuf); - if (rc >= 0) - return 1; - return 0; -} - /* pmem12s -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s * dev: 259:0 * device -> ../../../btt12.1 @@ -291,128 +259,6 @@ sysfs_parse_pmem(uint8_t *buf, ssize_t size, ssize_t *off, } static ssize_t -sysfs_parse_sas(uint8_t *buf, ssize_t size, ssize_t *off, - const char *pbuf, ssize_t psize, ssize_t *poff, - struct disk_info *info) -{ - int rc; - int psz = 0; - uint8_t *filebuf = NULL; - uint64_t sas_address; - - char *newpbuf; - - newpbuf = strndupa(pbuf, psize+1); - if (!newpbuf) - return -1; - newpbuf[psize] = '\0'; - - *poff = 0; - *off = 0; - - /* buf is: - * host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc/sdc1 - */ - uint32_t tosser0, tosser1, tosser2; - - /* ignore a bunch of stuff - * host4/port-4:0 - * or host4/port-4:0:0 - */ - rc = sscanf(newpbuf+*poff, "host%d/port-%d:%d%n", &tosser0, &tosser1, - &tosser2, &psz); - if (rc != 3) - return -1; - *poff += psz; - - psz = 0; - rc = sscanf(pbuf+*poff, ":%d%n", &tosser0, &psz); - if (rc != 0 && rc != 1) - return -1; - *poff += psz; - - /* next: - * /end_device-4:0 - * or /end_device-4:0:0 - * awesomely these are the exact same fields that go into port-blah, - * but we don't care for now about any of them anyway. - */ - rc = sscanf(newpbuf+*poff, "/end_device-%d:%d%n", &tosser0, &tosser1, - &psz); - if (rc != 2) - return -1; - *poff += psz; - - psz = 0; - rc = sscanf(newpbuf+*poff, ":%d%n", &tosser0, &psz); - if (rc != 0 && rc != 1) - return -1; - *poff += psz; - - /* now: - * /target4:0:0/ - */ - uint64_t tosser3; - rc = sscanf(newpbuf+*poff, "/target%d:%d:%"PRIu64"/%n", &tosser0, - &tosser1, &tosser3, &psz); - if (rc != 3) - return -1; - *poff += psz; - - /* now: - * %d:%d:%d:%llu/ - */ - rc = sscanf(newpbuf+*poff, "%d:%d:%d:%"PRIu64"/%n", - &info->sas_info.scsi_bus, - &info->sas_info.scsi_device, - &info->sas_info.scsi_target, - &info->sas_info.scsi_lun, &psz); - if (rc != 4) - return -1; - *poff += psz; - - /* what's left is: - * block/sdc/sdc1 - */ - char *disk_name = NULL; - char *part_name = NULL; - rc = sscanf(newpbuf+*poff, "block/%m[^/]/%m[^/]%n", &disk_name, - &part_name, &psz); - if (rc != 2) - return -1; - *poff += psz; - - /* check the original of this; it's guaranteed in our copy */ - if (pbuf[*poff] != '\0') { - free(disk_name); - free(part_name); - errno = EINVAL; - return -1; - } - - /* - * we also need to get the actual sas_address from someplace... - */ - rc = read_sysfs_file(&filebuf, - "class/block/%s/device/sas_address", - disk_name); - if (rc < 0 || filebuf == NULL) - return -1; - - rc = sscanf((char *)filebuf, "%"PRIx64, &sas_address); - if (rc != 1) - return -1; - - info->sas_info.sas_address = sas_address; - info->disk_name = disk_name; - info->part_name = part_name; - info->interface_type = sas; - - *off = efidp_make_sas(buf, size, sas_address); - return *off; -} - -static ssize_t make_pci_path(uint8_t *buf, ssize_t size, char *pathstr, ssize_t *pathoff) { ssize_t off=0, sz=0; @@ -597,31 +443,6 @@ make_blockdev_path(uint8_t *buf, ssize_t size, struct disk_info *info) } - /* /dev/sdc as SAS looks like: - * /sys/dev/block/8:32 -> ../../devices/pci0000:00/0000:00:01.0/0000:01:00.0/host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc - */ - if (!found) { - rc = sysfs_test_sas(linkbuf+loff, PATH_MAX-off); - if (rc < 0) - return -1; - else if (rc > 0) { - ssize_t linksz=0; - rc = sysfs_parse_sas(buf+off, size?size-off:0, &sz, - linkbuf+loff, PATH_MAX-off, - &linksz, info); - if (rc < 0) - return -1; - /* - * clang-analyzer complains about this because they - * don't believe in writing code to avoid introducing - * bugs later. - */ - // loff += linksz; - off += sz; - found = 1; - } - } - if (!found) { errno = ENOENT; return -1; diff --git a/src/linux.h b/src/linux.h index 17f1586..60b72cf 100644 --- a/src/linux.h +++ b/src/linux.h @@ -44,12 +44,12 @@ struct scsi_info { }; struct sas_info { - uint32_t scsi_bus; - uint32_t scsi_device; - uint32_t scsi_target; - uint64_t scsi_lun; + uint32_t scsi_bus; + uint32_t scsi_device; + uint32_t scsi_target; + uint64_t scsi_lun; - uint64_t sas_address; + uint64_t sas_address; }; struct sata_info { @@ -259,6 +259,7 @@ extern ssize_t parse_scsi_link(const char *current, uint32_t *host, #define set_part(x, y) /* XXX remove later */ /* device support implementations */ +extern struct dev_probe sas_parser; extern struct dev_probe sata_parser; extern struct dev_probe nvme_parser; extern struct dev_probe virtblk_parser;