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