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