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