move 32-bit libs to lib/i386 subdirs & 64-bit libs to lib/
[unleashed.git] / usr / src / lib / scsi / libsmp / common / smp_engine.c
blob1a30daed6094d384cd97b11f6eb5d53dfad6ff01
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/isa_defs.h>
28 #include <sys/systeminfo.h>
29 #include <sys/scsi/generic/smp_frames.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stddef.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <dlfcn.h>
37 #include <limits.h>
38 #include <pthread.h>
39 #include <synch.h>
41 #include <scsi/libsmp.h>
42 #include "smp_impl.h"
44 static pthread_mutex_t _libsmp_lock = PTHREAD_MUTEX_INITIALIZER;
45 static smp_engine_t *_libsmp_engines;
46 static int _libsmp_refcnt;
48 static boolean_t _libsmp_engine_dlclose;
50 static void
51 smp_engine_free(smp_engine_t *ep)
53 if (ep == NULL)
54 return;
56 smp_free(ep->se_name);
57 smp_free(ep);
60 static void
61 smp_engine_destroy(smp_engine_t *ep)
63 smp_engine_t **pp;
65 ASSERT(MUTEX_HELD(&_libsmp_lock));
67 if (ep->se_fini != NULL)
68 ep->se_fini(ep);
70 if (_libsmp_engine_dlclose)
71 (void) dlclose(ep->se_object);
73 ASSERT(ep->se_refcnt == 0);
74 for (pp = &_libsmp_engines; *pp != NULL; pp = &((*pp)->se_next))
75 if (*pp == ep)
76 break;
78 if (*pp != NULL)
79 *pp = (*pp)->se_next;
81 smp_engine_free(ep);
84 void
85 smp_engine_init(void)
87 (void) pthread_mutex_lock(&_libsmp_lock);
88 ++_libsmp_refcnt;
89 (void) pthread_mutex_unlock(&_libsmp_lock);
92 void
93 smp_engine_fini(void)
95 smp_engine_t *ep;
97 (void) pthread_mutex_lock(&_libsmp_lock);
98 ASSERT(_libsmp_refcnt > 0);
99 if (--_libsmp_refcnt == 0) {
100 while (_libsmp_engines != NULL) {
101 ep = _libsmp_engines;
102 _libsmp_engines = ep->se_next;
103 smp_engine_destroy(ep);
106 (void) pthread_mutex_unlock(&_libsmp_lock);
109 static int
110 smp_engine_loadone(const char *path)
112 smp_engine_t *ep;
113 void *obj;
115 ASSERT(MUTEX_HELD(&_libsmp_lock));
117 if ((obj = dlopen(path, RTLD_PARENT | RTLD_LOCAL | RTLD_LAZY)) == NULL)
118 return (smp_set_errno(ESMP_NOENGINE));
120 if ((ep = smp_zalloc(sizeof (smp_engine_t))) == NULL) {
121 (void) dlclose(obj);
122 return (-1);
125 ep->se_object = obj;
126 ep->se_init = (int (*)())dlsym(obj, "_smp_init");
127 ep->se_fini = (void (*)())dlsym(obj, "_smp_fini");
129 if (ep->se_init == NULL) {
130 smp_engine_free(ep);
131 return (smp_set_errno(ESMP_BADENGINE));
134 if (ep->se_init(ep) != 0) {
135 smp_engine_free(ep);
136 return (-1);
139 return (0);
143 smp_engine_register(smp_engine_t *ep, int version,
144 const smp_engine_config_t *ecp)
146 ASSERT(MUTEX_HELD(&_libsmp_lock));
148 if (version != LIBSMP_ENGINE_VERSION)
149 return (smp_set_errno(ESMP_VERSION));
151 ep->se_ops = ecp->sec_ops;
152 ep->se_name = smp_strdup(ecp->sec_name);
154 if (ep->se_name == NULL)
155 return (-1);
157 ep->se_next = _libsmp_engines;
158 _libsmp_engines = ep;
160 return (0);
163 static smp_engine_t *
164 smp_engine_hold_cached(const char *name)
166 smp_engine_t *ep;
168 ASSERT(MUTEX_HELD(&_libsmp_lock));
170 for (ep = _libsmp_engines; ep != NULL; ep = ep->se_next) {
171 if (strcmp(ep->se_name, name) == 0) {
172 ++ep->se_refcnt;
173 return (ep);
177 (void) smp_set_errno(ESMP_NOENGINE);
178 return (NULL);
181 static smp_engine_t *
182 smp_engine_hold(const char *name)
184 smp_engine_t *ep;
185 const char *pluginpath, *p, *q;
186 char pluginroot[PATH_MAX];
187 char path[PATH_MAX];
188 char isa[257];
190 (void) pthread_mutex_lock(&_libsmp_lock);
191 ep = smp_engine_hold_cached(name);
192 if (ep != NULL) {
193 (void) pthread_mutex_unlock(&_libsmp_lock);
194 return (ep);
197 #if defined(_LP64)
198 isa[0] = '\0';
199 #else
200 strcpy(isa, "i386");
201 #endif
203 if ((pluginpath = getenv("SMP_PLUGINPATH")) == NULL)
204 pluginpath = LIBSMP_DEFAULT_PLUGINDIR;
206 _libsmp_engine_dlclose = (getenv("SMP_NODLCLOSE") == NULL);
208 for (p = pluginpath; p != NULL; p = q) {
209 if ((q = strchr(p, ':')) != NULL) {
210 ptrdiff_t len = q - p;
211 (void) strncpy(pluginroot, p, len);
212 pluginroot[len] = '\0';
213 while (*q == ':')
214 ++q;
215 if (*q == '\0')
216 q = NULL;
217 if (len == 0)
218 continue;
219 } else {
220 (void) strcpy(pluginroot, p);
223 if (pluginroot[0] != '/')
224 continue;
226 (void) snprintf(path, PATH_MAX, "%s/%s/%s/%s%s",
227 pluginroot, LIBSMP_PLUGIN_ENGINE,
228 isa, name, LIBSMP_PLUGIN_EXT);
230 if (smp_engine_loadone(path) == 0) {
231 ep = smp_engine_hold_cached(name);
232 (void) pthread_mutex_unlock(&_libsmp_lock);
233 return (ep);
237 return (NULL);
240 static void
241 smp_engine_rele(smp_engine_t *ep)
243 (void) pthread_mutex_lock(&_libsmp_lock);
244 ASSERT(ep->se_refcnt > 0);
245 --ep->se_refcnt;
246 (void) pthread_mutex_unlock(&_libsmp_lock);
249 static void
250 smp_parse_mtbf(const char *envvar, uint_t *intp)
252 const char *strval;
253 int intval;
255 if ((strval = getenv(envvar)) != NULL &&
256 (intval = atoi(strval)) > 0) {
257 srand48(gethrtime());
258 *intp = intval;
262 smp_target_t *
263 smp_open(const smp_target_def_t *tdp)
265 smp_engine_t *ep;
266 smp_target_t *tp;
267 void *private;
268 const char *engine;
270 if ((engine = tdp->std_engine) == NULL) {
271 if ((engine = getenv("LIBSMP_DEFAULT_ENGINE")) == NULL)
272 engine = LIBSMP_DEFAULT_ENGINE;
275 if ((ep = smp_engine_hold(engine)) == NULL)
276 return (NULL);
278 if ((tp = smp_zalloc(sizeof (smp_target_t))) == NULL) {
279 smp_engine_rele(ep);
280 return (NULL);
283 if ((private = ep->se_ops->seo_open(tdp->std_def)) == NULL) {
284 smp_engine_rele(ep);
285 smp_free(tp);
286 return (NULL);
289 smp_parse_mtbf("LIBSMP_MTBF_REQUEST", &tp->st_mtbf_request);
290 smp_parse_mtbf("LIBSMP_MTBF_RESPONSE", &tp->st_mtbf_response);
292 tp->st_engine = ep;
293 tp->st_priv = private;
295 if (smp_plugin_load(tp) != 0) {
296 smp_close(tp);
297 return (NULL);
300 return (tp);
303 void
304 smp_target_name(const smp_target_t *tp, char *buf, size_t len)
306 tp->st_engine->se_ops->seo_target_name(tp->st_priv, buf, len);
309 uint64_t
310 smp_target_addr(const smp_target_t *tp)
312 return (tp->st_engine->se_ops->seo_target_addr(tp->st_priv));
315 const char *
316 smp_target_vendor(const smp_target_t *tp)
318 return (tp->st_vendor);
321 const char *
322 smp_target_product(const smp_target_t *tp)
324 return (tp->st_product);
327 const char *
328 smp_target_revision(const smp_target_t *tp)
330 return (tp->st_revision);
333 const char *
334 smp_target_component_vendor(const smp_target_t *tp)
336 return (tp->st_component_vendor);
339 uint16_t
340 smp_target_component_id(const smp_target_t *tp)
342 return (tp->st_component_id);
345 uint8_t
346 smp_target_component_revision(const smp_target_t *tp)
348 return (tp->st_component_revision);
351 uint_t
352 smp_target_getcap(const smp_target_t *tp)
354 uint_t cap = 0;
356 if (tp->st_repgen.srgr_long_response)
357 cap |= SMP_TARGET_C_LONG_RESP;
359 if (tp->st_repgen.srgr_zoning_supported)
360 cap |= SMP_TARGET_C_ZONING;
362 if (tp->st_repgen.srgr_number_of_zone_grps == SMP_ZONE_GROUPS_256)
363 cap |= SMP_TARGET_C_ZG_256;
365 return (cap);
368 void
369 smp_target_set_change_count(smp_target_t *tp, uint16_t cc)
371 tp->st_change_count = cc;
374 uint16_t
375 smp_target_get_change_count(const smp_target_t *tp)
377 return (tp->st_change_count);
380 uint8_t
381 smp_target_get_number_of_phys(const smp_target_t *tp)
383 return (tp->st_repgen.srgr_number_of_phys);
386 uint16_t
387 smp_target_get_exp_route_indexes(const smp_target_t *tp)
389 return (tp->st_repgen.srgr_exp_route_indexes);
392 void
393 smp_close(smp_target_t *tp)
395 smp_free(tp->st_vendor);
396 smp_free(tp->st_product);
397 smp_free(tp->st_revision);
398 smp_free(tp->st_component_vendor);
400 smp_plugin_unload(tp);
402 tp->st_engine->se_ops->seo_close(tp->st_priv);
403 smp_engine_rele(tp->st_engine);
405 smp_free(tp);
409 * Set the timeout in seconds for this action. If no timeout is specified
410 * or if the timeout is set to 0, an implementation-specific timeout will be
411 * used (which may vary based on the target, command or other variables).
412 * Not all engines support all timeout values. Setting the timeout to a value
413 * not supported by the engine will cause engine-defined behavior when the
414 * action is executed.
416 void
417 smp_action_set_timeout(smp_action_t *ap, uint32_t timeout)
419 ap->sa_timeout = timeout;
423 * Obtain the timeout setting for this action.
425 uint32_t
426 smp_action_get_timeout(const smp_action_t *ap)
428 return (ap->sa_timeout);
431 const smp_function_def_t *
432 smp_action_get_function_def(const smp_action_t *ap)
434 return (ap->sa_def);
438 * Obtain the user-requested request allocation size. Note that the
439 * interpretation of this is function-dependent.
441 size_t
442 smp_action_get_rqsd(const smp_action_t *ap)
444 return (ap->sa_request_rqsd);
448 * Obtains the address and amount of space allocated for the portion of the
449 * request data that lies between the header (if any) and the CRC.
451 void
452 smp_action_get_request(const smp_action_t *ap, void **reqp, size_t *dlenp)
454 if (reqp != NULL) {
455 if (ap->sa_request_data_off >= 0) {
456 *reqp = ap->sa_request + ap->sa_request_data_off;
457 } else {
458 *reqp = NULL;
462 if (dlenp != NULL)
463 *dlenp = ap->sa_request_alloc_len -
464 (ap->sa_request_data_off + sizeof (smp_crc_t));
468 * Obtains the address and amount of valid response data (that part of the
469 * response frame, if any, that lies between the header and the CRC). The
470 * result, if any, is also returned in the location pointed to by result.
472 void
473 smp_action_get_response(const smp_action_t *ap, smp_result_t *resultp,
474 void **respp, size_t *dlenp)
476 if (resultp != NULL)
477 *resultp = ap->sa_result;
479 if (respp != NULL)
480 *respp = (ap->sa_response_data_len > 0) ?
481 (ap->sa_response + ap->sa_response_data_off) : NULL;
483 if (dlenp != NULL)
484 *dlenp = ap->sa_response_data_len;
488 * Obtains the entire request frame and the amount of space allocated for it.
489 * This is intended only for use by plugins; front-end consumers should use
490 * smp_action_get_request() instead.
492 void
493 smp_action_get_request_frame(const smp_action_t *ap, void **reqp, size_t *alenp)
495 if (reqp != NULL)
496 *reqp = ap->sa_request;
498 if (alenp != NULL)
499 *alenp = ap->sa_request_alloc_len;
503 * Obtains the entire response frame and the amount of space allocated for it.
504 * This is intended only for use by plugins; front-end consumers should use
505 * smp_action_get_response() instead.
507 void
508 smp_action_get_response_frame(const smp_action_t *ap,
509 void **respp, size_t *lenp)
511 if (respp != NULL)
512 *respp = ap->sa_response;
514 if (lenp != NULL) {
515 if (ap->sa_flags & SMP_ACTION_F_EXEC)
516 *lenp = ap->sa_response_engine_len;
517 else
518 *lenp = ap->sa_response_alloc_len;
523 * Set the total response frame length as determined by the engine. This
524 * should never be called by consumers or plugins other than engines.
526 void
527 smp_action_set_response_len(smp_action_t *ap, size_t elen)
529 ap->sa_response_engine_len = elen;
532 void
533 smp_action_set_result(smp_action_t *ap, smp_result_t result)
535 ap->sa_result = result;
539 * Allocate an action object. The object will contain a request buffer
540 * to hold the frame to be transmitted to the target, a response buffer
541 * for the frame to be received from it, and auxiliary private information.
543 * For the request, callers may specify:
545 * - An externally-allocated buffer and its size in bytes, or
546 * - NULL and a function-specific size descriptor, or
548 * Note that for some functions, the size descriptor may be 0, indicating that
549 * a default buffer length will be used. It is the caller's responsibility
550 * to correctly interpret function-specific buffer lengths. See appropriate
551 * plugin documentation for information on buffer sizes and buffer content
552 * interpretation.
554 * For the response, callers may specify:
556 * - An externally-allocated buffer and its size in bytes, or
557 * - NULL and 0, to use a guaranteed-sufficient buffer.
559 * If an invalid request size descriptor is provided, or a preallocated
560 * buffer is provided and it is insufficiently large, this function will
561 * fail with ESMP_RANGE.
563 * Callers are discouraged from allocating their own buffers and must be
564 * aware of the consequences of specifying non-default lengths.
566 smp_action_t *
567 smp_action_xalloc(smp_function_t fn, smp_target_t *tp,
568 void *rq, size_t rqsd, void *rs, size_t rslen)
570 smp_plugin_t *pp;
571 const smp_function_def_t *dp = NULL;
572 smp_action_t *ap;
573 uint_t cap;
574 size_t rqlen, len;
575 uint8_t *alloc;
576 int i;
578 cap = smp_target_getcap(tp);
580 for (pp = tp->st_plugin_first; pp != NULL; pp = pp->sp_next) {
581 if (pp->sp_functions == NULL)
582 continue;
584 for (i = 0; pp->sp_functions[i].sfd_rq_len != NULL; i++) {
585 dp = &pp->sp_functions[i];
586 if (dp->sfd_function == fn &&
587 ((cap & dp->sfd_capmask) == dp->sfd_capset))
588 break;
592 if (dp == NULL) {
593 (void) smp_set_errno(ESMP_BADFUNC);
594 return (NULL);
597 if (rq == NULL) {
598 if ((rqlen = dp->sfd_rq_len(rqsd, tp)) == 0)
599 return (NULL);
600 } else if (rqlen < SMP_REQ_MINLEN) {
601 (void) smp_set_errno(ESMP_RANGE);
602 return (NULL);
605 if (rs == NULL) {
606 rslen = 1020 + SMP_RESP_MINLEN;
607 } else if (rslen < SMP_RESP_MINLEN) {
608 (void) smp_set_errno(ESMP_RANGE);
609 return (NULL);
612 len = offsetof(smp_action_t, sa_buf[0]);
613 if (rq == NULL)
614 len += rqlen;
615 if (rs == NULL)
616 len += rslen;
618 if ((ap = smp_zalloc(len)) == NULL)
619 return (NULL);
621 ap->sa_def = dp;
622 alloc = ap->sa_buf;
624 if (rq == NULL) {
625 ap->sa_request = alloc;
626 alloc += rqlen;
628 ap->sa_request_alloc_len = rqlen;
630 if (rs == NULL) {
631 ap->sa_response = alloc;
632 alloc += rslen;
634 ap->sa_response_alloc_len = rslen;
636 ASSERT(alloc - (uint8_t *)ap == len);
638 ap->sa_request_data_off = dp->sfd_rq_dataoff(ap, tp);
639 ap->sa_flags |= SMP_ACTION_F_OFFSET;
641 return (ap);
645 * Simplified action allocator. All buffers are allocated for the
646 * caller. The request buffer size will be based on the function-specific
647 * interpretation of the rqsize parameter. The response buffer size will be
648 * a function-specific value sufficiently large to capture any response.
650 smp_action_t *
651 smp_action_alloc(smp_function_t fn, smp_target_t *tp, size_t rqsd)
653 return (smp_action_xalloc(fn, tp, NULL, rqsd, NULL, 0));
656 void
657 smp_action_free(smp_action_t *ap)
659 if (ap == NULL)
660 return;
662 smp_free(ap);
666 * For testing purposes, we allow data to be corrupted via an environment
667 * variable setting. This helps ensure that higher level software can cope with
668 * arbitrarily broken targets. The mtbf value represents the number of bytes we
669 * will see, on average, in between each failure. Therefore, for each N bytes,
670 * we would expect to see (N / mtbf) bytes of corruption.
672 static void
673 smp_inject_errors(void *data, size_t len, uint_t mtbf)
675 char *buf = data;
676 double prob;
677 size_t index;
679 if (len == 0)
680 return;
682 prob = (double)len / mtbf;
684 while (prob > 1) {
685 index = lrand48() % len;
686 buf[index] = (lrand48() % 256);
687 prob -= 1;
690 if (drand48() <= prob) {
691 index = lrand48() % len;
692 buf[index] = (lrand48() % 256);
697 smp_exec(smp_action_t *ap, smp_target_t *tp)
699 const smp_function_def_t *dp;
700 int ret;
702 dp = ap->sa_def;
703 dp->sfd_rq_setframe(ap, tp);
705 if (tp->st_mtbf_request != 0) {
706 smp_inject_errors(ap->sa_request, ap->sa_request_alloc_len,
707 tp->st_mtbf_request);
710 ret = tp->st_engine->se_ops->seo_exec(tp->st_priv, ap);
712 if (ret == 0 && tp->st_mtbf_response != 0) {
713 smp_inject_errors(ap->sa_response, ap->sa_response_engine_len,
714 tp->st_mtbf_response);
717 if (ret != 0)
718 return (ret);
720 ap->sa_flags |= SMP_ACTION_F_EXEC;
723 * Obtain the data length and offset from the underlying plugins.
724 * Then offer the plugins the opportunity to set any parameters in the
725 * target to reflect state observed in the response.
727 ap->sa_response_data_len = dp->sfd_rs_datalen(ap, tp);
728 ap->sa_response_data_off = dp->sfd_rs_dataoff(ap, tp);
729 dp->sfd_rs_getparams(ap, tp);
731 ap->sa_flags |= SMP_ACTION_F_DECODE;
733 return (0);