/
githubmirror
/
efivar
Обзор
Документация
Войти
/
githubmirror
/
efivar
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
38
src/linux-sas.c
256 строк
9 KB
Peter Jones
SPDX-ify all the license text in source files.
03 фев 2020, 21:37
03 фев 2020, 21:37
ce42f1d
Код
Авторство
О чём код?
// SPDX-License-Identifier: LGPL-2.1-or-later /* * libefiboot - library for the manipulation of EFI boot variables * Copyright 2012-2018 Red Hat, Inc. */ #include "fix_coverity.h" #include <errno.h> #include <fcntl.h> #include <inttypes.h> #include <stdint.h> #include <unistd.h> #include "efiboot.h" static int get_port_expander_sas_address(uint64_t *sas_address, uint32_t scsi_host, uint32_t local_port_id, uint32_t remote_port_id, uint32_t remote_scsi_target) { uint8_t *filebuf = NULL; int rc; /* * We find sas_address via this insanity: * /sys/class/scsi_host/host2 -> ../../devices/pci0000:74/0000:74:02.0/host2/scsi_host/host2 * /sys/devices/pci0000:74/0000:74:02.0/host2/scsi_host/host2/device -> ../../../host2 * /sys/devices/pci0000:74/0000:74:02.0/host2/device -> ../../../host2 * /sys/devices/host2/port-2:0/expander-2:0/sas_device/expander-2:0/sas_address * * But since host2 is always host2, we can skip most of that and just * go for: * /sys/devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/port-2:0:2/end_device-2:0:2/sas_device/end_device-2:0:2/sas_address */ #if 0 /* previously thought this was right, but it's the expander's address, not the target's address */ /* * /sys/class/scsi_host/host2/device/port-2:0/expander-2:0/sas_device/expander-2:0/sas_address * ... I think. I would have expected that to be port-2:0:0 and I * don't understand why it isn't. (I do now; this is the expander not * the port.) */ debug("looking for /sys/class/scsi_host/host%d/device/port-%d:%d/expander-%d:%d/sas_device/expander-%d:%d/sas_address", scsi_host, scsi_host, port_id, scsi_host, remote_scsi_target, scsi_host, remote_scsi_target); rc = read_sysfs_file(&filebuf, "class/scsi_host/host%d/device/port-%d:%d/expander-%d:%d/sas_device/expander-%d:%d/sas_address", scsi_host, scsi_host, port_id, scsi_host, remote_scsi_target, scsi_host, remote_scsi_target); if (rc < 0 || filebuf == NULL) { debug("didn't find it."); return -1; } #else debug("looking for /sys/class/scsi_host/host%d/device/port-%d:%d/expander-%d:%d/port-%d:%d:%d/end_device-%d:%d:%d/sas_device/end_device-%d:%d:%d/sas_address", scsi_host, scsi_host, local_port_id, scsi_host, remote_scsi_target, scsi_host, remote_scsi_target, remote_port_id, scsi_host, remote_scsi_target, remote_port_id, scsi_host, remote_scsi_target, remote_port_id); rc = read_sysfs_file(&filebuf, "class/scsi_host/host%d/device/port-%d:%d/expander-%d:%d/port-%d:%d:%d/end_device-%d:%d:%d/sas_device/end_device-%d:%d:%d/sas_address", scsi_host, scsi_host, local_port_id, scsi_host, remote_scsi_target, scsi_host, remote_scsi_target, remote_port_id, scsi_host, remote_scsi_target, remote_port_id, scsi_host, remote_scsi_target, remote_port_id); if (rc < 0 || filebuf == NULL) { debug("didn't find it."); return -1; } #endif rc = sscanf((char *)filebuf, "%"PRIx64, sas_address); if (rc != 1) return -1; return 0; } static int get_local_sas_address(uint64_t *sas_address, struct device *dev) { int rc; char *filebuf = NULL; 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; return 0; } /* * 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. * * There are also other devices that look like: * * 8:0 -> ../../devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/port-2:0:2/end_device-2:0:2/target2:0:0/2:0:0:0/block/sda * 8:1 -> ../../devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/port-2:0:2/end_device-2:0:2/target2:0:0/2:0:0:0/block/sda/sda1 * * /sys/dev/block/8:0/device -> ../../../2:0:0:0 * * This exists: * * /sys/class/scsi_host/host2 -> ../../devices/pci0000:74/0000:74:02.0/host2/scsi_host/host2 * /sys/devices/pci0000:74/0000:74:02.0/host2/scsi_host/host2/device -> ../../../host2 * /sys/devices/pci0000:74/0000:74:02.0/host2/device -> ../../../host2 * /sys/devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/sas_device/expander-2:0/sas_address * * but the device doesn't actually have a sas_host_address, because it's on a * port expander, and sas_address doesn't directly exist under /sys/class/ * anywhere. */ static ssize_t parse_sas(struct device *dev, const char *path, const char *root UNUSED) { const char *current = path; struct stat statbuf = { 0, }; int rc; uint32_t scsi_host, scsi_bus, scsi_device, scsi_target; uint32_t local_port_id = 0, remote_port_id = 0; uint32_t remote_scsi_target = 0; uint64_t scsi_lun; ssize_t pos; uint64_t sas_address = 0; debug("entry"); pos = parse_scsi_link(current, &scsi_host, &scsi_bus, &scsi_device, &scsi_target, &scsi_lun, &local_port_id, &remote_port_id, &remote_scsi_target); /* * If we can't parse the scsi data, it isn't a sas device, so return 0 * not error. */ if (pos < 0) return 0; current += pos; /* * Make sure it has the actual /SAS/ bits before we continue * validating all this junk. */ debug("looking for /sys/class/scsi_host/host%d/host_sas_address", scsi_host); 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) { debug("didn't find it."); /* * If it's on a port expander, it won't have the * host_sas_address, so we need to check if it's a sas_host * instead. * It may work to just check this to begin with, but I don't * have such a device in front of me right now. */ debug("looking for /sys/class/sas_host/host%d", scsi_host); rc = sysfs_stat(&statbuf, "class/sas_host/host%d", scsi_host); if (rc < 0) { debug("didn't find it."); return 0; } debug("found it."); /* * So it *is* a sas_host, and we have to fish the sas_address * from the remote port */ rc = get_port_expander_sas_address(&sas_address, scsi_host, local_port_id, remote_port_id, remote_scsi_target); if (rc < 0) { debug("Couldn't find port expander sas address"); return 0; } } else { /* * we also need to get the actual sas_address from someplace... */ debug("found it."); rc = get_local_sas_address(&sas_address, dev); if (rc < 0) { debug("Couldn't find sas address"); return 0; } } debug("sas address is 0x%"PRIx64, sas_address); 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; debug("current:'%s' sz:%zd", current, current - path); return current - path; } static ssize_t dp_create_sas(struct device *dev, uint8_t *buf, ssize_t size, ssize_t off) { ssize_t sz; 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, }; // vim:fenc=utf-8:tw=75:noet