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 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 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 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 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 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 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 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 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 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