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