xref: /onnv-gate/usr/src/lib/scsi/libsmp/common/smp_engine.c (revision 13094:efddb0166961)
112126SHyon.Kim@Sun.COM /*
212126SHyon.Kim@Sun.COM  * CDDL HEADER START
312126SHyon.Kim@Sun.COM  *
412126SHyon.Kim@Sun.COM  * The contents of this file are subject to the terms of the
512126SHyon.Kim@Sun.COM  * Common Development and Distribution License (the "License").
612126SHyon.Kim@Sun.COM  * You may not use this file except in compliance with the License.
712126SHyon.Kim@Sun.COM  *
812126SHyon.Kim@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
912126SHyon.Kim@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1012126SHyon.Kim@Sun.COM  * See the License for the specific language governing permissions
1112126SHyon.Kim@Sun.COM  * and limitations under the License.
1212126SHyon.Kim@Sun.COM  *
1312126SHyon.Kim@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1412126SHyon.Kim@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1512126SHyon.Kim@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1612126SHyon.Kim@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1712126SHyon.Kim@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1812126SHyon.Kim@Sun.COM  *
1912126SHyon.Kim@Sun.COM  * CDDL HEADER END
2012126SHyon.Kim@Sun.COM  */
2112126SHyon.Kim@Sun.COM 
2212126SHyon.Kim@Sun.COM /*
2312126SHyon.Kim@Sun.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2412126SHyon.Kim@Sun.COM  */
2512126SHyon.Kim@Sun.COM 
2612126SHyon.Kim@Sun.COM #include <sys/types.h>
2712126SHyon.Kim@Sun.COM #include <sys/isa_defs.h>
2812126SHyon.Kim@Sun.COM #include <sys/systeminfo.h>
2912126SHyon.Kim@Sun.COM #include <sys/scsi/generic/smp_frames.h>
3012126SHyon.Kim@Sun.COM 
3112126SHyon.Kim@Sun.COM #include <stdio.h>
3212126SHyon.Kim@Sun.COM #include <stdlib.h>
3312126SHyon.Kim@Sun.COM #include <stddef.h>
3412126SHyon.Kim@Sun.COM #include <string.h>
3512126SHyon.Kim@Sun.COM #include <strings.h>
3612126SHyon.Kim@Sun.COM #include <dlfcn.h>
3712126SHyon.Kim@Sun.COM #include <limits.h>
3812126SHyon.Kim@Sun.COM #include <pthread.h>
3912126SHyon.Kim@Sun.COM #include <synch.h>
4012126SHyon.Kim@Sun.COM 
4112126SHyon.Kim@Sun.COM #include <scsi/libsmp.h>
4212126SHyon.Kim@Sun.COM #include "smp_impl.h"
4312126SHyon.Kim@Sun.COM 
4412126SHyon.Kim@Sun.COM static pthread_mutex_t _libsmp_lock = PTHREAD_MUTEX_INITIALIZER;
4512126SHyon.Kim@Sun.COM static smp_engine_t *_libsmp_engines;
4612126SHyon.Kim@Sun.COM static int _libsmp_refcnt;
4712126SHyon.Kim@Sun.COM 
4812126SHyon.Kim@Sun.COM static boolean_t _libsmp_engine_dlclose;
4912126SHyon.Kim@Sun.COM 
5012126SHyon.Kim@Sun.COM static void
smp_engine_free(smp_engine_t * ep)5112126SHyon.Kim@Sun.COM smp_engine_free(smp_engine_t *ep)
5212126SHyon.Kim@Sun.COM {
5312126SHyon.Kim@Sun.COM 	if (ep == NULL)
5412126SHyon.Kim@Sun.COM 		return;
5512126SHyon.Kim@Sun.COM 
5612126SHyon.Kim@Sun.COM 	smp_free(ep->se_name);
5712126SHyon.Kim@Sun.COM 	smp_free(ep);
5812126SHyon.Kim@Sun.COM }
5912126SHyon.Kim@Sun.COM 
6012126SHyon.Kim@Sun.COM static void
smp_engine_destroy(smp_engine_t * ep)6112126SHyon.Kim@Sun.COM smp_engine_destroy(smp_engine_t *ep)
6212126SHyon.Kim@Sun.COM {
6312126SHyon.Kim@Sun.COM 	smp_engine_t **pp;
6412126SHyon.Kim@Sun.COM 
6512126SHyon.Kim@Sun.COM 	ASSERT(MUTEX_HELD(&_libsmp_lock));
6612126SHyon.Kim@Sun.COM 
6712126SHyon.Kim@Sun.COM 	if (ep->se_fini != NULL)
6812126SHyon.Kim@Sun.COM 		ep->se_fini(ep);
6912126SHyon.Kim@Sun.COM 
7012126SHyon.Kim@Sun.COM 	if (_libsmp_engine_dlclose)
7112126SHyon.Kim@Sun.COM 		(void) dlclose(ep->se_object);
7212126SHyon.Kim@Sun.COM 
7312126SHyon.Kim@Sun.COM 	ASSERT(ep->se_refcnt == 0);
7412126SHyon.Kim@Sun.COM 	for (pp = &_libsmp_engines; *pp != NULL; pp = &((*pp)->se_next))
7512126SHyon.Kim@Sun.COM 		if (*pp == ep)
7612126SHyon.Kim@Sun.COM 			break;
7712126SHyon.Kim@Sun.COM 
7812126SHyon.Kim@Sun.COM 	if (*pp != NULL)
7912126SHyon.Kim@Sun.COM 		*pp = (*pp)->se_next;
8012126SHyon.Kim@Sun.COM 
8112126SHyon.Kim@Sun.COM 	smp_engine_free(ep);
8212126SHyon.Kim@Sun.COM }
8312126SHyon.Kim@Sun.COM 
8412126SHyon.Kim@Sun.COM void
smp_engine_init(void)8512126SHyon.Kim@Sun.COM smp_engine_init(void)
8612126SHyon.Kim@Sun.COM {
8712126SHyon.Kim@Sun.COM 	(void) pthread_mutex_lock(&_libsmp_lock);
8812126SHyon.Kim@Sun.COM 	++_libsmp_refcnt;
8912126SHyon.Kim@Sun.COM 	(void) pthread_mutex_unlock(&_libsmp_lock);
9012126SHyon.Kim@Sun.COM }
9112126SHyon.Kim@Sun.COM 
9212126SHyon.Kim@Sun.COM void
smp_engine_fini(void)9312126SHyon.Kim@Sun.COM smp_engine_fini(void)
9412126SHyon.Kim@Sun.COM {
9512126SHyon.Kim@Sun.COM 	smp_engine_t *ep;
9612126SHyon.Kim@Sun.COM 
9712126SHyon.Kim@Sun.COM 	(void) pthread_mutex_lock(&_libsmp_lock);
9812126SHyon.Kim@Sun.COM 	ASSERT(_libsmp_refcnt > 0);
9912126SHyon.Kim@Sun.COM 	if (--_libsmp_refcnt == 0) {
10012126SHyon.Kim@Sun.COM 		while (_libsmp_engines != NULL) {
10112126SHyon.Kim@Sun.COM 			ep = _libsmp_engines;
10212126SHyon.Kim@Sun.COM 			_libsmp_engines = ep->se_next;
10312126SHyon.Kim@Sun.COM 			smp_engine_destroy(ep);
10412126SHyon.Kim@Sun.COM 		}
10512126SHyon.Kim@Sun.COM 	}
10612126SHyon.Kim@Sun.COM 	(void) pthread_mutex_unlock(&_libsmp_lock);
10712126SHyon.Kim@Sun.COM }
10812126SHyon.Kim@Sun.COM 
10912126SHyon.Kim@Sun.COM static int
smp_engine_loadone(const char * path)11012126SHyon.Kim@Sun.COM smp_engine_loadone(const char *path)
11112126SHyon.Kim@Sun.COM {
11212126SHyon.Kim@Sun.COM 	smp_engine_t *ep;
11312126SHyon.Kim@Sun.COM 	void *obj;
11412126SHyon.Kim@Sun.COM 
11512126SHyon.Kim@Sun.COM 	ASSERT(MUTEX_HELD(&_libsmp_lock));
11612126SHyon.Kim@Sun.COM 
11712126SHyon.Kim@Sun.COM 	if ((obj = dlopen(path, RTLD_PARENT | RTLD_LOCAL | RTLD_LAZY)) == NULL)
11812126SHyon.Kim@Sun.COM 		return (smp_set_errno(ESMP_NOENGINE));
11912126SHyon.Kim@Sun.COM 
12012126SHyon.Kim@Sun.COM 	if ((ep = smp_zalloc(sizeof (smp_engine_t))) == NULL) {
12112126SHyon.Kim@Sun.COM 		(void) dlclose(obj);
12212126SHyon.Kim@Sun.COM 		return (-1);
12312126SHyon.Kim@Sun.COM 	}
12412126SHyon.Kim@Sun.COM 
12512126SHyon.Kim@Sun.COM 	ep->se_object = obj;
12612126SHyon.Kim@Sun.COM 	ep->se_init = (int (*)())dlsym(obj, "_smp_init");
12712126SHyon.Kim@Sun.COM 	ep->se_fini = (void (*)())dlsym(obj, "_smp_fini");
12812126SHyon.Kim@Sun.COM 
12912126SHyon.Kim@Sun.COM 	if (ep->se_init == NULL) {
13012126SHyon.Kim@Sun.COM 		smp_engine_free(ep);
13112126SHyon.Kim@Sun.COM 		return (smp_set_errno(ESMP_BADENGINE));
13212126SHyon.Kim@Sun.COM 	}
13312126SHyon.Kim@Sun.COM 
13412126SHyon.Kim@Sun.COM 	if (ep->se_init(ep) != 0) {
13512126SHyon.Kim@Sun.COM 		smp_engine_free(ep);
13612126SHyon.Kim@Sun.COM 		return (-1);
13712126SHyon.Kim@Sun.COM 	}
13812126SHyon.Kim@Sun.COM 
13912126SHyon.Kim@Sun.COM 	return (0);
14012126SHyon.Kim@Sun.COM }
14112126SHyon.Kim@Sun.COM 
14212126SHyon.Kim@Sun.COM int
smp_engine_register(smp_engine_t * ep,int version,const smp_engine_config_t * ecp)14312126SHyon.Kim@Sun.COM smp_engine_register(smp_engine_t *ep, int version,
14412126SHyon.Kim@Sun.COM     const smp_engine_config_t *ecp)
14512126SHyon.Kim@Sun.COM {
14612126SHyon.Kim@Sun.COM 	ASSERT(MUTEX_HELD(&_libsmp_lock));
14712126SHyon.Kim@Sun.COM 
14812126SHyon.Kim@Sun.COM 	if (version != LIBSMP_ENGINE_VERSION)
14912126SHyon.Kim@Sun.COM 		return (smp_set_errno(ESMP_VERSION));
15012126SHyon.Kim@Sun.COM 
15112126SHyon.Kim@Sun.COM 	ep->se_ops = ecp->sec_ops;
15212126SHyon.Kim@Sun.COM 	ep->se_name = smp_strdup(ecp->sec_name);
15312126SHyon.Kim@Sun.COM 
15412126SHyon.Kim@Sun.COM 	if (ep->se_name == NULL)
15512126SHyon.Kim@Sun.COM 		return (-1);
15612126SHyon.Kim@Sun.COM 
15712126SHyon.Kim@Sun.COM 	ep->se_next = _libsmp_engines;
15812126SHyon.Kim@Sun.COM 	_libsmp_engines = ep;
15912126SHyon.Kim@Sun.COM 
16012126SHyon.Kim@Sun.COM 	return (0);
16112126SHyon.Kim@Sun.COM }
16212126SHyon.Kim@Sun.COM 
16312126SHyon.Kim@Sun.COM static smp_engine_t *
smp_engine_hold_cached(const char * name)16412126SHyon.Kim@Sun.COM smp_engine_hold_cached(const char *name)
16512126SHyon.Kim@Sun.COM {
16612126SHyon.Kim@Sun.COM 	smp_engine_t *ep;
16712126SHyon.Kim@Sun.COM 
16812126SHyon.Kim@Sun.COM 	ASSERT(MUTEX_HELD(&_libsmp_lock));
16912126SHyon.Kim@Sun.COM 
17012126SHyon.Kim@Sun.COM 	for (ep = _libsmp_engines; ep != NULL; ep = ep->se_next) {
17112126SHyon.Kim@Sun.COM 		if (strcmp(ep->se_name, name) == 0) {
17212126SHyon.Kim@Sun.COM 			++ep->se_refcnt;
17312126SHyon.Kim@Sun.COM 			return (ep);
17412126SHyon.Kim@Sun.COM 		}
17512126SHyon.Kim@Sun.COM 	}
17612126SHyon.Kim@Sun.COM 
17712126SHyon.Kim@Sun.COM 	(void) smp_set_errno(ESMP_NOENGINE);
17812126SHyon.Kim@Sun.COM 	return (NULL);
17912126SHyon.Kim@Sun.COM }
18012126SHyon.Kim@Sun.COM 
18112126SHyon.Kim@Sun.COM static smp_engine_t *
smp_engine_hold(const char * name)18212126SHyon.Kim@Sun.COM smp_engine_hold(const char *name)
18312126SHyon.Kim@Sun.COM {
18412126SHyon.Kim@Sun.COM 	smp_engine_t *ep;
18512126SHyon.Kim@Sun.COM 	const char *pluginpath, *p, *q;
18612126SHyon.Kim@Sun.COM 	char pluginroot[PATH_MAX];
18712126SHyon.Kim@Sun.COM 	char path[PATH_MAX];
18812126SHyon.Kim@Sun.COM 	char isa[257];
18912126SHyon.Kim@Sun.COM 
19012126SHyon.Kim@Sun.COM 	(void) pthread_mutex_lock(&_libsmp_lock);
19112126SHyon.Kim@Sun.COM 	ep = smp_engine_hold_cached(name);
19212126SHyon.Kim@Sun.COM 	if (ep != NULL) {
19312126SHyon.Kim@Sun.COM 		(void) pthread_mutex_unlock(&_libsmp_lock);
19412126SHyon.Kim@Sun.COM 		return (ep);
19512126SHyon.Kim@Sun.COM 	}
19612126SHyon.Kim@Sun.COM 
19712126SHyon.Kim@Sun.COM #if defined(_LP64)
19812126SHyon.Kim@Sun.COM 	if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0)
19912126SHyon.Kim@Sun.COM 		isa[0] = '\0';
20012126SHyon.Kim@Sun.COM #else
20112126SHyon.Kim@Sun.COM 	isa[0] = '\0';
20212126SHyon.Kim@Sun.COM #endif
20312126SHyon.Kim@Sun.COM 
20412126SHyon.Kim@Sun.COM 	if ((pluginpath = getenv("SMP_PLUGINPATH")) == NULL)
20512126SHyon.Kim@Sun.COM 		pluginpath = LIBSMP_DEFAULT_PLUGINDIR;
20612126SHyon.Kim@Sun.COM 
20712126SHyon.Kim@Sun.COM 	_libsmp_engine_dlclose = (getenv("SMP_NODLCLOSE") == NULL);
20812126SHyon.Kim@Sun.COM 
20912126SHyon.Kim@Sun.COM 	for (p = pluginpath; p != NULL; p = q) {
21012126SHyon.Kim@Sun.COM 		if ((q = strchr(p, ':')) != NULL) {
21112126SHyon.Kim@Sun.COM 			ptrdiff_t len = q - p;
21212126SHyon.Kim@Sun.COM 			(void) strncpy(pluginroot, p, len);
21312126SHyon.Kim@Sun.COM 			pluginroot[len] = '\0';
21412126SHyon.Kim@Sun.COM 			while (*q == ':')
21512126SHyon.Kim@Sun.COM 				++q;
21612126SHyon.Kim@Sun.COM 			if (*q == '\0')
21712126SHyon.Kim@Sun.COM 				q = NULL;
21812126SHyon.Kim@Sun.COM 			if (len == 0)
21912126SHyon.Kim@Sun.COM 				continue;
22012126SHyon.Kim@Sun.COM 		} else {
22112126SHyon.Kim@Sun.COM 			(void) strcpy(pluginroot, p);
22212126SHyon.Kim@Sun.COM 		}
22312126SHyon.Kim@Sun.COM 
22412126SHyon.Kim@Sun.COM 		if (pluginroot[0] != '/')
22512126SHyon.Kim@Sun.COM 			continue;
22612126SHyon.Kim@Sun.COM 
22712126SHyon.Kim@Sun.COM 		(void) snprintf(path, PATH_MAX, "%s/%s/%s/%s%s",
22812126SHyon.Kim@Sun.COM 		    pluginroot, LIBSMP_PLUGIN_ENGINE,
22912126SHyon.Kim@Sun.COM 		    isa, name, LIBSMP_PLUGIN_EXT);
23012126SHyon.Kim@Sun.COM 
23112126SHyon.Kim@Sun.COM 		if (smp_engine_loadone(path) == 0) {
23212126SHyon.Kim@Sun.COM 			ep = smp_engine_hold_cached(name);
23312126SHyon.Kim@Sun.COM 			(void) pthread_mutex_unlock(&_libsmp_lock);
23412126SHyon.Kim@Sun.COM 			return (ep);
23512126SHyon.Kim@Sun.COM 		}
23612126SHyon.Kim@Sun.COM 	}
23712126SHyon.Kim@Sun.COM 
23812126SHyon.Kim@Sun.COM 	return (NULL);
23912126SHyon.Kim@Sun.COM }
24012126SHyon.Kim@Sun.COM 
24112126SHyon.Kim@Sun.COM static void
smp_engine_rele(smp_engine_t * ep)24212126SHyon.Kim@Sun.COM smp_engine_rele(smp_engine_t *ep)
24312126SHyon.Kim@Sun.COM {
24412126SHyon.Kim@Sun.COM 	(void) pthread_mutex_lock(&_libsmp_lock);
24512126SHyon.Kim@Sun.COM 	ASSERT(ep->se_refcnt > 0);
24612126SHyon.Kim@Sun.COM 	--ep->se_refcnt;
24712126SHyon.Kim@Sun.COM 	(void) pthread_mutex_unlock(&_libsmp_lock);
24812126SHyon.Kim@Sun.COM }
24912126SHyon.Kim@Sun.COM 
25012126SHyon.Kim@Sun.COM static void
smp_parse_mtbf(const char * envvar,uint_t * intp)25112126SHyon.Kim@Sun.COM smp_parse_mtbf(const char *envvar, uint_t *intp)
25212126SHyon.Kim@Sun.COM {
25312126SHyon.Kim@Sun.COM 	const char *strval;
25412126SHyon.Kim@Sun.COM 	int intval;
25512126SHyon.Kim@Sun.COM 
25612126SHyon.Kim@Sun.COM 	if ((strval = getenv(envvar)) != NULL &&
25712126SHyon.Kim@Sun.COM 	    (intval = atoi(strval)) > 0) {
25812126SHyon.Kim@Sun.COM 		srand48(gethrtime());
25912126SHyon.Kim@Sun.COM 		*intp = intval;
26012126SHyon.Kim@Sun.COM 	}
26112126SHyon.Kim@Sun.COM }
26212126SHyon.Kim@Sun.COM 
26312126SHyon.Kim@Sun.COM smp_target_t *
smp_open(const smp_target_def_t * tdp)26412126SHyon.Kim@Sun.COM smp_open(const smp_target_def_t *tdp)
26512126SHyon.Kim@Sun.COM {
26612126SHyon.Kim@Sun.COM 	smp_engine_t *ep;
26712126SHyon.Kim@Sun.COM 	smp_target_t *tp;
26812126SHyon.Kim@Sun.COM 	void *private;
26912126SHyon.Kim@Sun.COM 	const char *engine;
27012126SHyon.Kim@Sun.COM 
27112126SHyon.Kim@Sun.COM 	if ((engine = tdp->std_engine) == NULL) {
27212126SHyon.Kim@Sun.COM 		if ((engine = getenv("LIBSMP_DEFAULT_ENGINE")) == NULL)
27312126SHyon.Kim@Sun.COM 			engine = LIBSMP_DEFAULT_ENGINE;
27412126SHyon.Kim@Sun.COM 	}
27512126SHyon.Kim@Sun.COM 
27612126SHyon.Kim@Sun.COM 	if ((ep = smp_engine_hold(engine)) == NULL)
27712126SHyon.Kim@Sun.COM 		return (NULL);
27812126SHyon.Kim@Sun.COM 
27912126SHyon.Kim@Sun.COM 	if ((tp = smp_zalloc(sizeof (smp_target_t))) == NULL) {
28012126SHyon.Kim@Sun.COM 		smp_engine_rele(ep);
28112126SHyon.Kim@Sun.COM 		return (NULL);
28212126SHyon.Kim@Sun.COM 	}
28312126SHyon.Kim@Sun.COM 
28412126SHyon.Kim@Sun.COM 	if ((private = ep->se_ops->seo_open(tdp->std_def)) == NULL) {
28512126SHyon.Kim@Sun.COM 		smp_engine_rele(ep);
28612126SHyon.Kim@Sun.COM 		smp_free(tp);
28712126SHyon.Kim@Sun.COM 		return (NULL);
28812126SHyon.Kim@Sun.COM 	}
28912126SHyon.Kim@Sun.COM 
29012126SHyon.Kim@Sun.COM 	smp_parse_mtbf("LIBSMP_MTBF_REQUEST", &tp->st_mtbf_request);
29112126SHyon.Kim@Sun.COM 	smp_parse_mtbf("LIBSMP_MTBF_RESPONSE", &tp->st_mtbf_response);
29212126SHyon.Kim@Sun.COM 
29312126SHyon.Kim@Sun.COM 	tp->st_engine = ep;
29412126SHyon.Kim@Sun.COM 	tp->st_priv = private;
29512126SHyon.Kim@Sun.COM 
29612126SHyon.Kim@Sun.COM 	if (smp_plugin_load(tp) != 0) {
29712126SHyon.Kim@Sun.COM 		smp_close(tp);
29812126SHyon.Kim@Sun.COM 		return (NULL);
29912126SHyon.Kim@Sun.COM 	}
30012126SHyon.Kim@Sun.COM 
30112126SHyon.Kim@Sun.COM 	return (tp);
30212126SHyon.Kim@Sun.COM }
30312126SHyon.Kim@Sun.COM 
30412126SHyon.Kim@Sun.COM void
smp_target_name(const smp_target_t * tp,char * buf,size_t len)30512126SHyon.Kim@Sun.COM smp_target_name(const smp_target_t *tp, char *buf, size_t len)
30612126SHyon.Kim@Sun.COM {
30712126SHyon.Kim@Sun.COM 	tp->st_engine->se_ops->seo_target_name(tp->st_priv, buf, len);
30812126SHyon.Kim@Sun.COM }
30912126SHyon.Kim@Sun.COM 
31012126SHyon.Kim@Sun.COM uint64_t
smp_target_addr(const smp_target_t * tp)31112126SHyon.Kim@Sun.COM smp_target_addr(const smp_target_t *tp)
31212126SHyon.Kim@Sun.COM {
31312126SHyon.Kim@Sun.COM 	return (tp->st_engine->se_ops->seo_target_addr(tp->st_priv));
31412126SHyon.Kim@Sun.COM }
31512126SHyon.Kim@Sun.COM 
31612126SHyon.Kim@Sun.COM const char *
smp_target_vendor(const smp_target_t * tp)31712126SHyon.Kim@Sun.COM smp_target_vendor(const smp_target_t *tp)
31812126SHyon.Kim@Sun.COM {
31912126SHyon.Kim@Sun.COM 	return (tp->st_vendor);
32012126SHyon.Kim@Sun.COM }
32112126SHyon.Kim@Sun.COM 
32212126SHyon.Kim@Sun.COM const char *
smp_target_product(const smp_target_t * tp)32312126SHyon.Kim@Sun.COM smp_target_product(const smp_target_t *tp)
32412126SHyon.Kim@Sun.COM {
32512126SHyon.Kim@Sun.COM 	return (tp->st_product);
32612126SHyon.Kim@Sun.COM }
32712126SHyon.Kim@Sun.COM 
32812126SHyon.Kim@Sun.COM const char *
smp_target_revision(const smp_target_t * tp)32912126SHyon.Kim@Sun.COM smp_target_revision(const smp_target_t *tp)
33012126SHyon.Kim@Sun.COM {
33112126SHyon.Kim@Sun.COM 	return (tp->st_revision);
33212126SHyon.Kim@Sun.COM }
33312126SHyon.Kim@Sun.COM 
33412126SHyon.Kim@Sun.COM const char *
smp_target_component_vendor(const smp_target_t * tp)33512126SHyon.Kim@Sun.COM smp_target_component_vendor(const smp_target_t *tp)
33612126SHyon.Kim@Sun.COM {
33712126SHyon.Kim@Sun.COM 	return (tp->st_component_vendor);
33812126SHyon.Kim@Sun.COM }
33912126SHyon.Kim@Sun.COM 
34012126SHyon.Kim@Sun.COM uint16_t
smp_target_component_id(const smp_target_t * tp)34112126SHyon.Kim@Sun.COM smp_target_component_id(const smp_target_t *tp)
34212126SHyon.Kim@Sun.COM {
34312126SHyon.Kim@Sun.COM 	return (tp->st_component_id);
34412126SHyon.Kim@Sun.COM }
34512126SHyon.Kim@Sun.COM 
34612126SHyon.Kim@Sun.COM uint8_t
smp_target_component_revision(const smp_target_t * tp)34712126SHyon.Kim@Sun.COM smp_target_component_revision(const smp_target_t *tp)
34812126SHyon.Kim@Sun.COM {
34912126SHyon.Kim@Sun.COM 	return (tp->st_component_revision);
35012126SHyon.Kim@Sun.COM }
35112126SHyon.Kim@Sun.COM 
35212126SHyon.Kim@Sun.COM uint_t
smp_target_getcap(const smp_target_t * tp)35312126SHyon.Kim@Sun.COM smp_target_getcap(const smp_target_t *tp)
35412126SHyon.Kim@Sun.COM {
35512126SHyon.Kim@Sun.COM 	uint_t cap = 0;
35612126SHyon.Kim@Sun.COM 
35712126SHyon.Kim@Sun.COM 	if (tp->st_repgen.srgr_long_response)
35812126SHyon.Kim@Sun.COM 		cap |= SMP_TARGET_C_LONG_RESP;
35912126SHyon.Kim@Sun.COM 
36012126SHyon.Kim@Sun.COM 	if (tp->st_repgen.srgr_zoning_supported)
36112126SHyon.Kim@Sun.COM 		cap |= SMP_TARGET_C_ZONING;
36212126SHyon.Kim@Sun.COM 
36312126SHyon.Kim@Sun.COM 	if (tp->st_repgen.srgr_number_of_zone_grps == SMP_ZONE_GROUPS_256)
36412126SHyon.Kim@Sun.COM 		cap |= SMP_TARGET_C_ZG_256;
36512126SHyon.Kim@Sun.COM 
36612126SHyon.Kim@Sun.COM 	return (cap);
36712126SHyon.Kim@Sun.COM }
36812126SHyon.Kim@Sun.COM 
36912126SHyon.Kim@Sun.COM void
smp_target_set_change_count(smp_target_t * tp,uint16_t cc)37012126SHyon.Kim@Sun.COM smp_target_set_change_count(smp_target_t *tp, uint16_t cc)
37112126SHyon.Kim@Sun.COM {
37212126SHyon.Kim@Sun.COM 	tp->st_change_count = cc;
37312126SHyon.Kim@Sun.COM }
37412126SHyon.Kim@Sun.COM 
37512126SHyon.Kim@Sun.COM uint16_t
smp_target_get_change_count(const smp_target_t * tp)37612126SHyon.Kim@Sun.COM smp_target_get_change_count(const smp_target_t *tp)
37712126SHyon.Kim@Sun.COM {
37812126SHyon.Kim@Sun.COM 	return (tp->st_change_count);
37912126SHyon.Kim@Sun.COM }
38012126SHyon.Kim@Sun.COM 
381*13094Sdavid.hollister@oracle.com uint8_t
smp_target_get_number_of_phys(const smp_target_t * tp)382*13094Sdavid.hollister@oracle.com smp_target_get_number_of_phys(const smp_target_t *tp)
383*13094Sdavid.hollister@oracle.com {
384*13094Sdavid.hollister@oracle.com 	return (tp->st_repgen.srgr_number_of_phys);
385*13094Sdavid.hollister@oracle.com }
386*13094Sdavid.hollister@oracle.com 
387*13094Sdavid.hollister@oracle.com uint16_t
smp_target_get_exp_route_indexes(const smp_target_t * tp)388*13094Sdavid.hollister@oracle.com smp_target_get_exp_route_indexes(const smp_target_t *tp)
389*13094Sdavid.hollister@oracle.com {
390*13094Sdavid.hollister@oracle.com 	return (tp->st_repgen.srgr_exp_route_indexes);
391*13094Sdavid.hollister@oracle.com }
392*13094Sdavid.hollister@oracle.com 
39312126SHyon.Kim@Sun.COM void
smp_close(smp_target_t * tp)39412126SHyon.Kim@Sun.COM smp_close(smp_target_t *tp)
39512126SHyon.Kim@Sun.COM {
39612126SHyon.Kim@Sun.COM 	smp_free(tp->st_vendor);
39712126SHyon.Kim@Sun.COM 	smp_free(tp->st_product);
39812126SHyon.Kim@Sun.COM 	smp_free(tp->st_revision);
39912126SHyon.Kim@Sun.COM 	smp_free(tp->st_component_vendor);
40012126SHyon.Kim@Sun.COM 
40112126SHyon.Kim@Sun.COM 	smp_plugin_unload(tp);
40212126SHyon.Kim@Sun.COM 
40312126SHyon.Kim@Sun.COM 	tp->st_engine->se_ops->seo_close(tp->st_priv);
40412126SHyon.Kim@Sun.COM 	smp_engine_rele(tp->st_engine);
40512126SHyon.Kim@Sun.COM 
40612126SHyon.Kim@Sun.COM 	smp_free(tp);
40712126SHyon.Kim@Sun.COM }
40812126SHyon.Kim@Sun.COM 
40912126SHyon.Kim@Sun.COM /*
41012126SHyon.Kim@Sun.COM  * Set the timeout in seconds for this action.  If no timeout is specified
41112126SHyon.Kim@Sun.COM  * or if the timeout is set to 0, an implementation-specific timeout will be
41212126SHyon.Kim@Sun.COM  * used (which may vary based on the target, command or other variables).
41312126SHyon.Kim@Sun.COM  * Not all engines support all timeout values.  Setting the timeout to a value
41412126SHyon.Kim@Sun.COM  * not supported by the engine will cause engine-defined behavior when the
41512126SHyon.Kim@Sun.COM  * action is executed.
41612126SHyon.Kim@Sun.COM  */
41712126SHyon.Kim@Sun.COM void
smp_action_set_timeout(smp_action_t * ap,uint32_t timeout)41812126SHyon.Kim@Sun.COM smp_action_set_timeout(smp_action_t *ap, uint32_t timeout)
41912126SHyon.Kim@Sun.COM {
42012126SHyon.Kim@Sun.COM 	ap->sa_timeout = timeout;
42112126SHyon.Kim@Sun.COM }
42212126SHyon.Kim@Sun.COM 
42312126SHyon.Kim@Sun.COM /*
42412126SHyon.Kim@Sun.COM  * Obtain the timeout setting for this action.
42512126SHyon.Kim@Sun.COM  */
42612126SHyon.Kim@Sun.COM uint32_t
smp_action_get_timeout(const smp_action_t * ap)42712126SHyon.Kim@Sun.COM smp_action_get_timeout(const smp_action_t *ap)
42812126SHyon.Kim@Sun.COM {
42912126SHyon.Kim@Sun.COM 	return (ap->sa_timeout);
43012126SHyon.Kim@Sun.COM }
43112126SHyon.Kim@Sun.COM 
43212126SHyon.Kim@Sun.COM const smp_function_def_t *
smp_action_get_function_def(const smp_action_t * ap)43312126SHyon.Kim@Sun.COM smp_action_get_function_def(const smp_action_t *ap)
43412126SHyon.Kim@Sun.COM {
43512126SHyon.Kim@Sun.COM 	return (ap->sa_def);
43612126SHyon.Kim@Sun.COM }
43712126SHyon.Kim@Sun.COM 
43812126SHyon.Kim@Sun.COM /*
43912126SHyon.Kim@Sun.COM  * Obtain the user-requested request allocation size.  Note that the
44012126SHyon.Kim@Sun.COM  * interpretation of this is function-dependent.
44112126SHyon.Kim@Sun.COM  */
44212126SHyon.Kim@Sun.COM size_t
smp_action_get_rqsd(const smp_action_t * ap)44312126SHyon.Kim@Sun.COM smp_action_get_rqsd(const smp_action_t *ap)
44412126SHyon.Kim@Sun.COM {
44512126SHyon.Kim@Sun.COM 	return (ap->sa_request_rqsd);
44612126SHyon.Kim@Sun.COM }
44712126SHyon.Kim@Sun.COM 
44812126SHyon.Kim@Sun.COM /*
44912126SHyon.Kim@Sun.COM  * Obtains the address and amount of space allocated for the portion of the
45012126SHyon.Kim@Sun.COM  * request data that lies between the header (if any) and the CRC.
45112126SHyon.Kim@Sun.COM  */
45212126SHyon.Kim@Sun.COM void
smp_action_get_request(const smp_action_t * ap,void ** reqp,size_t * dlenp)45312126SHyon.Kim@Sun.COM smp_action_get_request(const smp_action_t *ap, void **reqp, size_t *dlenp)
45412126SHyon.Kim@Sun.COM {
45512126SHyon.Kim@Sun.COM 	if (reqp != NULL) {
45612126SHyon.Kim@Sun.COM 		if (ap->sa_request_data_off >= 0) {
45712126SHyon.Kim@Sun.COM 			*reqp = ap->sa_request + ap->sa_request_data_off;
45812126SHyon.Kim@Sun.COM 		} else {
45912126SHyon.Kim@Sun.COM 			*reqp = NULL;
46012126SHyon.Kim@Sun.COM 		}
46112126SHyon.Kim@Sun.COM 	}
46212126SHyon.Kim@Sun.COM 
46312126SHyon.Kim@Sun.COM 	if (dlenp != NULL)
46412126SHyon.Kim@Sun.COM 		*dlenp = ap->sa_request_alloc_len -
46512126SHyon.Kim@Sun.COM 		    (ap->sa_request_data_off + sizeof (smp_crc_t));
46612126SHyon.Kim@Sun.COM }
46712126SHyon.Kim@Sun.COM 
46812126SHyon.Kim@Sun.COM /*
46912126SHyon.Kim@Sun.COM  * Obtains the address and amount of valid response data (that part of the
47012126SHyon.Kim@Sun.COM  * response frame, if any, that lies between the header and the CRC).  The
47112126SHyon.Kim@Sun.COM  * result, if any, is also returned in the location pointed to by result.
47212126SHyon.Kim@Sun.COM  */
47312126SHyon.Kim@Sun.COM void
smp_action_get_response(const smp_action_t * ap,smp_result_t * resultp,void ** respp,size_t * dlenp)47412126SHyon.Kim@Sun.COM smp_action_get_response(const smp_action_t *ap, smp_result_t *resultp,
47512126SHyon.Kim@Sun.COM     void **respp, size_t *dlenp)
47612126SHyon.Kim@Sun.COM {
47712126SHyon.Kim@Sun.COM 	if (resultp != NULL)
47812126SHyon.Kim@Sun.COM 		*resultp = ap->sa_result;
47912126SHyon.Kim@Sun.COM 
48012126SHyon.Kim@Sun.COM 	if (respp != NULL)
48112126SHyon.Kim@Sun.COM 		*respp = (ap->sa_response_data_len > 0) ?
48212126SHyon.Kim@Sun.COM 		    (ap->sa_response + ap->sa_response_data_off) : NULL;
48312126SHyon.Kim@Sun.COM 
48412126SHyon.Kim@Sun.COM 	if (dlenp != NULL)
48512126SHyon.Kim@Sun.COM 		*dlenp = ap->sa_response_data_len;
48612126SHyon.Kim@Sun.COM }
48712126SHyon.Kim@Sun.COM 
48812126SHyon.Kim@Sun.COM /*
48912126SHyon.Kim@Sun.COM  * Obtains the entire request frame and the amount of space allocated for it.
49012126SHyon.Kim@Sun.COM  * This is intended only for use by plugins; front-end consumers should use
49112126SHyon.Kim@Sun.COM  * smp_action_get_request() instead.
49212126SHyon.Kim@Sun.COM  */
49312126SHyon.Kim@Sun.COM void
smp_action_get_request_frame(const smp_action_t * ap,void ** reqp,size_t * alenp)49412126SHyon.Kim@Sun.COM smp_action_get_request_frame(const smp_action_t *ap, void **reqp, size_t *alenp)
49512126SHyon.Kim@Sun.COM {
49612126SHyon.Kim@Sun.COM 	if (reqp != NULL)
49712126SHyon.Kim@Sun.COM 		*reqp = ap->sa_request;
49812126SHyon.Kim@Sun.COM 
49912126SHyon.Kim@Sun.COM 	if (alenp != NULL)
50012126SHyon.Kim@Sun.COM 		*alenp = ap->sa_request_alloc_len;
50112126SHyon.Kim@Sun.COM }
50212126SHyon.Kim@Sun.COM 
50312126SHyon.Kim@Sun.COM /*
50412126SHyon.Kim@Sun.COM  * Obtains the entire response frame and the amount of space allocated for it.
50512126SHyon.Kim@Sun.COM  * This is intended only for use by plugins; front-end consumers should use
50612126SHyon.Kim@Sun.COM  * smp_action_get_response() instead.
50712126SHyon.Kim@Sun.COM  */
50812126SHyon.Kim@Sun.COM void
smp_action_get_response_frame(const smp_action_t * ap,void ** respp,size_t * lenp)50912126SHyon.Kim@Sun.COM smp_action_get_response_frame(const smp_action_t *ap,
51012126SHyon.Kim@Sun.COM     void **respp, size_t *lenp)
51112126SHyon.Kim@Sun.COM {
51212126SHyon.Kim@Sun.COM 	if (respp != NULL)
51312126SHyon.Kim@Sun.COM 		*respp = ap->sa_response;
51412126SHyon.Kim@Sun.COM 
51512126SHyon.Kim@Sun.COM 	if (lenp != NULL) {
51612126SHyon.Kim@Sun.COM 		if (ap->sa_flags & SMP_ACTION_F_EXEC)
51712126SHyon.Kim@Sun.COM 			*lenp = ap->sa_response_engine_len;
51812126SHyon.Kim@Sun.COM 		else
51912126SHyon.Kim@Sun.COM 			*lenp = ap->sa_response_alloc_len;
52012126SHyon.Kim@Sun.COM 	}
52112126SHyon.Kim@Sun.COM }
52212126SHyon.Kim@Sun.COM 
52312126SHyon.Kim@Sun.COM /*
52412126SHyon.Kim@Sun.COM  * Set the total response frame length as determined by the engine.  This
52512126SHyon.Kim@Sun.COM  * should never be called by consumers or plugins other than engines.
52612126SHyon.Kim@Sun.COM  */
52712126SHyon.Kim@Sun.COM void
smp_action_set_response_len(smp_action_t * ap,size_t elen)52812126SHyon.Kim@Sun.COM smp_action_set_response_len(smp_action_t *ap, size_t elen)
52912126SHyon.Kim@Sun.COM {
53012126SHyon.Kim@Sun.COM 	ap->sa_response_engine_len = elen;
53112126SHyon.Kim@Sun.COM }
53212126SHyon.Kim@Sun.COM 
53312126SHyon.Kim@Sun.COM void
smp_action_set_result(smp_action_t * ap,smp_result_t result)53412126SHyon.Kim@Sun.COM smp_action_set_result(smp_action_t *ap, smp_result_t result)
53512126SHyon.Kim@Sun.COM {
53612126SHyon.Kim@Sun.COM 	ap->sa_result = result;
53712126SHyon.Kim@Sun.COM }
53812126SHyon.Kim@Sun.COM 
53912126SHyon.Kim@Sun.COM /*
54012126SHyon.Kim@Sun.COM  * Allocate an action object.  The object will contain a request buffer
54112126SHyon.Kim@Sun.COM  * to hold the frame to be transmitted to the target, a response buffer
54212126SHyon.Kim@Sun.COM  * for the frame to be received from it, and auxiliary private information.
54312126SHyon.Kim@Sun.COM  *
54412126SHyon.Kim@Sun.COM  * For the request, callers may specify:
54512126SHyon.Kim@Sun.COM  *
54612126SHyon.Kim@Sun.COM  * - An externally-allocated buffer and its size in bytes, or
54712126SHyon.Kim@Sun.COM  * - NULL and a function-specific size descriptor, or
54812126SHyon.Kim@Sun.COM  *
54912126SHyon.Kim@Sun.COM  * Note that for some functions, the size descriptor may be 0, indicating that
55012126SHyon.Kim@Sun.COM  * a default buffer length will be used.  It is the caller's responsibility
55112126SHyon.Kim@Sun.COM  * to correctly interpret function-specific buffer lengths.  See appropriate
55212126SHyon.Kim@Sun.COM  * plugin documentation for information on buffer sizes and buffer content
55312126SHyon.Kim@Sun.COM  * interpretation.
55412126SHyon.Kim@Sun.COM  *
55512126SHyon.Kim@Sun.COM  * For the response, callers may specify:
55612126SHyon.Kim@Sun.COM  *
55712126SHyon.Kim@Sun.COM  * - An externally-allocated buffer and its size in bytes, or
55812126SHyon.Kim@Sun.COM  * - NULL and 0, to use a guaranteed-sufficient buffer.
55912126SHyon.Kim@Sun.COM  *
56012126SHyon.Kim@Sun.COM  * If an invalid request size descriptor is provided, or a preallocated
56112126SHyon.Kim@Sun.COM  * buffer is provided and it is insufficiently large, this function will
56212126SHyon.Kim@Sun.COM  * fail with ESMP_RANGE.
56312126SHyon.Kim@Sun.COM  *
56412126SHyon.Kim@Sun.COM  * Callers are discouraged from allocating their own buffers and must be
56512126SHyon.Kim@Sun.COM  * aware of the consequences of specifying non-default lengths.
56612126SHyon.Kim@Sun.COM  */
56712126SHyon.Kim@Sun.COM smp_action_t *
smp_action_xalloc(smp_function_t fn,smp_target_t * tp,void * rq,size_t rqsd,void * rs,size_t rslen)56812126SHyon.Kim@Sun.COM smp_action_xalloc(smp_function_t fn, smp_target_t *tp,
56912126SHyon.Kim@Sun.COM     void *rq, size_t rqsd, void *rs, size_t rslen)
57012126SHyon.Kim@Sun.COM {
57112126SHyon.Kim@Sun.COM 	smp_plugin_t *pp;
57212126SHyon.Kim@Sun.COM 	const smp_function_def_t *dp = NULL;
57312126SHyon.Kim@Sun.COM 	smp_action_t *ap;
57412126SHyon.Kim@Sun.COM 	uint_t cap;
57512126SHyon.Kim@Sun.COM 	size_t rqlen, len;
57612126SHyon.Kim@Sun.COM 	uint8_t *alloc;
57712126SHyon.Kim@Sun.COM 	int i;
57812126SHyon.Kim@Sun.COM 
57912126SHyon.Kim@Sun.COM 	cap = smp_target_getcap(tp);
58012126SHyon.Kim@Sun.COM 
58112126SHyon.Kim@Sun.COM 	for (pp = tp->st_plugin_first; pp != NULL; pp = pp->sp_next) {
58212126SHyon.Kim@Sun.COM 		if (pp->sp_functions == NULL)
58312126SHyon.Kim@Sun.COM 			continue;
58412126SHyon.Kim@Sun.COM 
58512126SHyon.Kim@Sun.COM 		for (i = 0; pp->sp_functions[i].sfd_rq_len != NULL; i++) {
58612126SHyon.Kim@Sun.COM 			dp = &pp->sp_functions[i];
58712126SHyon.Kim@Sun.COM 			if (dp->sfd_function == fn &&
58812126SHyon.Kim@Sun.COM 			    ((cap & dp->sfd_capmask) == dp->sfd_capset))
58912126SHyon.Kim@Sun.COM 				break;
59012126SHyon.Kim@Sun.COM 		}
59112126SHyon.Kim@Sun.COM 	}
59212126SHyon.Kim@Sun.COM 
59312126SHyon.Kim@Sun.COM 	if (dp == NULL) {
59412126SHyon.Kim@Sun.COM 		(void) smp_set_errno(ESMP_BADFUNC);
59512126SHyon.Kim@Sun.COM 		return (NULL);
59612126SHyon.Kim@Sun.COM 	}
59712126SHyon.Kim@Sun.COM 
59812126SHyon.Kim@Sun.COM 	if (rq == NULL) {
59912126SHyon.Kim@Sun.COM 		if ((rqlen = dp->sfd_rq_len(rqsd, tp)) == 0)
60012126SHyon.Kim@Sun.COM 			return (NULL);
60112126SHyon.Kim@Sun.COM 	} else if (rqlen < SMP_REQ_MINLEN) {
60212126SHyon.Kim@Sun.COM 		(void) smp_set_errno(ESMP_RANGE);
60312126SHyon.Kim@Sun.COM 		return (NULL);
60412126SHyon.Kim@Sun.COM 	}
60512126SHyon.Kim@Sun.COM 
60612126SHyon.Kim@Sun.COM 	if (rs == NULL) {
60712126SHyon.Kim@Sun.COM 		rslen = 1020 + SMP_RESP_MINLEN;
60812126SHyon.Kim@Sun.COM 	} else if (rslen < SMP_RESP_MINLEN) {
60912126SHyon.Kim@Sun.COM 		(void) smp_set_errno(ESMP_RANGE);
61012126SHyon.Kim@Sun.COM 		return (NULL);
61112126SHyon.Kim@Sun.COM 	}
61212126SHyon.Kim@Sun.COM 
61312126SHyon.Kim@Sun.COM 	len = offsetof(smp_action_t, sa_buf[0]);
61412126SHyon.Kim@Sun.COM 	if (rq == NULL)
61512126SHyon.Kim@Sun.COM 		len += rqlen;
61612126SHyon.Kim@Sun.COM 	if (rs == NULL)
61712126SHyon.Kim@Sun.COM 		len += rslen;
61812126SHyon.Kim@Sun.COM 
61912126SHyon.Kim@Sun.COM 	if ((ap = smp_zalloc(len)) == NULL)
62012126SHyon.Kim@Sun.COM 		return (NULL);
62112126SHyon.Kim@Sun.COM 
62212126SHyon.Kim@Sun.COM 	ap->sa_def = dp;
62312126SHyon.Kim@Sun.COM 	alloc = ap->sa_buf;
62412126SHyon.Kim@Sun.COM 
62512126SHyon.Kim@Sun.COM 	if (rq == NULL) {
62612126SHyon.Kim@Sun.COM 		ap->sa_request = alloc;
62712126SHyon.Kim@Sun.COM 		alloc += rqlen;
62812126SHyon.Kim@Sun.COM 	}
62912126SHyon.Kim@Sun.COM 	ap->sa_request_alloc_len = rqlen;
63012126SHyon.Kim@Sun.COM 
63112126SHyon.Kim@Sun.COM 	if (rs == NULL) {
63212126SHyon.Kim@Sun.COM 		ap->sa_response = alloc;
63312126SHyon.Kim@Sun.COM 		alloc += rslen;
63412126SHyon.Kim@Sun.COM 	}
63512126SHyon.Kim@Sun.COM 	ap->sa_response_alloc_len = rslen;
63612126SHyon.Kim@Sun.COM 
63712126SHyon.Kim@Sun.COM 	ASSERT(alloc - (uint8_t *)ap == len);
63812126SHyon.Kim@Sun.COM 
63912126SHyon.Kim@Sun.COM 	ap->sa_request_data_off = dp->sfd_rq_dataoff(ap, tp);
64012126SHyon.Kim@Sun.COM 	ap->sa_flags |= SMP_ACTION_F_OFFSET;
64112126SHyon.Kim@Sun.COM 
64212126SHyon.Kim@Sun.COM 	return (ap);
64312126SHyon.Kim@Sun.COM }
64412126SHyon.Kim@Sun.COM 
64512126SHyon.Kim@Sun.COM /*
64612126SHyon.Kim@Sun.COM  * Simplified action allocator.  All buffers are allocated for the
64712126SHyon.Kim@Sun.COM  * caller.  The request buffer size will be based on the function-specific
64812126SHyon.Kim@Sun.COM  * interpretation of the rqsize parameter.  The response buffer size will be
64912126SHyon.Kim@Sun.COM  * a function-specific value sufficiently large to capture any response.
65012126SHyon.Kim@Sun.COM  */
65112126SHyon.Kim@Sun.COM smp_action_t *
smp_action_alloc(smp_function_t fn,smp_target_t * tp,size_t rqsd)65212126SHyon.Kim@Sun.COM smp_action_alloc(smp_function_t fn, smp_target_t *tp, size_t rqsd)
65312126SHyon.Kim@Sun.COM {
65412126SHyon.Kim@Sun.COM 	return (smp_action_xalloc(fn, tp, NULL, rqsd, NULL, 0));
65512126SHyon.Kim@Sun.COM }
65612126SHyon.Kim@Sun.COM 
65712126SHyon.Kim@Sun.COM void
smp_action_free(smp_action_t * ap)65812126SHyon.Kim@Sun.COM smp_action_free(smp_action_t *ap)
65912126SHyon.Kim@Sun.COM {
66012126SHyon.Kim@Sun.COM 	if (ap == NULL)
66112126SHyon.Kim@Sun.COM 		return;
66212126SHyon.Kim@Sun.COM 
66312126SHyon.Kim@Sun.COM 	smp_free(ap);
66412126SHyon.Kim@Sun.COM }
66512126SHyon.Kim@Sun.COM 
66612126SHyon.Kim@Sun.COM /*
66712126SHyon.Kim@Sun.COM  * For testing purposes, we allow data to be corrupted via an environment
66812126SHyon.Kim@Sun.COM  * variable setting.  This helps ensure that higher level software can cope with
66912126SHyon.Kim@Sun.COM  * arbitrarily broken targets.  The mtbf value represents the number of bytes we
67012126SHyon.Kim@Sun.COM  * will see, on average, in between each failure.  Therefore, for each N bytes,
67112126SHyon.Kim@Sun.COM  * we would expect to see (N / mtbf) bytes of corruption.
67212126SHyon.Kim@Sun.COM  */
67312126SHyon.Kim@Sun.COM static void
smp_inject_errors(void * data,size_t len,uint_t mtbf)67412126SHyon.Kim@Sun.COM smp_inject_errors(void *data, size_t len, uint_t mtbf)
67512126SHyon.Kim@Sun.COM {
67612126SHyon.Kim@Sun.COM 	char *buf = data;
67712126SHyon.Kim@Sun.COM 	double prob;
67812126SHyon.Kim@Sun.COM 	size_t index;
67912126SHyon.Kim@Sun.COM 
68012126SHyon.Kim@Sun.COM 	if (len == 0)
68112126SHyon.Kim@Sun.COM 		return;
68212126SHyon.Kim@Sun.COM 
68312126SHyon.Kim@Sun.COM 	prob = (double)len / mtbf;
68412126SHyon.Kim@Sun.COM 
68512126SHyon.Kim@Sun.COM 	while (prob > 1) {
68612126SHyon.Kim@Sun.COM 		index = lrand48() % len;
68712126SHyon.Kim@Sun.COM 		buf[index] = (lrand48() % 256);
68812126SHyon.Kim@Sun.COM 		prob -= 1;
68912126SHyon.Kim@Sun.COM 	}
69012126SHyon.Kim@Sun.COM 
69112126SHyon.Kim@Sun.COM 	if (drand48() <= prob) {
69212126SHyon.Kim@Sun.COM 		index = lrand48() % len;
69312126SHyon.Kim@Sun.COM 		buf[index] = (lrand48() % 256);
69412126SHyon.Kim@Sun.COM 	}
69512126SHyon.Kim@Sun.COM }
69612126SHyon.Kim@Sun.COM 
69712126SHyon.Kim@Sun.COM int
smp_exec(smp_action_t * ap,smp_target_t * tp)69812126SHyon.Kim@Sun.COM smp_exec(smp_action_t *ap, smp_target_t *tp)
69912126SHyon.Kim@Sun.COM {
70012126SHyon.Kim@Sun.COM 	const smp_function_def_t *dp;
70112126SHyon.Kim@Sun.COM 	int ret;
70212126SHyon.Kim@Sun.COM 
70312126SHyon.Kim@Sun.COM 	dp = ap->sa_def;
70412126SHyon.Kim@Sun.COM 	dp->sfd_rq_setframe(ap, tp);
70512126SHyon.Kim@Sun.COM 
70612126SHyon.Kim@Sun.COM 	if (tp->st_mtbf_request != 0) {
70712126SHyon.Kim@Sun.COM 		smp_inject_errors(ap->sa_request, ap->sa_request_alloc_len,
70812126SHyon.Kim@Sun.COM 		    tp->st_mtbf_request);
70912126SHyon.Kim@Sun.COM 	}
71012126SHyon.Kim@Sun.COM 
71112126SHyon.Kim@Sun.COM 	ret = tp->st_engine->se_ops->seo_exec(tp->st_priv, ap);
71212126SHyon.Kim@Sun.COM 
71312126SHyon.Kim@Sun.COM 	if (ret == 0 && tp->st_mtbf_response != 0) {
71412126SHyon.Kim@Sun.COM 		smp_inject_errors(ap->sa_response, ap->sa_response_engine_len,
71512126SHyon.Kim@Sun.COM 		    tp->st_mtbf_response);
71612126SHyon.Kim@Sun.COM 	}
71712126SHyon.Kim@Sun.COM 
71812126SHyon.Kim@Sun.COM 	if (ret != 0)
71912126SHyon.Kim@Sun.COM 		return (ret);
72012126SHyon.Kim@Sun.COM 
72112126SHyon.Kim@Sun.COM 	ap->sa_flags |= SMP_ACTION_F_EXEC;
72212126SHyon.Kim@Sun.COM 
72312126SHyon.Kim@Sun.COM 	/*
72412126SHyon.Kim@Sun.COM 	 * Obtain the data length and offset from the underlying plugins.
72512126SHyon.Kim@Sun.COM 	 * Then offer the plugins the opportunity to set any parameters in the
72612126SHyon.Kim@Sun.COM 	 * target to reflect state observed in the response.
72712126SHyon.Kim@Sun.COM 	 */
72812126SHyon.Kim@Sun.COM 	ap->sa_response_data_len = dp->sfd_rs_datalen(ap, tp);
72912126SHyon.Kim@Sun.COM 	ap->sa_response_data_off = dp->sfd_rs_dataoff(ap, tp);
73012126SHyon.Kim@Sun.COM 	dp->sfd_rs_getparams(ap, tp);
73112126SHyon.Kim@Sun.COM 
73212126SHyon.Kim@Sun.COM 	ap->sa_flags |= SMP_ACTION_F_DECODE;
73312126SHyon.Kim@Sun.COM 
73412126SHyon.Kim@Sun.COM 	return (0);
73512126SHyon.Kim@Sun.COM }
736