xref: /onnv-gate/usr/src/common/devid/devid.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*0Sstevel@tonic-gate 
28*0Sstevel@tonic-gate #include <sys/types.h>
29*0Sstevel@tonic-gate #include <sys/stropts.h>
30*0Sstevel@tonic-gate #include <sys/debug.h>
31*0Sstevel@tonic-gate #include <sys/isa_defs.h>
32*0Sstevel@tonic-gate #include <sys/dditypes.h>
33*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
34*0Sstevel@tonic-gate #include "devid_impl.h"
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate static int devid_str_decode_id(char *devidstr, ddi_devid_t *devidp,
37*0Sstevel@tonic-gate     char **minor_namep, impl_devid_t *id);
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate /*
41*0Sstevel@tonic-gate  * Validate device id.
42*0Sstevel@tonic-gate  */
43*0Sstevel@tonic-gate int
44*0Sstevel@tonic-gate #ifdef	_KERNEL
ddi_devid_valid(ddi_devid_t devid)45*0Sstevel@tonic-gate ddi_devid_valid(ddi_devid_t devid)
46*0Sstevel@tonic-gate #else	/* !_KERNEL */
47*0Sstevel@tonic-gate devid_valid(ddi_devid_t devid)
48*0Sstevel@tonic-gate #endif	/* _KERNEL */
49*0Sstevel@tonic-gate {
50*0Sstevel@tonic-gate 	impl_devid_t	*id = (impl_devid_t *)devid;
51*0Sstevel@tonic-gate 	ushort_t	type;
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate 	DEVID_ASSERT(devid != NULL);
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate 	if (id->did_magic_hi != DEVID_MAGIC_MSB)
56*0Sstevel@tonic-gate 		return (DEVID_RET_INVALID);
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate 	if (id->did_magic_lo != DEVID_MAGIC_LSB)
59*0Sstevel@tonic-gate 		return (DEVID_RET_INVALID);
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate 	if (id->did_rev_hi != DEVID_REV_MSB)
62*0Sstevel@tonic-gate 		return (DEVID_RET_INVALID);
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate 	if (id->did_rev_lo != DEVID_REV_LSB)
65*0Sstevel@tonic-gate 		return (DEVID_RET_INVALID);
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate 	type = DEVID_GETTYPE(id);
68*0Sstevel@tonic-gate 	if ((type == DEVID_NONE) || (type > DEVID_MAXTYPE))
69*0Sstevel@tonic-gate 		return (DEVID_RET_INVALID);
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate 	return (DEVID_RET_VALID);
72*0Sstevel@tonic-gate }
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate /*
75*0Sstevel@tonic-gate  * Return the sizeof a device id. If called with NULL devid it returns
76*0Sstevel@tonic-gate  * the amount of space needed to determine the size.
77*0Sstevel@tonic-gate  */
78*0Sstevel@tonic-gate size_t
79*0Sstevel@tonic-gate #ifdef	_KERNEL
ddi_devid_sizeof(ddi_devid_t devid)80*0Sstevel@tonic-gate ddi_devid_sizeof(ddi_devid_t devid)
81*0Sstevel@tonic-gate #else	/* !_KERNEL */
82*0Sstevel@tonic-gate devid_sizeof(ddi_devid_t devid)
83*0Sstevel@tonic-gate #endif	/* _KERNEL */
84*0Sstevel@tonic-gate {
85*0Sstevel@tonic-gate 	impl_devid_t	*id = (impl_devid_t *)devid;
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate 	if (id == NULL)
88*0Sstevel@tonic-gate 		return (sizeof (*id) - sizeof (id->did_id));
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate 	DEVID_ASSERT(DEVID_FUNC(devid_valid)(devid) == DEVID_RET_VALID);
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 	return (sizeof (*id) + DEVID_GETLEN(id) - sizeof (id->did_id));
93*0Sstevel@tonic-gate }
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate /*
96*0Sstevel@tonic-gate  * Compare two device id's.
97*0Sstevel@tonic-gate  *	-1 - less than
98*0Sstevel@tonic-gate  *	0  - equal
99*0Sstevel@tonic-gate  * 	1  - greater than
100*0Sstevel@tonic-gate  */
101*0Sstevel@tonic-gate int
102*0Sstevel@tonic-gate #ifdef	_KERNEL
ddi_devid_compare(ddi_devid_t id1,ddi_devid_t id2)103*0Sstevel@tonic-gate ddi_devid_compare(ddi_devid_t id1, ddi_devid_t id2)
104*0Sstevel@tonic-gate #else	/* !_KERNEL */
105*0Sstevel@tonic-gate devid_compare(ddi_devid_t id1, ddi_devid_t id2)
106*0Sstevel@tonic-gate #endif	/* _KERNEL */
107*0Sstevel@tonic-gate {
108*0Sstevel@tonic-gate 	int		rval;
109*0Sstevel@tonic-gate 	impl_devid_t	*i_id1	= (impl_devid_t *)id1;
110*0Sstevel@tonic-gate 	impl_devid_t	*i_id2	= (impl_devid_t *)id2;
111*0Sstevel@tonic-gate 	ushort_t	i_id1_type;
112*0Sstevel@tonic-gate 	ushort_t	i_id2_type;
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate 	DEVID_ASSERT((id1 != NULL) && (id2 != NULL));
115*0Sstevel@tonic-gate 	DEVID_ASSERT(DEVID_FUNC(devid_valid)(id1) == DEVID_RET_VALID);
116*0Sstevel@tonic-gate 	DEVID_ASSERT(DEVID_FUNC(devid_valid)(id2) == DEVID_RET_VALID);
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 	/* magic and revision comparison */
119*0Sstevel@tonic-gate 	if ((rval = bcmp(id1, id2, 4)) != 0) {
120*0Sstevel@tonic-gate 		return (rval);
121*0Sstevel@tonic-gate 	}
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	/* get current devid types */
124*0Sstevel@tonic-gate 	i_id1_type = DEVID_GETTYPE(i_id1);
125*0Sstevel@tonic-gate 	i_id2_type = DEVID_GETTYPE(i_id2);
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	/*
128*0Sstevel@tonic-gate 	 * Originaly all page83 devids used DEVID_SCSI3_WWN.
129*0Sstevel@tonic-gate 	 * To avoid a possible uniqueness issue each type of page83
130*0Sstevel@tonic-gate 	 * encoding supported is represented as a separate
131*0Sstevel@tonic-gate 	 * devid type.  If comparing DEVID_SCSI3_WWN against
132*0Sstevel@tonic-gate 	 * one of the new page83 encodings we assume that no
133*0Sstevel@tonic-gate 	 * uniqueness issue exists (since we had apparently been
134*0Sstevel@tonic-gate 	 * running with the old DEVID_SCSI3_WWN encoding without
135*0Sstevel@tonic-gate 	 * a problem).
136*0Sstevel@tonic-gate 	 */
137*0Sstevel@tonic-gate 	if ((i_id1_type == DEVID_SCSI3_WWN) ||
138*0Sstevel@tonic-gate 	    (i_id2_type == DEVID_SCSI3_WWN)) {
139*0Sstevel@tonic-gate 		/*
140*0Sstevel@tonic-gate 		 * Atleast one devid is using old scsi
141*0Sstevel@tonic-gate 		 * encode algorithm.  Force devid types
142*0Sstevel@tonic-gate 		 * to same scheme for comparison.
143*0Sstevel@tonic-gate 		 */
144*0Sstevel@tonic-gate 		if (IS_DEVID_SCSI3_VPD_TYPE(i_id1_type)) {
145*0Sstevel@tonic-gate 			i_id1_type = DEVID_SCSI3_WWN;
146*0Sstevel@tonic-gate 		}
147*0Sstevel@tonic-gate 		if (IS_DEVID_SCSI3_VPD_TYPE(i_id2_type)) {
148*0Sstevel@tonic-gate 			i_id2_type = DEVID_SCSI3_WWN;
149*0Sstevel@tonic-gate 		}
150*0Sstevel@tonic-gate 	}
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	/* type comparison */
153*0Sstevel@tonic-gate 	if (i_id1_type != i_id2_type) {
154*0Sstevel@tonic-gate 		return ((i_id1_type < i_id2_type) ? -1 : 1);
155*0Sstevel@tonic-gate 	}
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 	/* length comparison */
158*0Sstevel@tonic-gate 	if (DEVID_GETLEN(i_id1) != DEVID_GETLEN(i_id2)) {
159*0Sstevel@tonic-gate 		return (DEVID_GETLEN(i_id1) < DEVID_GETLEN(i_id2) ? -1 : 1);
160*0Sstevel@tonic-gate 	}
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	/* id comparison */
163*0Sstevel@tonic-gate 	rval = bcmp(i_id1->did_id, i_id2->did_id, DEVID_GETLEN(i_id1));
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	return (rval);
166*0Sstevel@tonic-gate }
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate /*
169*0Sstevel@tonic-gate  * Free a Device Id
170*0Sstevel@tonic-gate  */
171*0Sstevel@tonic-gate void
172*0Sstevel@tonic-gate #ifdef	_KERNEL
ddi_devid_free(ddi_devid_t devid)173*0Sstevel@tonic-gate ddi_devid_free(ddi_devid_t devid)
174*0Sstevel@tonic-gate #else	/* !_KERNEL */
175*0Sstevel@tonic-gate devid_free(ddi_devid_t devid)
176*0Sstevel@tonic-gate #endif	/* _KERNEL */
177*0Sstevel@tonic-gate {
178*0Sstevel@tonic-gate 	DEVID_ASSERT(devid != NULL);
179*0Sstevel@tonic-gate 	DEVID_FREE(devid, DEVID_FUNC(devid_sizeof)(devid));
180*0Sstevel@tonic-gate }
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate /*
183*0Sstevel@tonic-gate  * Encode a device id into a string.  See ddi_impldefs.h for details.
184*0Sstevel@tonic-gate  */
185*0Sstevel@tonic-gate char *
186*0Sstevel@tonic-gate #ifdef	_KERNEL
ddi_devid_str_encode(ddi_devid_t devid,char * minor_name)187*0Sstevel@tonic-gate ddi_devid_str_encode(ddi_devid_t devid, char *minor_name)
188*0Sstevel@tonic-gate #else	/* !_KERNEL */
189*0Sstevel@tonic-gate devid_str_encode(ddi_devid_t devid, char *minor_name)
190*0Sstevel@tonic-gate #endif	/* _KERNEL */
191*0Sstevel@tonic-gate {
192*0Sstevel@tonic-gate 	impl_devid_t	*id = (impl_devid_t *)devid;
193*0Sstevel@tonic-gate 	size_t		driver_len, devid_len, slen;
194*0Sstevel@tonic-gate 	char		*sbuf, *dsp, *dp, ta;
195*0Sstevel@tonic-gate 	int		i, n, ascii;
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate 	/* "id0" is the encoded representation of a NULL device id */
198*0Sstevel@tonic-gate 	if (devid == NULL) {
199*0Sstevel@tonic-gate 		if ((sbuf = DEVID_MALLOC(4)) == NULL)
200*0Sstevel@tonic-gate 			return (NULL);
201*0Sstevel@tonic-gate 		*(sbuf+0) = DEVID_MAGIC_MSB;
202*0Sstevel@tonic-gate 		*(sbuf+1) = DEVID_MAGIC_LSB;
203*0Sstevel@tonic-gate 		*(sbuf+2) = '0';
204*0Sstevel@tonic-gate 		*(sbuf+3) = 0;
205*0Sstevel@tonic-gate 		return (sbuf);
206*0Sstevel@tonic-gate 	}
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	/* verify input */
209*0Sstevel@tonic-gate 	if (DEVID_FUNC(devid_valid)(devid) != DEVID_RET_VALID)
210*0Sstevel@tonic-gate 		return (NULL);
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	/* scan the driver hint to see how long the hint is */
213*0Sstevel@tonic-gate 	for (driver_len = 0; driver_len < DEVID_HINT_SIZE; driver_len++)
214*0Sstevel@tonic-gate 		if (id->did_driver[driver_len] == '\0')
215*0Sstevel@tonic-gate 			break;
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	/* scan the contained did_id to see if it meets ascii requirements */
218*0Sstevel@tonic-gate 	devid_len = DEVID_GETLEN(id);
219*0Sstevel@tonic-gate 	for (ascii = 1, i = 0; i < devid_len; i++)
220*0Sstevel@tonic-gate 		if (!DEVID_IDBYTE_ISASCII(id->did_id[i])) {
221*0Sstevel@tonic-gate 			ascii = 0;
222*0Sstevel@tonic-gate 			break;
223*0Sstevel@tonic-gate 		}
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	/* some types should always go hex even if they look ascii */
226*0Sstevel@tonic-gate 	if (DEVID_TYPE_BIN_FORCEHEX(id->did_type_lo))
227*0Sstevel@tonic-gate 		ascii = 0;
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	/* set the length of the resulting string */
230*0Sstevel@tonic-gate 	slen = 2 + 1;					/* <magic><rev> "id1" */
231*0Sstevel@tonic-gate 	slen += 1 + driver_len + 1 + 1;			/* ",<driver>@<type>" */
232*0Sstevel@tonic-gate 	slen += ascii ? devid_len : (devid_len * 2);	/* did_id field */
233*0Sstevel@tonic-gate 	if (minor_name) {
234*0Sstevel@tonic-gate 		slen += 1;				/* '/' */
235*0Sstevel@tonic-gate 		slen += strlen(minor_name);		/* len of minor_name */
236*0Sstevel@tonic-gate 	}
237*0Sstevel@tonic-gate 	slen += 1;					/* NULL */
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 	/* allocate string */
240*0Sstevel@tonic-gate 	if ((sbuf = DEVID_MALLOC(slen)) == NULL)
241*0Sstevel@tonic-gate 		return (NULL);
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	/* perform encode of id to hex string */
244*0Sstevel@tonic-gate 	dsp = sbuf;
245*0Sstevel@tonic-gate 	*dsp++ = id->did_magic_hi;
246*0Sstevel@tonic-gate 	*dsp++ = id->did_magic_lo;
247*0Sstevel@tonic-gate 	*dsp++ = DEVID_REV_BINTOASCII(id->did_rev_lo);
248*0Sstevel@tonic-gate 	*dsp++ = ',';
249*0Sstevel@tonic-gate 	for (i = 0; i < driver_len; i++)
250*0Sstevel@tonic-gate 		*dsp++ = id->did_driver[i];
251*0Sstevel@tonic-gate 	*dsp++ = '@';
252*0Sstevel@tonic-gate 	ta = DEVID_TYPE_BINTOASCII(id->did_type_lo);
253*0Sstevel@tonic-gate 	if (ascii)
254*0Sstevel@tonic-gate 		ta = DEVID_TYPE_SETASCII(ta);
255*0Sstevel@tonic-gate 	*dsp++ = ta;
256*0Sstevel@tonic-gate 	for (i = 0, dp = &id->did_id[0]; i < devid_len; i++, dp++) {
257*0Sstevel@tonic-gate 		if (ascii) {
258*0Sstevel@tonic-gate 			if (*dp == ' ')
259*0Sstevel@tonic-gate 				*dsp++ = '_';
260*0Sstevel@tonic-gate 			else if (*dp == 0x00)
261*0Sstevel@tonic-gate 				*dsp++ = '~';
262*0Sstevel@tonic-gate 			else
263*0Sstevel@tonic-gate 				*dsp++ = *dp;
264*0Sstevel@tonic-gate 		} else {
265*0Sstevel@tonic-gate 			n = ((*dp) >> 4) & 0xF;
266*0Sstevel@tonic-gate 			*dsp++ = (n < 10) ? (n + '0') : (n + ('a' - 10));
267*0Sstevel@tonic-gate 			n = (*dp) & 0xF;
268*0Sstevel@tonic-gate 			*dsp++ = (n < 10) ? (n + '0') : (n + ('a' - 10));
269*0Sstevel@tonic-gate 		}
270*0Sstevel@tonic-gate 	}
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	if (minor_name) {
273*0Sstevel@tonic-gate 		*dsp++ = '/';
274*0Sstevel@tonic-gate 		(void) strcpy(dsp, minor_name);
275*0Sstevel@tonic-gate 	} else
276*0Sstevel@tonic-gate 		*dsp++ = 0;
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	/* ensure that (strlen + 1) is correct length for free */
279*0Sstevel@tonic-gate 	DEVID_ASSERT((strlen(sbuf) + 1) == slen);
280*0Sstevel@tonic-gate 	return (sbuf);
281*0Sstevel@tonic-gate }
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate /* free the string returned by devid_str_encode */
284*0Sstevel@tonic-gate void
285*0Sstevel@tonic-gate #ifdef	_KERNEL
ddi_devid_str_free(char * devidstr)286*0Sstevel@tonic-gate ddi_devid_str_free(char *devidstr)
287*0Sstevel@tonic-gate #else	/* !_KERNEL */
288*0Sstevel@tonic-gate devid_str_free(char *devidstr)
289*0Sstevel@tonic-gate #endif	/* _KERNEL */
290*0Sstevel@tonic-gate {
291*0Sstevel@tonic-gate 	DEVID_FREE(devidstr, strlen(devidstr) + 1);
292*0Sstevel@tonic-gate }
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate /*
295*0Sstevel@tonic-gate  * given the string representation of a device id returned by calling
296*0Sstevel@tonic-gate  * devid_str_encode (passed in as devidstr), return pointers to the
297*0Sstevel@tonic-gate  * broken out devid and minor_name as requested. Devidstr remains
298*0Sstevel@tonic-gate  * allocated and unmodified. The devid returned in *devidp should be freed by
299*0Sstevel@tonic-gate  * calling devid_free.  The minor_name returned in minor_namep should
300*0Sstevel@tonic-gate  * be freed by calling devid_str_free(minor_namep).
301*0Sstevel@tonic-gate  *
302*0Sstevel@tonic-gate  * See ddi_impldefs.h for format details.
303*0Sstevel@tonic-gate  */
304*0Sstevel@tonic-gate int
305*0Sstevel@tonic-gate #ifdef	_KERNEL
ddi_devid_str_decode(char * devidstr,ddi_devid_t * devidp,char ** minor_namep)306*0Sstevel@tonic-gate ddi_devid_str_decode(
307*0Sstevel@tonic-gate #else	/* !_KERNEL */
308*0Sstevel@tonic-gate devid_str_decode(
309*0Sstevel@tonic-gate #endif	/* _KERNEL */
310*0Sstevel@tonic-gate     char *devidstr, ddi_devid_t *devidp, char **minor_namep)
311*0Sstevel@tonic-gate {
312*0Sstevel@tonic-gate 	return (devid_str_decode_id(devidstr, devidp, minor_namep, NULL));
313*0Sstevel@tonic-gate }
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate /* implementation for (ddi_)devid_str_decode */
316*0Sstevel@tonic-gate static int
devid_str_decode_id(char * devidstr,ddi_devid_t * devidp,char ** minor_namep,impl_devid_t * id)317*0Sstevel@tonic-gate devid_str_decode_id(char *devidstr, ddi_devid_t *devidp,
318*0Sstevel@tonic-gate     char **minor_namep, impl_devid_t *id)
319*0Sstevel@tonic-gate {
320*0Sstevel@tonic-gate 	char		*str, *msp, *dsp, *dp, ta;
321*0Sstevel@tonic-gate 	int		slen, devid_len, ascii, i, n, c, pre_alloc = FALSE;
322*0Sstevel@tonic-gate 	unsigned short	id_len, type;		/* for hibyte/lobyte */
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	if (devidp != NULL)
325*0Sstevel@tonic-gate 		*devidp = NULL;
326*0Sstevel@tonic-gate 	if (minor_namep != NULL)
327*0Sstevel@tonic-gate 		*minor_namep = NULL;
328*0Sstevel@tonic-gate 	if (id != NULL)
329*0Sstevel@tonic-gate 		pre_alloc = TRUE;
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 	if (devidstr == NULL)
332*0Sstevel@tonic-gate 		return (DEVID_FAILURE);
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 	/* the string must atleast contain the ascii two byte header */
335*0Sstevel@tonic-gate 	slen = strlen(devidstr);
336*0Sstevel@tonic-gate 	if ((slen < 3) || (devidstr[0] != DEVID_MAGIC_MSB) ||
337*0Sstevel@tonic-gate 	    (devidstr[1] != DEVID_MAGIC_LSB))
338*0Sstevel@tonic-gate 		return (DEVID_FAILURE);
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	/* "id0" is the encoded representation of a NULL device id */
341*0Sstevel@tonic-gate 	if ((devidstr[2] == '0') && (slen == 3))
342*0Sstevel@tonic-gate 		return (DEVID_SUCCESS);
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	/* "id1,@S0" is the shortest possible, reject if shorter */
345*0Sstevel@tonic-gate 	if (slen <  7)
346*0Sstevel@tonic-gate 		return (DEVID_FAILURE);
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate 	/* find the optional minor name, start after ',' */
349*0Sstevel@tonic-gate 	if ((msp = strchr(&devidstr[4], '/')) != NULL)
350*0Sstevel@tonic-gate 		msp++;
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 	/* skip devid processing if we are not asked to return it */
353*0Sstevel@tonic-gate 	if (devidp) {
354*0Sstevel@tonic-gate 		/* find the required '@' separator */
355*0Sstevel@tonic-gate 		if ((str = strchr(devidstr, '@')) == NULL)
356*0Sstevel@tonic-gate 			return (DEVID_FAILURE);
357*0Sstevel@tonic-gate 		str++;					/* skip '@' */
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 		/* pick up <type> after the '@' and verify */
360*0Sstevel@tonic-gate 		ta = *str++;
361*0Sstevel@tonic-gate 		ascii = DEVID_TYPE_ISASCII(ta);
362*0Sstevel@tonic-gate 		type = DEVID_TYPE_ASCIITOBIN(ta);
363*0Sstevel@tonic-gate 		if (type > DEVID_MAXTYPE)
364*0Sstevel@tonic-gate 			return (DEVID_FAILURE);
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 		/* determine length of id->did_id field */
367*0Sstevel@tonic-gate 		if (msp == NULL)
368*0Sstevel@tonic-gate 			id_len = strlen(str);
369*0Sstevel@tonic-gate 		else
370*0Sstevel@tonic-gate 			id_len = msp - str - 1;
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 		/* account for encoding: with hex, binary is half the size */
373*0Sstevel@tonic-gate 		if (!ascii) {
374*0Sstevel@tonic-gate 			/* hex id field must be even length */
375*0Sstevel@tonic-gate 			if (id_len & 1)
376*0Sstevel@tonic-gate 				return (DEVID_FAILURE);
377*0Sstevel@tonic-gate 			id_len /= 2;
378*0Sstevel@tonic-gate 		}
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 		/* add in size of the binary devid header */
381*0Sstevel@tonic-gate 		devid_len = id_len + sizeof (*id) - sizeof (id->did_id);
382*0Sstevel@tonic-gate 
383*0Sstevel@tonic-gate 		/*
384*0Sstevel@tonic-gate 		 * Allocate space for devid if we are asked to decode it
385*0Sstevel@tonic-gate 		 * decode it and space wasn't pre-allocated.
386*0Sstevel@tonic-gate 		 */
387*0Sstevel@tonic-gate 		if (pre_alloc == FALSE) {
388*0Sstevel@tonic-gate 			if ((id = (impl_devid_t *)DEVID_MALLOC(
389*0Sstevel@tonic-gate 			    devid_len)) == NULL)
390*0Sstevel@tonic-gate 			return (DEVID_FAILURE);
391*0Sstevel@tonic-gate 		}
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 		/* decode header portion of the string into the binary devid */
394*0Sstevel@tonic-gate 		dsp = devidstr;
395*0Sstevel@tonic-gate 		id->did_magic_hi = *dsp++;		/* <magic> "id" */
396*0Sstevel@tonic-gate 		id->did_magic_lo = *dsp++;
397*0Sstevel@tonic-gate 		id->did_rev_hi = 0;
398*0Sstevel@tonic-gate 		id->did_rev_lo =
399*0Sstevel@tonic-gate 		    DEVID_REV_ASCIITOBIN(*dsp);		/* <rev> "1" */
400*0Sstevel@tonic-gate 		dsp++;					/* skip "1" */
401*0Sstevel@tonic-gate 		dsp++;					/* skip "," */
402*0Sstevel@tonic-gate 		for (i = 0; i < DEVID_HINT_SIZE; i++) {	/* <driver>@ */
403*0Sstevel@tonic-gate 			if (*dsp == '@')
404*0Sstevel@tonic-gate 				break;
405*0Sstevel@tonic-gate 			id->did_driver[i] = *dsp++;
406*0Sstevel@tonic-gate 		}
407*0Sstevel@tonic-gate 		for (; i < DEVID_HINT_SIZE; i++)
408*0Sstevel@tonic-gate 			id->did_driver[i] = 0;
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 		/* we must now be at the '@' */
411*0Sstevel@tonic-gate 		if (*dsp != '@')
412*0Sstevel@tonic-gate 			goto efree;
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 		/* set the type and length */
415*0Sstevel@tonic-gate 		DEVID_FORMTYPE(id, type);
416*0Sstevel@tonic-gate 		DEVID_FORMLEN(id, id_len);
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 		/* decode devid portion of string into the binary */
419*0Sstevel@tonic-gate 		for (i = 0, dsp = str, dp = &id->did_id[0];
420*0Sstevel@tonic-gate 		    i < id_len; i++, dp++) {
421*0Sstevel@tonic-gate 			if (ascii) {
422*0Sstevel@tonic-gate 				if (*dsp == '_')
423*0Sstevel@tonic-gate 					*dp = ' ';
424*0Sstevel@tonic-gate 				else if (*dsp == '~')
425*0Sstevel@tonic-gate 					*dp = 0x00;
426*0Sstevel@tonic-gate 				else
427*0Sstevel@tonic-gate 					*dp = *dsp;
428*0Sstevel@tonic-gate 				dsp++;
429*0Sstevel@tonic-gate 			} else {
430*0Sstevel@tonic-gate 				c = *dsp++;
431*0Sstevel@tonic-gate 				if (c >= '0' && c <= '9')
432*0Sstevel@tonic-gate 					n = (c - '0') & 0xFF;
433*0Sstevel@tonic-gate 				else if (c >= 'a' && c <= 'f')
434*0Sstevel@tonic-gate 					n = (c - ('a' - 10)) & 0xFF;
435*0Sstevel@tonic-gate 				else
436*0Sstevel@tonic-gate 					goto efree;
437*0Sstevel@tonic-gate 				n <<= 4;
438*0Sstevel@tonic-gate 				c = *dsp++;
439*0Sstevel@tonic-gate 				if (c >= '0' && c <= '9')
440*0Sstevel@tonic-gate 					n |= (c - '0') & 0xFF;
441*0Sstevel@tonic-gate 				else if (c >= 'a' && c <= 'f')
442*0Sstevel@tonic-gate 					n |= (c - ('a' - 10)) & 0xFF;
443*0Sstevel@tonic-gate 				else
444*0Sstevel@tonic-gate 					goto efree;
445*0Sstevel@tonic-gate 				*dp = n;
446*0Sstevel@tonic-gate 			}
447*0Sstevel@tonic-gate 		}
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate 		/* verify result */
450*0Sstevel@tonic-gate 		if (DEVID_FUNC(devid_valid)((ddi_devid_t)id) != DEVID_RET_VALID)
451*0Sstevel@tonic-gate 			goto efree;
452*0Sstevel@tonic-gate 	}
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	/* duplicate minor_name if we are asked to decode it */
455*0Sstevel@tonic-gate 	if (minor_namep && msp) {
456*0Sstevel@tonic-gate 		if ((*minor_namep = DEVID_MALLOC(strlen(msp) + 1)) == NULL)
457*0Sstevel@tonic-gate 			goto efree;
458*0Sstevel@tonic-gate 		(void) strcpy(*minor_namep, msp);
459*0Sstevel@tonic-gate 	}
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 	/* return pointer to binary */
462*0Sstevel@tonic-gate 	if (devidp)
463*0Sstevel@tonic-gate 		*devidp = (ddi_devid_t)id;
464*0Sstevel@tonic-gate 	return (DEVID_SUCCESS);
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate efree:
467*0Sstevel@tonic-gate 	if ((pre_alloc == FALSE) && (id))
468*0Sstevel@tonic-gate 		DEVID_FREE(id, devid_len);
469*0Sstevel@tonic-gate 	return (DEVID_FAILURE);
470*0Sstevel@tonic-gate }
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate /*
474*0Sstevel@tonic-gate  * Compare two device id's in string form
475*0Sstevel@tonic-gate  *	-1 - id1 less than id2
476*0Sstevel@tonic-gate  *	0  - equal
477*0Sstevel@tonic-gate  * 	1  - id1 greater than id2
478*0Sstevel@tonic-gate  */
479*0Sstevel@tonic-gate int
480*0Sstevel@tonic-gate #ifdef	_KERNEL
ddi_devid_str_compare(char * id1_str,char * id2_str)481*0Sstevel@tonic-gate ddi_devid_str_compare(char *id1_str, char *id2_str)
482*0Sstevel@tonic-gate #else	/* !_KERNEL */
483*0Sstevel@tonic-gate devid_str_compare(char *id1_str, char *id2_str)
484*0Sstevel@tonic-gate #endif	/* _KERNEL */
485*0Sstevel@tonic-gate {
486*0Sstevel@tonic-gate 	int		rval	= DEVID_FAILURE;
487*0Sstevel@tonic-gate 	ddi_devid_t	devid1;
488*0Sstevel@tonic-gate 	ddi_devid_t	devid2;
489*0Sstevel@tonic-gate #ifdef	_KERNEL
490*0Sstevel@tonic-gate 	/* kernel use static protected by lock. */
491*0Sstevel@tonic-gate 	static kmutex_t	id_lock;
492*0Sstevel@tonic-gate 	static uchar_t	id1[sizeof (impl_devid_t) + MAXPATHLEN];
493*0Sstevel@tonic-gate 	static uchar_t	id2[sizeof (impl_devid_t) + MAXPATHLEN];
494*0Sstevel@tonic-gate #else	/* !_KERNEL */
495*0Sstevel@tonic-gate 	/* userland place on stack, since malloc might fail */
496*0Sstevel@tonic-gate 	uchar_t		id1[sizeof (impl_devid_t) + MAXPATHLEN];
497*0Sstevel@tonic-gate 	uchar_t		id2[sizeof (impl_devid_t) + MAXPATHLEN];
498*0Sstevel@tonic-gate #endif	/* _KERNEL */
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate #ifdef	_KERNEL
501*0Sstevel@tonic-gate 	mutex_enter(&id_lock);
502*0Sstevel@tonic-gate #endif	/* _KERNEL */
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 	/*
505*0Sstevel@tonic-gate 	 * encode string form of devid
506*0Sstevel@tonic-gate 	 */
507*0Sstevel@tonic-gate 	if ((devid_str_decode_id(id1_str, &devid1, NULL, (impl_devid_t *)id1) ==
508*0Sstevel@tonic-gate 	    DEVID_SUCCESS) &&
509*0Sstevel@tonic-gate 	    (devid_str_decode_id(id2_str, &devid2, NULL, (impl_devid_t *)id2) ==
510*0Sstevel@tonic-gate 	    DEVID_SUCCESS)) {
511*0Sstevel@tonic-gate 		rval = DEVID_FUNC(devid_compare)(devid1, devid2);
512*0Sstevel@tonic-gate 	}
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate #ifdef	_KERNEL
515*0Sstevel@tonic-gate 	mutex_exit(&id_lock);
516*0Sstevel@tonic-gate #endif	/* _KERNEL */
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	return (rval);
519*0Sstevel@tonic-gate }
520