Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0+ */
2 : : /*
3 : : * Copyright © IBM Corp. 2003
4 : : *
5 : : * Author: Patrick Mansfield<patmans@us.ibm.com>
6 : : */
7 : :
8 : : #include <errno.h>
9 : : #include <fcntl.h>
10 : : #include <inttypes.h>
11 : : #include <linux/bsg.h>
12 : : #include <linux/types.h>
13 : : #include <scsi/scsi.h>
14 : : #include <scsi/sg.h>
15 : : #include <stdio.h>
16 : : #include <stdlib.h>
17 : : #include <string.h>
18 : : #include <sys/ioctl.h>
19 : : #include <sys/stat.h>
20 : : #include <sys/types.h>
21 : : #include <time.h>
22 : : #include <unistd.h>
23 : :
24 : : #include "memory-util.h"
25 : : #include "random-util.h"
26 : : #include "scsi.h"
27 : : #include "scsi_id.h"
28 : : #include "string-util.h"
29 : :
30 : : /*
31 : : * A priority based list of id, naa, and binary/ascii for the identifier
32 : : * descriptor in VPD page 0x83.
33 : : *
34 : : * Brute force search for a match starting with the first value in the
35 : : * following id_search_list. This is not a performance issue, since there
36 : : * is normally one or some small number of descriptors.
37 : : */
38 : : static const struct scsi_id_search_values id_search_list[] = {
39 : : { SCSI_ID_TGTGROUP, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY },
40 : : { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY },
41 : : { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII },
42 : : { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_BINARY },
43 : : { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_ASCII },
44 : : /*
45 : : * Devices already exist using NAA values that are now marked
46 : : * reserved. These should not conflict with other values, or it is
47 : : * a bug in the device. As long as we find the IEEE extended one
48 : : * first, we really don't care what other ones are used. Using
49 : : * don't care here means that a device that returns multiple
50 : : * non-IEEE descriptors in a random order will get different
51 : : * names.
52 : : */
53 : : { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY },
54 : : { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII },
55 : : { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY },
56 : : { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII },
57 : : { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY },
58 : : { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII },
59 : : { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY },
60 : : { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII },
61 : : };
62 : :
63 : : static const char hex_str[]="0123456789abcdef";
64 : :
65 : : /*
66 : : * Values returned in the result/status, only the ones used by the code
67 : : * are used here.
68 : : */
69 : :
70 : : #define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */
71 : : #define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */
72 : : #define DID_TIME_OUT 0x03 /* Timed out for some other reason */
73 : : #define DRIVER_TIMEOUT 0x06
74 : : #define DRIVER_SENSE 0x08 /* Sense_buffer has been set */
75 : :
76 : : /* The following "category" function returns one of the following */
77 : : #define SG_ERR_CAT_CLEAN 0 /* No errors or other information */
78 : : #define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */
79 : : #define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */
80 : : #define SG_ERR_CAT_TIMEOUT 3
81 : : #define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */
82 : : #define SG_ERR_CAT_NOTSUPPORTED 5 /* Illegal / unsupported command */
83 : : #define SG_ERR_CAT_SENSE 98 /* Something else in the sense buffer */
84 : : #define SG_ERR_CAT_OTHER 99 /* Some other error/warning */
85 : :
86 : : static int do_scsi_page80_inquiry(struct scsi_id_device *dev_scsi, int fd,
87 : : char *serial, char *serial_short, int max_len);
88 : :
89 : 0 : static int sg_err_category_new(int scsi_status, int msg_status, int
90 : : host_status, int driver_status, const
91 : : unsigned char *sense_buffer, int sb_len) {
92 : 0 : scsi_status &= 0x7e;
93 : :
94 : : /*
95 : : * XXX change to return only two values - failed or OK.
96 : : */
97 : :
98 [ # # # # : 0 : if (!scsi_status && !host_status && !driver_status)
# # ]
99 : 0 : return SG_ERR_CAT_CLEAN;
100 : :
101 [ # # # # ]: 0 : if (IN_SET(scsi_status, SCSI_CHECK_CONDITION, SCSI_COMMAND_TERMINATED) ||
102 [ # # ]: 0 : (driver_status & 0xf) == DRIVER_SENSE) {
103 [ # # # # ]: 0 : if (sense_buffer && (sb_len > 2)) {
104 : : int sense_key;
105 : : unsigned char asc;
106 : :
107 [ # # ]: 0 : if (sense_buffer[0] & 0x2) {
108 : 0 : sense_key = sense_buffer[1] & 0xf;
109 : 0 : asc = sense_buffer[2];
110 : : } else {
111 : 0 : sense_key = sense_buffer[2] & 0xf;
112 [ # # ]: 0 : asc = (sb_len > 12) ? sense_buffer[12] : 0;
113 : : }
114 : :
115 [ # # ]: 0 : if (sense_key == RECOVERED_ERROR)
116 : 0 : return SG_ERR_CAT_RECOVERED;
117 [ # # ]: 0 : else if (sense_key == UNIT_ATTENTION) {
118 [ # # ]: 0 : if (0x28 == asc)
119 : 0 : return SG_ERR_CAT_MEDIA_CHANGED;
120 [ # # ]: 0 : if (0x29 == asc)
121 : 0 : return SG_ERR_CAT_RESET;
122 [ # # ]: 0 : } else if (sense_key == ILLEGAL_REQUEST)
123 : 0 : return SG_ERR_CAT_NOTSUPPORTED;
124 : : }
125 : 0 : return SG_ERR_CAT_SENSE;
126 : : }
127 [ # # ]: 0 : if (host_status) {
128 [ # # # # ]: 0 : if (IN_SET(host_status, DID_NO_CONNECT, DID_BUS_BUSY, DID_TIME_OUT))
129 : 0 : return SG_ERR_CAT_TIMEOUT;
130 : : }
131 [ # # ]: 0 : if (driver_status) {
132 [ # # ]: 0 : if (driver_status == DRIVER_TIMEOUT)
133 : 0 : return SG_ERR_CAT_TIMEOUT;
134 : : }
135 : 0 : return SG_ERR_CAT_OTHER;
136 : : }
137 : :
138 : 0 : static int sg_err_category3(struct sg_io_hdr *hp) {
139 : 0 : return sg_err_category_new(hp->status, hp->msg_status,
140 : 0 : hp->host_status, hp->driver_status,
141 : 0 : hp->sbp, hp->sb_len_wr);
142 : : }
143 : :
144 : 0 : static int sg_err_category4(struct sg_io_v4 *hp) {
145 : 0 : return sg_err_category_new(hp->device_status, 0,
146 : 0 : hp->transport_status, hp->driver_status,
147 : 0 : (unsigned char *)(uintptr_t)hp->response,
148 : 0 : hp->response_len);
149 : : }
150 : :
151 : 0 : static int scsi_dump_sense(struct scsi_id_device *dev_scsi,
152 : : unsigned char *sense_buffer, int sb_len) {
153 : : int s;
154 : : int code;
155 : : int sense_class;
156 : : int sense_key;
157 : : int asc, ascq;
158 : :
159 : : /*
160 : : * Figure out and print the sense key, asc and ascq.
161 : : *
162 : : * If you want to suppress these for a particular drive model, add
163 : : * a black list entry in the scsi_id config file.
164 : : *
165 : : * XXX We probably need to: lookup the sense/asc/ascq in a retry
166 : : * table, and if found return 1 (after dumping the sense, asc, and
167 : : * ascq). So, if/when we get something like a power on/reset,
168 : : * we'll retry the command.
169 : : */
170 : :
171 [ # # ]: 0 : if (sb_len < 1)
172 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
173 : : "%s: sense buffer empty",
174 : : dev_scsi->kernel);
175 : :
176 : 0 : sense_class = (sense_buffer[0] >> 4) & 0x07;
177 : 0 : code = sense_buffer[0] & 0xf;
178 : :
179 [ # # ]: 0 : if (sense_class == 7) {
180 : : /*
181 : : * extended sense data.
182 : : */
183 : 0 : s = sense_buffer[7] + 8;
184 [ # # ]: 0 : if (sb_len < s)
185 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
186 : : "%s: sense buffer too small %d bytes, %d bytes too short",
187 : : dev_scsi->kernel, sb_len,
188 : : s - sb_len);
189 : :
190 [ # # # # ]: 0 : if (IN_SET(code, 0x0, 0x1)) {
191 : 0 : sense_key = sense_buffer[2] & 0xf;
192 [ # # ]: 0 : if (s < 14)
193 : : /*
194 : : * Possible?
195 : : */
196 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
197 : : "%s: sense result too small %d bytes",
198 : : dev_scsi->kernel, s);
199 : :
200 : 0 : asc = sense_buffer[12];
201 : 0 : ascq = sense_buffer[13];
202 [ # # # # ]: 0 : } else if (IN_SET(code, 0x2, 0x3)) {
203 : 0 : sense_key = sense_buffer[1] & 0xf;
204 : 0 : asc = sense_buffer[2];
205 : 0 : ascq = sense_buffer[3];
206 : : } else
207 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
208 : : "%s: invalid sense code 0x%x",
209 : : dev_scsi->kernel, code);
210 : :
211 [ # # ]: 0 : log_debug("%s: sense key 0x%x ASC 0x%x ASCQ 0x%x",
212 : : dev_scsi->kernel, sense_key, asc, ascq);
213 : : } else {
214 [ # # ]: 0 : if (sb_len < 4)
215 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
216 : : "%s: sense buffer too small %d bytes, %d bytes too short",
217 : : dev_scsi->kernel, sb_len,
218 : : 4 - sb_len);
219 : :
220 [ # # ]: 0 : if (sense_buffer[0] < 15)
221 [ # # ]: 0 : log_debug("%s: old sense key: 0x%x", dev_scsi->kernel, sense_buffer[0] & 0x0f);
222 : : else
223 [ # # ]: 0 : log_debug("%s: sense = %2x %2x",
224 : : dev_scsi->kernel, sense_buffer[0], sense_buffer[2]);
225 [ # # ]: 0 : log_debug("%s: non-extended sense class %d code 0x%0x",
226 : : dev_scsi->kernel, sense_class, code);
227 : :
228 : : }
229 : :
230 : 0 : return -1;
231 : : }
232 : :
233 : 0 : static int scsi_dump(struct scsi_id_device *dev_scsi, struct sg_io_hdr *io) {
234 [ # # # # : 0 : if (!io->status && !io->host_status && !io->msg_status &&
# # ]
235 [ # # ]: 0 : !io->driver_status)
236 : : /*
237 : : * Impossible, should not be called.
238 : : */
239 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
240 : : "%s: called with no error",
241 : : __FUNCTION__);
242 : :
243 [ # # ]: 0 : log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x",
244 : : dev_scsi->kernel, io->driver_status, io->host_status, io->msg_status, io->status);
245 [ # # ]: 0 : if (io->status == SCSI_CHECK_CONDITION)
246 : 0 : return scsi_dump_sense(dev_scsi, io->sbp, io->sb_len_wr);
247 : : else
248 : 0 : return -1;
249 : : }
250 : :
251 : 0 : static int scsi_dump_v4(struct scsi_id_device *dev_scsi, struct sg_io_v4 *io) {
252 [ # # # # ]: 0 : if (!io->device_status && !io->transport_status &&
253 [ # # ]: 0 : !io->driver_status)
254 : : /*
255 : : * Impossible, should not be called.
256 : : */
257 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
258 : : "%s: called with no error",
259 : : __FUNCTION__);
260 : :
261 [ # # ]: 0 : log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x",
262 : : dev_scsi->kernel, io->driver_status, io->transport_status, io->device_status);
263 [ # # ]: 0 : if (io->device_status == SCSI_CHECK_CONDITION)
264 : 0 : return scsi_dump_sense(dev_scsi, (unsigned char *)(uintptr_t)io->response,
265 : 0 : io->response_len);
266 : : else
267 : 0 : return -1;
268 : : }
269 : :
270 : 0 : static int scsi_inquiry(struct scsi_id_device *dev_scsi, int fd,
271 : : unsigned char evpd, unsigned char page,
272 : : unsigned char *buf, unsigned buflen) {
273 : 0 : unsigned char inq_cmd[INQUIRY_CMDLEN] =
274 : : { INQUIRY_CMD, evpd, page, 0, buflen, 0 };
275 : : unsigned char sense[SENSE_BUFF_LEN];
276 : : void *io_buf;
277 : : struct sg_io_v4 io_v4;
278 : : struct sg_io_hdr io_hdr;
279 : 0 : int retry = 3; /* rather random */
280 : : int retval;
281 : :
282 [ # # ]: 0 : if (buflen > SCSI_INQ_BUFF_LEN)
283 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
284 : : "buflen %d too long", buflen);
285 : :
286 : 0 : resend:
287 [ # # ]: 0 : if (dev_scsi->use_sg == 4) {
288 [ # # ]: 0 : memzero(&io_v4, sizeof(struct sg_io_v4));
289 : 0 : io_v4.guard = 'Q';
290 : 0 : io_v4.protocol = BSG_PROTOCOL_SCSI;
291 : 0 : io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD;
292 : 0 : io_v4.request_len = sizeof(inq_cmd);
293 : 0 : io_v4.request = (uintptr_t)inq_cmd;
294 : 0 : io_v4.max_response_len = sizeof(sense);
295 : 0 : io_v4.response = (uintptr_t)sense;
296 : 0 : io_v4.din_xfer_len = buflen;
297 : 0 : io_v4.din_xferp = (uintptr_t)buf;
298 : 0 : io_buf = (void *)&io_v4;
299 : : } else {
300 [ # # ]: 0 : memzero(&io_hdr, sizeof(struct sg_io_hdr));
301 : 0 : io_hdr.interface_id = 'S';
302 : 0 : io_hdr.cmd_len = sizeof(inq_cmd);
303 : 0 : io_hdr.mx_sb_len = sizeof(sense);
304 : 0 : io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
305 : 0 : io_hdr.dxfer_len = buflen;
306 : 0 : io_hdr.dxferp = buf;
307 : 0 : io_hdr.cmdp = inq_cmd;
308 : 0 : io_hdr.sbp = sense;
309 : 0 : io_hdr.timeout = DEF_TIMEOUT;
310 : 0 : io_buf = (void *)&io_hdr;
311 : : }
312 : :
313 : 0 : retval = ioctl(fd, SG_IO, io_buf);
314 [ # # ]: 0 : if (retval < 0) {
315 [ # # # # : 0 : if (IN_SET(errno, EINVAL, ENOSYS) && dev_scsi->use_sg == 4) {
# # ]
316 : 0 : dev_scsi->use_sg = 3;
317 : 0 : goto resend;
318 : : }
319 [ # # ]: 0 : log_debug_errno(errno, "%s: ioctl failed: %m", dev_scsi->kernel);
320 : 0 : goto error;
321 : : }
322 : :
323 [ # # ]: 0 : if (dev_scsi->use_sg == 4)
324 : 0 : retval = sg_err_category4(io_buf);
325 : : else
326 : 0 : retval = sg_err_category3(io_buf);
327 : :
328 [ # # # ]: 0 : switch (retval) {
329 : 0 : case SG_ERR_CAT_NOTSUPPORTED:
330 : 0 : buf[1] = 0;
331 : : _fallthrough_;
332 : 0 : case SG_ERR_CAT_CLEAN:
333 : : case SG_ERR_CAT_RECOVERED:
334 : 0 : retval = 0;
335 : 0 : break;
336 : :
337 : 0 : default:
338 [ # # ]: 0 : if (dev_scsi->use_sg == 4)
339 : 0 : retval = scsi_dump_v4(dev_scsi, io_buf);
340 : : else
341 : 0 : retval = scsi_dump(dev_scsi, io_buf);
342 : : }
343 : :
344 [ # # ]: 0 : if (!retval) {
345 : 0 : retval = buflen;
346 [ # # ]: 0 : } else if (retval > 0) {
347 [ # # ]: 0 : if (--retry > 0)
348 : 0 : goto resend;
349 : 0 : retval = -1;
350 : : }
351 : :
352 : 0 : error:
353 [ # # ]: 0 : if (retval < 0)
354 [ # # ]: 0 : log_debug("%s: Unable to get INQUIRY vpd %d page 0x%x.",
355 : : dev_scsi->kernel, evpd, page);
356 : :
357 : 0 : return retval;
358 : : }
359 : :
360 : : /* Get list of supported EVPD pages */
361 : 0 : static int do_scsi_page0_inquiry(struct scsi_id_device *dev_scsi, int fd,
362 : : unsigned char *buffer, unsigned len) {
363 : : int retval;
364 : :
365 [ # # ]: 0 : memzero(buffer, len);
366 : 0 : retval = scsi_inquiry(dev_scsi, fd, 1, 0x0, buffer, len);
367 [ # # ]: 0 : if (retval < 0)
368 : 0 : return 1;
369 : :
370 [ # # ]: 0 : if (buffer[1] != 0) {
371 [ # # ]: 0 : log_debug("%s: page 0 not available.", dev_scsi->kernel);
372 : 0 : return 1;
373 : : }
374 [ # # ]: 0 : if (buffer[3] > len) {
375 [ # # ]: 0 : log_debug("%s: page 0 buffer too long %d", dev_scsi->kernel, buffer[3]);
376 : 0 : return 1;
377 : : }
378 : :
379 : : /*
380 : : * Following check is based on code once included in the 2.5.x
381 : : * kernel.
382 : : *
383 : : * Some ill behaved devices return the standard inquiry here
384 : : * rather than the evpd data, snoop the data to verify.
385 : : */
386 [ # # ]: 0 : if (buffer[3] > MODEL_LENGTH) {
387 : : /*
388 : : * If the vendor id appears in the page assume the page is
389 : : * invalid.
390 : : */
391 [ # # ]: 0 : if (strneq((char*) buffer + VENDOR_LENGTH, dev_scsi->vendor, VENDOR_LENGTH)) {
392 [ # # ]: 0 : log_debug("%s: invalid page0 data", dev_scsi->kernel);
393 : 0 : return 1;
394 : : }
395 : : }
396 : 0 : return 0;
397 : : }
398 : :
399 : 0 : static int append_vendor_model(
400 : : const struct scsi_id_device *dev_scsi,
401 : : char buf[static VENDOR_LENGTH + MODEL_LENGTH]) {
402 : :
403 [ # # ]: 0 : assert(dev_scsi);
404 [ # # ]: 0 : assert(buf);
405 : :
406 [ # # ]: 0 : if (strnlen(dev_scsi->vendor, VENDOR_LENGTH) != VENDOR_LENGTH)
407 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
408 : : "%s: bad vendor string \"%s\"",
409 : : dev_scsi->kernel, dev_scsi->vendor);
410 [ # # ]: 0 : if (strnlen(dev_scsi->model, MODEL_LENGTH) != MODEL_LENGTH)
411 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
412 : : "%s: bad model string \"%s\"",
413 : : dev_scsi->kernel, dev_scsi->model);
414 : 0 : memcpy(buf, dev_scsi->vendor, VENDOR_LENGTH);
415 : 0 : memcpy(buf + VENDOR_LENGTH, dev_scsi->model, MODEL_LENGTH);
416 : 0 : return VENDOR_LENGTH + MODEL_LENGTH;
417 : : }
418 : :
419 : : /*
420 : : * check_fill_0x83_id - check the page 0x83 id, if OK allocate and fill
421 : : * serial number.
422 : : */
423 : 0 : static int check_fill_0x83_id(struct scsi_id_device *dev_scsi,
424 : : unsigned char *page_83,
425 : : const struct scsi_id_search_values
426 : : *id_search, char *serial, char *serial_short,
427 : : int max_len, char *wwn,
428 : : char *wwn_vendor_extension, char *tgpt_group) {
429 : : int i, j, s, len;
430 : :
431 : : /*
432 : : * ASSOCIATION must be with the device (value 0)
433 : : * or with the target port for SCSI_ID_TGTPORT
434 : : */
435 [ # # ]: 0 : if ((page_83[1] & 0x30) == 0x10) {
436 [ # # ]: 0 : if (id_search->id_type != SCSI_ID_TGTGROUP)
437 : 0 : return 1;
438 [ # # ]: 0 : } else if ((page_83[1] & 0x30) != 0)
439 : 0 : return 1;
440 : :
441 [ # # ]: 0 : if ((page_83[1] & 0x0f) != id_search->id_type)
442 : 0 : return 1;
443 : :
444 : : /*
445 : : * Possibly check NAA sub-type.
446 : : */
447 [ # # ]: 0 : if ((id_search->naa_type != SCSI_ID_NAA_DONT_CARE) &&
448 [ # # ]: 0 : (id_search->naa_type != (page_83[4] & 0xf0) >> 4))
449 : 0 : return 1;
450 : :
451 : : /*
452 : : * Check for matching code set - ASCII or BINARY.
453 : : */
454 [ # # ]: 0 : if ((page_83[0] & 0x0f) != id_search->code_set)
455 : 0 : return 1;
456 : :
457 : : /*
458 : : * page_83[3]: identifier length
459 : : */
460 : 0 : len = page_83[3];
461 [ # # ]: 0 : if ((page_83[0] & 0x0f) != SCSI_ID_ASCII)
462 : : /*
463 : : * If not ASCII, use two bytes for each binary value.
464 : : */
465 : 0 : len *= 2;
466 : :
467 : : /*
468 : : * Add one byte for the NUL termination, and one for the id_type.
469 : : */
470 : 0 : len += 2;
471 [ # # ]: 0 : if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC)
472 : 0 : len += VENDOR_LENGTH + MODEL_LENGTH;
473 : :
474 [ # # ]: 0 : if (max_len < len) {
475 [ # # ]: 0 : log_debug("%s: length %d too short - need %d",
476 : : dev_scsi->kernel, max_len, len);
477 : 0 : return 1;
478 : : }
479 : :
480 [ # # # # ]: 0 : if (id_search->id_type == SCSI_ID_TGTGROUP && tgpt_group != NULL) {
481 : : unsigned group;
482 : :
483 : 0 : group = ((unsigned)page_83[6] << 8) | page_83[7];
484 : 0 : sprintf(tgpt_group,"%x", group);
485 : 0 : return 1;
486 : : }
487 : :
488 : 0 : serial[0] = hex_str[id_search->id_type];
489 : :
490 : : /*
491 : : * For SCSI_ID_VENDOR_SPECIFIC prepend the vendor and model before
492 : : * the id since it is not unique across all vendors and models,
493 : : * this differs from SCSI_ID_T10_VENDOR, where the vendor is
494 : : * included in the identifier.
495 : : */
496 [ # # ]: 0 : if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC)
497 [ # # ]: 0 : if (append_vendor_model(dev_scsi, serial + 1) < 0)
498 : 0 : return 1;
499 : :
500 : 0 : i = 4; /* offset to the start of the identifier */
501 : 0 : s = j = strlen(serial);
502 [ # # ]: 0 : if ((page_83[0] & 0x0f) == SCSI_ID_ASCII) {
503 : : /*
504 : : * ASCII descriptor.
505 : : */
506 [ # # ]: 0 : while (i < (4 + page_83[3]))
507 : 0 : serial[j++] = page_83[i++];
508 : : } else {
509 : : /*
510 : : * Binary descriptor, convert to ASCII, using two bytes of
511 : : * ASCII for each byte in the page_83.
512 : : */
513 [ # # ]: 0 : while (i < (4 + page_83[3])) {
514 : 0 : serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4];
515 : 0 : serial[j++] = hex_str[page_83[i] & 0x0f];
516 : 0 : i++;
517 : : }
518 : : }
519 : :
520 : 0 : strcpy(serial_short, serial + s);
521 : :
522 [ # # # # ]: 0 : if (id_search->id_type == SCSI_ID_NAA && wwn != NULL) {
523 : 0 : strncpy(wwn, serial + s, 16);
524 [ # # ]: 0 : if (wwn_vendor_extension)
525 : 0 : strncpy(wwn_vendor_extension, serial + s + 16, 16);
526 : : }
527 : :
528 : 0 : return 0;
529 : : }
530 : :
531 : : /* Extract the raw binary from VPD 0x83 pre-SPC devices */
532 : 0 : static int check_fill_0x83_prespc3(struct scsi_id_device *dev_scsi,
533 : : unsigned char *page_83,
534 : : const struct scsi_id_search_values
535 : : *id_search, char *serial, char *serial_short, int max_len) {
536 : : int i, j;
537 : :
538 : 0 : serial[0] = hex_str[SCSI_ID_NAA];
539 : : /* serial has been memset to zero before */
540 : 0 : j = strlen(serial); /* j = 1; */
541 : :
542 [ # # # # ]: 0 : for (i = 0; (i < page_83[3]) && (j < max_len-3); ++i) {
543 : 0 : serial[j++] = hex_str[(page_83[4+i] & 0xf0) >> 4];
544 : 0 : serial[j++] = hex_str[ page_83[4+i] & 0x0f];
545 : : }
546 : 0 : serial[max_len-1] = 0;
547 : 0 : strncpy(serial_short, serial, max_len-1);
548 : 0 : return 0;
549 : : }
550 : :
551 : : /* Get device identification VPD page */
552 : 0 : static int do_scsi_page83_inquiry(struct scsi_id_device *dev_scsi, int fd,
553 : : char *serial, char *serial_short, int len,
554 : : char *unit_serial_number, char *wwn,
555 : : char *wwn_vendor_extension, char *tgpt_group) {
556 : : int retval;
557 : : unsigned id_ind, j;
558 : : unsigned char page_83[SCSI_INQ_BUFF_LEN];
559 : :
560 : : /* also pick up the page 80 serial number */
561 : 0 : do_scsi_page80_inquiry(dev_scsi, fd, NULL, unit_serial_number, MAX_SERIAL_LEN);
562 : :
563 [ # # ]: 0 : memzero(page_83, SCSI_INQ_BUFF_LEN);
564 : 0 : retval = scsi_inquiry(dev_scsi, fd, 1, PAGE_83, page_83,
565 : : SCSI_INQ_BUFF_LEN);
566 [ # # ]: 0 : if (retval < 0)
567 : 0 : return 1;
568 : :
569 [ # # ]: 0 : if (page_83[1] != PAGE_83) {
570 [ # # ]: 0 : log_debug("%s: Invalid page 0x83", dev_scsi->kernel);
571 : 0 : return 1;
572 : : }
573 : :
574 : : /*
575 : : * XXX Some devices (IBM 3542) return all spaces for an identifier if
576 : : * the LUN is not actually configured. This leads to identifiers of
577 : : * the form: "1 ".
578 : : */
579 : :
580 : : /*
581 : : * Model 4, 5, and (some) model 6 EMC Symmetrix devices return
582 : : * a page 83 reply according to SCSI-2 format instead of SPC-2/3.
583 : : *
584 : : * The SCSI-2 page 83 format returns an IEEE WWN in binary
585 : : * encoded hexi-decimal in the 16 bytes following the initial
586 : : * 4-byte page 83 reply header.
587 : : *
588 : : * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part
589 : : * of an Identification descriptor. The 3rd byte of the first
590 : : * Identification descriptor is a reserved (BSZ) byte field.
591 : : *
592 : : * Reference the 7th byte of the page 83 reply to determine
593 : : * whether the reply is compliant with SCSI-2 or SPC-2/3
594 : : * specifications. A zero value in the 7th byte indicates
595 : : * an SPC-2/3 conformant reply, (i.e., the reserved field of the
596 : : * first Identification descriptor). This byte will be non-zero
597 : : * for a SCSI-2 conformant page 83 reply from these EMC
598 : : * Symmetrix models since the 7th byte of the reply corresponds
599 : : * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is,
600 : : * 0x006048.
601 : : */
602 : :
603 [ # # ]: 0 : if (page_83[6] != 0)
604 : 0 : return check_fill_0x83_prespc3(dev_scsi, page_83, id_search_list,
605 : : serial, serial_short, len);
606 : :
607 : : /*
608 : : * Search for a match in the prioritized id_search_list - since WWN ids
609 : : * come first we can pick up the WWN in check_fill_0x83_id().
610 : : */
611 [ # # ]: 0 : for (id_ind = 0;
612 : : id_ind < sizeof(id_search_list)/sizeof(id_search_list[0]);
613 : 0 : id_ind++) {
614 : : /*
615 : : * Examine each descriptor returned. There is normally only
616 : : * one or a small number of descriptors.
617 : : */
618 [ # # ]: 0 : for (j = 4; j <= ((unsigned)page_83[2] << 8) + (unsigned)page_83[3] + 3; j += page_83[j + 3] + 4) {
619 : 0 : retval = check_fill_0x83_id(dev_scsi, page_83 + j,
620 : 0 : id_search_list + id_ind,
621 : : serial, serial_short, len,
622 : : wwn, wwn_vendor_extension,
623 : : tgpt_group);
624 [ # # ]: 0 : if (!retval)
625 : 0 : return retval;
626 [ # # ]: 0 : else if (retval < 0)
627 : 0 : return retval;
628 : : }
629 : : }
630 : 0 : return 1;
631 : : }
632 : :
633 : : /*
634 : : * Get device identification VPD page for older SCSI-2 device which is not
635 : : * compliant with either SPC-2 or SPC-3 format.
636 : : *
637 : : * Return the hard coded error code value 2 if the page 83 reply is not
638 : : * conformant to the SCSI-2 format.
639 : : */
640 : 0 : static int do_scsi_page83_prespc3_inquiry(struct scsi_id_device *dev_scsi, int fd,
641 : : char *serial, char *serial_short, int len) {
642 : : int retval;
643 : : int i, j;
644 : : unsigned char page_83[SCSI_INQ_BUFF_LEN];
645 : :
646 [ # # ]: 0 : memzero(page_83, SCSI_INQ_BUFF_LEN);
647 : 0 : retval = scsi_inquiry(dev_scsi, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN);
648 [ # # ]: 0 : if (retval < 0)
649 : 0 : return 1;
650 : :
651 [ # # ]: 0 : if (page_83[1] != PAGE_83) {
652 [ # # ]: 0 : log_debug("%s: Invalid page 0x83", dev_scsi->kernel);
653 : 0 : return 1;
654 : : }
655 : : /*
656 : : * Model 4, 5, and (some) model 6 EMC Symmetrix devices return
657 : : * a page 83 reply according to SCSI-2 format instead of SPC-2/3.
658 : : *
659 : : * The SCSI-2 page 83 format returns an IEEE WWN in binary
660 : : * encoded hexi-decimal in the 16 bytes following the initial
661 : : * 4-byte page 83 reply header.
662 : : *
663 : : * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part
664 : : * of an Identification descriptor. The 3rd byte of the first
665 : : * Identification descriptor is a reserved (BSZ) byte field.
666 : : *
667 : : * Reference the 7th byte of the page 83 reply to determine
668 : : * whether the reply is compliant with SCSI-2 or SPC-2/3
669 : : * specifications. A zero value in the 7th byte indicates
670 : : * an SPC-2/3 conformant reply, (i.e., the reserved field of the
671 : : * first Identification descriptor). This byte will be non-zero
672 : : * for a SCSI-2 conformant page 83 reply from these EMC
673 : : * Symmetrix models since the 7th byte of the reply corresponds
674 : : * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is,
675 : : * 0x006048.
676 : : */
677 [ # # ]: 0 : if (page_83[6] == 0)
678 : 0 : return 2;
679 : :
680 : 0 : serial[0] = hex_str[SCSI_ID_NAA];
681 : : /*
682 : : * The first four bytes contain data, not a descriptor.
683 : : */
684 : 0 : i = 4;
685 : 0 : j = strlen(serial);
686 : : /*
687 : : * Binary descriptor, convert to ASCII,
688 : : * using two bytes of ASCII for each byte
689 : : * in the page_83.
690 : : */
691 [ # # ]: 0 : while (i < (page_83[3]+4)) {
692 : 0 : serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4];
693 : 0 : serial[j++] = hex_str[page_83[i] & 0x0f];
694 : 0 : i++;
695 : : }
696 : 0 : return 0;
697 : : }
698 : :
699 : : /* Get unit serial number VPD page */
700 : 0 : static int do_scsi_page80_inquiry(struct scsi_id_device *dev_scsi, int fd,
701 : : char *serial, char *serial_short, int max_len) {
702 : : int retval;
703 : : int ser_ind;
704 : : int i;
705 : : int len;
706 : : unsigned char buf[SCSI_INQ_BUFF_LEN];
707 : :
708 [ # # ]: 0 : memzero(buf, SCSI_INQ_BUFF_LEN);
709 : 0 : retval = scsi_inquiry(dev_scsi, fd, 1, PAGE_80, buf, SCSI_INQ_BUFF_LEN);
710 [ # # ]: 0 : if (retval < 0)
711 : 0 : return retval;
712 : :
713 [ # # ]: 0 : if (buf[1] != PAGE_80) {
714 [ # # ]: 0 : log_debug("%s: Invalid page 0x80", dev_scsi->kernel);
715 : 0 : return 1;
716 : : }
717 : :
718 : 0 : len = 1 + VENDOR_LENGTH + MODEL_LENGTH + buf[3];
719 [ # # ]: 0 : if (max_len < len) {
720 [ # # ]: 0 : log_debug("%s: length %d too short - need %d",
721 : : dev_scsi->kernel, max_len, len);
722 : 0 : return 1;
723 : : }
724 : : /*
725 : : * Prepend 'S' to avoid unlikely collision with page 0x83 vendor
726 : : * specific type where we prepend '0' + vendor + model.
727 : : */
728 : 0 : len = buf[3];
729 [ # # ]: 0 : if (serial) {
730 : 0 : serial[0] = 'S';
731 : 0 : ser_ind = append_vendor_model(dev_scsi, serial + 1);
732 [ # # ]: 0 : if (ser_ind < 0)
733 : 0 : return 1;
734 : 0 : ser_ind++; /* for the leading 'S' */
735 [ # # ]: 0 : for (i = 4; i < len + 4; i++, ser_ind++)
736 : 0 : serial[ser_ind] = buf[i];
737 : : }
738 [ # # ]: 0 : if (serial_short) {
739 : 0 : memcpy(serial_short, buf + 4, len);
740 : 0 : serial_short[len] = '\0';
741 : : }
742 : 0 : return 0;
743 : : }
744 : :
745 : 0 : int scsi_std_inquiry(struct scsi_id_device *dev_scsi, const char *devname) {
746 : : int fd;
747 : : unsigned char buf[SCSI_INQ_BUFF_LEN];
748 : : struct stat statbuf;
749 : 0 : int err = 0;
750 : :
751 : 0 : fd = open(devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
752 [ # # ]: 0 : if (fd < 0) {
753 [ # # ]: 0 : log_debug_errno(errno, "scsi_id: cannot open %s: %m", devname);
754 : 0 : return 1;
755 : : }
756 : :
757 [ # # ]: 0 : if (fstat(fd, &statbuf) < 0) {
758 [ # # ]: 0 : log_debug_errno(errno, "scsi_id: cannot stat %s: %m", devname);
759 : 0 : err = 2;
760 : 0 : goto out;
761 : : }
762 : 0 : sprintf(dev_scsi->kernel,"%d:%d", major(statbuf.st_rdev),
763 : : minor(statbuf.st_rdev));
764 : :
765 [ # # ]: 0 : memzero(buf, SCSI_INQ_BUFF_LEN);
766 : 0 : err = scsi_inquiry(dev_scsi, fd, 0, 0, buf, SCSI_INQ_BUFF_LEN);
767 [ # # ]: 0 : if (err < 0)
768 : 0 : goto out;
769 : :
770 : 0 : err = 0;
771 : 0 : memcpy(dev_scsi->vendor, buf + 8, 8);
772 : 0 : dev_scsi->vendor[8] = '\0';
773 : 0 : memcpy(dev_scsi->model, buf + 16, 16);
774 : 0 : dev_scsi->model[16] = '\0';
775 : 0 : memcpy(dev_scsi->revision, buf + 32, 4);
776 : 0 : dev_scsi->revision[4] = '\0';
777 : 0 : sprintf(dev_scsi->type,"%x", buf[0] & 0x1f);
778 : :
779 : 0 : out:
780 : 0 : close(fd);
781 : 0 : return err;
782 : : }
783 : :
784 : 0 : int scsi_get_serial(struct scsi_id_device *dev_scsi, const char *devname,
785 : : int page_code, int len) {
786 : : unsigned char page0[SCSI_INQ_BUFF_LEN];
787 : 0 : int fd = -1;
788 : : int cnt;
789 : : int ind;
790 : : int retval;
791 : :
792 [ # # ]: 0 : memzero(dev_scsi->serial, len);
793 : 0 : initialize_srand();
794 [ # # ]: 0 : for (cnt = 20; cnt > 0; cnt--) {
795 : : struct timespec duration;
796 : :
797 : 0 : fd = open(devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
798 [ # # # # ]: 0 : if (fd >= 0 || errno != EBUSY)
799 : : break;
800 : 0 : duration.tv_sec = 0;
801 : 0 : duration.tv_nsec = (200 * 1000 * 1000) + (rand() % 100 * 1000 * 1000);
802 : 0 : nanosleep(&duration, NULL);
803 : : }
804 [ # # ]: 0 : if (fd < 0)
805 : 0 : return 1;
806 : :
807 [ # # ]: 0 : if (page_code == PAGE_80) {
808 [ # # ]: 0 : if (do_scsi_page80_inquiry(dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len)) {
809 : 0 : retval = 1;
810 : 0 : goto completed;
811 : : } else {
812 : 0 : retval = 0;
813 : 0 : goto completed;
814 : : }
815 [ # # ]: 0 : } else if (page_code == PAGE_83) {
816 [ # # ]: 0 : if (do_scsi_page83_inquiry(dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) {
817 : 0 : retval = 1;
818 : 0 : goto completed;
819 : : } else {
820 : 0 : retval = 0;
821 : 0 : goto completed;
822 : : }
823 [ # # ]: 0 : } else if (page_code == PAGE_83_PRE_SPC3) {
824 : 0 : retval = do_scsi_page83_prespc3_inquiry(dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len);
825 [ # # ]: 0 : if (retval) {
826 : : /*
827 : : * Fallback to servicing a SPC-2/3 compliant page 83
828 : : * inquiry if the page 83 reply format does not
829 : : * conform to pre-SPC3 expectations.
830 : : */
831 [ # # ]: 0 : if (retval == 2) {
832 [ # # ]: 0 : if (do_scsi_page83_inquiry(dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) {
833 : 0 : retval = 1;
834 : 0 : goto completed;
835 : : } else {
836 : 0 : retval = 0;
837 : 0 : goto completed;
838 : : }
839 : : }
840 : : else {
841 : 0 : retval = 1;
842 : 0 : goto completed;
843 : : }
844 : : } else {
845 : 0 : retval = 0;
846 : 0 : goto completed;
847 : : }
848 [ # # ]: 0 : } else if (page_code != 0x00) {
849 [ # # ]: 0 : log_debug("%s: unsupported page code 0x%d", dev_scsi->kernel, page_code);
850 : 0 : retval = 1;
851 : 0 : goto completed;
852 : : }
853 : :
854 : : /*
855 : : * Get page 0, the page of the pages. By default, try from best to
856 : : * worst of supported pages: 0x83 then 0x80.
857 : : */
858 [ # # ]: 0 : if (do_scsi_page0_inquiry(dev_scsi, fd, page0, SCSI_INQ_BUFF_LEN)) {
859 : : /*
860 : : * Don't try anything else. Black list if a specific page
861 : : * should be used for this vendor+model, or maybe have an
862 : : * optional fall-back to page 0x80 or page 0x83.
863 : : */
864 : 0 : retval = 1;
865 : 0 : goto completed;
866 : : }
867 : :
868 [ # # ]: 0 : for (ind = 4; ind <= page0[3] + 3; ind++)
869 [ # # ]: 0 : if (page0[ind] == PAGE_83)
870 [ # # ]: 0 : if (!do_scsi_page83_inquiry(dev_scsi, fd,
871 : 0 : dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) {
872 : : /*
873 : : * Success
874 : : */
875 : 0 : retval = 0;
876 : 0 : goto completed;
877 : : }
878 : :
879 [ # # ]: 0 : for (ind = 4; ind <= page0[3] + 3; ind++)
880 [ # # ]: 0 : if (page0[ind] == PAGE_80)
881 [ # # ]: 0 : if (!do_scsi_page80_inquiry(dev_scsi, fd,
882 : 0 : dev_scsi->serial, dev_scsi->serial_short, len)) {
883 : : /*
884 : : * Success
885 : : */
886 : 0 : retval = 0;
887 : 0 : goto completed;
888 : : }
889 : 0 : retval = 1;
890 : :
891 : 0 : completed:
892 : 0 : close(fd);
893 : 0 : return retval;
894 : : }
|