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 uint8_t 382 smp_target_get_number_of_phys(const smp_target_t *tp) 383 { 384 return (tp->st_repgen.srgr_number_of_phys); 385 } 386 387 uint16_t 388 smp_target_get_exp_route_indexes(const smp_target_t *tp) 389 { 390 return (tp->st_repgen.srgr_exp_route_indexes); 391 } 392 393 void 394 smp_close(smp_target_t *tp) 395 { 396 smp_free(tp->st_vendor); 397 smp_free(tp->st_product); 398 smp_free(tp->st_revision); 399 smp_free(tp->st_component_vendor); 400 401 smp_plugin_unload(tp); 402 403 tp->st_engine->se_ops->seo_close(tp->st_priv); 404 smp_engine_rele(tp->st_engine); 405 406 smp_free(tp); 407 } 408 409 /* 410 * Set the timeout in seconds for this action. If no timeout is specified 411 * or if the timeout is set to 0, an implementation-specific timeout will be 412 * used (which may vary based on the target, command or other variables). 413 * Not all engines support all timeout values. Setting the timeout to a value 414 * not supported by the engine will cause engine-defined behavior when the 415 * action is executed. 416 */ 417 void 418 smp_action_set_timeout(smp_action_t *ap, uint32_t timeout) 419 { 420 ap->sa_timeout = timeout; 421 } 422 423 /* 424 * Obtain the timeout setting for this action. 425 */ 426 uint32_t 427 smp_action_get_timeout(const smp_action_t *ap) 428 { 429 return (ap->sa_timeout); 430 } 431 432 const smp_function_def_t * 433 smp_action_get_function_def(const smp_action_t *ap) 434 { 435 return (ap->sa_def); 436 } 437 438 /* 439 * Obtain the user-requested request allocation size. Note that the 440 * interpretation of this is function-dependent. 441 */ 442 size_t 443 smp_action_get_rqsd(const smp_action_t *ap) 444 { 445 return (ap->sa_request_rqsd); 446 } 447 448 /* 449 * Obtains the address and amount of space allocated for the portion of the 450 * request data that lies between the header (if any) and the CRC. 451 */ 452 void 453 smp_action_get_request(const smp_action_t *ap, void **reqp, size_t *dlenp) 454 { 455 if (reqp != NULL) { 456 if (ap->sa_request_data_off >= 0) { 457 *reqp = ap->sa_request + ap->sa_request_data_off; 458 } else { 459 *reqp = NULL; 460 } 461 } 462 463 if (dlenp != NULL) 464 *dlenp = ap->sa_request_alloc_len - 465 (ap->sa_request_data_off + sizeof (smp_crc_t)); 466 } 467 468 /* 469 * Obtains the address and amount of valid response data (that part of the 470 * response frame, if any, that lies between the header and the CRC). The 471 * result, if any, is also returned in the location pointed to by result. 472 */ 473 void 474 smp_action_get_response(const smp_action_t *ap, smp_result_t *resultp, 475 void **respp, size_t *dlenp) 476 { 477 if (resultp != NULL) 478 *resultp = ap->sa_result; 479 480 if (respp != NULL) 481 *respp = (ap->sa_response_data_len > 0) ? 482 (ap->sa_response + ap->sa_response_data_off) : NULL; 483 484 if (dlenp != NULL) 485 *dlenp = ap->sa_response_data_len; 486 } 487 488 /* 489 * Obtains the entire request frame and the amount of space allocated for it. 490 * This is intended only for use by plugins; front-end consumers should use 491 * smp_action_get_request() instead. 492 */ 493 void 494 smp_action_get_request_frame(const smp_action_t *ap, void **reqp, size_t *alenp) 495 { 496 if (reqp != NULL) 497 *reqp = ap->sa_request; 498 499 if (alenp != NULL) 500 *alenp = ap->sa_request_alloc_len; 501 } 502 503 /* 504 * Obtains the entire response frame and the amount of space allocated for it. 505 * This is intended only for use by plugins; front-end consumers should use 506 * smp_action_get_response() instead. 507 */ 508 void 509 smp_action_get_response_frame(const smp_action_t *ap, 510 void **respp, size_t *lenp) 511 { 512 if (respp != NULL) 513 *respp = ap->sa_response; 514 515 if (lenp != NULL) { 516 if (ap->sa_flags & SMP_ACTION_F_EXEC) 517 *lenp = ap->sa_response_engine_len; 518 else 519 *lenp = ap->sa_response_alloc_len; 520 } 521 } 522 523 /* 524 * Set the total response frame length as determined by the engine. This 525 * should never be called by consumers or plugins other than engines. 526 */ 527 void 528 smp_action_set_response_len(smp_action_t *ap, size_t elen) 529 { 530 ap->sa_response_engine_len = elen; 531 } 532 533 void 534 smp_action_set_result(smp_action_t *ap, smp_result_t result) 535 { 536 ap->sa_result = result; 537 } 538 539 /* 540 * Allocate an action object. The object will contain a request buffer 541 * to hold the frame to be transmitted to the target, a response buffer 542 * for the frame to be received from it, and auxiliary private information. 543 * 544 * For the request, callers may specify: 545 * 546 * - An externally-allocated buffer and its size in bytes, or 547 * - NULL and a function-specific size descriptor, or 548 * 549 * Note that for some functions, the size descriptor may be 0, indicating that 550 * a default buffer length will be used. It is the caller's responsibility 551 * to correctly interpret function-specific buffer lengths. See appropriate 552 * plugin documentation for information on buffer sizes and buffer content 553 * interpretation. 554 * 555 * For the response, callers may specify: 556 * 557 * - An externally-allocated buffer and its size in bytes, or 558 * - NULL and 0, to use a guaranteed-sufficient buffer. 559 * 560 * If an invalid request size descriptor is provided, or a preallocated 561 * buffer is provided and it is insufficiently large, this function will 562 * fail with ESMP_RANGE. 563 * 564 * Callers are discouraged from allocating their own buffers and must be 565 * aware of the consequences of specifying non-default lengths. 566 */ 567 smp_action_t * 568 smp_action_xalloc(smp_function_t fn, smp_target_t *tp, 569 void *rq, size_t rqsd, void *rs, size_t rslen) 570 { 571 smp_plugin_t *pp; 572 const smp_function_def_t *dp = NULL; 573 smp_action_t *ap; 574 uint_t cap; 575 size_t rqlen, len; 576 uint8_t *alloc; 577 int i; 578 579 cap = smp_target_getcap(tp); 580 581 for (pp = tp->st_plugin_first; pp != NULL; pp = pp->sp_next) { 582 if (pp->sp_functions == NULL) 583 continue; 584 585 for (i = 0; pp->sp_functions[i].sfd_rq_len != NULL; i++) { 586 dp = &pp->sp_functions[i]; 587 if (dp->sfd_function == fn && 588 ((cap & dp->sfd_capmask) == dp->sfd_capset)) 589 break; 590 } 591 } 592 593 if (dp == NULL) { 594 (void) smp_set_errno(ESMP_BADFUNC); 595 return (NULL); 596 } 597 598 if (rq == NULL) { 599 if ((rqlen = dp->sfd_rq_len(rqsd, tp)) == 0) 600 return (NULL); 601 } else if (rqlen < SMP_REQ_MINLEN) { 602 (void) smp_set_errno(ESMP_RANGE); 603 return (NULL); 604 } 605 606 if (rs == NULL) { 607 rslen = 1020 + SMP_RESP_MINLEN; 608 } else if (rslen < SMP_RESP_MINLEN) { 609 (void) smp_set_errno(ESMP_RANGE); 610 return (NULL); 611 } 612 613 len = offsetof(smp_action_t, sa_buf[0]); 614 if (rq == NULL) 615 len += rqlen; 616 if (rs == NULL) 617 len += rslen; 618 619 if ((ap = smp_zalloc(len)) == NULL) 620 return (NULL); 621 622 ap->sa_def = dp; 623 alloc = ap->sa_buf; 624 625 if (rq == NULL) { 626 ap->sa_request = alloc; 627 alloc += rqlen; 628 } 629 ap->sa_request_alloc_len = rqlen; 630 631 if (rs == NULL) { 632 ap->sa_response = alloc; 633 alloc += rslen; 634 } 635 ap->sa_response_alloc_len = rslen; 636 637 ASSERT(alloc - (uint8_t *)ap == len); 638 639 ap->sa_request_data_off = dp->sfd_rq_dataoff(ap, tp); 640 ap->sa_flags |= SMP_ACTION_F_OFFSET; 641 642 return (ap); 643 } 644 645 /* 646 * Simplified action allocator. All buffers are allocated for the 647 * caller. The request buffer size will be based on the function-specific 648 * interpretation of the rqsize parameter. The response buffer size will be 649 * a function-specific value sufficiently large to capture any response. 650 */ 651 smp_action_t * 652 smp_action_alloc(smp_function_t fn, smp_target_t *tp, size_t rqsd) 653 { 654 return (smp_action_xalloc(fn, tp, NULL, rqsd, NULL, 0)); 655 } 656 657 void 658 smp_action_free(smp_action_t *ap) 659 { 660 if (ap == NULL) 661 return; 662 663 smp_free(ap); 664 } 665 666 /* 667 * For testing purposes, we allow data to be corrupted via an environment 668 * variable setting. This helps ensure that higher level software can cope with 669 * arbitrarily broken targets. The mtbf value represents the number of bytes we 670 * will see, on average, in between each failure. Therefore, for each N bytes, 671 * we would expect to see (N / mtbf) bytes of corruption. 672 */ 673 static void 674 smp_inject_errors(void *data, size_t len, uint_t mtbf) 675 { 676 char *buf = data; 677 double prob; 678 size_t index; 679 680 if (len == 0) 681 return; 682 683 prob = (double)len / mtbf; 684 685 while (prob > 1) { 686 index = lrand48() % len; 687 buf[index] = (lrand48() % 256); 688 prob -= 1; 689 } 690 691 if (drand48() <= prob) { 692 index = lrand48() % len; 693 buf[index] = (lrand48() % 256); 694 } 695 } 696 697 int 698 smp_exec(smp_action_t *ap, smp_target_t *tp) 699 { 700 const smp_function_def_t *dp; 701 int ret; 702 703 dp = ap->sa_def; 704 dp->sfd_rq_setframe(ap, tp); 705 706 if (tp->st_mtbf_request != 0) { 707 smp_inject_errors(ap->sa_request, ap->sa_request_alloc_len, 708 tp->st_mtbf_request); 709 } 710 711 ret = tp->st_engine->se_ops->seo_exec(tp->st_priv, ap); 712 713 if (ret == 0 && tp->st_mtbf_response != 0) { 714 smp_inject_errors(ap->sa_response, ap->sa_response_engine_len, 715 tp->st_mtbf_response); 716 } 717 718 if (ret != 0) 719 return (ret); 720 721 ap->sa_flags |= SMP_ACTION_F_EXEC; 722 723 /* 724 * Obtain the data length and offset from the underlying plugins. 725 * Then offer the plugins the opportunity to set any parameters in the 726 * target to reflect state observed in the response. 727 */ 728 ap->sa_response_data_len = dp->sfd_rs_datalen(ap, tp); 729 ap->sa_response_data_off = dp->sfd_rs_dataoff(ap, tp); 730 dp->sfd_rs_getparams(ap, tp); 731 732 ap->sa_flags |= SMP_ACTION_F_DECODE; 733 734 return (0); 735 } 736