#include <sys/types.h>
#include <sys/stropts.h>
#include <sys/debug.h>
#include <sys/isa_defs.h>
#include <sys/dditypes.h>
#include <sys/ddi_impldefs.h>
#include "devid_impl.h"
static int devid_str_decode_id(char *devidstr, ddi_devid_t *devidp,
char **minor_namep, impl_devid_t *id);
int
#ifdef _KERNEL
ddi_devid_valid(ddi_devid_t devid)
#else
devid_valid(ddi_devid_t devid)
#endif
{
impl_devid_t *id = (impl_devid_t *)devid;
ushort_t type;
DEVID_ASSERT(devid != NULL);
if (id->did_magic_hi != DEVID_MAGIC_MSB)
return (DEVID_RET_INVALID);
if (id->did_magic_lo != DEVID_MAGIC_LSB)
return (DEVID_RET_INVALID);
if (id->did_rev_hi != DEVID_REV_MSB)
return (DEVID_RET_INVALID);
if (id->did_rev_lo != DEVID_REV_LSB)
return (DEVID_RET_INVALID);
type = DEVID_GETTYPE(id);
if ((type == DEVID_NONE) || (type > DEVID_MAXTYPE))
return (DEVID_RET_INVALID);
return (DEVID_RET_VALID);
}
size_t
#ifdef _KERNEL
ddi_devid_sizeof(ddi_devid_t devid)
#else
devid_sizeof(ddi_devid_t devid)
#endif
{
impl_devid_t *id = (impl_devid_t *)devid;
if (id == NULL)
return (sizeof (*id) - sizeof (id->did_id));
DEVID_ASSERT(DEVID_FUNC(devid_valid)(devid) == DEVID_RET_VALID);
return (sizeof (*id) + DEVID_GETLEN(id) - sizeof (id->did_id));
}
int
#ifdef _KERNEL
ddi_devid_compare(ddi_devid_t id1, ddi_devid_t id2)
#else
devid_compare(ddi_devid_t id1, ddi_devid_t id2)
#endif
{
int rval;
impl_devid_t *i_id1 = (impl_devid_t *)id1;
impl_devid_t *i_id2 = (impl_devid_t *)id2;
ushort_t i_id1_type;
ushort_t i_id2_type;
DEVID_ASSERT((id1 != NULL) && (id2 != NULL));
DEVID_ASSERT(DEVID_FUNC(devid_valid)(id1) == DEVID_RET_VALID);
DEVID_ASSERT(DEVID_FUNC(devid_valid)(id2) == DEVID_RET_VALID);
if ((rval = bcmp(id1, id2, 4)) != 0) {
return (rval);
}
i_id1_type = DEVID_GETTYPE(i_id1);
i_id2_type = DEVID_GETTYPE(i_id2);
if ((i_id1_type == DEVID_SCSI3_WWN) ||
(i_id2_type == DEVID_SCSI3_WWN)) {
if (IS_DEVID_SCSI3_VPD_TYPE(i_id1_type)) {
i_id1_type = DEVID_SCSI3_WWN;
}
if (IS_DEVID_SCSI3_VPD_TYPE(i_id2_type)) {
i_id2_type = DEVID_SCSI3_WWN;
}
}
if (i_id1_type != i_id2_type) {
return ((i_id1_type < i_id2_type) ? -1 : 1);
}
if (DEVID_GETLEN(i_id1) != DEVID_GETLEN(i_id2)) {
return (DEVID_GETLEN(i_id1) < DEVID_GETLEN(i_id2) ? -1 : 1);
}
rval = bcmp(i_id1->did_id, i_id2->did_id, DEVID_GETLEN(i_id1));
return (rval);
}
void
#ifdef _KERNEL
ddi_devid_free(ddi_devid_t devid)
#else
devid_free(ddi_devid_t devid)
#endif
{
DEVID_ASSERT(devid != NULL);
DEVID_FREE(devid, DEVID_FUNC(devid_sizeof)(devid));
}
char *
#ifdef _KERNEL
ddi_devid_str_encode(ddi_devid_t devid, char *minor_name)
#else
devid_str_encode(ddi_devid_t devid, char *minor_name)
#endif
{
impl_devid_t *id = (impl_devid_t *)devid;
size_t driver_len, devid_len, slen;
char *sbuf, *dsp, *dp, ta;
int i, n, ascii;
if (devid == NULL) {
if ((sbuf = DEVID_MALLOC(4)) == NULL)
return (NULL);
*(sbuf+0) = DEVID_MAGIC_MSB;
*(sbuf+1) = DEVID_MAGIC_LSB;
*(sbuf+2) = '0';
*(sbuf+3) = 0;
return (sbuf);
}
if (DEVID_FUNC(devid_valid)(devid) != DEVID_RET_VALID)
return (NULL);
for (driver_len = 0; driver_len < DEVID_HINT_SIZE; driver_len++)
if (id->did_driver[driver_len] == '\0')
break;
devid_len = DEVID_GETLEN(id);
for (ascii = 1, i = 0; i < devid_len; i++)
if (!DEVID_IDBYTE_ISASCII(id->did_id[i])) {
ascii = 0;
break;
}
if (DEVID_TYPE_BIN_FORCEHEX(id->did_type_lo))
ascii = 0;
slen = 2 + 1;
slen += 1 + driver_len + 1 + 1;
slen += ascii ? devid_len : (devid_len * 2);
if (minor_name) {
slen += 1;
slen += strlen(minor_name);
}
slen += 1;
if ((sbuf = DEVID_MALLOC(slen)) == NULL)
return (NULL);
dsp = sbuf;
*dsp++ = id->did_magic_hi;
*dsp++ = id->did_magic_lo;
*dsp++ = DEVID_REV_BINTOASCII(id->did_rev_lo);
*dsp++ = ',';
for (i = 0; i < driver_len; i++)
*dsp++ = id->did_driver[i];
*dsp++ = '@';
ta = DEVID_TYPE_BINTOASCII(id->did_type_lo);
if (ascii)
ta = DEVID_TYPE_SETASCII(ta);
*dsp++ = ta;
for (i = 0, dp = &id->did_id[0]; i < devid_len; i++, dp++) {
if (ascii) {
if (*dp == ' ')
*dsp++ = '_';
else if (*dp == 0x00)
*dsp++ = '~';
else
*dsp++ = *dp;
} else {
n = ((*dp) >> 4) & 0xF;
*dsp++ = (n < 10) ? (n + '0') : (n + ('a' - 10));
n = (*dp) & 0xF;
*dsp++ = (n < 10) ? (n + '0') : (n + ('a' - 10));
}
}
if (minor_name) {
*dsp++ = '/';
(void) strcpy(dsp, minor_name);
} else
*dsp++ = 0;
DEVID_ASSERT((strlen(sbuf) + 1) == slen);
return (sbuf);
}
void
#ifdef _KERNEL
ddi_devid_str_free(char *devidstr)
#else
devid_str_free(char *devidstr)
#endif
{
DEVID_FREE(devidstr, strlen(devidstr) + 1);
}
int
#ifdef _KERNEL
ddi_devid_str_decode(
#else
devid_str_decode(
#endif
char *devidstr, ddi_devid_t *devidp, char **minor_namep)
{
return (devid_str_decode_id(devidstr, devidp, minor_namep, NULL));
}
static int
devid_str_decode_id(char *devidstr, ddi_devid_t *devidp,
char **minor_namep, impl_devid_t *id)
{
char *str, *msp, *dsp, *dp, ta;
int slen, devid_len, ascii, i, n, c, pre_alloc = FALSE;
unsigned short id_len, type;
devid_len = 0;
if (devidp != NULL)
*devidp = NULL;
if (minor_namep != NULL)
*minor_namep = NULL;
if (id != NULL)
pre_alloc = TRUE;
if (devidstr == NULL)
return (DEVID_FAILURE);
slen = strlen(devidstr);
if ((slen < 3) || (devidstr[0] != DEVID_MAGIC_MSB) ||
(devidstr[1] != DEVID_MAGIC_LSB))
return (DEVID_FAILURE);
if ((devidstr[2] == '0') && (slen == 3))
return (DEVID_SUCCESS);
if (slen < 7)
return (DEVID_FAILURE);
if ((msp = strchr(&devidstr[4], '/')) != NULL)
msp++;
if (devidp) {
if ((str = strchr(devidstr, '@')) == NULL)
return (DEVID_FAILURE);
str++;
ta = *str++;
ascii = DEVID_TYPE_ISASCII(ta);
type = DEVID_TYPE_ASCIITOBIN(ta);
if (type > DEVID_MAXTYPE)
return (DEVID_FAILURE);
if (msp == NULL)
id_len = strlen(str);
else
id_len = msp - str - 1;
if (!ascii) {
if (id_len & 1)
return (DEVID_FAILURE);
id_len /= 2;
}
devid_len = id_len + sizeof (*id) - sizeof (id->did_id);
if (pre_alloc == FALSE) {
if ((id = (impl_devid_t *)DEVID_MALLOC(
devid_len)) == NULL)
return (DEVID_FAILURE);
}
dsp = devidstr;
id->did_magic_hi = *dsp++;
id->did_magic_lo = *dsp++;
id->did_rev_hi = 0;
id->did_rev_lo =
DEVID_REV_ASCIITOBIN(*dsp);
dsp++;
dsp++;
for (i = 0; i < DEVID_HINT_SIZE; i++) {
if (*dsp == '@')
break;
id->did_driver[i] = *dsp++;
}
for (; i < DEVID_HINT_SIZE; i++)
id->did_driver[i] = 0;
if (*dsp != '@')
goto efree;
DEVID_FORMTYPE(id, type);
DEVID_FORMLEN(id, id_len);
for (i = 0, dsp = str, dp = &id->did_id[0];
i < id_len; i++, dp++) {
if (ascii) {
if (*dsp == '_')
*dp = ' ';
else if (*dsp == '~')
*dp = 0x00;
else
*dp = *dsp;
dsp++;
} else {
c = *dsp++;
if (c >= '0' && c <= '9')
n = (c - '0') & 0xFF;
else if (c >= 'a' && c <= 'f')
n = (c - ('a' - 10)) & 0xFF;
else
goto efree;
n <<= 4;
c = *dsp++;
if (c >= '0' && c <= '9')
n |= (c - '0') & 0xFF;
else if (c >= 'a' && c <= 'f')
n |= (c - ('a' - 10)) & 0xFF;
else
goto efree;
*dp = n;
}
}
if (DEVID_FUNC(devid_valid)((ddi_devid_t)id) != DEVID_RET_VALID)
goto efree;
}
if (minor_namep && msp) {
if ((*minor_namep = DEVID_MALLOC(strlen(msp) + 1)) == NULL)
goto efree;
(void) strcpy(*minor_namep, msp);
}
if (devidp)
*devidp = (ddi_devid_t)id;
return (DEVID_SUCCESS);
efree:
if ((pre_alloc == FALSE) && (id))
DEVID_FREE(id, devid_len);
return (DEVID_FAILURE);
}
int
#ifdef _KERNEL
ddi_devid_str_compare(char *id1_str, char *id2_str)
#else
devid_str_compare(char *id1_str, char *id2_str)
#endif
{
int rval = DEVID_FAILURE;
ddi_devid_t devid1;
ddi_devid_t devid2;
#ifdef _KERNEL
static kmutex_t id_lock;
static uchar_t id1[sizeof (impl_devid_t) + MAXPATHLEN];
static uchar_t id2[sizeof (impl_devid_t) + MAXPATHLEN];
#else
uchar_t id1[sizeof (impl_devid_t) + MAXPATHLEN];
uchar_t id2[sizeof (impl_devid_t) + MAXPATHLEN];
#endif
#ifdef _KERNEL
mutex_enter(&id_lock);
#endif
if ((devid_str_decode_id(id1_str, &devid1, NULL, (impl_devid_t *)id1) ==
DEVID_SUCCESS) &&
(devid_str_decode_id(id2_str, &devid2, NULL, (impl_devid_t *)id2) ==
DEVID_SUCCESS)) {
rval = DEVID_FUNC(devid_compare)(devid1, devid2);
}
#ifdef _KERNEL
mutex_exit(&id_lock);
#endif
return (rval);
}