xref: /illumos-gate/usr/src/lib/scsi/libsmp/common/smp_engine.c (revision 8d0c3d29bb99f6521f2dc5058a7e4debebad7899)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/isa_defs.h>
28 #include <sys/systeminfo.h>
29 #include <sys/scsi/generic/smp_frames.h>
30 
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>
40 
41 #include <scsi/libsmp.h>
42 #include "smp_impl.h"
43 
44 static pthread_mutex_t _libsmp_lock = PTHREAD_MUTEX_INITIALIZER;
45 static smp_engine_t *_libsmp_engines;
46 static int _libsmp_refcnt;
47 
48 static boolean_t _libsmp_engine_dlclose;
49 
50 static void
51 smp_engine_free(smp_engine_t *ep)
52 {
53 	if (ep == NULL)
54 		return;
55 
56 	smp_free(ep->se_name);
57 	smp_free(ep);
58 }
59 
60 static void
61 smp_engine_destroy(smp_engine_t *ep)
62 {
63 	smp_engine_t **pp;
64 
65 	ASSERT(MUTEX_HELD(&_libsmp_lock));
66 
67 	if (ep->se_fini != NULL)
68 		ep->se_fini(ep);
69 
70 	if (_libsmp_engine_dlclose)
71 		(void) dlclose(ep->se_object);
72 
73 	ASSERT(ep->se_refcnt == 0);
74 	for (pp = &_libsmp_engines; *pp != NULL; pp = &((*pp)->se_next))
75 		if (*pp == ep)
76 			break;
77 
78 	if (*pp != NULL)
79 		*pp = (*pp)->se_next;
80 
81 	smp_engine_free(ep);
82 }
83 
84 void
85 smp_engine_init(void)
86 {
87 	(void) pthread_mutex_lock(&_libsmp_lock);
88 	++_libsmp_refcnt;
89 	(void) pthread_mutex_unlock(&_libsmp_lock);
90 }
91 
92 void
93 smp_engine_fini(void)
94 {
95 	smp_engine_t *ep;
96 
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);
104 		}
105 	}
106 	(void) pthread_mutex_unlock(&_libsmp_lock);
107 }
108 
109 static int
110 smp_engine_loadone(const char *path)
111 {
112 	smp_engine_t *ep;
113 	void *obj;
114 
115 	ASSERT(MUTEX_HELD(&_libsmp_lock));
116 
117 	if ((obj = dlopen(path, RTLD_PARENT | RTLD_LOCAL | RTLD_LAZY)) == NULL)
118 		return (smp_set_errno(ESMP_NOENGINE));
119 
120 	if ((ep = smp_zalloc(sizeof (smp_engine_t))) == NULL) {
121 		(void) dlclose(obj);
122 		return (-1);
123 	}
124 
125 	ep->se_object = obj;
126 	ep->se_init = (int (*)())dlsym(obj, "_smp_init");
127 	ep->se_fini = (void (*)())dlsym(obj, "_smp_fini");
128 
129 	if (ep->se_init == NULL) {
130 		smp_engine_free(ep);
131 		return (smp_set_errno(ESMP_BADENGINE));
132 	}
133 
134 	if (ep->se_init(ep) != 0) {
135 		smp_engine_free(ep);
136 		return (-1);
137 	}
138 
139 	return (0);
140 }
141 
142 int
143 smp_engine_register(smp_engine_t *ep, int version,
144     const smp_engine_config_t *ecp)
145 {
146 	ASSERT(MUTEX_HELD(&_libsmp_lock));
147 
148 	if (version != LIBSMP_ENGINE_VERSION)
149 		return (smp_set_errno(ESMP_VERSION));
150 
151 	ep->se_ops = ecp->sec_ops;
152 	ep->se_name = smp_strdup(ecp->sec_name);
153 
154 	if (ep->se_name == NULL)
155 		return (-1);
156 
157 	ep->se_next = _libsmp_engines;
158 	_libsmp_engines = ep;
159 
160 	return (0);
161 }
162 
163 static smp_engine_t *
164 smp_engine_hold_cached(const char *name)
165 {
166 	smp_engine_t *ep;
167 
168 	ASSERT(MUTEX_HELD(&_libsmp_lock));
169 
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);
174 		}
175 	}
176 
177 	(void) smp_set_errno(ESMP_NOENGINE);
178 	return (NULL);
179 }
180 
181 static smp_engine_t *
182 smp_engine_hold(const char *name)
183 {
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];
189 
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);
195 	}
196 
197 #if defined(_LP64)
198 	if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0)
199 		isa[0] = '\0';
200 #else
201 	isa[0] = '\0';
202 #endif
203 
204 	if ((pluginpath = getenv("SMP_PLUGINPATH")) == NULL)
205 		pluginpath = LIBSMP_DEFAULT_PLUGINDIR;
206 
207 	_libsmp_engine_dlclose = (getenv("SMP_NODLCLOSE") == NULL);
208 
209 	for (p = pluginpath; p != NULL; p = q) {
210 		if ((q = strchr(p, ':')) != NULL) {
211 			ptrdiff_t len = q - p;
212 			(void) strncpy(pluginroot, p, len);
213 			pluginroot[len] = '\0';
214 			while (*q == ':')
215 				++q;
216 			if (*q == '\0')
217 				q = NULL;
218 			if (len == 0)
219 				continue;
220 		} else {
221 			(void) strcpy(pluginroot, p);
222 		}
223 
224 		if (pluginroot[0] != '/')
225 			continue;
226 
227 		(void) snprintf(path, PATH_MAX, "%s/%s/%s/%s%s",
228 		    pluginroot, LIBSMP_PLUGIN_ENGINE,
229 		    isa, name, LIBSMP_PLUGIN_EXT);
230 
231 		if (smp_engine_loadone(path) == 0) {
232 			ep = smp_engine_hold_cached(name);
233 			(void) pthread_mutex_unlock(&_libsmp_lock);
234 			return (ep);
235 		}
236 	}
237 
238 	return (NULL);
239 }
240 
241 static void
242 smp_engine_rele(smp_engine_t *ep)
243 {
244 	(void) pthread_mutex_lock(&_libsmp_lock);
245 	ASSERT(ep->se_refcnt > 0);
246 	--ep->se_refcnt;
247 	(void) pthread_mutex_unlock(&_libsmp_lock);
248 }
249 
250 static void
251 smp_parse_mtbf(const char *envvar, uint_t *intp)
252 {
253 	const char *strval;
254 	int intval;
255 
256 	if ((strval = getenv(envvar)) != NULL &&
257 	    (intval = atoi(strval)) > 0) {
258 		srand48(gethrtime());
259 		*intp = intval;
260 	}
261 }
262 
263 smp_target_t *
264 smp_open(const smp_target_def_t *tdp)
265 {
266 	smp_engine_t *ep;
267 	smp_target_t *tp;
268 	void *private;
269 	const char *engine;
270 
271 	if ((engine = tdp->std_engine) == NULL) {
272 		if ((engine = getenv("LIBSMP_DEFAULT_ENGINE")) == NULL)
273 			engine = LIBSMP_DEFAULT_ENGINE;
274 	}
275 
276 	if ((ep = smp_engine_hold(engine)) == NULL)
277 		return (NULL);
278 
279 	if ((tp = smp_zalloc(sizeof (smp_target_t))) == NULL) {
280 		smp_engine_rele(ep);
281 		return (NULL);
282 	}
283 
284 	if ((private = ep->se_ops->seo_open(tdp->std_def)) == NULL) {
285 		smp_engine_rele(ep);
286 		smp_free(tp);
287 		return (NULL);
288 	}
289 
290 	smp_parse_mtbf("LIBSMP_MTBF_REQUEST", &tp->st_mtbf_request);
291 	smp_parse_mtbf("LIBSMP_MTBF_RESPONSE", &tp->st_mtbf_response);
292 
293 	tp->st_engine = ep;
294 	tp->st_priv = private;
295 
296 	if (smp_plugin_load(tp) != 0) {
297 		smp_close(tp);
298 		return (NULL);
299 	}
300 
301 	return (tp);
302 }
303 
304 void
305 smp_target_name(const smp_target_t *tp, char *buf, size_t len)
306 {
307 	tp->st_engine->se_ops->seo_target_name(tp->st_priv, buf, len);
308 }
309 
310 uint64_t
311 smp_target_addr(const smp_target_t *tp)
312 {
313 	return (tp->st_engine->se_ops->seo_target_addr(tp->st_priv));
314 }
315 
316 const char *
317 smp_target_vendor(const smp_target_t *tp)
318 {
319 	return (tp->st_vendor);
320 }
321 
322 const char *
323 smp_target_product(const smp_target_t *tp)
324 {
325 	return (tp->st_product);
326 }
327 
328 const char *
329 smp_target_revision(const smp_target_t *tp)
330 {
331 	return (tp->st_revision);
332 }
333 
334 const char *
335 smp_target_component_vendor(const smp_target_t *tp)
336 {
337 	return (tp->st_component_vendor);
338 }
339 
340 uint16_t
341 smp_target_component_id(const smp_target_t *tp)
342 {
343 	return (tp->st_component_id);
344 }
345 
346 uint8_t
347 smp_target_component_revision(const smp_target_t *tp)
348 {
349 	return (tp->st_component_revision);
350 }
351 
352 uint_t
353 smp_target_getcap(const smp_target_t *tp)
354 {
355 	uint_t cap = 0;
356 
357 	if (tp->st_repgen.srgr_long_response)
358 		cap |= SMP_TARGET_C_LONG_RESP;
359 
360 	if (tp->st_repgen.srgr_zoning_supported)
361 		cap |= SMP_TARGET_C_ZONING;
362 
363 	if (tp->st_repgen.srgr_number_of_zone_grps == SMP_ZONE_GROUPS_256)
364 		cap |= SMP_TARGET_C_ZG_256;
365 
366 	return (cap);
367 }
368 
369 void
370 smp_target_set_change_count(smp_target_t *tp, uint16_t cc)
371 {
372 	tp->st_change_count = cc;
373 }
374 
375 uint16_t
376 smp_target_get_change_count(const smp_target_t *tp)
377 {
378 	return (tp->st_change_count);
379 }
380 
381 void
382 smp_close(smp_target_t *tp)
383 {
384 	smp_free(tp->st_vendor);
385 	smp_free(tp->st_product);
386 	smp_free(tp->st_revision);
387 	smp_free(tp->st_component_vendor);
388 
389 	smp_plugin_unload(tp);
390 
391 	tp->st_engine->se_ops->seo_close(tp->st_priv);
392 	smp_engine_rele(tp->st_engine);
393 
394 	smp_free(tp);
395 }
396 
397 /*
398  * Set the timeout in seconds for this action.  If no timeout is specified
399  * or if the timeout is set to 0, an implementation-specific timeout will be
400  * used (which may vary based on the target, command or other variables).
401  * Not all engines support all timeout values.  Setting the timeout to a value
402  * not supported by the engine will cause engine-defined behavior when the
403  * action is executed.
404  */
405 void
406 smp_action_set_timeout(smp_action_t *ap, uint32_t timeout)
407 {
408 	ap->sa_timeout = timeout;
409 }
410 
411 /*
412  * Obtain the timeout setting for this action.
413  */
414 uint32_t
415 smp_action_get_timeout(const smp_action_t *ap)
416 {
417 	return (ap->sa_timeout);
418 }
419 
420 const smp_function_def_t *
421 smp_action_get_function_def(const smp_action_t *ap)
422 {
423 	return (ap->sa_def);
424 }
425 
426 /*
427  * Obtain the user-requested request allocation size.  Note that the
428  * interpretation of this is function-dependent.
429  */
430 size_t
431 smp_action_get_rqsd(const smp_action_t *ap)
432 {
433 	return (ap->sa_request_rqsd);
434 }
435 
436 /*
437  * Obtains the address and amount of space allocated for the portion of the
438  * request data that lies between the header (if any) and the CRC.
439  */
440 void
441 smp_action_get_request(const smp_action_t *ap, void **reqp, size_t *dlenp)
442 {
443 	if (reqp != NULL) {
444 		if (ap->sa_request_data_off >= 0) {
445 			*reqp = ap->sa_request + ap->sa_request_data_off;
446 		} else {
447 			*reqp = NULL;
448 		}
449 	}
450 
451 	if (dlenp != NULL)
452 		*dlenp = ap->sa_request_alloc_len -
453 		    (ap->sa_request_data_off + sizeof (smp_crc_t));
454 }
455 
456 /*
457  * Obtains the address and amount of valid response data (that part of the
458  * response frame, if any, that lies between the header and the CRC).  The
459  * result, if any, is also returned in the location pointed to by result.
460  */
461 void
462 smp_action_get_response(const smp_action_t *ap, smp_result_t *resultp,
463     void **respp, size_t *dlenp)
464 {
465 	if (resultp != NULL)
466 		*resultp = ap->sa_result;
467 
468 	if (respp != NULL)
469 		*respp = (ap->sa_response_data_len > 0) ?
470 		    (ap->sa_response + ap->sa_response_data_off) : NULL;
471 
472 	if (dlenp != NULL)
473 		*dlenp = ap->sa_response_data_len;
474 }
475 
476 /*
477  * Obtains the entire request frame and the amount of space allocated for it.
478  * This is intended only for use by plugins; front-end consumers should use
479  * smp_action_get_request() instead.
480  */
481 void
482 smp_action_get_request_frame(const smp_action_t *ap, void **reqp, size_t *alenp)
483 {
484 	if (reqp != NULL)
485 		*reqp = ap->sa_request;
486 
487 	if (alenp != NULL)
488 		*alenp = ap->sa_request_alloc_len;
489 }
490 
491 /*
492  * Obtains the entire response frame and the amount of space allocated for it.
493  * This is intended only for use by plugins; front-end consumers should use
494  * smp_action_get_response() instead.
495  */
496 void
497 smp_action_get_response_frame(const smp_action_t *ap,
498     void **respp, size_t *lenp)
499 {
500 	if (respp != NULL)
501 		*respp = ap->sa_response;
502 
503 	if (lenp != NULL) {
504 		if (ap->sa_flags & SMP_ACTION_F_EXEC)
505 			*lenp = ap->sa_response_engine_len;
506 		else
507 			*lenp = ap->sa_response_alloc_len;
508 	}
509 }
510 
511 /*
512  * Set the total response frame length as determined by the engine.  This
513  * should never be called by consumers or plugins other than engines.
514  */
515 void
516 smp_action_set_response_len(smp_action_t *ap, size_t elen)
517 {
518 	ap->sa_response_engine_len = elen;
519 }
520 
521 void
522 smp_action_set_result(smp_action_t *ap, smp_result_t result)
523 {
524 	ap->sa_result = result;
525 }
526 
527 /*
528  * Allocate an action object.  The object will contain a request buffer
529  * to hold the frame to be transmitted to the target, a response buffer
530  * for the frame to be received from it, and auxiliary private information.
531  *
532  * For the request, callers may specify:
533  *
534  * - An externally-allocated buffer and its size in bytes, or
535  * - NULL and a function-specific size descriptor, or
536  *
537  * Note that for some functions, the size descriptor may be 0, indicating that
538  * a default buffer length will be used.  It is the caller's responsibility
539  * to correctly interpret function-specific buffer lengths.  See appropriate
540  * plugin documentation for information on buffer sizes and buffer content
541  * interpretation.
542  *
543  * For the response, callers may specify:
544  *
545  * - An externally-allocated buffer and its size in bytes, or
546  * - NULL and 0, to use a guaranteed-sufficient buffer.
547  *
548  * If an invalid request size descriptor is provided, or a preallocated
549  * buffer is provided and it is insufficiently large, this function will
550  * fail with ESMP_RANGE.
551  *
552  * Callers are discouraged from allocating their own buffers and must be
553  * aware of the consequences of specifying non-default lengths.
554  */
555 smp_action_t *
556 smp_action_xalloc(smp_function_t fn, smp_target_t *tp,
557     void *rq, size_t rqsd, void *rs, size_t rslen)
558 {
559 	smp_plugin_t *pp;
560 	const smp_function_def_t *dp = NULL;
561 	smp_action_t *ap;
562 	uint_t cap;
563 	size_t rqlen, len;
564 	uint8_t *alloc;
565 	int i;
566 
567 	cap = smp_target_getcap(tp);
568 
569 	for (pp = tp->st_plugin_first; pp != NULL; pp = pp->sp_next) {
570 		if (pp->sp_functions == NULL)
571 			continue;
572 
573 		for (i = 0; pp->sp_functions[i].sfd_rq_len != NULL; i++) {
574 			dp = &pp->sp_functions[i];
575 			if (dp->sfd_function == fn &&
576 			    ((cap & dp->sfd_capmask) == dp->sfd_capset))
577 				break;
578 		}
579 	}
580 
581 	if (dp == NULL) {
582 		(void) smp_set_errno(ESMP_BADFUNC);
583 		return (NULL);
584 	}
585 
586 	if (rq == NULL) {
587 		if ((rqlen = dp->sfd_rq_len(rqsd, tp)) == 0)
588 			return (NULL);
589 	} else if (rqlen < SMP_REQ_MINLEN) {
590 		(void) smp_set_errno(ESMP_RANGE);
591 		return (NULL);
592 	}
593 
594 	if (rs == NULL) {
595 		rslen = 1020 + SMP_RESP_MINLEN;
596 	} else if (rslen < SMP_RESP_MINLEN) {
597 		(void) smp_set_errno(ESMP_RANGE);
598 		return (NULL);
599 	}
600 
601 	len = offsetof(smp_action_t, sa_buf[0]);
602 	if (rq == NULL)
603 		len += rqlen;
604 	if (rs == NULL)
605 		len += rslen;
606 
607 	if ((ap = smp_zalloc(len)) == NULL)
608 		return (NULL);
609 
610 	ap->sa_def = dp;
611 	alloc = ap->sa_buf;
612 
613 	if (rq == NULL) {
614 		ap->sa_request = alloc;
615 		alloc += rqlen;
616 	}
617 	ap->sa_request_alloc_len = rqlen;
618 
619 	if (rs == NULL) {
620 		ap->sa_response = alloc;
621 		alloc += rslen;
622 	}
623 	ap->sa_response_alloc_len = rslen;
624 
625 	ASSERT(alloc - (uint8_t *)ap == len);
626 
627 	ap->sa_request_data_off = dp->sfd_rq_dataoff(ap, tp);
628 	ap->sa_flags |= SMP_ACTION_F_OFFSET;
629 
630 	return (ap);
631 }
632 
633 /*
634  * Simplified action allocator.  All buffers are allocated for the
635  * caller.  The request buffer size will be based on the function-specific
636  * interpretation of the rqsize parameter.  The response buffer size will be
637  * a function-specific value sufficiently large to capture any response.
638  */
639 smp_action_t *
640 smp_action_alloc(smp_function_t fn, smp_target_t *tp, size_t rqsd)
641 {
642 	return (smp_action_xalloc(fn, tp, NULL, rqsd, NULL, 0));
643 }
644 
645 void
646 smp_action_free(smp_action_t *ap)
647 {
648 	if (ap == NULL)
649 		return;
650 
651 	smp_free(ap);
652 }
653 
654 /*
655  * For testing purposes, we allow data to be corrupted via an environment
656  * variable setting.  This helps ensure that higher level software can cope with
657  * arbitrarily broken targets.  The mtbf value represents the number of bytes we
658  * will see, on average, in between each failure.  Therefore, for each N bytes,
659  * we would expect to see (N / mtbf) bytes of corruption.
660  */
661 static void
662 smp_inject_errors(void *data, size_t len, uint_t mtbf)
663 {
664 	char *buf = data;
665 	double prob;
666 	size_t index;
667 
668 	if (len == 0)
669 		return;
670 
671 	prob = (double)len / mtbf;
672 
673 	while (prob > 1) {
674 		index = lrand48() % len;
675 		buf[index] = (lrand48() % 256);
676 		prob -= 1;
677 	}
678 
679 	if (drand48() <= prob) {
680 		index = lrand48() % len;
681 		buf[index] = (lrand48() % 256);
682 	}
683 }
684 
685 int
686 smp_exec(smp_action_t *ap, smp_target_t *tp)
687 {
688 	const smp_function_def_t *dp;
689 	int ret;
690 
691 	dp = ap->sa_def;
692 	dp->sfd_rq_setframe(ap, tp);
693 
694 	if (tp->st_mtbf_request != 0) {
695 		smp_inject_errors(ap->sa_request, ap->sa_request_alloc_len,
696 		    tp->st_mtbf_request);
697 	}
698 
699 	ret = tp->st_engine->se_ops->seo_exec(tp->st_priv, ap);
700 
701 	if (ret == 0 && tp->st_mtbf_response != 0) {
702 		smp_inject_errors(ap->sa_response, ap->sa_response_engine_len,
703 		    tp->st_mtbf_response);
704 	}
705 
706 	if (ret != 0)
707 		return (ret);
708 
709 	ap->sa_flags |= SMP_ACTION_F_EXEC;
710 
711 	/*
712 	 * Obtain the data length and offset from the underlying plugins.
713 	 * Then offer the plugins the opportunity to set any parameters in the
714 	 * target to reflect state observed in the response.
715 	 */
716 	ap->sa_response_data_len = dp->sfd_rs_datalen(ap, tp);
717 	ap->sa_response_data_off = dp->sfd_rs_dataoff(ap, tp);
718 	dp->sfd_rs_getparams(ap, tp);
719 
720 	ap->sa_flags |= SMP_ACTION_F_DECODE;
721 
722 	return (0);
723 }
724