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