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