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) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/types.h>
27 #include <sys/systeminfo.h>
28 #include <sys/scsi/generic/commands.h>
29 #include <sys/scsi/impl/commands.h>
31 #include <scsi/libsmp.h>
32 #include <scsi/libsmp_plugin.h>
43 static boolean_t _libsmp_plugin_dlclose
;
46 * As part of basic initialization, we always retrieve the REPORT GENERAL
47 * data so that we will know whether this target supports the long response
51 smp_report_general(smp_target_t
*tp
)
54 smp_report_general_resp_t
*rp
;
58 if ((ap
= smp_action_alloc(SMP_FUNC_REPORT_GENERAL
, tp
, 0)) == NULL
)
61 if (smp_exec(ap
, tp
) != 0) {
63 return (smp_set_errno(ESMP_REPGEN_FAILED
));
66 smp_action_get_response(ap
, &result
, (void **)&rp
, &len
);
68 if (result
!= SMP_RES_FUNCTION_ACCEPTED
|| len
< 24) {
70 return (smp_set_errno(ESMP_REPGEN_FAILED
));
73 bcopy(rp
, &tp
->st_repgen
, sizeof (tp
->st_repgen
));
81 smp_report_manufacturer_information(smp_target_t
*tp
)
84 smp_report_manufacturer_info_resp_t
*rp
;
88 ap
= smp_action_alloc(SMP_FUNC_REPORT_MANUFACTURER_INFO
, tp
, 0);
92 if (smp_exec(ap
, tp
) != 0) {
94 return (smp_set_errno(ESMP_REPGEN_FAILED
));
97 smp_action_get_response(ap
, &result
, (void **)&rp
, &len
);
99 if (result
!= SMP_RES_FUNCTION_ACCEPTED
||
100 len
!= sizeof (smp_report_manufacturer_info_resp_t
)) {
102 return (0); /* Not supported */
105 tp
->st_vendor
= smp_trim_strdup(rp
->srmir_vendor_identification
,
106 sizeof (rp
->srmir_vendor_identification
));
107 tp
->st_product
= smp_trim_strdup(rp
->srmir_product_identification
,
108 sizeof (rp
->srmir_product_identification
));
109 tp
->st_revision
= smp_trim_strdup(rp
->srmir_product_revision_level
,
110 sizeof (rp
->srmir_product_revision_level
));
112 if (rp
->srmir_sas_1_1_format
) {
113 tp
->st_component_vendor
=
114 smp_trim_strdup(rp
->srmir_component_vendor_identification
,
115 sizeof (rp
->srmir_component_vendor_identification
));
117 tp
->st_component_id
= SCSI_READ16(&rp
->srmir_component_id
);
118 tp
->st_component_revision
= rp
->srmir_component_revision_level
;
121 if (tp
->st_vendor
== NULL
|| tp
->st_product
== NULL
||
122 tp
->st_revision
== NULL
||
123 (rp
->srmir_sas_1_1_format
&& tp
->st_component_vendor
== NULL
)) {
125 return (smp_set_errno(ESMP_NOMEM
));
134 smp_target_fill(smp_target_t
*tp
)
136 if (smp_report_general(tp
) != 0 ||
137 smp_report_manufacturer_information(tp
) != 0)
143 const smp_function_def_t
*
144 smp_get_funcdef(smp_target_t
*tp
, int fn
)
147 const smp_function_def_t
*dp
;
149 for (pp
= tp
->st_plugin_first
; pp
!= NULL
; pp
= pp
->sp_next
) {
150 if (pp
->sp_functions
== NULL
)
153 for (dp
= &pp
->sp_functions
[0]; dp
->sfd_rq_len
!= NULL
; dp
++) {
154 if (dp
->sfd_function
== fn
)
159 (void) smp_error(ESMP_BADFUNC
, "failed to find function 0x%x", fn
);
164 smp_plugin_register(smp_plugin_t
*pp
, int version
,
165 const smp_plugin_config_t
*pcp
)
167 if (version
!= LIBSMP_PLUGIN_VERSION
)
168 return (smp_set_errno(ESMP_VERSION
));
170 pp
->sp_functions
= pcp
->spc_functions
;
176 smp_plugin_setspecific(smp_plugin_t
*pp
, void *data
)
182 smp_plugin_getspecific(smp_plugin_t
*pp
)
184 return (pp
->sp_data
);
188 smp_plugin_cleanstr(char *s
)
191 if (*s
== ' ' || *s
== '/')
198 smp_plugin_destroy(smp_plugin_t
*pp
)
200 if (pp
->sp_initialized
&& pp
->sp_fini
!= NULL
)
203 if (_libsmp_plugin_dlclose
)
204 (void) dlclose(pp
->sp_object
);
210 smp_plugin_loadone(smp_target_t
*tp
, const char *path
, uint32_t pass
)
212 smp_plugin_t
*pp
, **loc
;
214 int (*smp_priority
)(void);
216 if ((obj
= dlopen(path
, RTLD_PARENT
| RTLD_LOCAL
| RTLD_LAZY
)) == NULL
)
219 if ((pp
= smp_zalloc(sizeof (smp_plugin_t
))) == NULL
) {
225 pp
->sp_init
= (int (*)())dlsym(obj
, "_smp_init");
226 pp
->sp_fini
= (void (*)())dlsym(obj
, "_smp_fini");
229 if (pp
->sp_init
== NULL
) {
230 smp_plugin_destroy(pp
);
235 * Framework modules can establish an explicit prioritying by declaring
236 * the '_smp_priority' symbol, which returns an integer used to create
237 * an explicit ordering between plugins.
239 if ((smp_priority
= (int (*)())dlsym(obj
, "_smp_priority")) != NULL
)
240 pp
->sp_priority
= smp_priority();
242 pp
->sp_priority
|= (uint64_t)pass
<< 32;
244 for (loc
= &tp
->st_plugin_first
; *loc
!= NULL
; loc
= &(*loc
)->sp_next
) {
245 if ((*loc
)->sp_priority
> pp
->sp_priority
)
250 (*loc
)->sp_prev
= pp
;
252 tp
->st_plugin_last
= pp
;
257 if (pp
->sp_init(pp
) != 0)
259 pp
->sp_initialized
= B_TRUE
;
265 smp_plugin_load_dir(smp_target_t
*tp
, const char *pluginroot
)
270 char *c_vendor
, *vendor
, *product
, *revision
;
273 (void) snprintf(path
, sizeof (path
), "%s/%s",
274 pluginroot
, LIBSMP_PLUGIN_FRAMEWORK
);
282 if ((dirp
= opendir(path
)) != NULL
) {
283 while ((dp
= readdir(dirp
)) != NULL
) {
284 if (strcmp(dp
->d_name
, ".") == 0 ||
285 strcmp(dp
->d_name
, "..") == 0)
288 (void) snprintf(path
, sizeof (path
), "%s/%s/%s/%s",
289 pluginroot
, LIBSMP_PLUGIN_FRAMEWORK
,
292 if (smp_plugin_loadone(tp
, path
, 0) != 0) {
293 (void) closedir(dirp
);
298 (void) closedir(dirp
);
302 * Now attempt to load platform-specific plugins. The framework
303 * plugins had better give us the ability to perform basic SMP
304 * functions like REPORT GENERAL and REPORT MANUFACTURER INFORMATION;
305 * if not, we're toast anyway. If the latter is not supported, we
306 * will not be able to use any vendor-specific plugins. Note that
307 * there are actually two possible specifications for vendor plugins:
308 * those matching the vendor/product/revision fields, and those
309 * matching the component vendor/id/revision fields. The component is
310 * less specific, so we try to load those first.
313 if (smp_target_fill(tp
) != 0)
316 if (tp
->st_vendor
== NULL
)
319 if (tp
->st_component_vendor
!= NULL
) {
320 c_vendor
= strdupa(tp
->st_component_vendor
);
321 smp_plugin_cleanstr(c_vendor
);
324 vendor
= strdupa(tp
->st_vendor
);
325 product
= strdupa(tp
->st_product
);
326 revision
= strdupa(tp
->st_revision
);
328 smp_plugin_cleanstr(vendor
);
329 smp_plugin_cleanstr(product
);
330 smp_plugin_cleanstr(revision
);
332 if (tp
->st_component_vendor
!= NULL
) {
333 (void) snprintf(path
, sizeof (path
), "%s/%s/%s/component_%s%s",
334 pluginroot
, LIBSMP_PLUGIN_VENDOR
, isa
, c_vendor
,
336 if (smp_plugin_loadone(tp
, path
, 1) != 0)
339 (void) snprintf(path
, sizeof (path
),
340 "%s/%s/%s/component_%s-%04x%s",
341 pluginroot
, LIBSMP_PLUGIN_VENDOR
, isa
, c_vendor
,
342 tp
->st_component_id
, LIBSMP_PLUGIN_EXT
);
343 if (smp_plugin_loadone(tp
, path
, 2) != 0)
346 (void) snprintf(path
, sizeof (path
),
347 "%s/%s/%s/component_%s-%04x-%02x%s",
348 pluginroot
, LIBSMP_PLUGIN_VENDOR
, isa
, c_vendor
,
349 tp
->st_component_id
, tp
->st_component_revision
,
351 if (smp_plugin_loadone(tp
, path
, 3) != 0)
355 (void) snprintf(path
, sizeof (path
), "%s/%s/%s/%s%s", pluginroot
,
356 LIBSMP_PLUGIN_VENDOR
, isa
, vendor
, LIBSMP_PLUGIN_EXT
);
357 if (smp_plugin_loadone(tp
, path
, 4) != 0)
360 (void) snprintf(path
, sizeof (path
), "%s/%s/%s/%s-%s%s", pluginroot
,
361 LIBSMP_PLUGIN_VENDOR
, isa
, vendor
, product
, LIBSMP_PLUGIN_EXT
);
362 if (smp_plugin_loadone(tp
, path
, 5) != 0)
365 (void) snprintf(path
, sizeof (path
), "%s/%s/%s/%s-%s-%s%s", pluginroot
,
366 LIBSMP_PLUGIN_VENDOR
, isa
, vendor
, product
,
367 revision
, LIBSMP_PLUGIN_EXT
);
368 if (smp_plugin_loadone(tp
, path
, 6) != 0)
375 smp_plugin_load(smp_target_t
*tp
)
377 char pluginroot
[PATH_MAX
];
378 const char *pluginpath
, *p
, *q
;
380 if ((pluginpath
= getenv("SMP_PLUGINPATH")) == NULL
)
381 pluginpath
= LIBSMP_DEFAULT_PLUGINDIR
;
382 _libsmp_plugin_dlclose
= (getenv("SMP_NODLCLOSE") == NULL
);
384 for (p
= pluginpath
; p
!= NULL
; p
= q
) {
385 if ((q
= strchr(p
, ':')) != NULL
) {
386 ptrdiff_t len
= q
- p
;
387 (void) strncpy(pluginroot
, p
, len
);
388 pluginroot
[len
] = '\0';
396 (void) strcpy(pluginroot
, p
);
399 if (pluginroot
[0] != '/')
402 if (smp_plugin_load_dir(tp
, pluginroot
) != 0)
406 if (tp
->st_plugin_first
== NULL
)
407 return (smp_error(ESMP_PLUGIN
, "no plugins found"));
413 smp_plugin_unload(smp_target_t
*tp
)
417 while ((pp
= tp
->st_plugin_first
) != NULL
) {
418 tp
->st_plugin_first
= pp
->sp_next
;
419 smp_plugin_destroy(pp
);