2 * libefiboot - library for the manipulation of EFI boot variables
3 * Copyright 2012-2018 Red Hat, Inc.
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.
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.
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/>.
21 #include "fix_coverity.h"
32 * support for Old-school SCSI devices
36 * helper for scsi formats...
39 parse_scsi_link(const char *current, uint32_t *scsi_host,
40 uint32_t *scsi_bus, uint32_t *scsi_device,
41 uint32_t *scsi_target, uint64_t *scsi_lun,
42 uint32_t *local_port_id, uint32_t *remote_port_id,
43 uint32_t *remote_target_id)
47 int pos0 = 0, pos1 = 0;
51 spaces = alloca(sz+1);
52 memset(spaces, ' ', sz+1);
58 * This structure is completely ridiculous.
60 * /dev/sdc as SAS looks like:
61 * /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
62 * /dev/sdc1 looks like:
63 * /sys/dev/block/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
67 * /dev/sdc as SAS looks like:
68 * /sys/dev/block/8:32 -> ../../devices/pci0000:00/0000:00:01.0/0000:01:00.0/host4/port-4:2:0/end_device-4:2:0/target4:2:0/4:2:0:0/block/sdc
69 * /dev/sdc1 looks like:
70 * /sys/dev/block/8:33 -> ../../devices/pci0000:00/0000:00:01.0/0000:01:00.0/host4/port-4:2:0/end_device-4:2:0/target4:2:0/4:2:0:0/block/sdc/sdc1
72 * /sys/block/sdc/device looks like:
73 * device-> ../../../4:2:0:0
77 * 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
78 * 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
80 * /sys/block/sda/device looks like:
81 * device -> ../../../2:0:0:0 *
83 * sas_address exists, but it's hard to find:
84 * /sys/devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/sas_device/expander-2:0/sas_address
85 * but sas_host_address is nowhere to be found, and sas_address
86 * doesn't directly exist under /sys/class/ anywhere. So you actually
88 * /sys/devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/sas_device/expander-2:0/sas_address
89 * and chop that off to
90 * /sys/devices/pci0000:74/0000:74:02.0/host2/port-2:0/expander-2:0/
91 * and then add a bunch of port and end device crap to it to get:
92 * /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
97 * So we start when current is:
98 * host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc/sdc1
100 * 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
102 uint32_t tosser0, tosser1, tosser2;
104 /* ignore a bunch of stuff
106 * or host4/port-4:0:0
108 debug("searching for host4/");
109 rc = sscanf(current, "host%d/%n", scsi_host, &pos0);
110 debug("current:\"%s\" rc:%d pos0:%d\n", current+sz, rc, pos0);
111 arrow(LOG_DEBUG, spaces, 9, pos0, rc, 1);
118 * We might have this next:
119 * 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
121 * port-2:0/end_device-2:0:2/target2:0:0/2:0:0:0/block/sda/sda1
122 * or maybe (not sure):
123 * port-2:0:2/end_device-2:0:2/target2:0:0/2:0:0:0/block/sda/sda1
125 debug("searching for port-4:0 or port-4:0:0");
126 rc = sscanf(current+sz, "port-%d:%d%n:%d%n", &tosser0,
127 &tosser1, &pos0, &tosser2, &pos1);
128 debug("current:\"%s\" rc:%d pos0:%d pos1:%d\n", current+sz, rc, pos0, pos1);
129 arrow(LOG_DEBUG, spaces, 9, pos0, rc, 2);
130 arrow(LOG_DEBUG, spaces, 9, pos1, rc, 3);
131 if (rc == 2 || rc == 3) {
134 if (local_port_id && rc == 2)
135 *local_port_id = tosser1;
136 if (remote_port_id && rc == 3)
137 *remote_port_id = tosser2;
139 if (current[sz] == '/')
143 * We might have this next:
144 * expander-2:0/port-2:0:2/end_device-2:0:2/target2:0:0/2:0:0:0/block/sda/sda1
149 * We don't actually care about either number in expander-.../,
150 * because they're replicated in all the other places. We just need
153 debug("searching for expander-4:0/");
154 rc = sscanf(current+sz, "expander-%d:%d/%n", &tosser0, &tosser1, &pos0);
155 debug("current:\"%s\" rc:%d pos0:%d\n", current+sz, rc, pos0);
156 arrow(LOG_DEBUG, spaces, 9, pos0, rc, 2);
158 if (!remote_target_id) {
159 efi_error("Device is PHY is a remote target, but remote_target_id is NULL");
162 *remote_target_id = tosser1;
167 * if we have that, we should have a 3-part port next
169 debug("searching for port-2:0:2/");
170 rc = sscanf(current+sz, "port-%d:%d:%d/%n", &tosser0, &tosser1, &tosser2, &pos0);
171 debug("current:\"%s\" rc:%d pos0:%d\n", current+sz, rc, pos0);
172 arrow(LOG_DEBUG, spaces, 9, pos0, rc, 3);
174 efi_error("Couldn't parse port expander port string");
183 * or /end_device-4:0:0
184 * awesomely these are the exact same fields that go into port-blah,
185 * but we don't care for now about any of them anyway.
187 debug("searching for end_device-4:0/ or end_device-4:0:0/");
188 rc = sscanf(current + sz, "end_device-%d:%d%n", &tosser0, &tosser1, &pos0);
189 debug("current:\"%s\" rc:%d pos0:%d\n", current+sz, rc, pos0);
194 rc = sscanf(current + sz + pos0, ":%d%n", &tosser2, &pos1);
195 arrow(LOG_DEBUG, spaces, 9, pos0, rc + 2, 2);
196 arrow(LOG_DEBUG, spaces, 9, pos0 + pos1, rc + 2, 3);
197 if (rc != 0 && rc != 1)
199 if (remote_port_id && rc == 1)
200 *remote_port_id = tosser2;
201 if (local_port_id && rc == 0)
202 *local_port_id = tosser1;
206 if (current[sz] == '/')
208 } else if (rc != 0) {
216 debug("searching for target4:0:0/");
217 rc = sscanf(current + sz, "target%d:%d:%"PRIu64"/%n", &tosser0, &tosser1,
219 debug("current:\"%s\" rc:%d pos0:%d\n", current+sz, rc, pos0);
220 arrow(LOG_DEBUG, spaces, 9, pos0, rc, 3);
229 debug("searching for 4:0:0:0/");
230 rc = sscanf(current + sz, "%d:%d:%d:%"PRIu64"/%n",
231 scsi_bus, scsi_device, scsi_target, scsi_lun, &pos0);
232 debug("current:\"%s\" rc:%d pos0:%d\n", current+sz, rc, pos0);
233 arrow(LOG_DEBUG, spaces, 9, pos0, rc, 4);
238 debug("returning %d", sz);
243 parse_scsi(struct device *dev, const char *current, const char *root UNUSED)
245 uint32_t scsi_host, scsi_bus, scsi_device, scsi_target;
252 pos = strlen(current);
253 spaces = alloca(pos+1);
254 memset(spaces, ' ', pos+1);
260 debug("searching for ../../../0:0:0:0");
261 rc = sscanf(dev->device, "../../../%d:%d:%d:%"PRIu64"%n",
262 &dev->scsi_info.scsi_bus,
263 &dev->scsi_info.scsi_device,
264 &dev->scsi_info.scsi_target,
265 &dev->scsi_info.scsi_lun,
267 debug("current:\"%s\" rc:%d pos:%d\n", dev->device, rc, pos);
268 arrow(LOG_DEBUG, spaces, 9, pos, rc, 3);
272 sz = parse_scsi_link(current, &scsi_host,
273 &scsi_bus, &scsi_device,
274 &scsi_target, &scsi_lun,
280 * SCSI disks can have up to 16 partitions, or 4 bits worth
281 * and have one bit for the disk number.
283 if (dev->major == 8) {
284 dev->interface_type = scsi;
285 dev->disknum = (dev->minor >> 4);
286 set_part(dev, dev->minor & 0xF);
287 } else if (dev->major >= 65 && dev->major <= 71) {
288 dev->interface_type = scsi;
289 dev->disknum = 16*(dev->major-64) + (dev->minor >> 4);
290 set_part(dev, dev->minor & 0xF);
291 } else if (dev->major >= 128 && dev->major <= 135) {
292 dev->interface_type = scsi;
293 dev->disknum = 16*(dev->major-128) + (dev->minor >> 4);
294 set_part(dev, dev->minor & 0xF);
296 efi_error("couldn't parse scsi major/minor");
304 dp_create_scsi(struct device *dev,
305 uint8_t *buf, ssize_t size, ssize_t off)
311 sz = efidp_make_scsi(buf + off, size ? size - off : 0,
312 dev->scsi_info.scsi_target,
313 dev->scsi_info.scsi_lun);
315 efi_error("efidp_make_scsi() failed");
320 enum interface_type scsi_iftypes[] = { scsi, unknown };
322 struct dev_probe HIDDEN scsi_parser = {
324 .iftypes = scsi_iftypes,
325 .flags = DEV_PROVIDES_HD,
327 .create = dp_create_scsi,