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