move 32-bit libs to lib/i386 subdirs & 64-bit libs to lib/
[unleashed.git] / usr / src / lib / scsi / libsmp / common / smp_plugin.c
blob9db98f081c9475717470a68d39beb8b8f2a8e358
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
34 #include <dlfcn.h>
35 #include <link.h>
36 #include <dirent.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <limits.h>
41 #include "smp_impl.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
48 * format.
50 static int
51 smp_report_general(smp_target_t *tp)
53 smp_action_t *ap;
54 smp_report_general_resp_t *rp;
55 smp_result_t result;
56 size_t len;
58 if ((ap = smp_action_alloc(SMP_FUNC_REPORT_GENERAL, tp, 0)) == NULL)
59 return (-1);
61 if (smp_exec(ap, tp) != 0) {
62 smp_action_free(ap);
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) {
69 smp_action_free(ap);
70 return (smp_set_errno(ESMP_REPGEN_FAILED));
73 bcopy(rp, &tp->st_repgen, sizeof (tp->st_repgen));
75 smp_action_free(ap);
77 return (0);
80 static int
81 smp_report_manufacturer_information(smp_target_t *tp)
83 smp_action_t *ap;
84 smp_report_manufacturer_info_resp_t *rp;
85 smp_result_t result;
86 size_t len;
88 ap = smp_action_alloc(SMP_FUNC_REPORT_MANUFACTURER_INFO, tp, 0);
89 if (ap == NULL)
90 return (-1);
92 if (smp_exec(ap, tp) != 0) {
93 smp_action_free(ap);
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)) {
101 smp_action_free(ap);
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)) {
124 smp_action_free(ap);
125 return (smp_set_errno(ESMP_NOMEM));
128 smp_action_free(ap);
130 return (0);
133 static int
134 smp_target_fill(smp_target_t *tp)
136 if (smp_report_general(tp) != 0 ||
137 smp_report_manufacturer_information(tp) != 0)
138 return (-1);
140 return (0);
143 const smp_function_def_t *
144 smp_get_funcdef(smp_target_t *tp, int fn)
146 smp_plugin_t *pp;
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)
151 continue;
153 for (dp = &pp->sp_functions[0]; dp->sfd_rq_len != NULL; dp++) {
154 if (dp->sfd_function == fn)
155 return (dp);
159 (void) smp_error(ESMP_BADFUNC, "failed to find function 0x%x", fn);
160 return (NULL);
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;
172 return (0);
175 void
176 smp_plugin_setspecific(smp_plugin_t *pp, void *data)
178 pp->sp_data = data;
181 void *
182 smp_plugin_getspecific(smp_plugin_t *pp)
184 return (pp->sp_data);
187 static void
188 smp_plugin_cleanstr(char *s)
190 while (*s != '\0') {
191 if (*s == ' ' || *s == '/')
192 *s = '-';
193 s++;
197 static void
198 smp_plugin_destroy(smp_plugin_t *pp)
200 if (pp->sp_initialized && pp->sp_fini != NULL)
201 pp->sp_fini(pp);
203 if (_libsmp_plugin_dlclose)
204 (void) dlclose(pp->sp_object);
206 smp_free(pp);
209 static int
210 smp_plugin_loadone(smp_target_t *tp, const char *path, uint32_t pass)
212 smp_plugin_t *pp, **loc;
213 void *obj;
214 int (*smp_priority)(void);
216 if ((obj = dlopen(path, RTLD_PARENT | RTLD_LOCAL | RTLD_LAZY)) == NULL)
217 return (0);
219 if ((pp = smp_zalloc(sizeof (smp_plugin_t))) == NULL) {
220 (void) dlclose(obj);
221 return (-1);
224 pp->sp_object = obj;
225 pp->sp_init = (int (*)())dlsym(obj, "_smp_init");
226 pp->sp_fini = (void (*)())dlsym(obj, "_smp_fini");
227 pp->sp_target = tp;
229 if (pp->sp_init == NULL) {
230 smp_plugin_destroy(pp);
231 return (0);
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)
246 break;
249 if (*loc != NULL)
250 (*loc)->sp_prev = pp;
251 else
252 tp->st_plugin_last = pp;
254 pp->sp_next = *loc;
255 *loc = pp;
257 if (pp->sp_init(pp) != 0)
258 return (-1);
259 pp->sp_initialized = B_TRUE;
261 return (0);
264 static int
265 smp_plugin_load_dir(smp_target_t *tp, const char *pluginroot)
267 char path[PATH_MAX];
268 DIR *dirp;
269 struct dirent *dp;
270 char *c_vendor, *vendor, *product, *revision;
271 char isa[257];
273 (void) snprintf(path, sizeof (path), "%s/%s",
274 pluginroot, LIBSMP_PLUGIN_FRAMEWORK);
276 #if defined(_LP64)
277 isa[0] = '\0';
278 #else
279 strcpy(isa, "i386");
280 #endif
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)
286 continue;
288 (void) snprintf(path, sizeof (path), "%s/%s/%s/%s",
289 pluginroot, LIBSMP_PLUGIN_FRAMEWORK,
290 isa, dp->d_name);
292 if (smp_plugin_loadone(tp, path, 0) != 0) {
293 (void) closedir(dirp);
294 return (-1);
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)
314 return (-1);
316 if (tp->st_vendor == NULL)
317 return (0);
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,
335 LIBSMP_PLUGIN_EXT);
336 if (smp_plugin_loadone(tp, path, 1) != 0)
337 return (-1);
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)
344 return (-1);
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,
350 LIBSMP_PLUGIN_EXT);
351 if (smp_plugin_loadone(tp, path, 3) != 0)
352 return (-1);
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)
358 return (-1);
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)
363 return (-1);
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)
369 return (-1);
371 return (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';
389 while (*q == ':')
390 ++q;
391 if (*q == '\0')
392 q = NULL;
393 if (len == 0)
394 continue;
395 } else {
396 (void) strcpy(pluginroot, p);
399 if (pluginroot[0] != '/')
400 continue;
402 if (smp_plugin_load_dir(tp, pluginroot) != 0)
403 return (-1);
406 if (tp->st_plugin_first == NULL)
407 return (smp_error(ESMP_PLUGIN, "no plugins found"));
409 return (0);
412 void
413 smp_plugin_unload(smp_target_t *tp)
415 smp_plugin_t *pp;
417 while ((pp = tp->st_plugin_first) != NULL) {
418 tp->st_plugin_first = pp->sp_next;
419 smp_plugin_destroy(pp);