xref: /titanic_52/usr/src/common/devid/devid_scsi.c (revision 59d2da88ef75ee90d89de8d98edf0521bea61f8d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * These functions are used to encode SCSI INQUIRY data into
29  * Solaris devid / guid values.
30  */
31 
32 #include <sys/types.h>
33 #include <sys/stropts.h>
34 #include <sys/debug.h>
35 #include <sys/isa_defs.h>
36 #include <sys/dditypes.h>
37 #include <sys/ddi_impldefs.h>
38 #include <sys/scsi/scsi.h>
39 #include "devid_impl.h"
40 
41 #define	SCSI_INQUIRY_VID_POS			9
42 #define	SCSI_INQUIRY_VID_SUN			"SUN"
43 #define	SCSI_INQUIRY_VID_SUN_LEN		3
44 #define	SCSI_INQUIRY_VID_HITACHI		"HITACHI"
45 #define	SCSI_INQUIRY_VID_HITACHI_LEN		7
46 #define	SCSI_INQUIRY_PID_HITACHI_OPEN		"OPEN-"
47 #define	SCSI_INQUIRY_PID_HITACHI_OPEN_LEN	5
48 #define	SCSI_INQUIRY_VID_EMC			"EMC     "
49 #define	SCSI_INQUIRY_VID_EMC_LEN		8
50 #define	SCSI_INQUIRY_PID_EMC_SYMMETRIX		"SYMMETRIX       "
51 #define	SCSI_INQUIRY_PID_EMC_SYMMETRIX_LEN	16
52 
53 #define	MSG_NOT_STANDARDS_COMPLIANT "!Page83 data not standards compliant "
54 #define	MSG_NOT_STANDARDS_COMPLIANT_SIZE	( \
55 	sizeof (MSG_NOT_STANDARDS_COMPLIANT) + \
56 	sizeof (((struct scsi_inquiry *)NULL)->inq_vid) + \
57 	sizeof (((struct scsi_inquiry *)NULL)->inq_pid) + \
58 	sizeof (((struct scsi_inquiry *)NULL)->inq_revision) + 4)
59 
60 #define	IS_DEVID_GUID_TYPE(type) ((type == DEVID_SCSI3_WWN)	|| \
61 				(IS_DEVID_SCSI3_VPD_TYPE(type)))
62 
63 #define	IS_DEVID_SCSI_TYPE(type) ((IS_DEVID_GUID_TYPE(type)) || \
64 				(type == DEVID_SCSI_SERIAL))
65 
66 /*
67  * The max inquiry page 83 size as expected in the code today
68  * is 0xf0 bytes. Defining a constant to make it easy incase
69  * this needs to be changed at a later time.
70  */
71 
72 #define	SCMD_MAX_INQUIRY_PAGE83_SIZE			0xFF
73 #define	SCMD_MIN_INQUIRY_PAGE83_SIZE			0x08
74 #define	SCMD_INQUIRY_PAGE83_HDR_SIZE			4
75 #define	SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN	16
76 
77 #define	SCMD_MAX_INQUIRY_PAGE80_SIZE	0xFF
78 #define	SCMD_MIN_INQUIRY_PAGE80_SIZE	0x04
79 
80 #define	SCMD_MIN_STANDARD_INQUIRY_SIZE	0x04
81 
82 #define	SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE		4
83 
84 #define	SCMD_INQUIRY_VPD_TYPE_T10	0x01
85 #define	SCMD_INQUIRY_VPD_TYPE_EUI	0x02
86 #define	SCMD_INQUIRY_VPD_TYPE_NAA	0x03
87 #define	SCMD_INQUIRY_VPD_TYPE_RTP	0x04
88 #define	SCMD_INQUIRY_VPD_TYPE_TPG	0x05
89 #define	SCMD_INQUIRY_VPD_TYPE_LUG	0x06
90 #define	SCMD_INQUIRY_VPD_TYPE_MD5	0x07
91 #define	SCMD_INQUIRY_VPD_TYPE_SSN	0x08
92 
93 static int is_page83_data_valid(uchar_t *inq83, size_t inq83_len);
94 static int is_page80_data_valid(uchar_t *inq80, size_t inq80_len);
95 static int is_initialized_id(uchar_t *id, size_t id_len);
96 
97 static void encode_scsi3_page83(int version, uchar_t *inq83,
98     size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
99 static void encode_scsi3_page83_emc(int version, uchar_t *inq83,
100     size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
101 static void encode_serialnum(int version, uchar_t *inq, uchar_t *inq80,
102     size_t inq80_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
103 static void encode_sun_serialnum(int version, uchar_t *inq,
104     size_t inq_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
105 
106 static int devid_scsi_init(char *driver_name,
107     uchar_t *raw_id, size_t raw_id_len, ushort_t raw_id_type,
108     ddi_devid_t *ret_devid);
109 
110 static char ctoi(char c);
111 
112 /*
113  *    Function: ddi_/devid_scsi_encode
114  *
115  * Description: This routine finds and encodes a unique devid
116  *
117  *   Arguments: version - id encode algorithm version
118  *		driver_name - binding driver name (if ! known use NULL)
119  *		inq - standard inquiry buffer
120  *		inq_len - standard inquiry buffer length
121  *		inq80 - serial number inquiry buffer
122  *		inq80_len - serial number inquiry buffer length
123  *		inq83 - vpd inquiry buffer
124  *		inq83_len - vpd inquiry buffer length
125  *		devid - id returned
126  *
127  * Return Code: DEVID_SUCCESS - success
128  *		DEVID_FAILURE - failure
129  *		DEVID_RETRY - LUN is in a transitional state.  A delay should
130  *		occur and then this inquiry data should be re-acquired and
131  *		this function should be called again.
132  */
133 int
134 #ifdef _KERNEL
135 ddi_devid_scsi_encode(
136 #else /* ! _KERNEL */
137 devid_scsi_encode(
138 #endif /* _KERNEL */
139     int version,	/* IN */
140     char *driver_name,	/* IN */
141     uchar_t *inq,	/* IN */
142     size_t inq_len,	/* IN */
143     uchar_t *inq80,	/* IN */
144     size_t inq80_len,	/* IN */
145     uchar_t *inq83,	/* IN */
146     size_t inq83_len,	/* IN */
147     ddi_devid_t *devid)	/* OUT */
148 {
149 	int			rval		= DEVID_FAILURE;
150 	uchar_t			*id		= NULL;
151 	size_t			id_len		= 0;
152 	ushort_t		id_type		= DEVID_NONE;
153 	struct scsi_inquiry	*inq_std	= (struct scsi_inquiry *)inq;
154 #ifdef	_KERNEL
155 	char			*msg		= NULL;
156 #endif	/* _KERNEL */
157 
158 	DEVID_ASSERT(devid != NULL);
159 
160 	/* verify valid version */
161 	if (version > DEVID_SCSI_ENCODE_VERSION_LATEST) {
162 		return (rval);
163 	}
164 
165 	/* make sure minimum inquiry bytes are available */
166 	if (inq_len < SCMD_MIN_STANDARD_INQUIRY_SIZE) {
167 		return (rval);
168 	}
169 
170 	/*
171 	 * If 0x83 is availible, that is the best choice.  Our next choice is
172 	 * 0x80.  If neither are availible, we leave it to the caller to
173 	 * determine possible alternate ID, although discouraged.  In the
174 	 * case of the target drivers they create a fabricated id which is
175 	 * stored in the acyl.  The HBA drivers should avoid using an
176 	 * alternate id.  Although has already created a hack of using the
177 	 * node wwn in some cases.  Which needs to be carried forward for
178 	 * legacy reasons.
179 	 */
180 	if (inq83 != NULL) {
181 		/*
182 		 * Perform page 83 validation tests and report offenders.
183 		 * We cannot enforce the page 83 specification because
184 		 * many Sun partners (ex. HDS) do not conform to the
185 		 * standards yet.
186 		 */
187 		if (is_page83_data_valid(inq83, inq83_len) ==
188 		    DEVID_RET_INVALID) {
189 			/*
190 			 * invalid page 83 data.  bug 4939576 introduced
191 			 * handling for EMC non-standard data.
192 			 */
193 			if ((bcmp(inq_std->inq_vid, SCSI_INQUIRY_VID_EMC,
194 			    SCSI_INQUIRY_VID_EMC_LEN) == 0) &&
195 			    (bcmp(inq_std->inq_pid,
196 			    SCSI_INQUIRY_PID_EMC_SYMMETRIX,
197 			    SCSI_INQUIRY_PID_EMC_SYMMETRIX_LEN) == 0)) {
198 				encode_scsi3_page83_emc(version, inq83,
199 				    inq83_len, &id, &id_len, &id_type);
200 			}
201 #ifdef	_KERNEL
202 			/*
203 			 * invalid page 83 data. Special hack for HDS
204 			 * specific device, to suppress the warning msg.
205 			 */
206 			if ((bcmp(inq_std->inq_vid, SCSI_INQUIRY_VID_HITACHI,
207 			    SCSI_INQUIRY_VID_HITACHI_LEN) != 0) ||
208 			    (bcmp(inq_std->inq_pid,
209 			    SCSI_INQUIRY_PID_HITACHI_OPEN,
210 			    SCSI_INQUIRY_PID_HITACHI_OPEN_LEN) != 0)) {
211 				/*
212 				 * report the page 0x83 standards violation.
213 				 */
214 				msg = kmem_alloc(
215 				    MSG_NOT_STANDARDS_COMPLIANT_SIZE,
216 				    KM_SLEEP);
217 				(void) strcpy(msg, MSG_NOT_STANDARDS_COMPLIANT);
218 				(void) strncat(msg, inq_std->inq_vid,
219 				    sizeof (inq_std->inq_vid));
220 				(void) strcat(msg, " ");
221 				(void) strncat(msg, inq_std->inq_pid,
222 				    sizeof (inq_std->inq_pid));
223 				(void) strcat(msg, " ");
224 				(void) strncat(msg, inq_std->inq_revision,
225 				    sizeof (inq_std->inq_revision));
226 				(void) strcat(msg, "\n");
227 				cmn_err(CE_WARN, msg);
228 				kmem_free(msg,
229 				    MSG_NOT_STANDARDS_COMPLIANT_SIZE);
230 			}
231 #endif	/* _KERNEL */
232 		}
233 
234 		if (id_type == DEVID_NONE) {
235 			encode_scsi3_page83(version, inq83,
236 			    inq83_len, &id, &id_len, &id_type);
237 		}
238 	}
239 
240 	/*
241 	 * If no vpd page is available at this point then we
242 	 * attempt to use a SCSI serial number from page 0x80.
243 	 */
244 	if ((id_type == DEVID_NONE) &&
245 	    (inq != NULL) &&
246 	    (inq80 != NULL)) {
247 		if (is_page80_data_valid(inq80, inq80_len) == DEVID_RET_VALID) {
248 			encode_serialnum(version, inq, inq80,
249 			    inq80_len, &id, &id_len, &id_type);
250 		}
251 	}
252 
253 	/*
254 	 * If no vpd page  or serial is available at this point and
255 	 * it's a SUN disk it conforms to the disk qual. 850 specifications
256 	 * and we can fabricate a serial number id based on the standard
257 	 * inquiry page.
258 	 */
259 	if ((id_type == DEVID_NONE) &&
260 	    (inq != NULL)) {
261 		encode_sun_serialnum(version, inq, inq_len,
262 		    &id, &id_len, &id_type);
263 	}
264 
265 	if (id_type != DEVID_NONE) {
266 		if (is_initialized_id(id, id_len) == DEVID_RET_VALID) {
267 			rval = devid_scsi_init(driver_name,
268 			    id, id_len, id_type, devid);
269 		} else {
270 			rval = DEVID_RETRY;
271 		}
272 		DEVID_FREE(id, id_len);
273 	}
274 
275 	return (rval);
276 }
277 
278 
279 /*
280  *    Function: is_page83_data_valid
281  *
282  * Description: This routine is used to validate the page 0x83 data
283  *		passed in valid based on the standards specification.
284  *
285  *   Arguments: inq83 -
286  *		inq83_len -
287  *
288  * Return Code: DEVID_RET_VALID
289  *              DEVID_RET_INVALID
290  *
291  */
292 static int
293 is_page83_data_valid(uchar_t *inq83, size_t inq83_len)
294 {
295 
296 	int 	covered_desc_len	= 0;
297 	int	dlen			= 0;
298 	uchar_t	*dblk			= NULL;
299 
300 	DEVID_ASSERT(inq83 != NULL);
301 
302 	/* if not large enough fail */
303 	if (inq83_len < SCMD_MIN_INQUIRY_PAGE83_SIZE)
304 		return (DEVID_RET_INVALID);
305 
306 	/*
307 	 * Ensuring that the Peripheral device type(bits 0 - 4) has
308 	 * the valid settings - the value 0x1f indicates no device type.
309 	 * Only this value can be validated since all other fields are
310 	 * either used or reserved.
311 	 */
312 	if ((inq83[0] & DTYPE_MASK) == DTYPE_UNKNOWN) {
313 		/* failed-peripheral devtype */
314 		return (DEVID_RET_INVALID);
315 	}
316 
317 	/*
318 	 * Ensure that the page length field - third and 4th bytes
319 	 * contain a non zero length value. Our implementation
320 	 * does not seem to expect more that 255 bytes of data...
321 	 * what is to be done if the reported size is > 255 bytes?
322 	 * Yes the device will return only 255 bytes as we provide
323 	 * buffer to house only that much data but the standards
324 	 * prevent the targets from reporting the truncated size
325 	 * in this field.
326 	 *
327 	 * Currently reporting sizes more than 255 as failure.
328 	 *
329 	 */
330 
331 	if ((inq83[2] == 0) && (inq83[3] == 0)) {
332 		/* length field is 0! */
333 		return (DEVID_RET_INVALID);
334 	}
335 	if (inq83[3] > (SCMD_MAX_INQUIRY_PAGE83_SIZE - 3)) {
336 		/* length field exceeds expected size of 255 bytes */
337 		return (DEVID_RET_INVALID);
338 	}
339 
340 	/*
341 	 * Validation of individual descriptor blocks are done in the
342 	 * following while loop. It is possible to have multiple
343 	 * descriptor blocks.
344 	 * the 'dblk' pointer will be pointing to the start of
345 	 * each entry of the descriptor block.
346 	 */
347 	covered_desc_len = 0;
348 	dblk = &inq83[4]; /* start of first decriptor blk */
349 	while (covered_desc_len < inq83[3]) {
350 
351 		/*
352 		 * Ensure that the length field is non zero
353 		 * Further length validations will be done
354 		 * along with the 'identifier type' as some of
355 		 * the lengths are dependent on it.
356 		 */
357 		dlen = dblk[3];
358 		if (dlen == 0) {
359 			/* descr length is 0 */
360 			return (DEVID_RET_INVALID);
361 		}
362 
363 		/*
364 		 * ensure that the size of the descriptor block does
365 		 * not claim to be larger than the entire page83
366 		 * data that has been received.
367 		 */
368 		if ((covered_desc_len + dlen) > inq83[3]) {
369 			/* failed-descr length */
370 			return (DEVID_RET_INVALID);
371 		}
372 
373 		/*
374 		 * The spec says that if the PIV field is 0 OR the
375 		 * association field contains value other than 1 and 2,
376 		 * then the protocol identifier field should be ignored.
377 		 * If association field contains a value of 1 or 2
378 		 * and the PIV field is set, then the protocol identifier
379 		 * field has to be validated.
380 		 * The protocol identifier values 0 - f are either assigned
381 		 * or reserved. Nothing to validate here, hence skipping
382 		 * over to the next check.
383 		 */
384 
385 		/*
386 		 * Check for valid code set values.
387 		 * All possible values are reserved or assigned. Nothing
388 		 * to validate - skipping over.
389 		 */
390 
391 		/*
392 		 * Identifier Type validation
393 		 * All SPC3rev22 identified types and the expected lengths
394 		 * are validated.
395 		 */
396 		switch (dblk[1] & 0x0f) {
397 		case SCMD_INQUIRY_VPD_TYPE_T10: /* T10 vendor Id */
398 			/* No specific length validation required */
399 			break;
400 
401 		case SCMD_INQUIRY_VPD_TYPE_EUI: /* EUI 64 ID */
402 			/* EUI-64: size is expected to be 8, 12, or 16 bytes */
403 			if ((dlen != 8) && (dlen != 12) && (dlen != 16)) {
404 				/* page83 validation failed-EIU64 */
405 				return (DEVID_RET_INVALID);
406 			}
407 			break;
408 
409 		case SCMD_INQUIRY_VPD_TYPE_NAA: /* NAA Id type */
410 
411 			/*
412 			 * the size for this varies -
413 			 * IEEE extended/registered is 8 bytes
414 			 * IEEE Registered extended is 16 bytes
415 			 */
416 			switch (dblk[4] & 0xf0) {
417 
418 				case 0x20: /* IEEE Ext */
419 				case 0x50: /* IEEE Reg */
420 					if (dlen != 8) {
421 						/* failed-IEE E/R len */
422 						return (DEVID_RET_INVALID);
423 					}
424 					/*
425 					 * the codeSet for this MUST
426 					 * be set to 1
427 					 */
428 					if ((dblk[0] & 0x0f) != 1) {
429 						/*
430 						 * failed-IEEE E/R
431 						 * codeSet != 1.
432 						 */
433 						return (DEVID_RET_INVALID);
434 					}
435 				break;
436 
437 				case 0x60: /* IEEE EXT REG */
438 					if (dlen != 16) {
439 						/* failed-IEEE ER len */
440 						return (DEVID_RET_INVALID);
441 					}
442 					/*
443 					 * the codeSet for this MUST
444 					 * be set to 1
445 					 */
446 					if ((dblk[0] & 0x0f) != 1) {
447 						/*
448 						 * failed-IEEE ER
449 						 * codeSet != 1.
450 						 */
451 						return (DEVID_RET_INVALID);
452 						}
453 				break;
454 
455 				default:
456 					/* reserved values */
457 					break;
458 			}
459 			break;
460 
461 		case SCMD_INQUIRY_VPD_TYPE_RTP: /* Relative Target port */
462 			if (dlen != 4) {
463 				/* failed-Rel target Port length */
464 				return (DEVID_RET_INVALID);
465 			}
466 			break;
467 
468 		case SCMD_INQUIRY_VPD_TYPE_TPG: /* Target port group */
469 			if (dlen != 4) {
470 				/* failed-target Port group length */
471 				return (DEVID_RET_INVALID);
472 			}
473 			break;
474 
475 		case SCMD_INQUIRY_VPD_TYPE_LUG: /* Logical unit group */
476 			if (dlen != 4) {
477 				/* failed-Logical Unit group length */
478 				return (DEVID_RET_INVALID);
479 			}
480 			break;
481 
482 		case SCMD_INQUIRY_VPD_TYPE_MD5: /* MD5 unit group */
483 			if (dlen != 16) {
484 				/* failed-MD5 Unit grp */
485 				return (DEVID_RET_INVALID);
486 			}
487 			break;
488 
489 		default:
490 			break;
491 		}
492 
493 		/*
494 		 * Now lets advance to the next descriptor block
495 		 * and validate it.
496 		 * the descriptor block size is <descr Header> + <descr Data>
497 		 * <descr Header> is equal to 4 bytes
498 		 * <descr Data> is available in dlen or dblk[3].
499 		 */
500 		dblk = &dblk[4 + dlen];
501 
502 		/*
503 		 * update the covered_desc_len so that we can ensure that
504 		 * the 'while' loop terminates.
505 		 */
506 		covered_desc_len += (dlen + 4);
507 	}
508 	return (DEVID_RET_VALID);
509 }
510 
511 
512 /*
513  *    Function: is_initialized_id
514  *
515  * Description: Routine to ensure that the ID calculated is not a
516  *		space or zero filled ID. Returning a space / zero
517  *		filled ID when the luns on the target are not fully
518  *		initialized is a valid response from the target as
519  *		per the T10 spec. When a space/zero filled ID is
520  *		found its information needs to be polled again
521  *		after sometime time to see if the luns are fully
522  *		initialized to return a valid guid information.
523  *
524  *   Arguments: id - raw id
525  *              id_len - raw id len
526  *
527  * Return Code:	DEVID_VALID - indicates a non space/zero filled id
528  *		DEVID_INVALID - indicates id contains uninitialized data
529  *		and suggests retry of the collection commands.
530  */
531 static int
532 is_initialized_id(uchar_t *id, size_t id_len)
533 {
534 	int idx;
535 
536 	if ((id == NULL) ||
537 	    (id_len == 0)) {
538 		/* got id length as 0 fetch info again */
539 		return (DEVID_RET_INVALID);
540 	}
541 
542 	/* First lets check if the guid is filled with spaces */
543 	for (idx = 0; idx < id_len; idx++) {
544 		if (id[idx] != ' ') {
545 			break;
546 		}
547 	}
548 
549 	/*
550 	 * Lets exit if we find that it contains ALL spaces
551 	 * saying that it has an uninitialized guid
552 	 */
553 	if (idx >= id_len) {
554 		/* guid filled with spaces found */
555 		return (DEVID_RET_INVALID);
556 	}
557 
558 	/*
559 	 * Since we have found that it is not filled with spaces
560 	 * now lets ensure that the guid is not filled with only
561 	 * zeros.
562 	 */
563 	for (idx = 0; idx < id_len; idx ++) {
564 		if (id[idx] != 0) {
565 			return (DEVID_RET_VALID);
566 		}
567 	}
568 
569 	/* guid filled with zeros found */
570 	return (DEVID_RET_INVALID);
571 }
572 
573 
574 /*
575  *    Function: is_page80_data_valid
576  *
577  * Description: This routine is used to validate the page 0x80 data
578  *		passed in valid based on the standards specification.
579  *
580  *   Arguments: inq80 -
581  *		inq80_len -
582  *
583  * Return Code: DEVID_RET_VALID
584  *              DEVID_RET_INVALID
585  *
586  */
587 /* ARGSUSED */
588 static int
589 is_page80_data_valid(uchar_t *inq80, size_t inq80_len)
590 {
591 	DEVID_ASSERT(inq80);
592 
593 	/* if not large enough fail */
594 	if (inq80_len < SCMD_MIN_INQUIRY_PAGE80_SIZE) {
595 		return (DEVID_RET_INVALID);
596 	}
597 
598 	/*
599 	 * (inq80_len - 4) is the size of the buffer space available
600 	 * for the product serial number.  So inq80[3] (ie. product
601 	 * serial number) should be <= (inq80_len -4).
602 	 */
603 	if (inq80[3] > (inq80_len - 4)) {
604 		return (DEVID_RET_INVALID);
605 	}
606 
607 	return (DEVID_RET_VALID);
608 }
609 
610 
611 /*
612  *    Function: encode_devid_page
613  *
614  * Description: This routine finds the unique devid if available and
615  *		fills the devid and length parameters.
616  *
617  *   Arguments: version - encode version
618  *		inq83 - driver soft state (unit) structure
619  *		inq83_len - length of raw inq83 data
620  *		id - raw id
621  *		id_len - len of raw id
622  *		id_type - type of id
623  *
624  *        Note: DEVID_NONE is returned in the id_type field
625  *		if no supported page 83 id is found.
626  */
627 static void
628 encode_scsi3_page83(int version, uchar_t *inq83, size_t inq83_len,
629     uchar_t **id, size_t *id_len, ushort_t *id_type)
630 {
631 	size_t	descriptor_bytes_left   = 0;
632 	size_t	offset			= 0;
633 	int	idx			= 0;
634 	size_t	offset_id_type[4];
635 
636 	DEVID_ASSERT(inq83 != NULL);
637 	/* inq83 length was already validate in is_page83_valid */
638 	DEVID_ASSERT(id != NULL);
639 	DEVID_ASSERT(id_len != NULL);
640 	DEVID_ASSERT(id_type != NULL);
641 
642 	/* preset defaults */
643 	*id = NULL;
644 	*id_len = 0;
645 	*id_type = DEVID_NONE;
646 
647 	/* verify we have enough memory for a ident header */
648 	if (inq83_len < SCMD_INQUIRY_PAGE83_HDR_SIZE) {
649 		return;
650 	}
651 
652 	/*
653 	 * Attempt to validate the page data.  Once validated, we'll walk
654 	 * the descriptors, looking for certain identifier types that will
655 	 * mark this device with a unique id/wwn.  Note the comment below
656 	 * for what we really want to receive.
657 	 */
658 
659 	/*
660 	 * The format of the inq83 data (Device Identification VPD page) is
661 	 * a header (containing the total length of the page, from which
662 	 * descriptor_bytes_left is calculated), followed by a list of
663 	 * identification descriptors. Each identifcation descriptor has a
664 	 * header which includes the length of the individual identification
665 	 * descriptor).
666 	 *
667 	 * Set the offset to the beginning byte of the first identification
668 	 * descriptor.  We'll index everything from there.
669 	 */
670 	offset = SCMD_INQUIRY_PAGE83_HDR_SIZE;
671 	descriptor_bytes_left = (size_t)((inq83[2] << 8) | inq83[3]);
672 
673 	/*
674 	 * If the raw data states that the data is larger
675 	 * than what is actually received abort encode.
676 	 * Otherwise we will run off into unknown memory
677 	 * on the decode.
678 	 */
679 	if ((descriptor_bytes_left + offset) > inq83_len) {
680 		return;
681 	}
682 
683 
684 	/* Zero out our offset array */
685 	bzero(offset_id_type, sizeof (offset_id_type));
686 
687 	/*
688 	 * According to the scsi spec 8.4.3 SPC-2, there could be several
689 	 * descriptors associated with each lun.  Some we care about and some
690 	 * we don't.  This loop is set up to iterate through the descriptors.
691 	 * We want the 0x03 case which represents an FC-PH, FC-PH3 or FC-FS
692 	 * Name_Identifier.  The spec mentions nothing about ordering, so we
693 	 * don't assume any.
694 	 *
695 	 * We need to check if we've finished walking the list of descriptors,
696 	 * we also perform additional checks to be sure the newly calculated
697 	 * offset is within the bounds of the buffer, and the identifier length
698 	 * (as calculated by the length field in the header) is valid. This is
699 	 * done to protect against devices which return bad page83 data.
700 	 */
701 	while ((descriptor_bytes_left > 0) && (offset_id_type[3] == 0) &&
702 	    (offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE <= inq83_len) &&
703 	    (offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE +
704 	    (size_t)inq83[offset + 3] <= inq83_len)) {
705 		/*
706 		 * Inspect the Identification descriptor list. Store the
707 		 * offsets in the devid page separately for 0x03, 0x01 and
708 		 * 0x02.  Identifiers 0x00 and 0x04 are not useful as they
709 		 * don't represent unique identifiers for a lun.  We also
710 		 * check the association by masking with 0x3f because we want
711 		 * an association of 0x0 - indicating the identifier field is
712 		 * associated with the addressed physical or logical device
713 		 * and not the port.
714 		 */
715 		switch ((inq83[offset + 1] & 0x3f)) {
716 		case SCMD_INQUIRY_VPD_TYPE_T10:
717 			offset_id_type[SCMD_INQUIRY_VPD_TYPE_T10] = offset;
718 			break;
719 		case SCMD_INQUIRY_VPD_TYPE_EUI:
720 			offset_id_type[SCMD_INQUIRY_VPD_TYPE_EUI] = offset;
721 			break;
722 		case SCMD_INQUIRY_VPD_TYPE_NAA:
723 			offset_id_type[SCMD_INQUIRY_VPD_TYPE_NAA] = offset;
724 			break;
725 		default:
726 			/* Devid page undesired id type */
727 			break;
728 		}
729 		/*
730 		 * Calculate the descriptor bytes left and move to
731 		 * the beginning byte of the next id descriptor.
732 		 */
733 		descriptor_bytes_left -= (size_t)(inq83[offset + 3] +
734 		    SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE);
735 		offset += (SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE +
736 		    (size_t)inq83[offset + 3]);
737 	}
738 
739 	offset = 0;
740 
741 	/*
742 	 * We can't depend on an order from a device by identifier type, but
743 	 * once we have them, we'll walk them in the same order to prevent a
744 	 * firmware upgrade from breaking our algorithm.  Start with the one
745 	 * we want the most: id_offset_type[3].
746 	 */
747 	for (idx = 3; idx > 0; idx--) {
748 		if (offset_id_type[idx] > 0) {
749 			offset = offset_id_type[idx];
750 			break;
751 		}
752 	}
753 
754 	/*
755 	 * We have a valid Device ID page, set the length of the
756 	 * identifier and copy the value into the wwn.
757 	 */
758 	if (offset > 0) {
759 		*id_len = (size_t)inq83[offset + 3];
760 		if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
761 			*id_len = 0;
762 			return;
763 		}
764 		bcopy(&inq83[offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE],
765 		    *id, *id_len);
766 
767 		/* set devid type */
768 		switch (version) {
769 		/* In version 1 all page 83 types were grouped */
770 		case DEVID_SCSI_ENCODE_VERSION1:
771 			*id_type = DEVID_SCSI3_WWN;
772 			break;
773 		/* In version 2 we break page 83 apart to be unique */
774 		case DEVID_SCSI_ENCODE_VERSION2:
775 			switch (idx) {
776 			case 3:
777 				*id_type = DEVID_SCSI3_VPD_NAA;
778 				break;
779 			case 2:
780 				*id_type = DEVID_SCSI3_VPD_EUI;
781 				break;
782 			case 1:
783 				*id_type = DEVID_SCSI3_VPD_T10;
784 				break;
785 			default:
786 				DEVID_FREE(*id, *id_len);
787 				*id_len = 0;
788 				break;
789 			}
790 			break;
791 		default:
792 			DEVID_FREE(*id, *id_len);
793 			*id_len = 0;
794 			break;
795 		}
796 	}
797 }
798 
799 
800 /*
801  *    Function: encode_scsi3_page83_emc
802  *
803  * Description: Routine to handle proprietary page 83 of EMC Symmetrix
804  *              device. Called by ssfcp_handle_page83()
805  *
806  *   Arguments: version - encode version
807  *		inq83 - scsi page 83 buffer
808  *		inq83_len - scsi page 83 buffer size
809  *		id - raw emc id
810  *		id_len - len of raw emc id
811  *		id_type - type of emc id
812  */
813 static void
814 encode_scsi3_page83_emc(int version, uchar_t *inq83,
815     size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type)
816 {
817 	uchar_t	*guidp	= NULL;
818 
819 	DEVID_ASSERT(inq83 != NULL);
820 	DEVID_ASSERT(id != NULL);
821 	DEVID_ASSERT(id_len != NULL);
822 	DEVID_ASSERT(id_type != NULL);
823 
824 	/* preset defaults */
825 	*id = NULL;
826 	*id_len = 0;
827 	*id_type = DEVID_NONE;
828 
829 	/* The initial devid algorithm didn't use EMC page 83 data */
830 	if (version == DEVID_SCSI_ENCODE_VERSION1) {
831 		return;
832 	}
833 
834 	/* EMC page 83 requires atleast 20 bytes */
835 	if (inq83_len < (SCMD_INQUIRY_PAGE83_HDR_SIZE +
836 	    SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN)) {
837 		return;
838 	}
839 
840 	/*
841 	 * The 4th byte in the page 83 info returned is most likely
842 	 * indicating the length of the id - which 0x10(16 bytes)
843 	 * and the 5th byte is indicating that the id is of
844 	 * IEEE Registered Extended Name format(6). Validate
845 	 * these code prints before proceeding further as the
846 	 * following proprietary approach is tied to the specific
847 	 * device type and incase the EMC firmware changes, we will
848 	 * have to validate for the changed device before we start
849 	 * supporting such a device.
850 	 */
851 	if ((inq83[3] != 0x10) || (inq83[4] != 0x60)) {
852 		/* unsupported emc symtx device type */
853 		return;
854 	} else {
855 		guidp = &inq83[SCMD_INQUIRY_PAGE83_HDR_SIZE];
856 		/*
857 		 * The GUID returned by the EMC device is
858 		 * in the IEEE Registered Extended Name format(6)
859 		 * as a result it is of 16 bytes in length.
860 		 * An IEEE Registered Name format(5) will be of
861 		 * 8 bytes which is NOT what is being returned
862 		 * by the device type for which we are providing
863 		 * the support.
864 		 */
865 		*id_len = SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN;
866 		if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
867 			*id_len = 0;
868 			return;
869 		}
870 		bcopy(guidp, *id, *id_len);
871 
872 		/* emc id matches type 3 */
873 		*id_type = DEVID_SCSI3_VPD_NAA;
874 	}
875 }
876 
877 
878 /*
879  *    Function: encode_serialnum
880  *
881  * Description: This routine finds the unique devid from the inquiry page
882  *		0x80, serial number page.  If available and fills the wwn
883  *		and length parameters.
884  *
885  *   Arguments: version - encode version
886  *		inq - standard inquiry data
887  *		inq80 - serial inquiry data
888  *		inq80_len - serial inquiry data len
889  *		id - raw id
890  *		id_len - raw id len
891  *		id_type - raw id type
892  */
893 /* ARGSUSED */
894 static void
895 encode_serialnum(int version, uchar_t *inq, uchar_t *inq80,
896     size_t inq80_len, uchar_t **id, size_t *id_len, ushort_t *id_type)
897 {
898 	struct scsi_inquiry	*inq_std	= (struct scsi_inquiry *)inq;
899 	int			idx		= 0;
900 
901 	DEVID_ASSERT(inq != NULL);
902 	DEVID_ASSERT(inq80 != NULL);
903 	DEVID_ASSERT(id != NULL);
904 	DEVID_ASSERT(id_len != NULL);
905 	DEVID_ASSERT(id_type != NULL);
906 
907 	/* preset defaults */
908 	*id = NULL;
909 	*id_len = 0;
910 	*id_type = DEVID_NONE;
911 
912 	/* verify inq80 buffer is large enough for a header */
913 	if (inq80_len < SCMD_MIN_INQUIRY_PAGE80_SIZE) {
914 		return;
915 	}
916 
917 	/*
918 	 * Attempt to validate the page data.  Once validated, we'll check
919 	 * the serial number.
920 	 */
921 	*id_len = (size_t)inq80[3]; /* Store Product Serial Number length */
922 
923 	/* verify buffer is large enough for serial number */
924 	if (inq80_len < (*id_len + SCMD_MIN_INQUIRY_PAGE80_SIZE)) {
925 		return;
926 	}
927 
928 	/*
929 	 * Device returns ASCII space (20h) in all the bytes of successful data
930 	 * transfer, if the product serial number is not available.  So we end
931 	 * up having to check all the bytes for a space until we reach
932 	 * something else.
933 	 */
934 	for (idx = 0; idx < *id_len; idx++) {
935 		if (inq80[4 + idx] == ' ') {
936 			continue;
937 		}
938 		/*
939 		 * The serial number is valid, but since this is only vendor
940 		 * unique, we'll combine the inquiry vid and pid with the
941 		 * serial number.
942 		 */
943 		*id_len += sizeof (inq_std->inq_vid);
944 		*id_len += sizeof (inq_std->inq_pid);
945 
946 		if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
947 			*id_len = 0;
948 			return;
949 		}
950 
951 		bcopy(&inq_std->inq_vid, *id, sizeof (inq_std->inq_vid));
952 		bcopy(&inq_std->inq_pid, &(*id)[sizeof (inq_std->inq_vid)],
953 		    sizeof (inq_std->inq_pid));
954 		bcopy(&inq80[4], &(*id)[sizeof (inq_std->inq_vid) +
955 		    sizeof (inq_std->inq_pid)], inq80[3]);
956 
957 		*id_type = DEVID_SCSI_SERIAL;
958 		break;
959 	}
960 
961 	/*
962 	 * The spec suggests that the command could succeed but return all
963 	 * spaces if the product serial number is not available.  In this case
964 	 * we need to fail this routine. To accomplish this, we compare our
965 	 * length to the serial number length. If they are the same, then we
966 	 * never copied in the vid and updated the length. That being the case,
967 	 * we must not have found a valid serial number.
968 	 */
969 	if (*id_len == (size_t)inq80[3]) {
970 		/* empty unit serial number */
971 		if (*id != NULL) {
972 			DEVID_FREE(*id, *id_len);
973 		}
974 		*id = NULL;
975 		*id_len = 0;
976 	}
977 }
978 
979 
980 /*
981  *    Function: encode_sun_serialnum
982  *
983  * Description: This routine finds the unique devid from the inquiry page
984  *		0x80, serial number page.  If available and fills the wwn
985  *		and length parameters.
986  *
987  *   Arguments: version - encode version
988  *		inq - standard inquiry data
989  *		inq_len - standard inquiry data len
990  *		id - raw id
991  *		id_len - raw id len
992  *		id_type - raw id type
993  *
994  * Return Code: DEVID_SUCCESS
995  *              DEVID_FAILURE
996  */
997 /* ARGSUSED */
998 static void
999 encode_sun_serialnum(int version, uchar_t *inq,
1000     size_t inq_len, uchar_t **id, size_t *id_len, ushort_t *id_type)
1001 {
1002 	struct scsi_inquiry *inq_std = (struct scsi_inquiry *)inq;
1003 
1004 	DEVID_ASSERT(inq != NULL);
1005 	DEVID_ASSERT(id != NULL);
1006 	DEVID_ASSERT(id_len != NULL);
1007 	DEVID_ASSERT(id_type != NULL);
1008 
1009 	/* verify enough buffer is available */
1010 	if (inq_len < SCMD_MIN_STANDARD_INQUIRY_SIZE) {
1011 		return;
1012 	}
1013 
1014 	/* sun qual drive */
1015 	if ((inq_std != NULL) &&
1016 	    (bcmp(&inq_std->inq_pid[SCSI_INQUIRY_VID_POS],
1017 	    SCSI_INQUIRY_VID_SUN, SCSI_INQUIRY_VID_SUN_LEN) == 0)) {
1018 		/*
1019 		 * VPD pages 0x83 and 0x80 are unavailable. This
1020 		 * is a Sun qualified disks as indicated by
1021 		 * "SUN" in bytes 25-27 of the inquiry data
1022 		 * (bytes 9-11 of the pid).  Devid's are created
1023 		 * for Sun qualified disks by combining the
1024 		 * vendor id with the product id with the serial
1025 		 * number located in bytes 36-47 of the inquiry data.
1026 		 */
1027 
1028 		/* get data size */
1029 		*id_len = sizeof (inq_std->inq_vid) +
1030 		    sizeof (inq_std->inq_pid) +
1031 		    sizeof (inq_std->inq_serial);
1032 
1033 		if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
1034 			*id_len = 0;
1035 			return;
1036 		}
1037 
1038 		/* copy the vid at the beginning */
1039 		bcopy(&inq_std->inq_vid, *id,
1040 		    sizeof (inq_std->inq_vid));
1041 			/* copy the pid after the vid */
1042 		bcopy(&inq_std->inq_pid,
1043 		    &(*id)[sizeof (inq_std->inq_vid)],
1044 		    sizeof (inq_std->inq_pid));
1045 			/* copy the serial number after the vid and pid */
1046 		bcopy(&inq_std->inq_serial,
1047 		    &(*id)[sizeof (inq_std->inq_vid) +
1048 		    sizeof (inq_std->inq_pid)],
1049 		    sizeof (inq_std->inq_serial));
1050 			/* devid formed from inquiry data */
1051 		*id_type = DEVID_SCSI_SERIAL;
1052 	}
1053 }
1054 
1055 
1056 /*
1057  *    Function: devid_scsi_init
1058  *
1059  * Description: This routine is used to create a devid for a scsi
1060  *		devid type.
1061  *
1062  *   Arguments: hint - driver soft state (unit) structure
1063  *		raw_id - pass by reference variable to hold wwn
1064  *		raw_id_len - wwn length
1065  *		raw_id_type -
1066  *		ret_devid -
1067  *
1068  * Return Code: DEVID_SUCCESS
1069  *              DEVID_FAILURE
1070  *
1071  */
1072 static int
1073 devid_scsi_init(
1074 	char		*driver_name,
1075 	uchar_t		*raw_id,
1076 	size_t		raw_id_len,
1077 	ushort_t	raw_id_type,
1078 	ddi_devid_t	*ret_devid)
1079 {
1080 	impl_devid_t	*i_devid	= NULL;
1081 	int		i_devid_len	= 0;
1082 	int		driver_name_len	= 0;
1083 	ushort_t	u_raw_id_len	= 0;
1084 
1085 	DEVID_ASSERT(raw_id != NULL);
1086 	DEVID_ASSERT(ret_devid != NULL);
1087 
1088 	if (!IS_DEVID_SCSI_TYPE(raw_id_type)) {
1089 		*ret_devid = NULL;
1090 		return (DEVID_FAILURE);
1091 	}
1092 
1093 	i_devid_len = sizeof (*i_devid) + raw_id_len - sizeof (i_devid->did_id);
1094 	if ((i_devid = DEVID_MALLOC(i_devid_len)) == NULL) {
1095 		*ret_devid = NULL;
1096 		return (DEVID_FAILURE);
1097 	}
1098 
1099 	i_devid->did_magic_hi = DEVID_MAGIC_MSB;
1100 	i_devid->did_magic_lo = DEVID_MAGIC_LSB;
1101 	i_devid->did_rev_hi = DEVID_REV_MSB;
1102 	i_devid->did_rev_lo = DEVID_REV_LSB;
1103 	DEVID_FORMTYPE(i_devid, raw_id_type);
1104 	u_raw_id_len = raw_id_len;
1105 	DEVID_FORMLEN(i_devid, u_raw_id_len);
1106 
1107 	/* Fill in driver name hint */
1108 	bzero(i_devid->did_driver, DEVID_HINT_SIZE);
1109 	if (driver_name != NULL) {
1110 		driver_name_len = strlen(driver_name);
1111 		if (driver_name_len > DEVID_HINT_SIZE) {
1112 			/* Pick up last four characters of driver name */
1113 			driver_name += driver_name_len - DEVID_HINT_SIZE;
1114 			driver_name_len = DEVID_HINT_SIZE;
1115 		}
1116 		bcopy(driver_name, i_devid->did_driver, driver_name_len);
1117 	}
1118 
1119 	bcopy(raw_id, i_devid->did_id, raw_id_len);
1120 
1121 	/* return device id */
1122 	*ret_devid = (ddi_devid_t)i_devid;
1123 	return (DEVID_SUCCESS);
1124 }
1125 
1126 
1127 /*
1128  *    Function: devid_to_guid
1129  *
1130  * Description: This routine extracts a guid string form a devid.
1131  *		The common use of this guid is for a HBA driver
1132  *		to pass into mdi_pi_alloc().
1133  *
1134  *   Arguments: devid - devid to extract guid from
1135  *
1136  * Return Code: guid string - success
1137  *		NULL - failure
1138  */
1139 char *
1140 #ifdef  _KERNEL
1141 ddi_devid_to_guid(ddi_devid_t devid)
1142 #else   /* !_KERNEL */
1143 devid_to_guid(ddi_devid_t devid)
1144 #endif  /* _KERNEL */
1145 {
1146 	impl_devid_t	*id	= (impl_devid_t *)devid;
1147 	int		len	= 0;
1148 	int		idx	= 0;
1149 	int		num	= 0;
1150 	char		*guid	= NULL;
1151 	char		*ptr	= NULL;
1152 	char		*dp	= NULL;
1153 
1154 	DEVID_ASSERT(devid != NULL);
1155 
1156 	/* NULL devid -> NULL guid */
1157 	if (devid == NULL)
1158 		return (NULL);
1159 
1160 	if (!IS_DEVID_GUID_TYPE(DEVID_GETTYPE(id)))
1161 		return (NULL);
1162 
1163 	/* guid is always converted to ascii, append NULL */
1164 	len = DEVID_GETLEN(id);
1165 
1166 	/* allocate guid string */
1167 	if ((guid = DEVID_MALLOC((len * 2) + 1)) == NULL)
1168 		return (NULL);
1169 
1170 	/* perform encode of id to hex string */
1171 	ptr = guid;
1172 	for (idx = 0, dp = &id->did_id[0]; idx < len; idx++, dp++) {
1173 		num = ((*dp) >> 4) & 0xF;
1174 		*ptr++ = (num < 10) ? (num + '0') : (num + ('a' - 10));
1175 		num = (*dp) & 0xF;
1176 		*ptr++ = (num < 10) ? (num + '0') : (num + ('a' - 10));
1177 	}
1178 	*ptr = 0;
1179 
1180 	return (guid);
1181 }
1182 
1183 /*
1184  *    Function: devid_free_guid
1185  *
1186  * Description: This routine frees a guid allocated by
1187  *		devid_to_guid().
1188  *
1189  *   Arguments: guid - guid to free
1190  */
1191 void
1192 #ifdef  _KERNEL
1193 ddi_devid_free_guid(char *guid)
1194 #else   /* !_KERNEL */
1195 devid_free_guid(char *guid)
1196 #endif  /* _KERNEL */
1197 {
1198 	if (guid != NULL) {
1199 		DEVID_FREE(guid, strlen(guid) + 1);
1200 	}
1201 }
1202 
1203 static char
1204 ctoi(char c)
1205 {
1206 	if ((c >= '0') && (c <= '9'))
1207 		c -= '0';
1208 	else if ((c >= 'A') && (c <= 'F'))
1209 		c = c - 'A' + 10;
1210 	else if ((c >= 'a') && (c <= 'f'))
1211 		c = c - 'a' + 10;
1212 	else
1213 		c = -1;
1214 	return (c);
1215 }
1216 
1217 /*
1218  *    Function: devid_str_to_wwn
1219  *
1220  * Description: This routine translates wwn from string to uint64 type.
1221  *
1222  *   Arguments: string - the string wwn to be transformed
1223  *              wwn - the pointer to 64 bit wwn
1224  */
1225 int
1226 #ifdef  _KERNEL
1227 ddi_devid_str_to_wwn(const char *string, uint64_t *wwn)
1228 #else   /* !_KERNEL */
1229 devid_str_to_wwn(const char *string, uint64_t *wwn)
1230 #endif  /* _KERNEL */
1231 {
1232 	int i;
1233 	char cl, ch;
1234 	uint64_t tmp;
1235 
1236 	if (wwn == NULL || strlen(string) != 16) {
1237 		return (DDI_FAILURE);
1238 	}
1239 
1240 	*wwn = 0;
1241 	for (i = 0; i < 8; i++) {
1242 		ch = ctoi(*string++);
1243 		cl = ctoi(*string++);
1244 		if (cl == -1 || ch == -1) {
1245 			return (DDI_FAILURE);
1246 		}
1247 		tmp = (ch << 4) + cl;
1248 		*wwn = (*wwn << 8) | tmp;
1249 	}
1250 	return (DDI_SUCCESS);
1251 }
1252