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