16316Seschrock /*
26316Seschrock * CDDL HEADER START
36316Seschrock *
46316Seschrock * The contents of this file are subject to the terms of the
56316Seschrock * Common Development and Distribution License (the "License").
66316Seschrock * You may not use this file except in compliance with the License.
76316Seschrock *
86316Seschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96316Seschrock * or http://www.opensolaris.org/os/licensing.
106316Seschrock * See the License for the specific language governing permissions
116316Seschrock * and limitations under the License.
126316Seschrock *
136316Seschrock * When distributing Covered Code, include this CDDL HEADER in each
146316Seschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156316Seschrock * If applicable, add the following below this CDDL HEADER, with the
166316Seschrock * fields enclosed by brackets "[]" replaced with your own identifying
176316Seschrock * information: Portions Copyright [yyyy] [name of copyright owner]
186316Seschrock *
196316Seschrock * CDDL HEADER END
206316Seschrock */
216316Seschrock
226316Seschrock /*
2312126SHyon.Kim@Sun.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
246316Seschrock */
256316Seschrock
266316Seschrock #include <scsi/libses.h>
276316Seschrock #include "ses_impl.h"
286316Seschrock
296316Seschrock static boolean_t ses_plugin_dlclose;
306316Seschrock
316316Seschrock /*ARGSUSED*/
326316Seschrock void *
ses_plugin_ctlpage_lookup(ses_plugin_t * sp,ses_snap_t * snap,int pagenum,size_t len,ses_node_t * np,boolean_t unique)336316Seschrock ses_plugin_ctlpage_lookup(ses_plugin_t *sp, ses_snap_t *snap, int pagenum,
346316Seschrock size_t len, ses_node_t *np, boolean_t unique)
356316Seschrock {
366316Seschrock ses_target_t *tp = snap->ss_target;
376316Seschrock ses_snap_page_t *pp;
386316Seschrock ses_pagedesc_t *dp;
396316Seschrock
406316Seschrock if ((pp = ses_snap_ctl_page(snap, pagenum, len, unique)) == NULL)
416316Seschrock return (NULL);
426316Seschrock
436316Seschrock if ((dp = ses_get_pagedesc(tp, pagenum, SES_PAGE_CTL)) == NULL)
446316Seschrock return (NULL);
456316Seschrock
466316Seschrock if (dp->spd_ctl_fill != NULL) {
476316Seschrock return (dp->spd_ctl_fill(sp, pp->ssp_page,
486316Seschrock pp->ssp_len, np));
496316Seschrock } else {
506316Seschrock return (pp->ssp_page);
516316Seschrock }
526316Seschrock }
536316Seschrock
546316Seschrock int
ses_fill_node(ses_node_t * np)556316Seschrock ses_fill_node(ses_node_t *np)
566316Seschrock {
576316Seschrock ses_target_t *tp = np->sn_snapshot->ss_target;
586316Seschrock ses_plugin_t *sp;
596316Seschrock
606316Seschrock for (sp = tp->st_plugin_first; sp != NULL; sp = sp->sp_next) {
616316Seschrock if (sp->sp_node_parse == NULL)
626316Seschrock continue;
636316Seschrock
646316Seschrock if (sp->sp_node_parse(sp, np) != 0)
656316Seschrock return (-1);
666316Seschrock }
676316Seschrock
686316Seschrock return (0);
696316Seschrock }
706316Seschrock
716316Seschrock int
ses_node_ctl(ses_node_t * np,const char * op,nvlist_t * arg)726316Seschrock ses_node_ctl(ses_node_t *np, const char *op, nvlist_t *arg)
736316Seschrock {
746316Seschrock ses_target_t *tp = np->sn_snapshot->ss_target;
756316Seschrock ses_plugin_t *sp;
766316Seschrock nvlist_t *nvl;
776316Seschrock nvpair_t *nvp;
786316Seschrock int ret;
796316Seschrock
806316Seschrock if (nvlist_dup(arg, &nvl, 0) != 0)
816316Seschrock return (ses_set_errno(ESES_NOMEM));
826316Seschrock
836316Seschrock /*
846316Seschrock * Technically we could get away with a per-snapshot lock while we fill
856316Seschrock * the control page contents, but this doesn't take much time and we
866316Seschrock * want actual control operations to be protected per-target, so we just
876316Seschrock * take the target lock.
886316Seschrock */
896316Seschrock (void) pthread_mutex_lock(&tp->st_lock);
906316Seschrock
916316Seschrock /*
926316Seschrock * We walk the list of plugins backwards, so that a product-specific
936316Seschrock * plugin can rewrite the nvlist to control operations in terms of the
946316Seschrock * standard mechanisms, if desired.
956316Seschrock */
966316Seschrock for (sp = tp->st_plugin_first; sp != NULL; sp = sp->sp_next) {
976316Seschrock if (sp->sp_node_ctl == NULL)
986316Seschrock continue;
996316Seschrock
1006316Seschrock if (sp->sp_node_ctl(sp, np, op, nvl) != 0) {
1016316Seschrock nvlist_free(nvl);
1026316Seschrock (void) pthread_mutex_unlock(&tp->st_lock);
1036316Seschrock return (-1);
1046316Seschrock }
1056316Seschrock }
1066316Seschrock
1076316Seschrock if ((nvp = nvlist_next_nvpair(nvl, NULL)) != NULL) {
1086316Seschrock (void) ses_error(ESES_NOTSUP, "property '%s' invalid for "
1096316Seschrock "this node", nvpair_name(nvp));
1106316Seschrock nvlist_free(nvl);
1116316Seschrock (void) pthread_mutex_unlock(&tp->st_lock);
1126316Seschrock return (-1);
1136316Seschrock }
1146316Seschrock
1156316Seschrock nvlist_free(nvl);
1166316Seschrock
1176316Seschrock ret = ses_snap_do_ctl(np->sn_snapshot);
1186316Seschrock (void) pthread_mutex_unlock(&tp->st_lock);
1196316Seschrock
1206316Seschrock return (ret);
1216316Seschrock }
1226316Seschrock
1236316Seschrock /*ARGSUSED*/
1246316Seschrock void *
ses_plugin_page_lookup(ses_plugin_t * sp,ses_snap_t * snap,int pagenum,ses_node_t * np,size_t * lenp)1256316Seschrock ses_plugin_page_lookup(ses_plugin_t *sp, ses_snap_t *snap, int pagenum,
1266316Seschrock ses_node_t *np, size_t *lenp)
1276316Seschrock {
1286316Seschrock ses_snap_page_t *pp;
1296316Seschrock ses_target_t *tp = sp->sp_target;
1306316Seschrock ses_pagedesc_t *dp;
1316316Seschrock
1326316Seschrock if ((dp = ses_get_pagedesc(tp, pagenum, SES_PAGE_DIAG)) == NULL)
1336316Seschrock return (NULL);
1346316Seschrock
1356316Seschrock if ((pp = ses_snap_find_page(snap, pagenum, B_FALSE)) == NULL)
1366316Seschrock return (NULL);
1376316Seschrock
1386316Seschrock if (dp->spd_index != NULL) {
1396316Seschrock return (dp->spd_index(sp, np, pp->ssp_page, pp->ssp_len,
1406316Seschrock lenp));
1416316Seschrock } else {
1426316Seschrock *lenp = pp->ssp_len;
1436316Seschrock return (pp->ssp_page);
1446316Seschrock }
1456316Seschrock }
1466316Seschrock
1476316Seschrock ses_pagedesc_t *
ses_get_pagedesc(ses_target_t * tp,int pagenum,ses_pagetype_t type)1486316Seschrock ses_get_pagedesc(ses_target_t *tp, int pagenum, ses_pagetype_t type)
1496316Seschrock {
1506316Seschrock ses_plugin_t *sp;
1516316Seschrock ses_pagedesc_t *dp;
1526316Seschrock
1536316Seschrock for (sp = tp->st_plugin_first; sp != NULL; sp = sp->sp_next) {
1546316Seschrock if (sp->sp_pages == NULL)
1556316Seschrock continue;
1566316Seschrock
1576316Seschrock for (dp = &sp->sp_pages[0]; dp->spd_pagenum != -1;
1586316Seschrock dp++) {
1596316Seschrock if ((type == SES_PAGE_CTL && dp->spd_ctl_len == NULL) ||
1606316Seschrock (type == SES_PAGE_DIAG && dp->spd_ctl_len != NULL))
1616316Seschrock continue;
1626316Seschrock
1636316Seschrock if (dp->spd_pagenum == pagenum)
1646316Seschrock return (dp);
1656316Seschrock }
1666316Seschrock }
1676316Seschrock
1686316Seschrock (void) ses_error(ESES_BAD_PAGE, "failed to find page 0x%x", pagenum);
1696316Seschrock return (NULL);
1706316Seschrock }
1716316Seschrock
1726316Seschrock int
ses_plugin_register(ses_plugin_t * sp,int version,ses_plugin_config_t * scp)1736316Seschrock ses_plugin_register(ses_plugin_t *sp, int version, ses_plugin_config_t *scp)
1746316Seschrock {
1756316Seschrock if (version != LIBSES_PLUGIN_VERSION)
1766316Seschrock return (ses_set_errno(ESES_VERSION));
1776316Seschrock
1786316Seschrock sp->sp_pages = scp->spc_pages;
1796316Seschrock sp->sp_node_parse = scp->spc_node_parse;
1806316Seschrock sp->sp_node_ctl = scp->spc_node_ctl;
1816316Seschrock
1826316Seschrock return (0);
1836316Seschrock }
1846316Seschrock
1856316Seschrock void
ses_plugin_setspecific(ses_plugin_t * sp,void * data)1866316Seschrock ses_plugin_setspecific(ses_plugin_t *sp, void *data)
1876316Seschrock {
1886316Seschrock sp->sp_data = data;
1896316Seschrock }
1906316Seschrock
1916316Seschrock void *
ses_plugin_getspecific(ses_plugin_t * sp)1926316Seschrock ses_plugin_getspecific(ses_plugin_t *sp)
1936316Seschrock {
1946316Seschrock return (sp->sp_data);
1956316Seschrock }
1966316Seschrock
1976316Seschrock static void
ses_plugin_cleanstr(char * s)1986316Seschrock ses_plugin_cleanstr(char *s)
1996316Seschrock {
2006316Seschrock while (*s != '\0') {
2016316Seschrock if (*s == ' ' || *s == '/')
2026316Seschrock *s = '-';
2036316Seschrock s++;
2046316Seschrock }
2056316Seschrock }
2066316Seschrock
2076316Seschrock static void
ses_plugin_destroy(ses_plugin_t * sp)2086316Seschrock ses_plugin_destroy(ses_plugin_t *sp)
2096316Seschrock {
2106316Seschrock if (sp->sp_initialized && sp->sp_fini != NULL)
2116316Seschrock sp->sp_fini(sp);
2126316Seschrock
2136643Seschrock if (ses_plugin_dlclose)
2146316Seschrock (void) dlclose(sp->sp_object);
2156316Seschrock
2166316Seschrock ses_free(sp);
2176316Seschrock }
2186316Seschrock
2196316Seschrock static int
ses_plugin_loadone(ses_target_t * tp,const char * path,uint32_t pass)2206316Seschrock ses_plugin_loadone(ses_target_t *tp, const char *path, uint32_t pass)
2216316Seschrock {
2226316Seschrock ses_plugin_t *sp, **loc;
2236316Seschrock void *obj;
2246316Seschrock int (*ses_priority)(void);
2256316Seschrock
2266316Seschrock if ((obj = dlopen(path, RTLD_PARENT | RTLD_LOCAL | RTLD_LAZY)) == NULL)
2276316Seschrock return (0);
2286316Seschrock
2296316Seschrock if ((sp = ses_zalloc(sizeof (ses_plugin_t))) == NULL) {
2306316Seschrock (void) dlclose(obj);
2316316Seschrock return (-1);
2326316Seschrock }
2336316Seschrock
2346316Seschrock sp->sp_object = obj;
2356316Seschrock sp->sp_init = (int (*)())dlsym(obj, "_ses_init");
2366316Seschrock sp->sp_fini = (void (*)())dlsym(obj, "_ses_fini");
2376316Seschrock sp->sp_target = tp;
2386316Seschrock
2396316Seschrock if (sp->sp_init == NULL) {
2406316Seschrock ses_plugin_destroy(sp);
2416316Seschrock return (0);
2426316Seschrock }
2436316Seschrock
2446316Seschrock /*
2456316Seschrock * Framework modules can establish an explicit prioritying by declaring
2466316Seschrock * the '_ses_priority' symbol, which returns an integer used to create
2476316Seschrock * an explicit ordering between plugins.
2486316Seschrock */
2496316Seschrock if ((ses_priority = (int (*)())dlsym(obj, "_ses_priority")) != NULL)
2506316Seschrock sp->sp_priority = ses_priority();
2516316Seschrock
2526316Seschrock sp->sp_priority |= (uint64_t)pass << 32;
2536316Seschrock
2546316Seschrock for (loc = &tp->st_plugin_first; *loc != NULL; loc = &(*loc)->sp_next) {
2556316Seschrock if ((*loc)->sp_priority > sp->sp_priority)
2566316Seschrock break;
2576316Seschrock }
2586316Seschrock
2596316Seschrock if (*loc != NULL)
2606316Seschrock (*loc)->sp_prev = sp;
2616316Seschrock else
2626316Seschrock tp->st_plugin_last = sp;
2636316Seschrock
2646316Seschrock sp->sp_next = *loc;
2656316Seschrock *loc = sp;
2666316Seschrock
2676316Seschrock if (sp->sp_init(sp) != 0)
2686316Seschrock return (-1);
2696316Seschrock sp->sp_initialized = B_TRUE;
2706316Seschrock
2716316Seschrock return (0);
2726316Seschrock }
2736316Seschrock
2746316Seschrock static int
ses_plugin_load_dir(ses_target_t * tp,const char * pluginroot)2756316Seschrock ses_plugin_load_dir(ses_target_t *tp, const char *pluginroot)
2766316Seschrock {
2776316Seschrock char path[PATH_MAX];
2786316Seschrock DIR *dirp;
2796316Seschrock struct dirent64 *dp;
2806316Seschrock char *vendor, *product, *revision;
2816316Seschrock char isa[257];
2826316Seschrock
2836316Seschrock (void) snprintf(path, sizeof (path), "%s/%s",
2846316Seschrock pluginroot, LIBSES_PLUGIN_FRAMEWORK);
2856316Seschrock
2866316Seschrock #if defined(_LP64)
2876316Seschrock if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0)
2886316Seschrock isa[0] = '\0';
2896316Seschrock #else
2906316Seschrock isa[0] = '\0';
2916316Seschrock #endif
2926316Seschrock
2936316Seschrock if ((dirp = opendir(path)) != NULL) {
2946316Seschrock while ((dp = readdir64(dirp)) != NULL) {
2956316Seschrock if (strcmp(dp->d_name, ".") == 0 ||
2966316Seschrock strcmp(dp->d_name, "..") == 0)
2976316Seschrock continue;
2986316Seschrock
2996316Seschrock (void) snprintf(path, sizeof (path), "%s/%s/%s/%s",
3006316Seschrock pluginroot, LIBSES_PLUGIN_FRAMEWORK,
3016316Seschrock isa, dp->d_name);
3026316Seschrock
3036316Seschrock if (ses_plugin_loadone(tp, path, 0) != 0) {
3046316Seschrock (void) closedir(dirp);
3056316Seschrock return (-1);
3066316Seschrock }
3076316Seschrock }
3086316Seschrock
3096316Seschrock (void) closedir(dirp);
3106316Seschrock }
3116316Seschrock
3126316Seschrock /*
3136316Seschrock * Create a local copy of the vendor/product/revision, strip out any
3146316Seschrock * questionable characters, and then attempt to load each plugin.
3156316Seschrock */
316*13093SRoger.Faulkner@Oracle.COM vendor = strdupa(libscsi_vendor(tp->st_target));
317*13093SRoger.Faulkner@Oracle.COM product = strdupa(libscsi_product(tp->st_target));
318*13093SRoger.Faulkner@Oracle.COM revision = strdupa(libscsi_revision(tp->st_target));
3196316Seschrock
3206316Seschrock ses_plugin_cleanstr(vendor);
3216316Seschrock ses_plugin_cleanstr(product);
3226316Seschrock ses_plugin_cleanstr(revision);
3236316Seschrock
3246316Seschrock (void) snprintf(path, sizeof (path), "%s/%s/%s/%s%s", pluginroot,
3256316Seschrock LIBSES_PLUGIN_VENDOR, isa, vendor,
3266316Seschrock LIBSES_PLUGIN_EXT);
3276316Seschrock if (ses_plugin_loadone(tp, path, 1) != 0)
3286316Seschrock return (-1);
3296316Seschrock
3306316Seschrock (void) snprintf(path, sizeof (path), "%s/%s/%s/%s-%s%s", pluginroot,
3316316Seschrock LIBSES_PLUGIN_VENDOR, isa, vendor, product,
3326316Seschrock LIBSES_PLUGIN_EXT);
3336316Seschrock if (ses_plugin_loadone(tp, path, 2) != 0)
3346316Seschrock return (-1);
3356316Seschrock
3366316Seschrock (void) snprintf(path, sizeof (path), "%s/%s/%s/%s-%s-%s%s", pluginroot,
3376316Seschrock LIBSES_PLUGIN_VENDOR, isa, vendor, product,
3386316Seschrock revision, LIBSES_PLUGIN_EXT);
3396316Seschrock if (ses_plugin_loadone(tp, path, 3) != 0)
3406316Seschrock return (-1);
3416316Seschrock
3426316Seschrock return (0);
3436316Seschrock }
3446316Seschrock
3456316Seschrock int
ses_plugin_load(ses_target_t * tp)3466316Seschrock ses_plugin_load(ses_target_t *tp)
3476316Seschrock {
3486316Seschrock char pluginroot[PATH_MAX];
3496316Seschrock const char *pluginpath, *p, *q;
3506316Seschrock
3516316Seschrock if ((pluginpath = getenv("SES_PLUGINPATH")) == NULL)
3526316Seschrock pluginpath = LIBSES_DEFAULT_PLUGINDIR;
3536316Seschrock ses_plugin_dlclose = (getenv("SES_NODLCLOSE") == NULL);
3546316Seschrock
35512126SHyon.Kim@Sun.COM for (p = pluginpath; p != NULL; p = q) {
35612126SHyon.Kim@Sun.COM if ((q = strchr(p, ':')) != NULL) {
3576316Seschrock ptrdiff_t len = q - p;
3586316Seschrock (void) strncpy(pluginroot, p, len);
3596316Seschrock pluginroot[len] = '\0';
3606316Seschrock while (*q == ':')
3616316Seschrock ++q;
3626316Seschrock if (*q == '\0')
3636316Seschrock q = NULL;
3646316Seschrock if (len == 0)
3656316Seschrock continue;
3666316Seschrock } else {
3676316Seschrock (void) strcpy(pluginroot, p);
3686316Seschrock }
3696316Seschrock
3706316Seschrock if (pluginroot[0] != '/')
3716316Seschrock continue;
3726316Seschrock
37312126SHyon.Kim@Sun.COM if (ses_plugin_load_dir(tp, pluginroot) != 0)
3746316Seschrock return (-1);
3756316Seschrock }
3766316Seschrock
3776316Seschrock if (tp->st_plugin_first == NULL)
3786316Seschrock return (ses_error(ESES_PLUGIN, "no plugins found"));
3796316Seschrock
3806316Seschrock return (0);
3816316Seschrock }
3826316Seschrock
3836316Seschrock void
ses_plugin_unload(ses_target_t * tp)3846316Seschrock ses_plugin_unload(ses_target_t *tp)
3856316Seschrock {
3866316Seschrock ses_plugin_t *sp;
3876316Seschrock
3886316Seschrock while ((sp = tp->st_plugin_first) != NULL) {
3896316Seschrock tp->st_plugin_first = sp->sp_next;
3906316Seschrock ses_plugin_destroy(sp);
3916316Seschrock }
3926316Seschrock }
393