mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
274 lines
5.8 KiB
C
274 lines
5.8 KiB
C
|
/*
|
||
|
* Copyright (C) 2024 Red Hat, Inc. All rights reserved.
|
||
|
*
|
||
|
* This file is part of LVM2.
|
||
|
*
|
||
|
* This copyrighted material is made available to anyone wishing to use,
|
||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||
|
* of the GNU Lesser General Public License v.2.1.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public License
|
||
|
* along with this program; if not, write to the Free Software Foundation,
|
||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
*/
|
||
|
|
||
|
#include "base/memory/zalloc.h"
|
||
|
#include "lib/misc/lib.h"
|
||
|
#include "lib/commands/toolcontext.h"
|
||
|
#include "lib/device/device.h"
|
||
|
#include "lib/device/device_id.h"
|
||
|
#include "lib/mm/xlate.h"
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <unistd.h>
|
||
|
#include <stdint.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <string.h>
|
||
|
#include <inttypes.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <ctype.h>
|
||
|
#include <limits.h>
|
||
|
#include <dirent.h>
|
||
|
#include <errno.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <assert.h>
|
||
|
|
||
|
#ifdef NVME_SUPPORT
|
||
|
#include <libnvme.h>
|
||
|
|
||
|
static int iszero(unsigned char *d, size_t n)
|
||
|
{
|
||
|
size_t i;
|
||
|
|
||
|
for (i = 0; i < n; ++i) {
|
||
|
if (d[i])
|
||
|
return 0;
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static void _save_uuid(struct device *dev, unsigned char *uuid)
|
||
|
{
|
||
|
char idname[DEV_WWID_SIZE] = {0};
|
||
|
int max, pos, num, i;
|
||
|
|
||
|
max = sizeof(idname);
|
||
|
pos = 0;
|
||
|
|
||
|
num = snprintf(idname + pos, max - pos, "uuid.");
|
||
|
if (num >= max - pos)
|
||
|
goto bad;
|
||
|
pos += num;
|
||
|
|
||
|
for (i = 0; i < NVME_UUID_LEN; ++i) {
|
||
|
num = snprintf(idname + pos, max - pos, "%02x", uuid[i]);
|
||
|
if (num >= max - pos)
|
||
|
goto bad;
|
||
|
pos += num;
|
||
|
|
||
|
if (i == 3 || i == 5 || i == 7 || i == 9) {
|
||
|
num = snprintf(idname + pos, max - pos, "-");
|
||
|
if (num >= max - pos)
|
||
|
goto bad;
|
||
|
pos += num;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
idname[DEV_WWID_SIZE-1] = '\0';
|
||
|
|
||
|
dev_add_nvme_wwid(idname, 3, &dev->wwids);
|
||
|
|
||
|
return;
|
||
|
bad:
|
||
|
log_debug("dev_read_nvme_wwids ignore invalid uuid %s for %s", uuid, dev_name(dev));
|
||
|
}
|
||
|
|
||
|
static void _save_nguid(struct device *dev, unsigned char *nguid)
|
||
|
{
|
||
|
char idname[DEV_WWID_SIZE] = {0};
|
||
|
int max, pos, num, i;
|
||
|
|
||
|
max = sizeof(idname);
|
||
|
pos = 0;
|
||
|
|
||
|
num = snprintf(idname + pos, max - pos, "eui.");
|
||
|
if (num >= max - pos)
|
||
|
goto bad;
|
||
|
pos += num;
|
||
|
|
||
|
for (i = 0; i < 16; ++i) {
|
||
|
num = snprintf(idname + pos, max - pos, "%02x", nguid[i]);
|
||
|
if (num >= max - pos)
|
||
|
goto bad;
|
||
|
pos += num;
|
||
|
}
|
||
|
|
||
|
idname[DEV_WWID_SIZE-1] = '\0';
|
||
|
|
||
|
dev_add_nvme_wwid(idname, 2, &dev->wwids);
|
||
|
|
||
|
return;
|
||
|
bad:
|
||
|
log_debug("dev_read_nvme_wwids ignore invalid nguid %s for %s", nguid, dev_name(dev));
|
||
|
}
|
||
|
|
||
|
static void _save_eui64(struct device *dev, unsigned char *eui64)
|
||
|
{
|
||
|
char idname[DEV_WWID_SIZE] = {0};
|
||
|
int max, pos, num, i;
|
||
|
|
||
|
max = sizeof(idname);
|
||
|
pos = 0;
|
||
|
|
||
|
num = snprintf(idname + pos, max - pos, "eui.");
|
||
|
if (num >= max - pos)
|
||
|
goto bad;
|
||
|
pos += num;
|
||
|
|
||
|
for (i = 0; i < 8; ++i) {
|
||
|
num = snprintf(idname + pos, max - pos, "%02x", eui64[i]);
|
||
|
if (num >= max - pos)
|
||
|
goto bad;
|
||
|
pos += num;
|
||
|
}
|
||
|
|
||
|
idname[DEV_WWID_SIZE-1] = '\0';
|
||
|
|
||
|
dev_add_nvme_wwid(idname, 1, &dev->wwids);
|
||
|
|
||
|
return;
|
||
|
bad:
|
||
|
log_debug("dev_read_nvme_wwids ignore invalid eui64 %s for %s", eui64, dev_name(dev));
|
||
|
}
|
||
|
|
||
|
#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
|
||
|
static void *_nvme_alloc(size_t len)
|
||
|
{
|
||
|
size_t _len = ROUND_UP(len, 0x1000);
|
||
|
void *p;
|
||
|
|
||
|
if (posix_memalign((void *)&p, getpagesize(), _len))
|
||
|
return NULL;
|
||
|
|
||
|
memset(p, 0, _len);
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
void dev_read_nvme_wwids(struct device *dev)
|
||
|
{
|
||
|
const char *devpath;
|
||
|
unsigned char *data = NULL;
|
||
|
struct nvme_id_ns *ns = NULL;
|
||
|
struct nvme_id_ctrl *ctrl_id = NULL;
|
||
|
unsigned char nguid[16] = {0};
|
||
|
unsigned char eui64[8] = {0};
|
||
|
unsigned char uuid[NVME_UUID_LEN] = {0};
|
||
|
uint32_t nsid;
|
||
|
int fd, i, len;
|
||
|
|
||
|
dev->flags |= DEV_ADDED_NVME_WWIDS;
|
||
|
|
||
|
/* shouldn't happen */
|
||
|
if (dm_list_empty(&dev->aliases))
|
||
|
return;
|
||
|
|
||
|
devpath = dev_name(dev);
|
||
|
|
||
|
if ((fd = open(devpath, O_RDONLY)) < 0) {
|
||
|
log_debug("dev_read_nvme_wwids cannot open %s", devpath);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (nvme_get_nsid(fd, &nsid)) {
|
||
|
log_print("dev_read_nvme_wwids nvme_get_nsid error %d %s", errno, devpath);
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
if (!(ns = _nvme_alloc(sizeof(*ns))))
|
||
|
goto_out;
|
||
|
|
||
|
if (nvme_identify_ns(fd, nsid, ns)) {
|
||
|
log_debug("dev_read_nvme_wwids nvme_identify_ns error %d %s", errno, devpath);
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
memcpy(nguid, ns->nguid, 16);
|
||
|
memcpy(eui64, ns->eui64, 8);
|
||
|
|
||
|
if (!iszero(nguid, 16))
|
||
|
_save_nguid(dev, nguid);
|
||
|
if (!iszero(eui64, 8))
|
||
|
_save_eui64(dev, eui64);
|
||
|
|
||
|
if (!(ctrl_id = _nvme_alloc(sizeof(struct nvme_id_ctrl))))
|
||
|
goto_out;
|
||
|
|
||
|
/* Avoid using nvme_identify_ns_descs before ver 1.3. */
|
||
|
if (!nvme_identify_ctrl(fd, ctrl_id)) {
|
||
|
if (le32_to_cpu(ctrl_id->ver) < 0x10300)
|
||
|
goto_out;
|
||
|
}
|
||
|
|
||
|
if (!(data = _nvme_alloc(NVME_IDENTIFY_DATA_SIZE)))
|
||
|
goto_out;
|
||
|
|
||
|
if (nvme_identify_ns_descs(fd, nsid, (struct nvme_ns_id_desc *)data)) {
|
||
|
log_debug("dev_read_nvme_wwids nvme_identify_ns_descs error %d %s", errno, devpath);
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < NVME_IDENTIFY_DATA_SIZE; i += len) {
|
||
|
struct nvme_ns_id_desc *cur = (struct nvme_ns_id_desc *)(data + i);
|
||
|
|
||
|
if (cur->nidl == 0)
|
||
|
break;
|
||
|
|
||
|
memset(eui64, 0, sizeof(eui64));
|
||
|
memset(nguid, 0, sizeof(nguid));
|
||
|
memset(uuid, 0, sizeof(uuid));
|
||
|
|
||
|
switch (cur->nidt) {
|
||
|
case NVME_NIDT_EUI64:
|
||
|
memcpy(eui64, data + i + sizeof(*cur), sizeof(eui64));
|
||
|
len = sizeof(eui64);
|
||
|
break;
|
||
|
case NVME_NIDT_NGUID:
|
||
|
memcpy(nguid, data + i + sizeof(*cur), sizeof(nguid));
|
||
|
len = sizeof(nguid);
|
||
|
break;
|
||
|
case NVME_NIDT_UUID:
|
||
|
memcpy(uuid, data + i + sizeof(*cur), NVME_UUID_LEN);
|
||
|
len = sizeof(uuid);
|
||
|
break;
|
||
|
case NVME_NIDT_CSI:
|
||
|
len = 1;
|
||
|
break;
|
||
|
default:
|
||
|
len = cur->nidl;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
len += sizeof(*cur);
|
||
|
|
||
|
if (!iszero(uuid, NVME_UUID_LEN))
|
||
|
_save_uuid(dev, uuid);
|
||
|
else if (!iszero(nguid, 16))
|
||
|
_save_nguid(dev, nguid);
|
||
|
else if (!iszero(eui64, 8))
|
||
|
_save_eui64(dev, eui64);
|
||
|
}
|
||
|
out:
|
||
|
free(ctrl_id);
|
||
|
free(ns);
|
||
|
free(data);
|
||
|
close(fd);
|
||
|
}
|
||
|
#else
|
||
|
void dev_read_nvme_wwids(struct device *dev)
|
||
|
{
|
||
|
}
|
||
|
#endif
|