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
105static int is_page83_data_valid(uchar_t *inq83, size_t inq83_len);
106static int is_page80_data_valid(uchar_t *inq80, size_t inq80_len);
107static int is_initialized_id(uchar_t *id, size_t id_len);
108
109static 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);
111static 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);
113static 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);
115static 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
118static 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
122static 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 */
145int
146#ifdef _KERNEL
147ddi_devid_scsi_encode(
148#else /* ! _KERNEL */
149devid_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 */
304static int
305is_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 */
543static int
544is_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 */
600static int
601is_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 */
639static void
640encode_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 */
825static void
826encode_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 */
906static void
907encode_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 */
1010static void
1011encode_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 */
1087static int
1088devid_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 */
1154char *
1155#ifdef  _KERNEL
1156ddi_devid_to_guid(ddi_devid_t devid)
1157#else   /* !_KERNEL */
1158devid_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 */
1206void
1207#ifdef  _KERNEL
1208ddi_devid_free_guid(char *guid)
1209#else   /* !_KERNEL */
1210devid_free_guid(char *guid)
1211#endif  /* _KERNEL */
1212{
1213	if (guid != NULL) {
1214		DEVID_FREE(guid, strlen(guid) + 1);
1215	}
1216}
1217
1218static char
1219ctoi(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 */
1242int
1243scsi_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 */
1286char *
1287scsi_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 */
1321void
1322scsi_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 */
1348const char *
1349scsi_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 */
1365void
1366scsi_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 */
1410scsi_lun64_t
1411scsi_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
1448scsi_lun_t
1449scsi_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 */
1488int
1489scsi_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