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