OSDN Git Service

linux-pci-root: remove an unused assignment
[android-x86/external-efivar.git] / src / linux-nvme.c
1 /*
2  * libefiboot - library for the manipulation of EFI boot variables
3  * Copyright 2012-2018 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public License as
7  * published by the Free Software Foundation; either version 2.1 of the
8  * License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, see
17  * <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "fix_coverity.h"
22
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <inttypes.h>
26 #include <stdint.h>
27 #include <unistd.h>
28
29 #include "efiboot.h"
30
31 /*
32  * support for NVMe devices
33  *
34  * /sys/dev/block/$major:$minor looks like:
35  * 259:0 -> ../../devices/pci0000:00/0000:00:1d.0/0000:05:00.0/nvme/nvme0/nvme0n1
36  * 259:1 -> ../../devices/pci0000:00/0000:00:1d.0/0000:05:00.0/nvme/nvme0/nvme0n1/nvme0n1p1
37  *
38  * /sys/dev/block/259:0/device looks like:
39  * device -> ../../nvme0
40  *
41  * /sys/dev/block/259:1/partition looks like:
42  * $ cat partition
43  * 1
44  *
45  * /sys/class/block/nvme0n1/eui looks like:
46  * $ cat /sys/class/block/nvme0n1/eui
47  * 00 25 38 53 5a 16 1d a9
48  */
49
50 static ssize_t
51 parse_nvme(struct device *dev, const char *current, const char *root UNUSED)
52 {
53         int rc;
54         int32_t tosser0, tosser1, tosser2, ctrl_id, ns_id, partition;
55         uint8_t *filebuf = NULL;
56         int pos0 = 0, pos1 = 0;
57         char *spaces;
58
59         pos0 = strlen(current);
60         spaces = alloca(pos0+1);
61         memset(spaces, ' ', pos0+1);
62         spaces[pos0] = '\0';
63         pos0 = 0;
64
65         debug("entry");
66
67         debug("searching for nvme/nvme0/nvme0n1 or nvme/nvme0/nvme0n1/nvme0n1p1");
68         rc = sscanf(current, "nvme/nvme%d/nvme%dn%d%n/nvme%dn%dp%d%n",
69                     &tosser0, &ctrl_id, &ns_id, &pos0,
70                     &tosser1, &tosser2, &partition, &pos1);
71         debug("current:\"%s\" rc:%d pos0:%d pos1:%d\n", current, rc, pos0, pos1);
72         arrow(LOG_DEBUG, spaces, 9, pos0, rc, 3);
73         arrow(LOG_DEBUG, spaces, 9, pos1, rc, 6);
74         /*
75          * If it isn't of that form, it's not one of our nvme devices.
76          */
77         if (rc != 3 && rc != 6)
78                 return 0;
79
80         dev->nvme_info.ctrl_id = ctrl_id;
81         dev->nvme_info.ns_id = ns_id;
82         dev->nvme_info.has_eui = 0;
83         dev->interface_type = nvme;
84
85         if (rc == 6) {
86                 if (dev->part == -1)
87                         dev->part = partition;
88
89                 pos0 = pos1;
90         }
91
92         /*
93          * now fish the eui out of sysfs is there is one...
94          */
95         rc = read_sysfs_file(&filebuf,
96                              "class/block/nvme%dn%d/eui",
97                              ctrl_id, ns_id);
98         if ((rc < 0 && errno == ENOENT) || filebuf == NULL) {
99                 rc = read_sysfs_file(&filebuf,
100                              "class/block/nvme%dn%d/device/eui",
101                              ctrl_id, ns_id);
102         }
103         if (rc >= 0 && filebuf != NULL) {
104                 uint8_t eui[8];
105                 if (rc < 23) {
106                         errno = EINVAL;
107                         return -1;
108                 }
109                 rc = sscanf((char *)filebuf,
110                             "%02hhx %02hhx %02hhx %02hhx "
111                             "%02hhx %02hhx %02hhx %02hhx",
112                             &eui[0], &eui[1], &eui[2], &eui[3],
113                             &eui[4], &eui[5], &eui[6], &eui[7]);
114                 if (rc < 8) {
115                         errno = EINVAL;
116                         return -1;
117                 }
118                 dev->nvme_info.has_eui = 1;
119                 memcpy(dev->nvme_info.eui, eui, sizeof(eui));
120         }
121
122         return pos0;
123 }
124
125 static ssize_t
126 dp_create_nvme(struct device *dev,
127                uint8_t *buf,  ssize_t size, ssize_t off)
128 {
129         ssize_t sz;
130
131         debug("entry");
132
133         sz = efidp_make_nvme(buf + off, size ? size - off : 0,
134                              dev->nvme_info.ns_id,
135                              dev->nvme_info.has_eui ? dev->nvme_info.eui
136                                                         : NULL);
137         return sz;
138 }
139
140 static char *
141 make_part_name(struct device *dev)
142 {
143         char *ret = NULL;
144         ssize_t rc;
145
146         if (dev->part < 1)
147                 return NULL;
148
149         rc = asprintf(&ret, "%sp%d", dev->disk_name, dev->part);
150         if (rc < 0) {
151                 efi_error("could not allocate memory");
152                 return NULL;
153         }
154
155         return ret;
156 }
157
158 static enum interface_type nvme_iftypes[] = { nvme, unknown };
159
160 struct dev_probe HIDDEN nvme_parser = {
161         .name = "nvme",
162         .iftypes = nvme_iftypes,
163         .flags = DEV_PROVIDES_HD,
164         .parse = parse_nvme,
165         .create = dp_create_nvme,
166         .make_part_name = make_part_name,
167 };
168