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