4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
29 #include <scsi/libses.h>
32 static boolean_t ses_plugin_dlclose
;
36 ses_plugin_ctlpage_lookup(ses_plugin_t
*sp
, ses_snap_t
*snap
, int pagenum
,
37 size_t len
, ses_node_t
*np
, boolean_t unique
)
39 ses_target_t
*tp
= snap
->ss_target
;
43 if ((pp
= ses_snap_ctl_page(snap
, pagenum
, len
, unique
)) == NULL
)
46 if ((dp
= ses_get_pagedesc(tp
, pagenum
, SES_PAGE_CTL
)) == NULL
)
49 if (np
!= NULL
&& dp
->spd_ctl_fill
!= NULL
) {
50 return (dp
->spd_ctl_fill(sp
, pp
->ssp_page
,
53 return (pp
->ssp_page
);
58 ses_fill_node(ses_node_t
*np
)
60 ses_target_t
*tp
= np
->sn_snapshot
->ss_target
;
63 for (sp
= tp
->st_plugin_first
; sp
!= NULL
; sp
= sp
->sp_next
) {
64 if (sp
->sp_node_parse
== NULL
)
67 if (sp
->sp_node_parse(sp
, np
) != 0)
75 ses_node_ctl(ses_node_t
*np
, const char *op
, nvlist_t
*arg
)
77 ses_target_t
*tp
= np
->sn_snapshot
->ss_target
;
83 if (nvlist_dup(arg
, &nvl
, 0) != 0)
84 return (ses_set_errno(ESES_NOMEM
));
87 * Technically we could get away with a per-snapshot lock while we fill
88 * the control page contents, but this doesn't take much time and we
89 * want actual control operations to be protected per-target, so we just
90 * take the target lock.
92 (void) pthread_mutex_lock(&tp
->st_lock
);
95 * We walk the list of plugins backwards, so that a product-specific
96 * plugin can rewrite the nvlist to control operations in terms of the
97 * standard mechanisms, if desired.
99 for (sp
= tp
->st_plugin_first
; sp
!= NULL
; sp
= sp
->sp_next
) {
100 if (sp
->sp_node_ctl
== NULL
)
103 if (sp
->sp_node_ctl(sp
, np
, op
, nvl
) != 0) {
105 (void) pthread_mutex_unlock(&tp
->st_lock
);
110 if ((nvp
= nvlist_next_nvpair(nvl
, NULL
)) != NULL
) {
111 (void) ses_error(ESES_NOTSUP
, "property '%s' invalid for "
112 "this node", nvpair_name(nvp
));
114 (void) pthread_mutex_unlock(&tp
->st_lock
);
120 ret
= ses_snap_do_ctl(np
->sn_snapshot
);
121 (void) pthread_mutex_unlock(&tp
->st_lock
);
128 ses_plugin_page_lookup(ses_plugin_t
*sp
, ses_snap_t
*snap
, int pagenum
,
129 ses_node_t
*np
, size_t *lenp
)
132 ses_target_t
*tp
= sp
->sp_target
;
135 if ((dp
= ses_get_pagedesc(tp
, pagenum
, SES_PAGE_DIAG
)) == NULL
)
138 if ((pp
= ses_snap_find_page(snap
, pagenum
, B_FALSE
)) == NULL
)
141 if (np
!= NULL
&& dp
->spd_index
!= NULL
) {
142 return (dp
->spd_index(sp
, np
, pp
->ssp_page
, pp
->ssp_len
,
146 return (pp
->ssp_page
);
151 ses_get_pagedesc(ses_target_t
*tp
, int pagenum
, ses_pagetype_t type
)
156 for (sp
= tp
->st_plugin_first
; sp
!= NULL
; sp
= sp
->sp_next
) {
157 if (sp
->sp_pages
== NULL
)
160 for (dp
= &sp
->sp_pages
[0]; dp
->spd_pagenum
!= -1;
162 if ((type
== SES_PAGE_CTL
&& dp
->spd_ctl_len
== NULL
) ||
163 (type
== SES_PAGE_DIAG
&& dp
->spd_ctl_len
!= NULL
))
166 if (dp
->spd_pagenum
== pagenum
)
171 (void) ses_error(ESES_BAD_PAGE
, "failed to find page 0x%x", pagenum
);
176 ses_plugin_register(ses_plugin_t
*sp
, int version
, ses_plugin_config_t
*scp
)
178 if (version
!= LIBSES_PLUGIN_VERSION
)
179 return (ses_set_errno(ESES_VERSION
));
181 sp
->sp_pages
= scp
->spc_pages
;
182 sp
->sp_node_parse
= scp
->spc_node_parse
;
183 sp
->sp_node_ctl
= scp
->spc_node_ctl
;
189 ses_plugin_setspecific(ses_plugin_t
*sp
, void *data
)
195 ses_plugin_getspecific(ses_plugin_t
*sp
)
197 return (sp
->sp_data
);
201 ses_plugin_cleanstr(char *s
)
204 if (*s
== ' ' || *s
== '/')
211 ses_plugin_destroy(ses_plugin_t
*sp
)
213 if (sp
->sp_initialized
&& sp
->sp_fini
!= NULL
)
216 if (ses_plugin_dlclose
)
217 (void) dlclose(sp
->sp_object
);
223 ses_plugin_loadone(ses_target_t
*tp
, const char *path
, uint32_t pass
)
225 ses_plugin_t
*sp
, **loc
;
227 int (*ses_priority
)(void);
229 if ((obj
= dlopen(path
, RTLD_PARENT
| RTLD_LOCAL
| RTLD_LAZY
)) == NULL
)
232 if ((sp
= ses_zalloc(sizeof (ses_plugin_t
))) == NULL
) {
238 sp
->sp_init
= (int (*)())dlsym(obj
, "_ses_init");
239 sp
->sp_fini
= (void (*)())dlsym(obj
, "_ses_fini");
242 if (sp
->sp_init
== NULL
) {
243 ses_plugin_destroy(sp
);
248 * Framework modules can establish an explicit prioritying by declaring
249 * the '_ses_priority' symbol, which returns an integer used to create
250 * an explicit ordering between plugins.
252 if ((ses_priority
= (int (*)())dlsym(obj
, "_ses_priority")) != NULL
)
253 sp
->sp_priority
= ses_priority();
255 sp
->sp_priority
|= (uint64_t)pass
<< 32;
257 for (loc
= &tp
->st_plugin_first
; *loc
!= NULL
; loc
= &(*loc
)->sp_next
) {
258 if ((*loc
)->sp_priority
> sp
->sp_priority
)
263 (*loc
)->sp_prev
= sp
;
265 tp
->st_plugin_last
= sp
;
270 if (sp
->sp_init(sp
) != 0)
272 sp
->sp_initialized
= B_TRUE
;
278 ses_plugin_load_dir(ses_target_t
*tp
, const char *pluginroot
)
283 char *vendor
, *product
, *revision
;
286 (void) snprintf(path
, sizeof (path
), "%s/%s",
287 pluginroot
, LIBSES_PLUGIN_FRAMEWORK
);
290 if (sysinfo(SI_ARCHITECTURE_64
, isa
, sizeof (isa
)) < 0)
296 if ((dirp
= opendir(path
)) != NULL
) {
297 while ((dp
= readdir64(dirp
)) != NULL
) {
298 if (strcmp(dp
->d_name
, ".") == 0 ||
299 strcmp(dp
->d_name
, "..") == 0)
302 (void) snprintf(path
, sizeof (path
), "%s/%s/%s/%s",
303 pluginroot
, LIBSES_PLUGIN_FRAMEWORK
,
306 if (ses_plugin_loadone(tp
, path
, 0) != 0) {
307 (void) closedir(dirp
);
312 (void) closedir(dirp
);
316 * Create a local copy of the vendor/product/revision, strip out any
317 * questionable characters, and then attempt to load each plugin.
319 vendor
= strdupa(libscsi_vendor(tp
->st_target
));
320 product
= strdupa(libscsi_product(tp
->st_target
));
321 revision
= strdupa(libscsi_revision(tp
->st_target
));
323 ses_plugin_cleanstr(vendor
);
324 ses_plugin_cleanstr(product
);
325 ses_plugin_cleanstr(revision
);
327 (void) snprintf(path
, sizeof (path
), "%s/%s/%s/%s%s", pluginroot
,
328 LIBSES_PLUGIN_VENDOR
, isa
, vendor
,
330 if (ses_plugin_loadone(tp
, path
, 1) != 0)
333 (void) snprintf(path
, sizeof (path
), "%s/%s/%s/%s-%s%s", pluginroot
,
334 LIBSES_PLUGIN_VENDOR
, isa
, vendor
, product
,
336 if (ses_plugin_loadone(tp
, path
, 2) != 0)
339 (void) snprintf(path
, sizeof (path
), "%s/%s/%s/%s-%s-%s%s", pluginroot
,
340 LIBSES_PLUGIN_VENDOR
, isa
, vendor
, product
,
341 revision
, LIBSES_PLUGIN_EXT
);
342 if (ses_plugin_loadone(tp
, path
, 3) != 0)
349 ses_plugin_load(ses_target_t
*tp
)
351 char pluginroot
[PATH_MAX
];
352 const char *pluginpath
, *p
, *q
;
354 if ((pluginpath
= getenv("SES_PLUGINPATH")) == NULL
)
355 pluginpath
= LIBSES_DEFAULT_PLUGINDIR
;
356 ses_plugin_dlclose
= (getenv("SES_NODLCLOSE") == NULL
);
358 for (p
= pluginpath
; p
!= NULL
; p
= q
) {
359 if ((q
= strchr(p
, ':')) != NULL
) {
360 ptrdiff_t len
= q
- p
;
361 (void) strncpy(pluginroot
, p
, len
);
362 pluginroot
[len
] = '\0';
370 (void) strcpy(pluginroot
, p
);
373 if (pluginroot
[0] != '/')
376 if (ses_plugin_load_dir(tp
, pluginroot
) != 0)
380 if (tp
->st_plugin_first
== NULL
)
381 return (ses_error(ESES_PLUGIN
, "no plugins found"));
387 ses_plugin_unload(ses_target_t
*tp
)
391 while ((sp
= tp
->st_plugin_first
) != NULL
) {
392 tp
->st_plugin_first
= sp
->sp_next
;
393 ses_plugin_destroy(sp
);