xref: /titanic_51/usr/src/common/devid/devid_scsi.c (revision ed141cfca535fc26451c4bd9a2cfb6172af449c2)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5f01c928dSlh195018  * Common Development and Distribution License (the "License").
6f01c928dSlh195018  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21936b7af6Sjw149990 
227c478bd9Sstevel@tonic-gate /*
2399025f2eSsrivijitha dugganapalli  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
26936b7af6Sjw149990 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * These functions are used to encode SCSI INQUIRY data into
297c478bd9Sstevel@tonic-gate  * Solaris devid / guid values.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
32*ed141cfcSsrivijitha dugganapalli #ifndef _KERNEL
33*ed141cfcSsrivijitha dugganapalli #include <stdio.h>
34*ed141cfcSsrivijitha dugganapalli #endif /* _KERNEL */
35*ed141cfcSsrivijitha dugganapalli 
36*ed141cfcSsrivijitha dugganapalli #include <sys/inttypes.h>
377c478bd9Sstevel@tonic-gate #include <sys/types.h>
387c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
397c478bd9Sstevel@tonic-gate #include <sys/debug.h>
407c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
417c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
427c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
437c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h>
447c478bd9Sstevel@tonic-gate #include "devid_impl.h"
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #define	SCSI_INQUIRY_VID_POS			9
477c478bd9Sstevel@tonic-gate #define	SCSI_INQUIRY_VID_SUN			"SUN"
487c478bd9Sstevel@tonic-gate #define	SCSI_INQUIRY_VID_SUN_LEN		3
49f01c928dSlh195018 #define	SCSI_INQUIRY_VID_HITACHI		"HITACHI"
50f01c928dSlh195018 #define	SCSI_INQUIRY_VID_HITACHI_LEN		7
51f01c928dSlh195018 #define	SCSI_INQUIRY_PID_HITACHI_OPEN		"OPEN-"
52f01c928dSlh195018 #define	SCSI_INQUIRY_PID_HITACHI_OPEN_LEN	5
537c478bd9Sstevel@tonic-gate #define	SCSI_INQUIRY_VID_EMC			"EMC     "
547c478bd9Sstevel@tonic-gate #define	SCSI_INQUIRY_VID_EMC_LEN		8
557c478bd9Sstevel@tonic-gate #define	SCSI_INQUIRY_PID_EMC_SYMMETRIX		"SYMMETRIX       "
567c478bd9Sstevel@tonic-gate #define	SCSI_INQUIRY_PID_EMC_SYMMETRIX_LEN	16
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #define	MSG_NOT_STANDARDS_COMPLIANT "!Page83 data not standards compliant "
597c478bd9Sstevel@tonic-gate #define	MSG_NOT_STANDARDS_COMPLIANT_SIZE	( \
607c478bd9Sstevel@tonic-gate 	sizeof (MSG_NOT_STANDARDS_COMPLIANT) + \
617c478bd9Sstevel@tonic-gate 	sizeof (((struct scsi_inquiry *)NULL)->inq_vid) + \
627c478bd9Sstevel@tonic-gate 	sizeof (((struct scsi_inquiry *)NULL)->inq_pid) + \
637c478bd9Sstevel@tonic-gate 	sizeof (((struct scsi_inquiry *)NULL)->inq_revision) + 4)
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate #define	IS_DEVID_GUID_TYPE(type) ((type == DEVID_SCSI3_WWN)	|| \
667c478bd9Sstevel@tonic-gate 				(IS_DEVID_SCSI3_VPD_TYPE(type)))
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #define	IS_DEVID_SCSI_TYPE(type) ((IS_DEVID_GUID_TYPE(type)) || \
697c478bd9Sstevel@tonic-gate 				(type == DEVID_SCSI_SERIAL))
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate  * The max inquiry page 83 size as expected in the code today
737c478bd9Sstevel@tonic-gate  * is 0xf0 bytes. Defining a constant to make it easy incase
747c478bd9Sstevel@tonic-gate  * this needs to be changed at a later time.
757c478bd9Sstevel@tonic-gate  */
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate #define	SCMD_MAX_INQUIRY_PAGE83_SIZE			0xFF
787c478bd9Sstevel@tonic-gate #define	SCMD_MIN_INQUIRY_PAGE83_SIZE			0x08
797c478bd9Sstevel@tonic-gate #define	SCMD_INQUIRY_PAGE83_HDR_SIZE			4
807c478bd9Sstevel@tonic-gate #define	SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN	16
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate #define	SCMD_MAX_INQUIRY_PAGE80_SIZE	0xFF
837c478bd9Sstevel@tonic-gate #define	SCMD_MIN_INQUIRY_PAGE80_SIZE	0x04
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate #define	SCMD_MIN_STANDARD_INQUIRY_SIZE	0x04
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate #define	SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE		4
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate #define	SCMD_INQUIRY_VPD_TYPE_T10	0x01
907c478bd9Sstevel@tonic-gate #define	SCMD_INQUIRY_VPD_TYPE_EUI	0x02
917c478bd9Sstevel@tonic-gate #define	SCMD_INQUIRY_VPD_TYPE_NAA	0x03
927c478bd9Sstevel@tonic-gate #define	SCMD_INQUIRY_VPD_TYPE_RTP	0x04
937c478bd9Sstevel@tonic-gate #define	SCMD_INQUIRY_VPD_TYPE_TPG	0x05
947c478bd9Sstevel@tonic-gate #define	SCMD_INQUIRY_VPD_TYPE_LUG	0x06
957c478bd9Sstevel@tonic-gate #define	SCMD_INQUIRY_VPD_TYPE_MD5	0x07
967c478bd9Sstevel@tonic-gate #define	SCMD_INQUIRY_VPD_TYPE_SSN	0x08
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate static int is_page83_data_valid(uchar_t *inq83, size_t inq83_len);
997c478bd9Sstevel@tonic-gate static int is_page80_data_valid(uchar_t *inq80, size_t inq80_len);
1007c478bd9Sstevel@tonic-gate static int is_initialized_id(uchar_t *id, size_t id_len);
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate static void encode_scsi3_page83(int version, uchar_t *inq83,
1037c478bd9Sstevel@tonic-gate     size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
1047c478bd9Sstevel@tonic-gate static void encode_scsi3_page83_emc(int version, uchar_t *inq83,
1057c478bd9Sstevel@tonic-gate     size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
1067c478bd9Sstevel@tonic-gate static void encode_serialnum(int version, uchar_t *inq, uchar_t *inq80,
1077c478bd9Sstevel@tonic-gate     size_t inq80_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
1087c478bd9Sstevel@tonic-gate static void encode_sun_serialnum(int version, uchar_t *inq,
1097c478bd9Sstevel@tonic-gate     size_t inq_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate static int devid_scsi_init(char *driver_name,
1127c478bd9Sstevel@tonic-gate     uchar_t *raw_id, size_t raw_id_len, ushort_t raw_id_type,
1137c478bd9Sstevel@tonic-gate     ddi_devid_t *ret_devid);
1147c478bd9Sstevel@tonic-gate 
115936b7af6Sjw149990 static char ctoi(char c);
116936b7af6Sjw149990 
1177c478bd9Sstevel@tonic-gate /*
1187c478bd9Sstevel@tonic-gate  *    Function: ddi_/devid_scsi_encode
1197c478bd9Sstevel@tonic-gate  *
1207c478bd9Sstevel@tonic-gate  * Description: This routine finds and encodes a unique devid
1217c478bd9Sstevel@tonic-gate  *
1227c478bd9Sstevel@tonic-gate  *   Arguments: version - id encode algorithm version
1237c478bd9Sstevel@tonic-gate  *		driver_name - binding driver name (if ! known use NULL)
1247c478bd9Sstevel@tonic-gate  *		inq - standard inquiry buffer
1257c478bd9Sstevel@tonic-gate  *		inq_len - standard inquiry buffer length
1267c478bd9Sstevel@tonic-gate  *		inq80 - serial number inquiry buffer
1277c478bd9Sstevel@tonic-gate  *		inq80_len - serial number inquiry buffer length
1287c478bd9Sstevel@tonic-gate  *		inq83 - vpd inquiry buffer
1297c478bd9Sstevel@tonic-gate  *		inq83_len - vpd inquiry buffer length
1307c478bd9Sstevel@tonic-gate  *		devid - id returned
1317c478bd9Sstevel@tonic-gate  *
1327c478bd9Sstevel@tonic-gate  * Return Code: DEVID_SUCCESS - success
1337c478bd9Sstevel@tonic-gate  *		DEVID_FAILURE - failure
1347c478bd9Sstevel@tonic-gate  *		DEVID_RETRY - LUN is in a transitional state.  A delay should
1357c478bd9Sstevel@tonic-gate  *		occur and then this inquiry data should be re-acquired and
1367c478bd9Sstevel@tonic-gate  *		this function should be called again.
1377c478bd9Sstevel@tonic-gate  */
1387c478bd9Sstevel@tonic-gate int
1397c478bd9Sstevel@tonic-gate #ifdef _KERNEL
1407c478bd9Sstevel@tonic-gate ddi_devid_scsi_encode(
1417c478bd9Sstevel@tonic-gate #else /* ! _KERNEL */
1427c478bd9Sstevel@tonic-gate devid_scsi_encode(
1437c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
1447c478bd9Sstevel@tonic-gate     int version,	/* IN */
1457c478bd9Sstevel@tonic-gate     char *driver_name,	/* IN */
1467c478bd9Sstevel@tonic-gate     uchar_t *inq,	/* IN */
1477c478bd9Sstevel@tonic-gate     size_t inq_len,	/* IN */
1487c478bd9Sstevel@tonic-gate     uchar_t *inq80,	/* IN */
1497c478bd9Sstevel@tonic-gate     size_t inq80_len,	/* IN */
1507c478bd9Sstevel@tonic-gate     uchar_t *inq83,	/* IN */
1517c478bd9Sstevel@tonic-gate     size_t inq83_len,	/* IN */
1527c478bd9Sstevel@tonic-gate     ddi_devid_t *devid)	/* OUT */
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	int			rval		= DEVID_FAILURE;
1557c478bd9Sstevel@tonic-gate 	uchar_t			*id		= NULL;
1567c478bd9Sstevel@tonic-gate 	size_t			id_len		= 0;
1577c478bd9Sstevel@tonic-gate 	ushort_t		id_type		= DEVID_NONE;
1587c478bd9Sstevel@tonic-gate 	struct scsi_inquiry	*inq_std	= (struct scsi_inquiry *)inq;
1597c478bd9Sstevel@tonic-gate #ifdef	_KERNEL
1607c478bd9Sstevel@tonic-gate 	char			*msg		= NULL;
1617c478bd9Sstevel@tonic-gate #endif	/* _KERNEL */
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(devid != NULL);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	/* verify valid version */
1667c478bd9Sstevel@tonic-gate 	if (version > DEVID_SCSI_ENCODE_VERSION_LATEST) {
1677c478bd9Sstevel@tonic-gate 		return (rval);
1687c478bd9Sstevel@tonic-gate 	}
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	/* make sure minimum inquiry bytes are available */
1717c478bd9Sstevel@tonic-gate 	if (inq_len < SCMD_MIN_STANDARD_INQUIRY_SIZE) {
1727c478bd9Sstevel@tonic-gate 		return (rval);
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	/*
1767c478bd9Sstevel@tonic-gate 	 * If 0x83 is availible, that is the best choice.  Our next choice is
1777c478bd9Sstevel@tonic-gate 	 * 0x80.  If neither are availible, we leave it to the caller to
1787c478bd9Sstevel@tonic-gate 	 * determine possible alternate ID, although discouraged.  In the
1797c478bd9Sstevel@tonic-gate 	 * case of the target drivers they create a fabricated id which is
1807c478bd9Sstevel@tonic-gate 	 * stored in the acyl.  The HBA drivers should avoid using an
1817c478bd9Sstevel@tonic-gate 	 * alternate id.  Although has already created a hack of using the
1827c478bd9Sstevel@tonic-gate 	 * node wwn in some cases.  Which needs to be carried forward for
1837c478bd9Sstevel@tonic-gate 	 * legacy reasons.
1847c478bd9Sstevel@tonic-gate 	 */
1857c478bd9Sstevel@tonic-gate 	if (inq83 != NULL) {
1867c478bd9Sstevel@tonic-gate 		/*
1877c478bd9Sstevel@tonic-gate 		 * Perform page 83 validation tests and report offenders.
1887c478bd9Sstevel@tonic-gate 		 * We cannot enforce the page 83 specification because
1897c478bd9Sstevel@tonic-gate 		 * many Sun partners (ex. HDS) do not conform to the
1907c478bd9Sstevel@tonic-gate 		 * standards yet.
1917c478bd9Sstevel@tonic-gate 		 */
1927c478bd9Sstevel@tonic-gate 		if (is_page83_data_valid(inq83, inq83_len) ==
1937c478bd9Sstevel@tonic-gate 		    DEVID_RET_INVALID) {
1947c478bd9Sstevel@tonic-gate 			/*
1957c478bd9Sstevel@tonic-gate 			 * invalid page 83 data.  bug 4939576 introduced
1967c478bd9Sstevel@tonic-gate 			 * handling for EMC non-standard data.
1977c478bd9Sstevel@tonic-gate 			 */
1987c478bd9Sstevel@tonic-gate 			if ((bcmp(inq_std->inq_vid, SCSI_INQUIRY_VID_EMC,
1997c478bd9Sstevel@tonic-gate 			    SCSI_INQUIRY_VID_EMC_LEN) == 0) &&
2007c478bd9Sstevel@tonic-gate 			    (bcmp(inq_std->inq_pid,
2017c478bd9Sstevel@tonic-gate 			    SCSI_INQUIRY_PID_EMC_SYMMETRIX,
2027c478bd9Sstevel@tonic-gate 			    SCSI_INQUIRY_PID_EMC_SYMMETRIX_LEN) == 0)) {
2037c478bd9Sstevel@tonic-gate 				encode_scsi3_page83_emc(version, inq83,
2047c478bd9Sstevel@tonic-gate 				    inq83_len, &id, &id_len, &id_type);
2057c478bd9Sstevel@tonic-gate 			}
2067c478bd9Sstevel@tonic-gate #ifdef	_KERNEL
2077c478bd9Sstevel@tonic-gate 			/*
208f01c928dSlh195018 			 * invalid page 83 data. Special hack for HDS
209f01c928dSlh195018 			 * specific device, to suppress the warning msg.
210f01c928dSlh195018 			 */
211f01c928dSlh195018 			if ((bcmp(inq_std->inq_vid, SCSI_INQUIRY_VID_HITACHI,
212f01c928dSlh195018 			    SCSI_INQUIRY_VID_HITACHI_LEN) != 0) ||
213f01c928dSlh195018 			    (bcmp(inq_std->inq_pid,
214f01c928dSlh195018 			    SCSI_INQUIRY_PID_HITACHI_OPEN,
215f01c928dSlh195018 			    SCSI_INQUIRY_PID_HITACHI_OPEN_LEN) != 0)) {
216f01c928dSlh195018 				/*
2177c478bd9Sstevel@tonic-gate 				 * report the page 0x83 standards violation.
2187c478bd9Sstevel@tonic-gate 				 */
219f01c928dSlh195018 				msg = kmem_alloc(
220f01c928dSlh195018 				    MSG_NOT_STANDARDS_COMPLIANT_SIZE,
2217c478bd9Sstevel@tonic-gate 				    KM_SLEEP);
2227c478bd9Sstevel@tonic-gate 				(void) strcpy(msg, MSG_NOT_STANDARDS_COMPLIANT);
2237c478bd9Sstevel@tonic-gate 				(void) strncat(msg, inq_std->inq_vid,
2247c478bd9Sstevel@tonic-gate 				    sizeof (inq_std->inq_vid));
2257c478bd9Sstevel@tonic-gate 				(void) strcat(msg, " ");
2267c478bd9Sstevel@tonic-gate 				(void) strncat(msg, inq_std->inq_pid,
2277c478bd9Sstevel@tonic-gate 				    sizeof (inq_std->inq_pid));
2287c478bd9Sstevel@tonic-gate 				(void) strcat(msg, " ");
2297c478bd9Sstevel@tonic-gate 				(void) strncat(msg, inq_std->inq_revision,
2307c478bd9Sstevel@tonic-gate 				    sizeof (inq_std->inq_revision));
2317c478bd9Sstevel@tonic-gate 				(void) strcat(msg, "\n");
2327c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, msg);
233f01c928dSlh195018 				kmem_free(msg,
234f01c928dSlh195018 				    MSG_NOT_STANDARDS_COMPLIANT_SIZE);
235f01c928dSlh195018 			}
2367c478bd9Sstevel@tonic-gate #endif	/* _KERNEL */
2377c478bd9Sstevel@tonic-gate 		}
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 		if (id_type == DEVID_NONE) {
2407c478bd9Sstevel@tonic-gate 			encode_scsi3_page83(version, inq83,
2417c478bd9Sstevel@tonic-gate 			    inq83_len, &id, &id_len, &id_type);
2427c478bd9Sstevel@tonic-gate 		}
2437c478bd9Sstevel@tonic-gate 	}
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	/*
2467c478bd9Sstevel@tonic-gate 	 * If no vpd page is available at this point then we
2477c478bd9Sstevel@tonic-gate 	 * attempt to use a SCSI serial number from page 0x80.
2487c478bd9Sstevel@tonic-gate 	 */
2497c478bd9Sstevel@tonic-gate 	if ((id_type == DEVID_NONE) &&
2507c478bd9Sstevel@tonic-gate 	    (inq != NULL) &&
2517c478bd9Sstevel@tonic-gate 	    (inq80 != NULL)) {
2527c478bd9Sstevel@tonic-gate 		if (is_page80_data_valid(inq80, inq80_len) == DEVID_RET_VALID) {
2537c478bd9Sstevel@tonic-gate 			encode_serialnum(version, inq, inq80,
2547c478bd9Sstevel@tonic-gate 			    inq80_len, &id, &id_len, &id_type);
2557c478bd9Sstevel@tonic-gate 		}
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	/*
2597c478bd9Sstevel@tonic-gate 	 * If no vpd page  or serial is available at this point and
2607c478bd9Sstevel@tonic-gate 	 * it's a SUN disk it conforms to the disk qual. 850 specifications
2617c478bd9Sstevel@tonic-gate 	 * and we can fabricate a serial number id based on the standard
2627c478bd9Sstevel@tonic-gate 	 * inquiry page.
2637c478bd9Sstevel@tonic-gate 	 */
2647c478bd9Sstevel@tonic-gate 	if ((id_type == DEVID_NONE) &&
2657c478bd9Sstevel@tonic-gate 	    (inq != NULL)) {
2667c478bd9Sstevel@tonic-gate 		encode_sun_serialnum(version, inq, inq_len,
2677c478bd9Sstevel@tonic-gate 		    &id, &id_len, &id_type);
2687c478bd9Sstevel@tonic-gate 	}
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	if (id_type != DEVID_NONE) {
2717c478bd9Sstevel@tonic-gate 		if (is_initialized_id(id, id_len) == DEVID_RET_VALID) {
2727c478bd9Sstevel@tonic-gate 			rval = devid_scsi_init(driver_name,
2737c478bd9Sstevel@tonic-gate 			    id, id_len, id_type, devid);
2747c478bd9Sstevel@tonic-gate 		} else {
2757c478bd9Sstevel@tonic-gate 			rval = DEVID_RETRY;
2767c478bd9Sstevel@tonic-gate 		}
2777c478bd9Sstevel@tonic-gate 		DEVID_FREE(id, id_len);
2787c478bd9Sstevel@tonic-gate 	}
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	return (rval);
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate /*
2857c478bd9Sstevel@tonic-gate  *    Function: is_page83_data_valid
2867c478bd9Sstevel@tonic-gate  *
2877c478bd9Sstevel@tonic-gate  * Description: This routine is used to validate the page 0x83 data
2887c478bd9Sstevel@tonic-gate  *		passed in valid based on the standards specification.
2897c478bd9Sstevel@tonic-gate  *
2907c478bd9Sstevel@tonic-gate  *   Arguments: inq83 -
2917c478bd9Sstevel@tonic-gate  *		inq83_len -
2927c478bd9Sstevel@tonic-gate  *
2937c478bd9Sstevel@tonic-gate  * Return Code: DEVID_RET_VALID
2947c478bd9Sstevel@tonic-gate  *              DEVID_RET_INVALID
2957c478bd9Sstevel@tonic-gate  *
2967c478bd9Sstevel@tonic-gate  */
2977c478bd9Sstevel@tonic-gate static int
2987c478bd9Sstevel@tonic-gate is_page83_data_valid(uchar_t *inq83, size_t inq83_len)
2997c478bd9Sstevel@tonic-gate {
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	int 	covered_desc_len	= 0;
3027c478bd9Sstevel@tonic-gate 	int	dlen			= 0;
3037c478bd9Sstevel@tonic-gate 	uchar_t	*dblk			= NULL;
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(inq83 != NULL);
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	/* if not large enough fail */
3087c478bd9Sstevel@tonic-gate 	if (inq83_len < SCMD_MIN_INQUIRY_PAGE83_SIZE)
3097c478bd9Sstevel@tonic-gate 		return (DEVID_RET_INVALID);
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	/*
3127c478bd9Sstevel@tonic-gate 	 * Ensuring that the Peripheral device type(bits 0 - 4) has
3137c478bd9Sstevel@tonic-gate 	 * the valid settings - the value 0x1f indicates no device type.
3147c478bd9Sstevel@tonic-gate 	 * Only this value can be validated since all other fields are
3157c478bd9Sstevel@tonic-gate 	 * either used or reserved.
3167c478bd9Sstevel@tonic-gate 	 */
3177c478bd9Sstevel@tonic-gate 	if ((inq83[0] & DTYPE_MASK) == DTYPE_UNKNOWN) {
3187c478bd9Sstevel@tonic-gate 		/* failed-peripheral devtype */
3197c478bd9Sstevel@tonic-gate 		return (DEVID_RET_INVALID);
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	/*
3237c478bd9Sstevel@tonic-gate 	 * Ensure that the page length field - third and 4th bytes
3247c478bd9Sstevel@tonic-gate 	 * contain a non zero length value. Our implementation
3257c478bd9Sstevel@tonic-gate 	 * does not seem to expect more that 255 bytes of data...
3267c478bd9Sstevel@tonic-gate 	 * what is to be done if the reported size is > 255 bytes?
3277c478bd9Sstevel@tonic-gate 	 * Yes the device will return only 255 bytes as we provide
3287c478bd9Sstevel@tonic-gate 	 * buffer to house only that much data but the standards
3297c478bd9Sstevel@tonic-gate 	 * prevent the targets from reporting the truncated size
3307c478bd9Sstevel@tonic-gate 	 * in this field.
3317c478bd9Sstevel@tonic-gate 	 *
3327c478bd9Sstevel@tonic-gate 	 * Currently reporting sizes more than 255 as failure.
3337c478bd9Sstevel@tonic-gate 	 *
3347c478bd9Sstevel@tonic-gate 	 */
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	if ((inq83[2] == 0) && (inq83[3] == 0)) {
3377c478bd9Sstevel@tonic-gate 		/* length field is 0! */
3387c478bd9Sstevel@tonic-gate 		return (DEVID_RET_INVALID);
3397c478bd9Sstevel@tonic-gate 	}
3407c478bd9Sstevel@tonic-gate 	if (inq83[3] > (SCMD_MAX_INQUIRY_PAGE83_SIZE - 3)) {
3417c478bd9Sstevel@tonic-gate 		/* length field exceeds expected size of 255 bytes */
3427c478bd9Sstevel@tonic-gate 		return (DEVID_RET_INVALID);
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	/*
3467c478bd9Sstevel@tonic-gate 	 * Validation of individual descriptor blocks are done in the
3477c478bd9Sstevel@tonic-gate 	 * following while loop. It is possible to have multiple
3487c478bd9Sstevel@tonic-gate 	 * descriptor blocks.
3497c478bd9Sstevel@tonic-gate 	 * the 'dblk' pointer will be pointing to the start of
3507c478bd9Sstevel@tonic-gate 	 * each entry of the descriptor block.
3517c478bd9Sstevel@tonic-gate 	 */
3527c478bd9Sstevel@tonic-gate 	covered_desc_len = 0;
3537c478bd9Sstevel@tonic-gate 	dblk = &inq83[4]; /* start of first decriptor blk */
3547c478bd9Sstevel@tonic-gate 	while (covered_desc_len < inq83[3]) {
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 		/*
3577c478bd9Sstevel@tonic-gate 		 * Ensure that the length field is non zero
3587c478bd9Sstevel@tonic-gate 		 * Further length validations will be done
3597c478bd9Sstevel@tonic-gate 		 * along with the 'identifier type' as some of
3607c478bd9Sstevel@tonic-gate 		 * the lengths are dependent on it.
3617c478bd9Sstevel@tonic-gate 		 */
3627c478bd9Sstevel@tonic-gate 		dlen = dblk[3];
3637c478bd9Sstevel@tonic-gate 		if (dlen == 0) {
3647c478bd9Sstevel@tonic-gate 			/* descr length is 0 */
3657c478bd9Sstevel@tonic-gate 			return (DEVID_RET_INVALID);
3667c478bd9Sstevel@tonic-gate 		}
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 		/*
3697c478bd9Sstevel@tonic-gate 		 * ensure that the size of the descriptor block does
3707c478bd9Sstevel@tonic-gate 		 * not claim to be larger than the entire page83
3717c478bd9Sstevel@tonic-gate 		 * data that has been received.
3727c478bd9Sstevel@tonic-gate 		 */
3737c478bd9Sstevel@tonic-gate 		if ((covered_desc_len + dlen) > inq83[3]) {
3747c478bd9Sstevel@tonic-gate 			/* failed-descr length */
3757c478bd9Sstevel@tonic-gate 			return (DEVID_RET_INVALID);
3767c478bd9Sstevel@tonic-gate 		}
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 		/*
3797c478bd9Sstevel@tonic-gate 		 * The spec says that if the PIV field is 0 OR the
3807c478bd9Sstevel@tonic-gate 		 * association field contains value other than 1 and 2,
3817c478bd9Sstevel@tonic-gate 		 * then the protocol identifier field should be ignored.
3827c478bd9Sstevel@tonic-gate 		 * If association field contains a value of 1 or 2
3837c478bd9Sstevel@tonic-gate 		 * and the PIV field is set, then the protocol identifier
3847c478bd9Sstevel@tonic-gate 		 * field has to be validated.
3857c478bd9Sstevel@tonic-gate 		 * The protocol identifier values 0 - f are either assigned
3867c478bd9Sstevel@tonic-gate 		 * or reserved. Nothing to validate here, hence skipping
3877c478bd9Sstevel@tonic-gate 		 * over to the next check.
3887c478bd9Sstevel@tonic-gate 		 */
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 		/*
3917c478bd9Sstevel@tonic-gate 		 * Check for valid code set values.
3927c478bd9Sstevel@tonic-gate 		 * All possible values are reserved or assigned. Nothing
3937c478bd9Sstevel@tonic-gate 		 * to validate - skipping over.
3947c478bd9Sstevel@tonic-gate 		 */
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 		/*
3977c478bd9Sstevel@tonic-gate 		 * Identifier Type validation
3987c478bd9Sstevel@tonic-gate 		 * All SPC3rev22 identified types and the expected lengths
3997c478bd9Sstevel@tonic-gate 		 * are validated.
4007c478bd9Sstevel@tonic-gate 		 */
4017c478bd9Sstevel@tonic-gate 		switch (dblk[1] & 0x0f) {
4027c478bd9Sstevel@tonic-gate 		case SCMD_INQUIRY_VPD_TYPE_T10: /* T10 vendor Id */
4037c478bd9Sstevel@tonic-gate 			/* No specific length validation required */
4047c478bd9Sstevel@tonic-gate 			break;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 		case SCMD_INQUIRY_VPD_TYPE_EUI: /* EUI 64 ID */
4077c478bd9Sstevel@tonic-gate 			/* EUI-64: size is expected to be 8, 12, or 16 bytes */
4087c478bd9Sstevel@tonic-gate 			if ((dlen != 8) && (dlen != 12) && (dlen != 16)) {
4097c478bd9Sstevel@tonic-gate 				/* page83 validation failed-EIU64 */
4107c478bd9Sstevel@tonic-gate 				return (DEVID_RET_INVALID);
4117c478bd9Sstevel@tonic-gate 			}
4127c478bd9Sstevel@tonic-gate 			break;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 		case SCMD_INQUIRY_VPD_TYPE_NAA: /* NAA Id type */
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 			/*
4177c478bd9Sstevel@tonic-gate 			 * the size for this varies -
4187c478bd9Sstevel@tonic-gate 			 * IEEE extended/registered is 8 bytes
4197c478bd9Sstevel@tonic-gate 			 * IEEE Registered extended is 16 bytes
4207c478bd9Sstevel@tonic-gate 			 */
4217c478bd9Sstevel@tonic-gate 			switch (dblk[4] & 0xf0) {
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 				case 0x20: /* IEEE Ext */
4247c478bd9Sstevel@tonic-gate 				case 0x50: /* IEEE Reg */
4257c478bd9Sstevel@tonic-gate 					if (dlen != 8) {
4267c478bd9Sstevel@tonic-gate 						/* failed-IEE E/R len */
4277c478bd9Sstevel@tonic-gate 						return (DEVID_RET_INVALID);
4287c478bd9Sstevel@tonic-gate 					}
4297c478bd9Sstevel@tonic-gate 					/*
4307c478bd9Sstevel@tonic-gate 					 * the codeSet for this MUST
4317c478bd9Sstevel@tonic-gate 					 * be set to 1
4327c478bd9Sstevel@tonic-gate 					 */
4337c478bd9Sstevel@tonic-gate 					if ((dblk[0] & 0x0f) != 1) {
4347c478bd9Sstevel@tonic-gate 						/*
4357c478bd9Sstevel@tonic-gate 						 * failed-IEEE E/R
4367c478bd9Sstevel@tonic-gate 						 * codeSet != 1.
4377c478bd9Sstevel@tonic-gate 						 */
4387c478bd9Sstevel@tonic-gate 						return (DEVID_RET_INVALID);
4397c478bd9Sstevel@tonic-gate 					}
4407c478bd9Sstevel@tonic-gate 				break;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 				case 0x60: /* IEEE EXT REG */
4437c478bd9Sstevel@tonic-gate 					if (dlen != 16) {
4447c478bd9Sstevel@tonic-gate 						/* failed-IEEE ER len */
4457c478bd9Sstevel@tonic-gate 						return (DEVID_RET_INVALID);
4467c478bd9Sstevel@tonic-gate 					}
4477c478bd9Sstevel@tonic-gate 					/*
4487c478bd9Sstevel@tonic-gate 					 * the codeSet for this MUST
4497c478bd9Sstevel@tonic-gate 					 * be set to 1
4507c478bd9Sstevel@tonic-gate 					 */
4517c478bd9Sstevel@tonic-gate 					if ((dblk[0] & 0x0f) != 1) {
4527c478bd9Sstevel@tonic-gate 						/*
4537c478bd9Sstevel@tonic-gate 						 * failed-IEEE ER
4547c478bd9Sstevel@tonic-gate 						 * codeSet != 1.
4557c478bd9Sstevel@tonic-gate 						 */
4567c478bd9Sstevel@tonic-gate 						return (DEVID_RET_INVALID);
4577c478bd9Sstevel@tonic-gate 						}
4587c478bd9Sstevel@tonic-gate 				break;
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 				default:
4617c478bd9Sstevel@tonic-gate 					/* reserved values */
4627c478bd9Sstevel@tonic-gate 					break;
4637c478bd9Sstevel@tonic-gate 			}
4647c478bd9Sstevel@tonic-gate 			break;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		case SCMD_INQUIRY_VPD_TYPE_RTP: /* Relative Target port */
4677c478bd9Sstevel@tonic-gate 			if (dlen != 4) {
4687c478bd9Sstevel@tonic-gate 				/* failed-Rel target Port length */
4697c478bd9Sstevel@tonic-gate 				return (DEVID_RET_INVALID);
4707c478bd9Sstevel@tonic-gate 			}
4717c478bd9Sstevel@tonic-gate 			break;
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 		case SCMD_INQUIRY_VPD_TYPE_TPG: /* Target port group */
4747c478bd9Sstevel@tonic-gate 			if (dlen != 4) {
4757c478bd9Sstevel@tonic-gate 				/* failed-target Port group length */
4767c478bd9Sstevel@tonic-gate 				return (DEVID_RET_INVALID);
4777c478bd9Sstevel@tonic-gate 			}
4787c478bd9Sstevel@tonic-gate 			break;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 		case SCMD_INQUIRY_VPD_TYPE_LUG: /* Logical unit group */
4817c478bd9Sstevel@tonic-gate 			if (dlen != 4) {
4827c478bd9Sstevel@tonic-gate 				/* failed-Logical Unit group length */
4837c478bd9Sstevel@tonic-gate 				return (DEVID_RET_INVALID);
4847c478bd9Sstevel@tonic-gate 			}
4857c478bd9Sstevel@tonic-gate 			break;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 		case SCMD_INQUIRY_VPD_TYPE_MD5: /* MD5 unit group */
4887c478bd9Sstevel@tonic-gate 			if (dlen != 16) {
4897c478bd9Sstevel@tonic-gate 				/* failed-MD5 Unit grp */
4907c478bd9Sstevel@tonic-gate 				return (DEVID_RET_INVALID);
4917c478bd9Sstevel@tonic-gate 			}
4927c478bd9Sstevel@tonic-gate 			break;
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 		default:
4957c478bd9Sstevel@tonic-gate 			break;
4967c478bd9Sstevel@tonic-gate 		}
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 		/*
4997c478bd9Sstevel@tonic-gate 		 * Now lets advance to the next descriptor block
5007c478bd9Sstevel@tonic-gate 		 * and validate it.
5017c478bd9Sstevel@tonic-gate 		 * the descriptor block size is <descr Header> + <descr Data>
5027c478bd9Sstevel@tonic-gate 		 * <descr Header> is equal to 4 bytes
5037c478bd9Sstevel@tonic-gate 		 * <descr Data> is available in dlen or dblk[3].
5047c478bd9Sstevel@tonic-gate 		 */
5057c478bd9Sstevel@tonic-gate 		dblk = &dblk[4 + dlen];
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 		/*
5087c478bd9Sstevel@tonic-gate 		 * update the covered_desc_len so that we can ensure that
5097c478bd9Sstevel@tonic-gate 		 * the 'while' loop terminates.
5107c478bd9Sstevel@tonic-gate 		 */
5117c478bd9Sstevel@tonic-gate 		covered_desc_len += (dlen + 4);
5127c478bd9Sstevel@tonic-gate 	}
5137c478bd9Sstevel@tonic-gate 	return (DEVID_RET_VALID);
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate /*
5187c478bd9Sstevel@tonic-gate  *    Function: is_initialized_id
5197c478bd9Sstevel@tonic-gate  *
5207c478bd9Sstevel@tonic-gate  * Description: Routine to ensure that the ID calculated is not a
5217c478bd9Sstevel@tonic-gate  *		space or zero filled ID. Returning a space / zero
5227c478bd9Sstevel@tonic-gate  *		filled ID when the luns on the target are not fully
5237c478bd9Sstevel@tonic-gate  *		initialized is a valid response from the target as
5247c478bd9Sstevel@tonic-gate  *		per the T10 spec. When a space/zero filled ID is
5257c478bd9Sstevel@tonic-gate  *		found its information needs to be polled again
5267c478bd9Sstevel@tonic-gate  *		after sometime time to see if the luns are fully
5277c478bd9Sstevel@tonic-gate  *		initialized to return a valid guid information.
5287c478bd9Sstevel@tonic-gate  *
5297c478bd9Sstevel@tonic-gate  *   Arguments: id - raw id
5307c478bd9Sstevel@tonic-gate  *              id_len - raw id len
5317c478bd9Sstevel@tonic-gate  *
5327c478bd9Sstevel@tonic-gate  * Return Code:	DEVID_VALID - indicates a non space/zero filled id
5337c478bd9Sstevel@tonic-gate  *		DEVID_INVALID - indicates id contains uninitialized data
5347c478bd9Sstevel@tonic-gate  *		and suggests retry of the collection commands.
5357c478bd9Sstevel@tonic-gate  */
5367c478bd9Sstevel@tonic-gate static int
5377c478bd9Sstevel@tonic-gate is_initialized_id(uchar_t *id, size_t id_len)
5387c478bd9Sstevel@tonic-gate {
5397c478bd9Sstevel@tonic-gate 	int idx;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	if ((id == NULL) ||
5427c478bd9Sstevel@tonic-gate 	    (id_len == 0)) {
5437c478bd9Sstevel@tonic-gate 		/* got id length as 0 fetch info again */
5447c478bd9Sstevel@tonic-gate 		return (DEVID_RET_INVALID);
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	/* First lets check if the guid is filled with spaces */
5487c478bd9Sstevel@tonic-gate 	for (idx = 0; idx < id_len; idx++) {
5497c478bd9Sstevel@tonic-gate 		if (id[idx] != ' ') {
5507c478bd9Sstevel@tonic-gate 			break;
5517c478bd9Sstevel@tonic-gate 		}
5527c478bd9Sstevel@tonic-gate 	}
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	/*
5557c478bd9Sstevel@tonic-gate 	 * Lets exit if we find that it contains ALL spaces
5567c478bd9Sstevel@tonic-gate 	 * saying that it has an uninitialized guid
5577c478bd9Sstevel@tonic-gate 	 */
5587c478bd9Sstevel@tonic-gate 	if (idx >= id_len) {
5597c478bd9Sstevel@tonic-gate 		/* guid filled with spaces found */
5607c478bd9Sstevel@tonic-gate 		return (DEVID_RET_INVALID);
5617c478bd9Sstevel@tonic-gate 	}
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	/*
5647c478bd9Sstevel@tonic-gate 	 * Since we have found that it is not filled with spaces
5657c478bd9Sstevel@tonic-gate 	 * now lets ensure that the guid is not filled with only
5667c478bd9Sstevel@tonic-gate 	 * zeros.
5677c478bd9Sstevel@tonic-gate 	 */
5687c478bd9Sstevel@tonic-gate 	for (idx = 0; idx < id_len; idx ++) {
5697c478bd9Sstevel@tonic-gate 		if (id[idx] != 0) {
5707c478bd9Sstevel@tonic-gate 			return (DEVID_RET_VALID);
5717c478bd9Sstevel@tonic-gate 		}
5727c478bd9Sstevel@tonic-gate 	}
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	/* guid filled with zeros found */
5757c478bd9Sstevel@tonic-gate 	return (DEVID_RET_INVALID);
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate /*
5807c478bd9Sstevel@tonic-gate  *    Function: is_page80_data_valid
5817c478bd9Sstevel@tonic-gate  *
5827c478bd9Sstevel@tonic-gate  * Description: This routine is used to validate the page 0x80 data
5837c478bd9Sstevel@tonic-gate  *		passed in valid based on the standards specification.
5847c478bd9Sstevel@tonic-gate  *
5857c478bd9Sstevel@tonic-gate  *   Arguments: inq80 -
5867c478bd9Sstevel@tonic-gate  *		inq80_len -
5877c478bd9Sstevel@tonic-gate  *
5887c478bd9Sstevel@tonic-gate  * Return Code: DEVID_RET_VALID
5897c478bd9Sstevel@tonic-gate  *              DEVID_RET_INVALID
5907c478bd9Sstevel@tonic-gate  *
5917c478bd9Sstevel@tonic-gate  */
5927c478bd9Sstevel@tonic-gate /* ARGSUSED */
5937c478bd9Sstevel@tonic-gate static int
5947c478bd9Sstevel@tonic-gate is_page80_data_valid(uchar_t *inq80, size_t inq80_len)
5957c478bd9Sstevel@tonic-gate {
5967c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(inq80);
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	/* if not large enough fail */
5997c478bd9Sstevel@tonic-gate 	if (inq80_len < SCMD_MIN_INQUIRY_PAGE80_SIZE) {
6007c478bd9Sstevel@tonic-gate 		return (DEVID_RET_INVALID);
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	/*
6047c478bd9Sstevel@tonic-gate 	 * (inq80_len - 4) is the size of the buffer space available
6057c478bd9Sstevel@tonic-gate 	 * for the product serial number.  So inq80[3] (ie. product
6067c478bd9Sstevel@tonic-gate 	 * serial number) should be <= (inq80_len -4).
6077c478bd9Sstevel@tonic-gate 	 */
6087c478bd9Sstevel@tonic-gate 	if (inq80[3] > (inq80_len - 4)) {
6097c478bd9Sstevel@tonic-gate 		return (DEVID_RET_INVALID);
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	return (DEVID_RET_VALID);
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate /*
6177c478bd9Sstevel@tonic-gate  *    Function: encode_devid_page
6187c478bd9Sstevel@tonic-gate  *
6197c478bd9Sstevel@tonic-gate  * Description: This routine finds the unique devid if available and
6207c478bd9Sstevel@tonic-gate  *		fills the devid and length parameters.
6217c478bd9Sstevel@tonic-gate  *
6227c478bd9Sstevel@tonic-gate  *   Arguments: version - encode version
6237c478bd9Sstevel@tonic-gate  *		inq83 - driver soft state (unit) structure
6247c478bd9Sstevel@tonic-gate  *		inq83_len - length of raw inq83 data
6257c478bd9Sstevel@tonic-gate  *		id - raw id
6267c478bd9Sstevel@tonic-gate  *		id_len - len of raw id
6277c478bd9Sstevel@tonic-gate  *		id_type - type of id
6287c478bd9Sstevel@tonic-gate  *
6297c478bd9Sstevel@tonic-gate  *        Note: DEVID_NONE is returned in the id_type field
6307c478bd9Sstevel@tonic-gate  *		if no supported page 83 id is found.
6317c478bd9Sstevel@tonic-gate  */
6327c478bd9Sstevel@tonic-gate static void
6337c478bd9Sstevel@tonic-gate encode_scsi3_page83(int version, uchar_t *inq83, size_t inq83_len,
6347c478bd9Sstevel@tonic-gate     uchar_t **id, size_t *id_len, ushort_t *id_type)
6357c478bd9Sstevel@tonic-gate {
6367c478bd9Sstevel@tonic-gate 	size_t	descriptor_bytes_left   = 0;
6377c478bd9Sstevel@tonic-gate 	size_t	offset			= 0;
6387c478bd9Sstevel@tonic-gate 	int	idx			= 0;
6397c478bd9Sstevel@tonic-gate 	size_t	offset_id_type[4];
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(inq83 != NULL);
6427c478bd9Sstevel@tonic-gate 	/* inq83 length was already validate in is_page83_valid */
6437c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(id != NULL);
6447c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(id_len != NULL);
6457c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(id_type != NULL);
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	/* preset defaults */
6487c478bd9Sstevel@tonic-gate 	*id = NULL;
6497c478bd9Sstevel@tonic-gate 	*id_len = 0;
6507c478bd9Sstevel@tonic-gate 	*id_type = DEVID_NONE;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	/* verify we have enough memory for a ident header */
6537c478bd9Sstevel@tonic-gate 	if (inq83_len < SCMD_INQUIRY_PAGE83_HDR_SIZE) {
6547c478bd9Sstevel@tonic-gate 		return;
6557c478bd9Sstevel@tonic-gate 	}
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	/*
6587c478bd9Sstevel@tonic-gate 	 * Attempt to validate the page data.  Once validated, we'll walk
6597c478bd9Sstevel@tonic-gate 	 * the descriptors, looking for certain identifier types that will
6607c478bd9Sstevel@tonic-gate 	 * mark this device with a unique id/wwn.  Note the comment below
6617c478bd9Sstevel@tonic-gate 	 * for what we really want to receive.
6627c478bd9Sstevel@tonic-gate 	 */
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	/*
6657c478bd9Sstevel@tonic-gate 	 * The format of the inq83 data (Device Identification VPD page) is
6667c478bd9Sstevel@tonic-gate 	 * a header (containing the total length of the page, from which
6677c478bd9Sstevel@tonic-gate 	 * descriptor_bytes_left is calculated), followed by a list of
6687c478bd9Sstevel@tonic-gate 	 * identification descriptors. Each identifcation descriptor has a
6697c478bd9Sstevel@tonic-gate 	 * header which includes the length of the individual identification
6707c478bd9Sstevel@tonic-gate 	 * descriptor).
6717c478bd9Sstevel@tonic-gate 	 *
6727c478bd9Sstevel@tonic-gate 	 * Set the offset to the beginning byte of the first identification
6737c478bd9Sstevel@tonic-gate 	 * descriptor.  We'll index everything from there.
6747c478bd9Sstevel@tonic-gate 	 */
6757c478bd9Sstevel@tonic-gate 	offset = SCMD_INQUIRY_PAGE83_HDR_SIZE;
6767c478bd9Sstevel@tonic-gate 	descriptor_bytes_left = (size_t)((inq83[2] << 8) | inq83[3]);
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	/*
6797c478bd9Sstevel@tonic-gate 	 * If the raw data states that the data is larger
6807c478bd9Sstevel@tonic-gate 	 * than what is actually received abort encode.
6817c478bd9Sstevel@tonic-gate 	 * Otherwise we will run off into unknown memory
6827c478bd9Sstevel@tonic-gate 	 * on the decode.
6837c478bd9Sstevel@tonic-gate 	 */
6847c478bd9Sstevel@tonic-gate 	if ((descriptor_bytes_left + offset) > inq83_len) {
6857c478bd9Sstevel@tonic-gate 		return;
6867c478bd9Sstevel@tonic-gate 	}
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	/* Zero out our offset array */
6907c478bd9Sstevel@tonic-gate 	bzero(offset_id_type, sizeof (offset_id_type));
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	/*
6937c478bd9Sstevel@tonic-gate 	 * According to the scsi spec 8.4.3 SPC-2, there could be several
6947c478bd9Sstevel@tonic-gate 	 * descriptors associated with each lun.  Some we care about and some
6957c478bd9Sstevel@tonic-gate 	 * we don't.  This loop is set up to iterate through the descriptors.
6967c478bd9Sstevel@tonic-gate 	 * We want the 0x03 case which represents an FC-PH, FC-PH3 or FC-FS
6977c478bd9Sstevel@tonic-gate 	 * Name_Identifier.  The spec mentions nothing about ordering, so we
6987c478bd9Sstevel@tonic-gate 	 * don't assume any.
6997c478bd9Sstevel@tonic-gate 	 *
7007c478bd9Sstevel@tonic-gate 	 * We need to check if we've finished walking the list of descriptors,
7017c478bd9Sstevel@tonic-gate 	 * we also perform additional checks to be sure the newly calculated
7027c478bd9Sstevel@tonic-gate 	 * offset is within the bounds of the buffer, and the identifier length
7037c478bd9Sstevel@tonic-gate 	 * (as calculated by the length field in the header) is valid. This is
7047c478bd9Sstevel@tonic-gate 	 * done to protect against devices which return bad page83 data.
7057c478bd9Sstevel@tonic-gate 	 */
7067c478bd9Sstevel@tonic-gate 	while ((descriptor_bytes_left > 0) && (offset_id_type[3] == 0) &&
7077c478bd9Sstevel@tonic-gate 	    (offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE <= inq83_len) &&
7087c478bd9Sstevel@tonic-gate 	    (offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE +
7097c478bd9Sstevel@tonic-gate 	    (size_t)inq83[offset + 3] <= inq83_len)) {
7107c478bd9Sstevel@tonic-gate 		/*
7117c478bd9Sstevel@tonic-gate 		 * Inspect the Identification descriptor list. Store the
7127c478bd9Sstevel@tonic-gate 		 * offsets in the devid page separately for 0x03, 0x01 and
7137c478bd9Sstevel@tonic-gate 		 * 0x02.  Identifiers 0x00 and 0x04 are not useful as they
7147c478bd9Sstevel@tonic-gate 		 * don't represent unique identifiers for a lun.  We also
7157c478bd9Sstevel@tonic-gate 		 * check the association by masking with 0x3f because we want
7167c478bd9Sstevel@tonic-gate 		 * an association of 0x0 - indicating the identifier field is
7177c478bd9Sstevel@tonic-gate 		 * associated with the addressed physical or logical device
7187c478bd9Sstevel@tonic-gate 		 * and not the port.
7197c478bd9Sstevel@tonic-gate 		 */
7207c478bd9Sstevel@tonic-gate 		switch ((inq83[offset + 1] & 0x3f)) {
7217c478bd9Sstevel@tonic-gate 		case SCMD_INQUIRY_VPD_TYPE_T10:
7227c478bd9Sstevel@tonic-gate 			offset_id_type[SCMD_INQUIRY_VPD_TYPE_T10] = offset;
7237c478bd9Sstevel@tonic-gate 			break;
7247c478bd9Sstevel@tonic-gate 		case SCMD_INQUIRY_VPD_TYPE_EUI:
7257c478bd9Sstevel@tonic-gate 			offset_id_type[SCMD_INQUIRY_VPD_TYPE_EUI] = offset;
7267c478bd9Sstevel@tonic-gate 			break;
7277c478bd9Sstevel@tonic-gate 		case SCMD_INQUIRY_VPD_TYPE_NAA:
7287c478bd9Sstevel@tonic-gate 			offset_id_type[SCMD_INQUIRY_VPD_TYPE_NAA] = offset;
7297c478bd9Sstevel@tonic-gate 			break;
7307c478bd9Sstevel@tonic-gate 		default:
7317c478bd9Sstevel@tonic-gate 			/* Devid page undesired id type */
7327c478bd9Sstevel@tonic-gate 			break;
7337c478bd9Sstevel@tonic-gate 		}
7347c478bd9Sstevel@tonic-gate 		/*
7357c478bd9Sstevel@tonic-gate 		 * Calculate the descriptor bytes left and move to
7367c478bd9Sstevel@tonic-gate 		 * the beginning byte of the next id descriptor.
7377c478bd9Sstevel@tonic-gate 		 */
7387c478bd9Sstevel@tonic-gate 		descriptor_bytes_left -= (size_t)(inq83[offset + 3] +
7397c478bd9Sstevel@tonic-gate 		    SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE);
7407c478bd9Sstevel@tonic-gate 		offset += (SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE +
7417c478bd9Sstevel@tonic-gate 		    (size_t)inq83[offset + 3]);
7427c478bd9Sstevel@tonic-gate 	}
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	offset = 0;
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	/*
7477c478bd9Sstevel@tonic-gate 	 * We can't depend on an order from a device by identifier type, but
7487c478bd9Sstevel@tonic-gate 	 * once we have them, we'll walk them in the same order to prevent a
7497c478bd9Sstevel@tonic-gate 	 * firmware upgrade from breaking our algorithm.  Start with the one
7507c478bd9Sstevel@tonic-gate 	 * we want the most: id_offset_type[3].
7517c478bd9Sstevel@tonic-gate 	 */
7527c478bd9Sstevel@tonic-gate 	for (idx = 3; idx > 0; idx--) {
7537c478bd9Sstevel@tonic-gate 		if (offset_id_type[idx] > 0) {
7547c478bd9Sstevel@tonic-gate 			offset = offset_id_type[idx];
7557c478bd9Sstevel@tonic-gate 			break;
7567c478bd9Sstevel@tonic-gate 		}
7577c478bd9Sstevel@tonic-gate 	}
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	/*
7607c478bd9Sstevel@tonic-gate 	 * We have a valid Device ID page, set the length of the
7617c478bd9Sstevel@tonic-gate 	 * identifier and copy the value into the wwn.
7627c478bd9Sstevel@tonic-gate 	 */
7637c478bd9Sstevel@tonic-gate 	if (offset > 0) {
7647c478bd9Sstevel@tonic-gate 		*id_len = (size_t)inq83[offset + 3];
7657c478bd9Sstevel@tonic-gate 		if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
7667c478bd9Sstevel@tonic-gate 			*id_len = 0;
7677c478bd9Sstevel@tonic-gate 			return;
7687c478bd9Sstevel@tonic-gate 		}
7697c478bd9Sstevel@tonic-gate 		bcopy(&inq83[offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE],
7707c478bd9Sstevel@tonic-gate 		    *id, *id_len);
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 		/* set devid type */
7737c478bd9Sstevel@tonic-gate 		switch (version) {
7747c478bd9Sstevel@tonic-gate 		/* In version 1 all page 83 types were grouped */
7757c478bd9Sstevel@tonic-gate 		case DEVID_SCSI_ENCODE_VERSION1:
7767c478bd9Sstevel@tonic-gate 			*id_type = DEVID_SCSI3_WWN;
7777c478bd9Sstevel@tonic-gate 			break;
7787c478bd9Sstevel@tonic-gate 		/* In version 2 we break page 83 apart to be unique */
7797c478bd9Sstevel@tonic-gate 		case DEVID_SCSI_ENCODE_VERSION2:
7807c478bd9Sstevel@tonic-gate 			switch (idx) {
7817c478bd9Sstevel@tonic-gate 			case 3:
7827c478bd9Sstevel@tonic-gate 				*id_type = DEVID_SCSI3_VPD_NAA;
7837c478bd9Sstevel@tonic-gate 				break;
7847c478bd9Sstevel@tonic-gate 			case 2:
7857c478bd9Sstevel@tonic-gate 				*id_type = DEVID_SCSI3_VPD_EUI;
7867c478bd9Sstevel@tonic-gate 				break;
7877c478bd9Sstevel@tonic-gate 			case 1:
7887c478bd9Sstevel@tonic-gate 				*id_type = DEVID_SCSI3_VPD_T10;
7897c478bd9Sstevel@tonic-gate 				break;
7907c478bd9Sstevel@tonic-gate 			default:
7917c478bd9Sstevel@tonic-gate 				DEVID_FREE(*id, *id_len);
7927c478bd9Sstevel@tonic-gate 				*id_len = 0;
7937c478bd9Sstevel@tonic-gate 				break;
7947c478bd9Sstevel@tonic-gate 			}
7957c478bd9Sstevel@tonic-gate 			break;
7967c478bd9Sstevel@tonic-gate 		default:
7977c478bd9Sstevel@tonic-gate 			DEVID_FREE(*id, *id_len);
7987c478bd9Sstevel@tonic-gate 			*id_len = 0;
7997c478bd9Sstevel@tonic-gate 			break;
8007c478bd9Sstevel@tonic-gate 		}
8017c478bd9Sstevel@tonic-gate 	}
8027c478bd9Sstevel@tonic-gate }
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate /*
8067c478bd9Sstevel@tonic-gate  *    Function: encode_scsi3_page83_emc
8077c478bd9Sstevel@tonic-gate  *
8087c478bd9Sstevel@tonic-gate  * Description: Routine to handle proprietary page 83 of EMC Symmetrix
8097c478bd9Sstevel@tonic-gate  *              device. Called by ssfcp_handle_page83()
8107c478bd9Sstevel@tonic-gate  *
8117c478bd9Sstevel@tonic-gate  *   Arguments: version - encode version
8127c478bd9Sstevel@tonic-gate  *		inq83 - scsi page 83 buffer
8137c478bd9Sstevel@tonic-gate  *		inq83_len - scsi page 83 buffer size
8147c478bd9Sstevel@tonic-gate  *		id - raw emc id
8157c478bd9Sstevel@tonic-gate  *		id_len - len of raw emc id
8167c478bd9Sstevel@tonic-gate  *		id_type - type of emc id
8177c478bd9Sstevel@tonic-gate  */
8187c478bd9Sstevel@tonic-gate static void
8197c478bd9Sstevel@tonic-gate encode_scsi3_page83_emc(int version, uchar_t *inq83,
8207c478bd9Sstevel@tonic-gate     size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type)
8217c478bd9Sstevel@tonic-gate {
8227c478bd9Sstevel@tonic-gate 	uchar_t	*guidp	= NULL;
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(inq83 != NULL);
8257c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(id != NULL);
8267c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(id_len != NULL);
8277c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(id_type != NULL);
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	/* preset defaults */
8307c478bd9Sstevel@tonic-gate 	*id = NULL;
8317c478bd9Sstevel@tonic-gate 	*id_len = 0;
8327c478bd9Sstevel@tonic-gate 	*id_type = DEVID_NONE;
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	/* The initial devid algorithm didn't use EMC page 83 data */
8357c478bd9Sstevel@tonic-gate 	if (version == DEVID_SCSI_ENCODE_VERSION1) {
8367c478bd9Sstevel@tonic-gate 		return;
8377c478bd9Sstevel@tonic-gate 	}
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	/* EMC page 83 requires atleast 20 bytes */
8407c478bd9Sstevel@tonic-gate 	if (inq83_len < (SCMD_INQUIRY_PAGE83_HDR_SIZE +
8417c478bd9Sstevel@tonic-gate 	    SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN)) {
8427c478bd9Sstevel@tonic-gate 		return;
8437c478bd9Sstevel@tonic-gate 	}
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	/*
8467c478bd9Sstevel@tonic-gate 	 * The 4th byte in the page 83 info returned is most likely
8477c478bd9Sstevel@tonic-gate 	 * indicating the length of the id - which 0x10(16 bytes)
8487c478bd9Sstevel@tonic-gate 	 * and the 5th byte is indicating that the id is of
8497c478bd9Sstevel@tonic-gate 	 * IEEE Registered Extended Name format(6). Validate
8507c478bd9Sstevel@tonic-gate 	 * these code prints before proceeding further as the
8517c478bd9Sstevel@tonic-gate 	 * following proprietary approach is tied to the specific
8527c478bd9Sstevel@tonic-gate 	 * device type and incase the EMC firmware changes, we will
8537c478bd9Sstevel@tonic-gate 	 * have to validate for the changed device before we start
8547c478bd9Sstevel@tonic-gate 	 * supporting such a device.
8557c478bd9Sstevel@tonic-gate 	 */
8567c478bd9Sstevel@tonic-gate 	if ((inq83[3] != 0x10) || (inq83[4] != 0x60)) {
8577c478bd9Sstevel@tonic-gate 		/* unsupported emc symtx device type */
8587c478bd9Sstevel@tonic-gate 		return;
8597c478bd9Sstevel@tonic-gate 	} else {
8607c478bd9Sstevel@tonic-gate 		guidp = &inq83[SCMD_INQUIRY_PAGE83_HDR_SIZE];
8617c478bd9Sstevel@tonic-gate 		/*
8627c478bd9Sstevel@tonic-gate 		 * The GUID returned by the EMC device is
8637c478bd9Sstevel@tonic-gate 		 * in the IEEE Registered Extended Name format(6)
8647c478bd9Sstevel@tonic-gate 		 * as a result it is of 16 bytes in length.
8657c478bd9Sstevel@tonic-gate 		 * An IEEE Registered Name format(5) will be of
8667c478bd9Sstevel@tonic-gate 		 * 8 bytes which is NOT what is being returned
8677c478bd9Sstevel@tonic-gate 		 * by the device type for which we are providing
8687c478bd9Sstevel@tonic-gate 		 * the support.
8697c478bd9Sstevel@tonic-gate 		 */
8707c478bd9Sstevel@tonic-gate 		*id_len = SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN;
8717c478bd9Sstevel@tonic-gate 		if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
8727c478bd9Sstevel@tonic-gate 			*id_len = 0;
8737c478bd9Sstevel@tonic-gate 			return;
8747c478bd9Sstevel@tonic-gate 		}
8757c478bd9Sstevel@tonic-gate 		bcopy(guidp, *id, *id_len);
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 		/* emc id matches type 3 */
8787c478bd9Sstevel@tonic-gate 		*id_type = DEVID_SCSI3_VPD_NAA;
8797c478bd9Sstevel@tonic-gate 	}
8807c478bd9Sstevel@tonic-gate }
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate /*
8847c478bd9Sstevel@tonic-gate  *    Function: encode_serialnum
8857c478bd9Sstevel@tonic-gate  *
8867c478bd9Sstevel@tonic-gate  * Description: This routine finds the unique devid from the inquiry page
8877c478bd9Sstevel@tonic-gate  *		0x80, serial number page.  If available and fills the wwn
8887c478bd9Sstevel@tonic-gate  *		and length parameters.
8897c478bd9Sstevel@tonic-gate  *
8907c478bd9Sstevel@tonic-gate  *   Arguments: version - encode version
8917c478bd9Sstevel@tonic-gate  *		inq - standard inquiry data
8927c478bd9Sstevel@tonic-gate  *		inq80 - serial inquiry data
8937c478bd9Sstevel@tonic-gate  *		inq80_len - serial inquiry data len
8947c478bd9Sstevel@tonic-gate  *		id - raw id
8957c478bd9Sstevel@tonic-gate  *		id_len - raw id len
8967c478bd9Sstevel@tonic-gate  *		id_type - raw id type
8977c478bd9Sstevel@tonic-gate  */
8987c478bd9Sstevel@tonic-gate /* ARGSUSED */
8997c478bd9Sstevel@tonic-gate static void
9007c478bd9Sstevel@tonic-gate encode_serialnum(int version, uchar_t *inq, uchar_t *inq80,
9017c478bd9Sstevel@tonic-gate     size_t inq80_len, uchar_t **id, size_t *id_len, ushort_t *id_type)
9027c478bd9Sstevel@tonic-gate {
9037c478bd9Sstevel@tonic-gate 	struct scsi_inquiry	*inq_std	= (struct scsi_inquiry *)inq;
9047c478bd9Sstevel@tonic-gate 	int			idx		= 0;
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(inq != NULL);
9077c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(inq80 != NULL);
9087c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(id != NULL);
9097c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(id_len != NULL);
9107c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(id_type != NULL);
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	/* preset defaults */
9137c478bd9Sstevel@tonic-gate 	*id = NULL;
9147c478bd9Sstevel@tonic-gate 	*id_len = 0;
9157c478bd9Sstevel@tonic-gate 	*id_type = DEVID_NONE;
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	/* verify inq80 buffer is large enough for a header */
9187c478bd9Sstevel@tonic-gate 	if (inq80_len < SCMD_MIN_INQUIRY_PAGE80_SIZE) {
9197c478bd9Sstevel@tonic-gate 		return;
9207c478bd9Sstevel@tonic-gate 	}
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	/*
9237c478bd9Sstevel@tonic-gate 	 * Attempt to validate the page data.  Once validated, we'll check
9247c478bd9Sstevel@tonic-gate 	 * the serial number.
9257c478bd9Sstevel@tonic-gate 	 */
9267c478bd9Sstevel@tonic-gate 	*id_len = (size_t)inq80[3]; /* Store Product Serial Number length */
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	/* verify buffer is large enough for serial number */
9297c478bd9Sstevel@tonic-gate 	if (inq80_len < (*id_len + SCMD_MIN_INQUIRY_PAGE80_SIZE)) {
9307c478bd9Sstevel@tonic-gate 		return;
9317c478bd9Sstevel@tonic-gate 	}
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	/*
9347c478bd9Sstevel@tonic-gate 	 * Device returns ASCII space (20h) in all the bytes of successful data
9357c478bd9Sstevel@tonic-gate 	 * transfer, if the product serial number is not available.  So we end
9367c478bd9Sstevel@tonic-gate 	 * up having to check all the bytes for a space until we reach
9377c478bd9Sstevel@tonic-gate 	 * something else.
9387c478bd9Sstevel@tonic-gate 	 */
9397c478bd9Sstevel@tonic-gate 	for (idx = 0; idx < *id_len; idx++) {
9407c478bd9Sstevel@tonic-gate 		if (inq80[4 + idx] == ' ') {
9417c478bd9Sstevel@tonic-gate 			continue;
9427c478bd9Sstevel@tonic-gate 		}
9437c478bd9Sstevel@tonic-gate 		/*
9447c478bd9Sstevel@tonic-gate 		 * The serial number is valid, but since this is only vendor
9457c478bd9Sstevel@tonic-gate 		 * unique, we'll combine the inquiry vid and pid with the
9467c478bd9Sstevel@tonic-gate 		 * serial number.
9477c478bd9Sstevel@tonic-gate 		 */
9487c478bd9Sstevel@tonic-gate 		*id_len += sizeof (inq_std->inq_vid);
9497c478bd9Sstevel@tonic-gate 		*id_len += sizeof (inq_std->inq_pid);
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 		if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
9527c478bd9Sstevel@tonic-gate 			*id_len = 0;
9537c478bd9Sstevel@tonic-gate 			return;
9547c478bd9Sstevel@tonic-gate 		}
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 		bcopy(&inq_std->inq_vid, *id, sizeof (inq_std->inq_vid));
9577c478bd9Sstevel@tonic-gate 		bcopy(&inq_std->inq_pid, &(*id)[sizeof (inq_std->inq_vid)],
9587c478bd9Sstevel@tonic-gate 		    sizeof (inq_std->inq_pid));
9597c478bd9Sstevel@tonic-gate 		bcopy(&inq80[4], &(*id)[sizeof (inq_std->inq_vid) +
9607c478bd9Sstevel@tonic-gate 		    sizeof (inq_std->inq_pid)], inq80[3]);
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 		*id_type = DEVID_SCSI_SERIAL;
9637c478bd9Sstevel@tonic-gate 		break;
9647c478bd9Sstevel@tonic-gate 	}
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	/*
9677c478bd9Sstevel@tonic-gate 	 * The spec suggests that the command could succeed but return all
9687c478bd9Sstevel@tonic-gate 	 * spaces if the product serial number is not available.  In this case
9697c478bd9Sstevel@tonic-gate 	 * we need to fail this routine. To accomplish this, we compare our
9707c478bd9Sstevel@tonic-gate 	 * length to the serial number length. If they are the same, then we
9717c478bd9Sstevel@tonic-gate 	 * never copied in the vid and updated the length. That being the case,
9727c478bd9Sstevel@tonic-gate 	 * we must not have found a valid serial number.
9737c478bd9Sstevel@tonic-gate 	 */
9747c478bd9Sstevel@tonic-gate 	if (*id_len == (size_t)inq80[3]) {
9757c478bd9Sstevel@tonic-gate 		/* empty unit serial number */
976f5689c9eSbg159949 		if (*id != NULL) {
9777c478bd9Sstevel@tonic-gate 			DEVID_FREE(*id, *id_len);
978f5689c9eSbg159949 		}
9797c478bd9Sstevel@tonic-gate 		*id = NULL;
9807c478bd9Sstevel@tonic-gate 		*id_len = 0;
9817c478bd9Sstevel@tonic-gate 	}
9827c478bd9Sstevel@tonic-gate }
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate /*
9867c478bd9Sstevel@tonic-gate  *    Function: encode_sun_serialnum
9877c478bd9Sstevel@tonic-gate  *
9887c478bd9Sstevel@tonic-gate  * Description: This routine finds the unique devid from the inquiry page
9897c478bd9Sstevel@tonic-gate  *		0x80, serial number page.  If available and fills the wwn
9907c478bd9Sstevel@tonic-gate  *		and length parameters.
9917c478bd9Sstevel@tonic-gate  *
9927c478bd9Sstevel@tonic-gate  *   Arguments: version - encode version
9937c478bd9Sstevel@tonic-gate  *		inq - standard inquiry data
9947c478bd9Sstevel@tonic-gate  *		inq_len - standard inquiry data len
9957c478bd9Sstevel@tonic-gate  *		id - raw id
9967c478bd9Sstevel@tonic-gate  *		id_len - raw id len
9977c478bd9Sstevel@tonic-gate  *		id_type - raw id type
9987c478bd9Sstevel@tonic-gate  *
9997c478bd9Sstevel@tonic-gate  * Return Code: DEVID_SUCCESS
10007c478bd9Sstevel@tonic-gate  *              DEVID_FAILURE
10017c478bd9Sstevel@tonic-gate  */
10027c478bd9Sstevel@tonic-gate /* ARGSUSED */
10037c478bd9Sstevel@tonic-gate static void
10047c478bd9Sstevel@tonic-gate encode_sun_serialnum(int version, uchar_t *inq,
10057c478bd9Sstevel@tonic-gate     size_t inq_len, uchar_t **id, size_t *id_len, ushort_t *id_type)
10067c478bd9Sstevel@tonic-gate {
10077c478bd9Sstevel@tonic-gate 	struct scsi_inquiry *inq_std = (struct scsi_inquiry *)inq;
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(inq != NULL);
10107c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(id != NULL);
10117c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(id_len != NULL);
10127c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(id_type != NULL);
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 	/* verify enough buffer is available */
10157c478bd9Sstevel@tonic-gate 	if (inq_len < SCMD_MIN_STANDARD_INQUIRY_SIZE) {
10167c478bd9Sstevel@tonic-gate 		return;
10177c478bd9Sstevel@tonic-gate 	}
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 	/* sun qual drive */
10207c478bd9Sstevel@tonic-gate 	if ((inq_std != NULL) &&
10217c478bd9Sstevel@tonic-gate 	    (bcmp(&inq_std->inq_pid[SCSI_INQUIRY_VID_POS],
10227c478bd9Sstevel@tonic-gate 	    SCSI_INQUIRY_VID_SUN, SCSI_INQUIRY_VID_SUN_LEN) == 0)) {
10237c478bd9Sstevel@tonic-gate 		/*
10247c478bd9Sstevel@tonic-gate 		 * VPD pages 0x83 and 0x80 are unavailable. This
10257c478bd9Sstevel@tonic-gate 		 * is a Sun qualified disks as indicated by
10267c478bd9Sstevel@tonic-gate 		 * "SUN" in bytes 25-27 of the inquiry data
10277c478bd9Sstevel@tonic-gate 		 * (bytes 9-11 of the pid).  Devid's are created
10287c478bd9Sstevel@tonic-gate 		 * for Sun qualified disks by combining the
10297c478bd9Sstevel@tonic-gate 		 * vendor id with the product id with the serial
10307c478bd9Sstevel@tonic-gate 		 * number located in bytes 36-47 of the inquiry data.
10317c478bd9Sstevel@tonic-gate 		 */
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 		/* get data size */
10347c478bd9Sstevel@tonic-gate 		*id_len = sizeof (inq_std->inq_vid) +
10357c478bd9Sstevel@tonic-gate 		    sizeof (inq_std->inq_pid) +
10367c478bd9Sstevel@tonic-gate 		    sizeof (inq_std->inq_serial);
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 		if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
10397c478bd9Sstevel@tonic-gate 			*id_len = 0;
10407c478bd9Sstevel@tonic-gate 			return;
10417c478bd9Sstevel@tonic-gate 		}
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate 		/* copy the vid at the beginning */
10447c478bd9Sstevel@tonic-gate 		bcopy(&inq_std->inq_vid, *id,
10457c478bd9Sstevel@tonic-gate 		    sizeof (inq_std->inq_vid));
10467c478bd9Sstevel@tonic-gate 			/* copy the pid after the vid */
10477c478bd9Sstevel@tonic-gate 		bcopy(&inq_std->inq_pid,
10487c478bd9Sstevel@tonic-gate 		    &(*id)[sizeof (inq_std->inq_vid)],
10497c478bd9Sstevel@tonic-gate 		    sizeof (inq_std->inq_pid));
10507c478bd9Sstevel@tonic-gate 			/* copy the serial number after the vid and pid */
10517c478bd9Sstevel@tonic-gate 		bcopy(&inq_std->inq_serial,
10527c478bd9Sstevel@tonic-gate 		    &(*id)[sizeof (inq_std->inq_vid) +
10537c478bd9Sstevel@tonic-gate 		    sizeof (inq_std->inq_pid)],
10547c478bd9Sstevel@tonic-gate 		    sizeof (inq_std->inq_serial));
10557c478bd9Sstevel@tonic-gate 			/* devid formed from inquiry data */
10567c478bd9Sstevel@tonic-gate 		*id_type = DEVID_SCSI_SERIAL;
10577c478bd9Sstevel@tonic-gate 	}
10587c478bd9Sstevel@tonic-gate }
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate /*
10627c478bd9Sstevel@tonic-gate  *    Function: devid_scsi_init
10637c478bd9Sstevel@tonic-gate  *
10647c478bd9Sstevel@tonic-gate  * Description: This routine is used to create a devid for a scsi
10657c478bd9Sstevel@tonic-gate  *		devid type.
10667c478bd9Sstevel@tonic-gate  *
10677c478bd9Sstevel@tonic-gate  *   Arguments: hint - driver soft state (unit) structure
10687c478bd9Sstevel@tonic-gate  *		raw_id - pass by reference variable to hold wwn
10697c478bd9Sstevel@tonic-gate  *		raw_id_len - wwn length
10707c478bd9Sstevel@tonic-gate  *		raw_id_type -
10717c478bd9Sstevel@tonic-gate  *		ret_devid -
10727c478bd9Sstevel@tonic-gate  *
10737c478bd9Sstevel@tonic-gate  * Return Code: DEVID_SUCCESS
10747c478bd9Sstevel@tonic-gate  *              DEVID_FAILURE
10757c478bd9Sstevel@tonic-gate  *
10767c478bd9Sstevel@tonic-gate  */
10777c478bd9Sstevel@tonic-gate static int
10787c478bd9Sstevel@tonic-gate devid_scsi_init(
10797c478bd9Sstevel@tonic-gate 	char		*driver_name,
10807c478bd9Sstevel@tonic-gate 	uchar_t		*raw_id,
10817c478bd9Sstevel@tonic-gate 	size_t		raw_id_len,
10827c478bd9Sstevel@tonic-gate 	ushort_t	raw_id_type,
10837c478bd9Sstevel@tonic-gate 	ddi_devid_t	*ret_devid)
10847c478bd9Sstevel@tonic-gate {
10857c478bd9Sstevel@tonic-gate 	impl_devid_t	*i_devid	= NULL;
10867c478bd9Sstevel@tonic-gate 	int		i_devid_len	= 0;
10877c478bd9Sstevel@tonic-gate 	int		driver_name_len	= 0;
10887c478bd9Sstevel@tonic-gate 	ushort_t	u_raw_id_len	= 0;
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(raw_id != NULL);
10917c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(ret_devid != NULL);
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 	if (!IS_DEVID_SCSI_TYPE(raw_id_type)) {
10947c478bd9Sstevel@tonic-gate 		*ret_devid = NULL;
10957c478bd9Sstevel@tonic-gate 		return (DEVID_FAILURE);
10967c478bd9Sstevel@tonic-gate 	}
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	i_devid_len = sizeof (*i_devid) + raw_id_len - sizeof (i_devid->did_id);
10997c478bd9Sstevel@tonic-gate 	if ((i_devid = DEVID_MALLOC(i_devid_len)) == NULL) {
11007c478bd9Sstevel@tonic-gate 		*ret_devid = NULL;
11017c478bd9Sstevel@tonic-gate 		return (DEVID_FAILURE);
11027c478bd9Sstevel@tonic-gate 	}
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	i_devid->did_magic_hi = DEVID_MAGIC_MSB;
11057c478bd9Sstevel@tonic-gate 	i_devid->did_magic_lo = DEVID_MAGIC_LSB;
11067c478bd9Sstevel@tonic-gate 	i_devid->did_rev_hi = DEVID_REV_MSB;
11077c478bd9Sstevel@tonic-gate 	i_devid->did_rev_lo = DEVID_REV_LSB;
11087c478bd9Sstevel@tonic-gate 	DEVID_FORMTYPE(i_devid, raw_id_type);
11097c478bd9Sstevel@tonic-gate 	u_raw_id_len = raw_id_len;
11107c478bd9Sstevel@tonic-gate 	DEVID_FORMLEN(i_devid, u_raw_id_len);
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 	/* Fill in driver name hint */
111399025f2eSsrivijitha dugganapalli 	bzero(i_devid->did_driver, DEVID_HINT_SIZE);
11147c478bd9Sstevel@tonic-gate 	if (driver_name != NULL) {
11157c478bd9Sstevel@tonic-gate 		driver_name_len = strlen(driver_name);
11167c478bd9Sstevel@tonic-gate 		if (driver_name_len > DEVID_HINT_SIZE) {
11177c478bd9Sstevel@tonic-gate 			/* Pick up last four characters of driver name */
11187c478bd9Sstevel@tonic-gate 			driver_name += driver_name_len - DEVID_HINT_SIZE;
11197c478bd9Sstevel@tonic-gate 			driver_name_len = DEVID_HINT_SIZE;
11207c478bd9Sstevel@tonic-gate 		}
11217c478bd9Sstevel@tonic-gate 		bcopy(driver_name, i_devid->did_driver, driver_name_len);
11227c478bd9Sstevel@tonic-gate 	}
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate 	bcopy(raw_id, i_devid->did_id, raw_id_len);
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	/* return device id */
11277c478bd9Sstevel@tonic-gate 	*ret_devid = (ddi_devid_t)i_devid;
11287c478bd9Sstevel@tonic-gate 	return (DEVID_SUCCESS);
11297c478bd9Sstevel@tonic-gate }
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate /*
11337c478bd9Sstevel@tonic-gate  *    Function: devid_to_guid
11347c478bd9Sstevel@tonic-gate  *
11357c478bd9Sstevel@tonic-gate  * Description: This routine extracts a guid string form a devid.
11367c478bd9Sstevel@tonic-gate  *		The common use of this guid is for a HBA driver
11377c478bd9Sstevel@tonic-gate  *		to pass into mdi_pi_alloc().
11387c478bd9Sstevel@tonic-gate  *
11397c478bd9Sstevel@tonic-gate  *   Arguments: devid - devid to extract guid from
11407c478bd9Sstevel@tonic-gate  *
11417c478bd9Sstevel@tonic-gate  * Return Code: guid string - success
11427c478bd9Sstevel@tonic-gate  *		NULL - failure
11437c478bd9Sstevel@tonic-gate  */
11447c478bd9Sstevel@tonic-gate char *
11457c478bd9Sstevel@tonic-gate #ifdef  _KERNEL
11467c478bd9Sstevel@tonic-gate ddi_devid_to_guid(ddi_devid_t devid)
11477c478bd9Sstevel@tonic-gate #else   /* !_KERNEL */
11487c478bd9Sstevel@tonic-gate devid_to_guid(ddi_devid_t devid)
11497c478bd9Sstevel@tonic-gate #endif  /* _KERNEL */
11507c478bd9Sstevel@tonic-gate {
11517c478bd9Sstevel@tonic-gate 	impl_devid_t	*id	= (impl_devid_t *)devid;
11527c478bd9Sstevel@tonic-gate 	int		len	= 0;
11537c478bd9Sstevel@tonic-gate 	int		idx	= 0;
11547c478bd9Sstevel@tonic-gate 	int		num	= 0;
11557c478bd9Sstevel@tonic-gate 	char		*guid	= NULL;
11567c478bd9Sstevel@tonic-gate 	char		*ptr	= NULL;
11577c478bd9Sstevel@tonic-gate 	char		*dp	= NULL;
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	DEVID_ASSERT(devid != NULL);
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	/* NULL devid -> NULL guid */
11627c478bd9Sstevel@tonic-gate 	if (devid == NULL)
11637c478bd9Sstevel@tonic-gate 		return (NULL);
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	if (!IS_DEVID_GUID_TYPE(DEVID_GETTYPE(id)))
11667c478bd9Sstevel@tonic-gate 		return (NULL);
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 	/* guid is always converted to ascii, append NULL */
11697c478bd9Sstevel@tonic-gate 	len = DEVID_GETLEN(id);
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 	/* allocate guid string */
11727c478bd9Sstevel@tonic-gate 	if ((guid = DEVID_MALLOC((len * 2) + 1)) == NULL)
11737c478bd9Sstevel@tonic-gate 		return (NULL);
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 	/* perform encode of id to hex string */
11767c478bd9Sstevel@tonic-gate 	ptr = guid;
11777c478bd9Sstevel@tonic-gate 	for (idx = 0, dp = &id->did_id[0]; idx < len; idx++, dp++) {
11787c478bd9Sstevel@tonic-gate 		num = ((*dp) >> 4) & 0xF;
11797c478bd9Sstevel@tonic-gate 		*ptr++ = (num < 10) ? (num + '0') : (num + ('a' - 10));
11807c478bd9Sstevel@tonic-gate 		num = (*dp) & 0xF;
11817c478bd9Sstevel@tonic-gate 		*ptr++ = (num < 10) ? (num + '0') : (num + ('a' - 10));
11827c478bd9Sstevel@tonic-gate 	}
11837c478bd9Sstevel@tonic-gate 	*ptr = 0;
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	return (guid);
11867c478bd9Sstevel@tonic-gate }
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate /*
11897c478bd9Sstevel@tonic-gate  *    Function: devid_free_guid
11907c478bd9Sstevel@tonic-gate  *
11917c478bd9Sstevel@tonic-gate  * Description: This routine frees a guid allocated by
11927c478bd9Sstevel@tonic-gate  *		devid_to_guid().
11937c478bd9Sstevel@tonic-gate  *
11947c478bd9Sstevel@tonic-gate  *   Arguments: guid - guid to free
11957c478bd9Sstevel@tonic-gate  */
11967c478bd9Sstevel@tonic-gate void
11977c478bd9Sstevel@tonic-gate #ifdef  _KERNEL
11987c478bd9Sstevel@tonic-gate ddi_devid_free_guid(char *guid)
11997c478bd9Sstevel@tonic-gate #else   /* !_KERNEL */
12007c478bd9Sstevel@tonic-gate devid_free_guid(char *guid)
12017c478bd9Sstevel@tonic-gate #endif  /* _KERNEL */
12027c478bd9Sstevel@tonic-gate {
12037c478bd9Sstevel@tonic-gate 	if (guid != NULL) {
12047c478bd9Sstevel@tonic-gate 		DEVID_FREE(guid, strlen(guid) + 1);
12057c478bd9Sstevel@tonic-gate 	}
12067c478bd9Sstevel@tonic-gate }
1207936b7af6Sjw149990 
1208936b7af6Sjw149990 static char
1209936b7af6Sjw149990 ctoi(char c)
1210936b7af6Sjw149990 {
1211936b7af6Sjw149990 	if ((c >= '0') && (c <= '9'))
1212936b7af6Sjw149990 		c -= '0';
1213936b7af6Sjw149990 	else if ((c >= 'A') && (c <= 'F'))
1214936b7af6Sjw149990 		c = c - 'A' + 10;
1215936b7af6Sjw149990 	else if ((c >= 'a') && (c <= 'f'))
1216936b7af6Sjw149990 		c = c - 'a' + 10;
1217936b7af6Sjw149990 	else
1218936b7af6Sjw149990 		c = -1;
1219936b7af6Sjw149990 	return (c);
1220936b7af6Sjw149990 }
1221936b7af6Sjw149990 
1222*ed141cfcSsrivijitha dugganapalli /* ====NOTE: The scsi_* interfaces are not related to devids :NOTE==== */
1223*ed141cfcSsrivijitha dugganapalli 
1224936b7af6Sjw149990 /*
1225*ed141cfcSsrivijitha dugganapalli  *    Function: scsi_wwnstr_to_wwn
1226936b7af6Sjw149990  *
1227*ed141cfcSsrivijitha dugganapalli  * Description: This routine translates wwn from wwnstr string to uint64 wwn.
1228936b7af6Sjw149990  *
1229*ed141cfcSsrivijitha dugganapalli  *   Arguments: wwnstr - the string wwn to be transformed
1230*ed141cfcSsrivijitha dugganapalli  *              wwnp - the pointer to 64 bit wwn
1231936b7af6Sjw149990  */
1232936b7af6Sjw149990 int
1233*ed141cfcSsrivijitha dugganapalli scsi_wwnstr_to_wwn(const char *wwnstr, uint64_t *wwnp)
1234936b7af6Sjw149990 {
1235936b7af6Sjw149990 	int		i;
1236936b7af6Sjw149990 	char		cl, ch;
1237936b7af6Sjw149990 	uint64_t	tmp;
1238936b7af6Sjw149990 
1239*ed141cfcSsrivijitha dugganapalli 	if (wwnp == NULL)
1240936b7af6Sjw149990 		return (DDI_FAILURE);
1241*ed141cfcSsrivijitha dugganapalli 	*wwnp = 0;
1242936b7af6Sjw149990 
1243*ed141cfcSsrivijitha dugganapalli 	if (wwnstr == NULL)
1244*ed141cfcSsrivijitha dugganapalli 		return (DDI_FAILURE);
1245*ed141cfcSsrivijitha dugganapalli 
1246*ed141cfcSsrivijitha dugganapalli 	/* Skip leading 'w' if wwnstr is in unit-address form */
1247*ed141cfcSsrivijitha dugganapalli 	if (*wwnstr == 'w')
1248*ed141cfcSsrivijitha dugganapalli 		wwnstr++;
1249*ed141cfcSsrivijitha dugganapalli 
1250*ed141cfcSsrivijitha dugganapalli 	if (strlen(wwnstr) != 16)
1251*ed141cfcSsrivijitha dugganapalli 		return (DDI_FAILURE);
1252*ed141cfcSsrivijitha dugganapalli 
1253936b7af6Sjw149990 	for (i = 0; i < 8; i++) {
1254*ed141cfcSsrivijitha dugganapalli 		ch = ctoi(*wwnstr++);
1255*ed141cfcSsrivijitha dugganapalli 		cl = ctoi(*wwnstr++);
1256936b7af6Sjw149990 		if (cl == -1 || ch == -1) {
1257936b7af6Sjw149990 			return (DDI_FAILURE);
1258936b7af6Sjw149990 		}
1259936b7af6Sjw149990 		tmp = (ch << 4) + cl;
1260*ed141cfcSsrivijitha dugganapalli 		*wwnp = (*wwnp << 8) | tmp;
1261936b7af6Sjw149990 	}
1262936b7af6Sjw149990 	return (DDI_SUCCESS);
1263936b7af6Sjw149990 }
1264*ed141cfcSsrivijitha dugganapalli 
1265*ed141cfcSsrivijitha dugganapalli /*
1266*ed141cfcSsrivijitha dugganapalli  *    Function: scsi_wwn_to_wwnstr
1267*ed141cfcSsrivijitha dugganapalli  *
1268*ed141cfcSsrivijitha dugganapalli  * Description: This routine translates from a uint64 wwn to a wwnstr
1269*ed141cfcSsrivijitha dugganapalli  *
1270*ed141cfcSsrivijitha dugganapalli  *   Arguments:
1271*ed141cfcSsrivijitha dugganapalli  *              wwn - the 64 bit wwn
1272*ed141cfcSsrivijitha dugganapalli  *		unit_address_form - do we want a leading 'w'?
1273*ed141cfcSsrivijitha dugganapalli  *		wwnstr - allow caller to perform wwnstr allocation.
1274*ed141cfcSsrivijitha dugganapalli  *			If non-NULL, don't use scsi_free_wwnstr(),
1275*ed141cfcSsrivijitha dugganapalli  *			and make sure you provide 18/17 bytes of  space.
1276*ed141cfcSsrivijitha dugganapalli  */
1277*ed141cfcSsrivijitha dugganapalli char *
1278*ed141cfcSsrivijitha dugganapalli scsi_wwn_to_wwnstr(uint64_t wwn, int unit_address_form, char *wwnstr)
1279*ed141cfcSsrivijitha dugganapalli {
1280*ed141cfcSsrivijitha dugganapalli 	int	len;
1281*ed141cfcSsrivijitha dugganapalli 
1282*ed141cfcSsrivijitha dugganapalli 	/* make space for leading 'w' */
1283*ed141cfcSsrivijitha dugganapalli 	if (unit_address_form)
1284*ed141cfcSsrivijitha dugganapalli 		len = 1 + 16 + 1;	/* "w0123456789abcdef\0" */
1285*ed141cfcSsrivijitha dugganapalli 	else
1286*ed141cfcSsrivijitha dugganapalli 		len = 16 + 1;		/* "0123456789abcdef\0" */
1287*ed141cfcSsrivijitha dugganapalli 
1288*ed141cfcSsrivijitha dugganapalli 	if (wwnstr == NULL) {
1289*ed141cfcSsrivijitha dugganapalli 		/* We allocate, caller uses scsi_free_wwnstr(). */
1290*ed141cfcSsrivijitha dugganapalli 		if ((wwnstr = DEVID_MALLOC(len)) == NULL)
1291*ed141cfcSsrivijitha dugganapalli 			return (NULL);
1292*ed141cfcSsrivijitha dugganapalli 	}
1293*ed141cfcSsrivijitha dugganapalli 
1294*ed141cfcSsrivijitha dugganapalli 	if (unit_address_form)
1295*ed141cfcSsrivijitha dugganapalli 		(void) snprintf(wwnstr, len, "w%016" PRIx64, wwn);
1296*ed141cfcSsrivijitha dugganapalli 	else
1297*ed141cfcSsrivijitha dugganapalli 		(void) snprintf(wwnstr, len, "%016" PRIx64, wwn);
1298*ed141cfcSsrivijitha dugganapalli 	return (wwnstr);
1299*ed141cfcSsrivijitha dugganapalli }
1300*ed141cfcSsrivijitha dugganapalli 
1301*ed141cfcSsrivijitha dugganapalli /*
1302*ed141cfcSsrivijitha dugganapalli  *    Function: scsi_wwnstr_hexcase
1303*ed141cfcSsrivijitha dugganapalli  *
1304*ed141cfcSsrivijitha dugganapalli  * Description: This routine switches a wwnstr to upper/lower case hex
1305*ed141cfcSsrivijitha dugganapalli  *		(a wwnstr uses lower-case hex by default).
1306*ed141cfcSsrivijitha dugganapalli  *
1307*ed141cfcSsrivijitha dugganapalli  *   Arguments:
1308*ed141cfcSsrivijitha dugganapalli  *              wwnstr - the pointer to the wwnstr string.
1309*ed141cfcSsrivijitha dugganapalli  *		upper_case_hex - non-zero will convert to upper_case hex
1310*ed141cfcSsrivijitha dugganapalli  *			zero will convert to lower case hex.
1311*ed141cfcSsrivijitha dugganapalli  */
1312*ed141cfcSsrivijitha dugganapalli void
1313*ed141cfcSsrivijitha dugganapalli scsi_wwnstr_hexcase(char *wwnstr, int upper_case_hex)
1314*ed141cfcSsrivijitha dugganapalli {
1315*ed141cfcSsrivijitha dugganapalli 	char	*s;
1316*ed141cfcSsrivijitha dugganapalli 	char	c;
1317*ed141cfcSsrivijitha dugganapalli 
1318*ed141cfcSsrivijitha dugganapalli 	for (s = wwnstr; *s; s++) {
1319*ed141cfcSsrivijitha dugganapalli 		c = *s;
1320*ed141cfcSsrivijitha dugganapalli 		if ((upper_case_hex != 0) &&
1321*ed141cfcSsrivijitha dugganapalli 		    ((c >= 'a') && (c <= 'f')))
1322*ed141cfcSsrivijitha dugganapalli 			c -= ('a' - 'A');	/* lower to upper */
1323*ed141cfcSsrivijitha dugganapalli 		else if ((upper_case_hex == 0) &&
1324*ed141cfcSsrivijitha dugganapalli 		    ((c >= 'A') && (c <= 'F')))
1325*ed141cfcSsrivijitha dugganapalli 			c += ('a' - 'A');	/* upper to lower */
1326*ed141cfcSsrivijitha dugganapalli 		*s = c;
1327*ed141cfcSsrivijitha dugganapalli 	}
1328*ed141cfcSsrivijitha dugganapalli }
1329*ed141cfcSsrivijitha dugganapalli 
1330*ed141cfcSsrivijitha dugganapalli /*
1331*ed141cfcSsrivijitha dugganapalli  *    Function: scsi_wwnstr_free
1332*ed141cfcSsrivijitha dugganapalli  *
1333*ed141cfcSsrivijitha dugganapalli  * Description: This routine frees a wwnstr returned by a call
1334*ed141cfcSsrivijitha dugganapalli  *		to scsi_wwn_to_strwwn with a NULL wwnstr argument.
1335*ed141cfcSsrivijitha dugganapalli  *
1336*ed141cfcSsrivijitha dugganapalli  *   Arguments:
1337*ed141cfcSsrivijitha dugganapalli  *              wwnstr - the pointer to the wwnstr string to free.
1338*ed141cfcSsrivijitha dugganapalli  */
1339*ed141cfcSsrivijitha dugganapalli void
1340*ed141cfcSsrivijitha dugganapalli scsi_free_wwnstr(char *wwnstr)
1341*ed141cfcSsrivijitha dugganapalli {
1342*ed141cfcSsrivijitha dugganapalli #ifdef	_KERNEL
1343*ed141cfcSsrivijitha dugganapalli 	kmem_free(wwnstr, strlen(wwnstr) + 1);
1344*ed141cfcSsrivijitha dugganapalli #else	/* _KERNEL */
1345*ed141cfcSsrivijitha dugganapalli 	free(wwnstr);
1346*ed141cfcSsrivijitha dugganapalli #endif	/* _KERNEL */
1347*ed141cfcSsrivijitha dugganapalli }
1348*ed141cfcSsrivijitha dugganapalli 
1349*ed141cfcSsrivijitha dugganapalli /*
1350*ed141cfcSsrivijitha dugganapalli  *    Function: scsi_lun_to_lun64/scsi_lun64_to_lun
1351*ed141cfcSsrivijitha dugganapalli  *
1352*ed141cfcSsrivijitha dugganapalli  * Description: Convert between normalized (SCSI-3) LUN format, as
1353*ed141cfcSsrivijitha dugganapalli  *		described by scsi_lun_t, and a normalized lun64_t
1354*ed141cfcSsrivijitha dugganapalli  *              representation (used by Solaris SCSI_ADDR_PROP_LUN64
1355*ed141cfcSsrivijitha dugganapalli  *		"lun64" property). The normalized representation maps
1356*ed141cfcSsrivijitha dugganapalli  *		in a compatible way to SCSI-2 LUNs. See scsi_address.h
1357*ed141cfcSsrivijitha dugganapalli  *
1358*ed141cfcSsrivijitha dugganapalli  *              SCSI-3 LUNs are 64 bits. SCSI-2 LUNs are 3 bits (up to
1359*ed141cfcSsrivijitha dugganapalli  *              5 bits in non-compliant implementations). SCSI-3 will
1360*ed141cfcSsrivijitha dugganapalli  *              pass a (64-bit) scsi_lun_t, but we need a
1361*ed141cfcSsrivijitha dugganapalli  *              representation from which we can for example, make
1362*ed141cfcSsrivijitha dugganapalli  *              device names. For unit-address compatibility, we represent
1363*ed141cfcSsrivijitha dugganapalli  *		64-bit LUN numbers in such a way that they appear like they
1364*ed141cfcSsrivijitha dugganapalli  *		would have under SCSI-2. This means that the single level
1365*ed141cfcSsrivijitha dugganapalli  *              LUN number is in the lowest byte with the second,
1366*ed141cfcSsrivijitha dugganapalli  *              third, and fourth level LUNs represented in
1367*ed141cfcSsrivijitha dugganapalli  *              successively higher bytes. In particular, if (and only
1368*ed141cfcSsrivijitha dugganapalli  *              if) the first byte of a 64 bit LUN is zero, denoting
1369*ed141cfcSsrivijitha dugganapalli  *              "Peripheral Device Addressing Method" and "Bus
1370*ed141cfcSsrivijitha dugganapalli  *              Identifier" zero, then the target implements LUNs
1371*ed141cfcSsrivijitha dugganapalli  *              compatible in spirit with SCSI-2 LUNs (although under
1372*ed141cfcSsrivijitha dugganapalli  *              SCSI-3 there may be up to 256 of them). Under SCSI-3
1373*ed141cfcSsrivijitha dugganapalli  *              rules, a target is *required* to use this format if it
1374*ed141cfcSsrivijitha dugganapalli  *              contains 256 or fewer Logical Units, none of which are
1375*ed141cfcSsrivijitha dugganapalli  *              dependent logical units. These routines have knowledge
1376*ed141cfcSsrivijitha dugganapalli  *		of the structure and size of a scsi_lun_t.
1377*ed141cfcSsrivijitha dugganapalli  *
1378*ed141cfcSsrivijitha dugganapalli  * NOTE: We tolerate vendors that use "Single level LUN structure using
1379*ed141cfcSsrivijitha dugganapalli  * peripheral device addressing method" with a non-zero bus identifier
1380*ed141cfcSsrivijitha dugganapalli  * (spec says bus identifier must be zero).  Described another way, we let
1381*ed141cfcSsrivijitha dugganapalli  * the non-'addressing method' bits of sl_lun1_msb contribute to our lun64
1382*ed141cfcSsrivijitha dugganapalli  * value).
1383*ed141cfcSsrivijitha dugganapalli  */
1384*ed141cfcSsrivijitha dugganapalli scsi_lun64_t
1385*ed141cfcSsrivijitha dugganapalli scsi_lun_to_lun64(scsi_lun_t lun)
1386*ed141cfcSsrivijitha dugganapalli {
1387*ed141cfcSsrivijitha dugganapalli 	scsi_lun64_t    lun64;
1388*ed141cfcSsrivijitha dugganapalli 
1389*ed141cfcSsrivijitha dugganapalli 	/*
1390*ed141cfcSsrivijitha dugganapalli 	 * Check to see if we have a single level lun that uses the
1391*ed141cfcSsrivijitha dugganapalli 	 * "Peripheral Device" addressing method. If so, the lun64 value is
1392*ed141cfcSsrivijitha dugganapalli 	 * kept in Solaris 'unit-address compatibility' form.
1393*ed141cfcSsrivijitha dugganapalli 	 */
1394*ed141cfcSsrivijitha dugganapalli 	if (((lun.sl_lun2_msb == 0) && (lun.sl_lun2_lsb == 0) &&
1395*ed141cfcSsrivijitha dugganapalli 	    (lun.sl_lun3_msb == 0) && (lun.sl_lun3_lsb == 0) &&
1396*ed141cfcSsrivijitha dugganapalli 	    (lun.sl_lun4_msb == 0) && (lun.sl_lun4_lsb == 0)) &&
1397*ed141cfcSsrivijitha dugganapalli 	    ((lun.sl_lun1_msb & SCSI_LUN_AM_MASK) == SCSI_LUN_AM_PDEV)) {
1398*ed141cfcSsrivijitha dugganapalli 		/*
1399*ed141cfcSsrivijitha dugganapalli 		 * LUN has Solaris 'unit-address compatibility' form, construct
1400*ed141cfcSsrivijitha dugganapalli 		 * lun64 value from non-'addressing method' bits of msb and lsb.
1401*ed141cfcSsrivijitha dugganapalli 		 */
1402*ed141cfcSsrivijitha dugganapalli 		lun64 = ((lun.sl_lun1_msb & ~SCSI_LUN_AM_MASK) << 8) |
1403*ed141cfcSsrivijitha dugganapalli 		    lun.sl_lun1_lsb;
1404*ed141cfcSsrivijitha dugganapalli 	} else {
1405*ed141cfcSsrivijitha dugganapalli 		/*
1406*ed141cfcSsrivijitha dugganapalli 		 * LUN does not have a Solaris 'unit-address compatibility'
1407*ed141cfcSsrivijitha dugganapalli 		 * form, construct lun64 value in full 64 bit LUN format.
1408*ed141cfcSsrivijitha dugganapalli 		 */
1409*ed141cfcSsrivijitha dugganapalli 		lun64 =
1410*ed141cfcSsrivijitha dugganapalli 		    ((scsi_lun64_t)lun.sl_lun1_msb << 56) |
1411*ed141cfcSsrivijitha dugganapalli 		    ((scsi_lun64_t)lun.sl_lun1_lsb << 48) |
1412*ed141cfcSsrivijitha dugganapalli 		    ((scsi_lun64_t)lun.sl_lun2_msb << 40) |
1413*ed141cfcSsrivijitha dugganapalli 		    ((scsi_lun64_t)lun.sl_lun2_lsb << 32) |
1414*ed141cfcSsrivijitha dugganapalli 		    ((scsi_lun64_t)lun.sl_lun3_msb << 24) |
1415*ed141cfcSsrivijitha dugganapalli 		    ((scsi_lun64_t)lun.sl_lun3_lsb << 16) |
1416*ed141cfcSsrivijitha dugganapalli 		    ((scsi_lun64_t)lun.sl_lun4_msb <<  8) |
1417*ed141cfcSsrivijitha dugganapalli 		    (scsi_lun64_t)lun.sl_lun4_lsb;
1418*ed141cfcSsrivijitha dugganapalli 	}
1419*ed141cfcSsrivijitha dugganapalli 	return (lun64);
1420*ed141cfcSsrivijitha dugganapalli }
1421*ed141cfcSsrivijitha dugganapalli 
1422*ed141cfcSsrivijitha dugganapalli scsi_lun_t
1423*ed141cfcSsrivijitha dugganapalli scsi_lun64_to_lun(scsi_lun64_t lun64)
1424*ed141cfcSsrivijitha dugganapalli {
1425*ed141cfcSsrivijitha dugganapalli 	scsi_lun_t	lun;
1426*ed141cfcSsrivijitha dugganapalli 
1427*ed141cfcSsrivijitha dugganapalli 	if (lun64 <= (((0xFF & ~SCSI_LUN_AM_MASK) << 8) | 0xFF)) {
1428*ed141cfcSsrivijitha dugganapalli 		/*
1429*ed141cfcSsrivijitha dugganapalli 		 * lun64 is in Solaris 'unit-address compatibility' form.
1430*ed141cfcSsrivijitha dugganapalli 		 */
1431*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun1_msb = SCSI_LUN_AM_PDEV | (lun64 >> 8);
1432*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun1_lsb = (uchar_t)lun64;
1433*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun2_msb = 0;
1434*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun2_lsb = 0;
1435*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun3_msb = 0;
1436*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun3_lsb = 0;
1437*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun4_msb = 0;
1438*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun4_lsb = 0;
1439*ed141cfcSsrivijitha dugganapalli 	} else {
1440*ed141cfcSsrivijitha dugganapalli 		/* lun64 is in full 64 bit LUN format. */
1441*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun1_msb = (uchar_t)(lun64 >> 56);
1442*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun1_lsb = (uchar_t)(lun64 >> 48);
1443*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun2_msb = (uchar_t)(lun64 >> 40);
1444*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun2_lsb = (uchar_t)(lun64 >> 32);
1445*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun3_msb = (uchar_t)(lun64 >> 24);
1446*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun3_lsb = (uchar_t)(lun64 >> 16);
1447*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun4_msb = (uchar_t)(lun64 >>  8);
1448*ed141cfcSsrivijitha dugganapalli 		lun.sl_lun4_lsb = (uchar_t)(lun64);
1449*ed141cfcSsrivijitha dugganapalli 	}
1450*ed141cfcSsrivijitha dugganapalli 	return (lun);
1451*ed141cfcSsrivijitha dugganapalli }
1452