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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/isa_defs.h> 31 #include <sys/systeminfo.h> 32 #include <sys/scsi/generic/commands.h> 33 #include <sys/scsi/impl/commands.h> 34 #include <sys/scsi/impl/uscsi.h> 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <stddef.h> 39 #include <string.h> 40 #include <dlfcn.h> 41 #include <limits.h> 42 43 #include <scsi/libscsi.h> 44 #include "libscsi_impl.h" 45 46 static const libscsi_engine_t * 47 get_engine(libscsi_hdl_t *hp, const char *name) 48 { 49 libscsi_engine_impl_t *eip; 50 const libscsi_engine_t *ep; 51 const char *engine_path, *p, *q; 52 char engine_dir[MAXPATHLEN]; 53 char engine_lib[MAXPATHLEN]; 54 char init_name[MAXPATHLEN]; 55 void *dl_hdl; 56 libscsi_engine_init_f init; 57 boolean_t found_lib = B_FALSE, found_init = B_FALSE; 58 int dirs_tried = 0; 59 char isa[257]; 60 61 for (eip = hp->lsh_engines; eip != NULL; eip = eip->lsei_next) { 62 if (strcmp(eip->lsei_engine->lse_name, name) == 0) 63 return (eip->lsei_engine); 64 } 65 66 if ((engine_path = getenv("LIBSCSI_ENGINE_PATH")) == NULL) 67 engine_path = LIBSCSI_DEFAULT_ENGINE_PATH; 68 69 #if defined(_LP64) 70 if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0) 71 isa[0] = '\0'; 72 #else 73 isa[0] = '\0'; 74 #endif 75 76 for (p = engine_path, q = strchr(p, ':'); p != NULL; p = q) { 77 if (q != NULL) { 78 ptrdiff_t len = q - p; 79 (void) strncpy(engine_dir, p, len); 80 engine_dir[len] = '\0'; 81 while (*q == ':') 82 ++q; 83 if (*q == '\0') 84 q = NULL; 85 if (len == 0) 86 continue; 87 } else { 88 (void) strcpy(engine_dir, p); 89 } 90 if (engine_dir[0] != '/') 91 continue; 92 93 ++dirs_tried; 94 95 (void) snprintf(engine_lib, MAXPATHLEN, "%s/%s/%s%s", 96 engine_dir, isa, name, LIBSCSI_ENGINE_EXT); 97 98 dl_hdl = dlopen(engine_lib, 99 RTLD_LOCAL | RTLD_LAZY | RTLD_PARENT); 100 if (dl_hdl == NULL) { 101 if (!found_lib) 102 (void) libscsi_error(hp, ESCSI_NOENGINE, 103 "unable to dlopen %s: %s", engine_lib, 104 dlerror()); 105 continue; 106 } 107 found_lib = B_TRUE; 108 (void) snprintf(init_name, MAXPATHLEN, "libscsi_%s_init", name); 109 init = (libscsi_engine_init_f)dlsym(dl_hdl, init_name); 110 if (init == NULL) { 111 if (!found_init) 112 (void) libscsi_error(hp, ESCSI_NOENGINE, 113 "failed to find %s in %s: %s", init_name, 114 engine_lib, dlerror()); 115 (void) dlclose(dl_hdl); 116 continue; 117 } 118 if ((ep = init(hp)) == NULL) { 119 (void) dlclose(dl_hdl); 120 /* 121 * libscsi errno set by init. 122 */ 123 return (NULL); 124 } 125 if (ep->lse_libversion != hp->lsh_version) { 126 (void) dlclose(dl_hdl); 127 (void) libscsi_error(hp, ESCSI_ENGINE_VER, "engine " 128 "%s version %u does not match library version %u", 129 engine_lib, ep->lse_libversion, hp->lsh_version); 130 return (NULL); 131 } 132 133 eip = libscsi_zalloc(hp, sizeof (libscsi_engine_impl_t)); 134 if (eip == NULL) { 135 (void) dlclose(dl_hdl); 136 return (NULL); 137 } 138 eip->lsei_engine = ep; 139 eip->lsei_dl_hdl = dl_hdl; 140 eip->lsei_next = hp->lsh_engines; 141 hp->lsh_engines = eip; 142 143 return (ep); 144 } 145 146 if (dirs_tried == 0) 147 (void) libscsi_error(hp, ESCSI_ENGINE_BADPATH, "no valid " 148 "directories found in engine path %s", engine_path); 149 150 return (NULL); 151 } 152 153 static void 154 scsi_parse_mtbf(const char *envvar, uint_t *intp) 155 { 156 const char *strval; 157 int intval; 158 159 if ((strval = getenv(envvar)) != NULL && 160 (intval = atoi(strval)) > 0) { 161 srand48(gethrtime()); 162 *intp = intval; 163 } 164 } 165 166 libscsi_target_t * 167 libscsi_open(libscsi_hdl_t *hp, const char *engine, const void *target) 168 { 169 const libscsi_engine_t *ep; 170 libscsi_target_t *tp; 171 void *private; 172 173 if (engine == NULL) { 174 if ((engine = getenv("LIBSCSI_DEFAULT_ENGINE")) == NULL) 175 engine = LIBSCSI_DEFAULT_ENGINE; 176 } 177 178 if ((ep = get_engine(hp, engine)) == NULL) 179 return (NULL); 180 181 if ((tp = libscsi_zalloc(hp, sizeof (libscsi_target_t))) == NULL) 182 return (NULL); 183 184 if ((private = ep->lse_ops->lseo_open(hp, target)) == NULL) { 185 libscsi_free(hp, tp); 186 return (NULL); 187 } 188 189 scsi_parse_mtbf("LIBSCSI_MTBF_CDB", &tp->lst_mtbf_cdb); 190 scsi_parse_mtbf("LIBSCSI_MTBF_READ", &tp->lst_mtbf_read); 191 scsi_parse_mtbf("LIBSCSI_MTBF_WRITE", &tp->lst_mtbf_write); 192 193 tp->lst_hdl = hp; 194 tp->lst_engine = ep; 195 tp->lst_priv = private; 196 197 ++hp->lsh_targets; 198 199 if (libscsi_get_inquiry(hp, tp) != 0) { 200 libscsi_close(hp, tp); 201 return (NULL); 202 } 203 204 return (tp); 205 } 206 207 libscsi_hdl_t * 208 libscsi_get_handle(libscsi_target_t *tp) 209 { 210 return (tp->lst_hdl); 211 } 212 213 void 214 libscsi_close(libscsi_hdl_t *hp, libscsi_target_t *tp) 215 { 216 tp->lst_engine->lse_ops->lseo_close(hp, tp->lst_priv); 217 libscsi_free(hp, tp->lst_vendor); 218 libscsi_free(hp, tp->lst_product); 219 libscsi_free(hp, tp->lst_revision); 220 libscsi_free(hp, tp); 221 --hp->lsh_targets; 222 } 223 224 sam4_status_t 225 libscsi_action_get_status(const libscsi_action_t *ap) 226 { 227 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap; 228 229 return (aip->lsai_status); 230 } 231 232 /* 233 * Set the timeout in seconds for this action. If no timeout is specified 234 * or if the timeout is set to 0, an implementation-specific timeout will be 235 * used (which may vary based on the target, command or other variables). 236 * Not all engines support all timeout values. Setting the timeout to a value 237 * not supported by the engine will cause engine-defined behavior when the 238 * action is executed. 239 */ 240 void 241 libscsi_action_set_timeout(libscsi_action_t *ap, uint32_t timeout) 242 { 243 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap; 244 245 aip->lsai_timeout = timeout; 246 } 247 248 /* 249 * Obtain the timeout setting for this action. 250 */ 251 uint32_t 252 libscsi_action_get_timeout(const libscsi_action_t *ap) 253 { 254 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap; 255 256 return (aip->lsai_timeout); 257 } 258 259 /* 260 * Returns the flags associated with this action. Never fails. 261 */ 262 uint_t 263 libscsi_action_get_flags(const libscsi_action_t *ap) 264 { 265 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap; 266 267 return (aip->lsai_flags); 268 } 269 270 /* 271 * Returns the address of the action's CDB. The CDB buffer is guaranteed to 272 * be large enough to hold the complete CDB for the command specified when the 273 * action was allocated. Therefore, changing the command/opcode portion of 274 * the CDB has undefined effects. The remainder of the CDB may be modified. 275 */ 276 uint8_t * 277 libscsi_action_get_cdb(const libscsi_action_t *ap) 278 { 279 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap; 280 281 return (aip->lsai_cdb); 282 } 283 284 /* 285 * Places the address of the action buffer in the location pointed to by bp, 286 * if bp is not NULL. If ap is not NULL, it will contain the allocated size 287 * of the buffer itself. If vp is not NULL, it will contain the number of 288 * bytes of valid data currently stored in the buffer. 289 * 290 * If the action has LIBSCSI_AF_WRITE set and it has not yet been executed 291 * successfully, the entire buffer is assumed to contain valid data. 292 * 293 * If the action has LIBSCSI_AF_READ set and it has not yet been executed 294 * successfully, the amount of valid data is 0. 295 * 296 * If both LIBSCSI_AF_READ and LIBSCSI_AF_WRITE are clear, this function 297 * fails with ESCSI_BADFLAGS to indicate that the action flags are 298 * incompatible with the action data buffer. 299 */ 300 int 301 libscsi_action_get_buffer(const libscsi_action_t *ap, uint8_t **bp, 302 size_t *sp, size_t *vp) 303 { 304 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap; 305 306 if ((aip->lsai_flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE)) == 0) 307 return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS, 308 "data buffer not supported for actions with both " 309 "LIBSCSI_AF_READ and LIBSCSI_AF_WRITE clear")); 310 311 if ((aip->lsai_flags & LIBSCSI_AF_WRITE) && 312 aip->lsai_status == LIBSCSI_STATUS_INVALID) { 313 if (bp != NULL) 314 *bp = aip->lsai_data; 315 if (sp != NULL) 316 *sp = aip->lsai_data_alloc; 317 if (vp != NULL) 318 *vp = aip->lsai_data_alloc; 319 320 return (0); 321 } 322 323 if ((aip->lsai_flags & LIBSCSI_AF_READ) && 324 aip->lsai_status != LIBSCSI_STATUS_INVALID) { 325 if (bp != NULL) 326 *bp = aip->lsai_data; 327 if (sp != NULL) 328 *sp = aip->lsai_data_alloc; 329 if (vp != NULL) 330 *vp = aip->lsai_data_len; 331 332 return (0); 333 } 334 335 if (aip->lsai_flags & LIBSCSI_AF_WRITE) { 336 if (bp != NULL) 337 *bp = NULL; 338 if (sp != NULL) 339 *sp = NULL; 340 if (vp != NULL) 341 *vp = 0; 342 } else { 343 if (bp != NULL) 344 *bp = aip->lsai_data; 345 if (sp != NULL) 346 *sp = aip->lsai_data_alloc; 347 if (vp != NULL) 348 *vp = 0; 349 } 350 351 return (0); 352 } 353 354 /* 355 * Obtain a pointer to the sense buffer for this action, if any, along with 356 * the size of the sense buffer and the amount of valid data it contains. 357 */ 358 int 359 libscsi_action_get_sense(const libscsi_action_t *ap, uint8_t **bp, 360 size_t *sp, size_t *vp) 361 { 362 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap; 363 364 if (!(aip->lsai_flags & LIBSCSI_AF_RQSENSE)) 365 return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS, 366 "sense data unavailable: LIBSCSI_AF_RQSENSE is clear")); 367 368 if (vp != NULL) { 369 if (aip->lsai_status == LIBSCSI_STATUS_INVALID) 370 *vp = 0; 371 else 372 *vp = aip->lsai_sense_len; 373 } 374 375 if (bp != NULL) { 376 ASSERT(aip->lsai_sense_data != NULL); 377 *bp = aip->lsai_sense_data; 378 } 379 380 if (sp != NULL) 381 *sp = UINT8_MAX; 382 383 return (0); 384 } 385 386 /* 387 * Set the SCSI status of the action. 388 * 389 * Engines only. 390 */ 391 void 392 libscsi_action_set_status(libscsi_action_t *ap, sam4_status_t status) 393 { 394 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap; 395 396 ASSERT(aip->lsai_status == LIBSCSI_STATUS_INVALID); 397 398 aip->lsai_status = status; 399 } 400 401 /* 402 * Set the length of valid data returned by a READ action. If the action is 403 * not a READ action, or the length exceeds the size of the buffer, an error 404 * results. 405 * 406 * Engines only. 407 */ 408 int 409 libscsi_action_set_datalen(libscsi_action_t *ap, size_t len) 410 { 411 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap; 412 413 if ((aip->lsai_flags & LIBSCSI_AF_READ) == 0) 414 return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS, 415 "data cannot be returned for actions with LIBSCSI_AF_READ " 416 "clear")); 417 if (len > aip->lsai_data_alloc) 418 return (libscsi_error(aip->lsai_hdl, ESCSI_BADLENGTH, 419 "data length %lu exceeds allocated buffer capacity %lu", 420 (ulong_t)len, (ulong_t)aip->lsai_data_alloc)); 421 422 ASSERT(aip->lsai_data_len == 0); 423 aip->lsai_data_len = len; 424 425 return (0); 426 } 427 428 /* 429 * Set the length of the valid sense data returned following the command, if 430 * LIBSCSI_AF_RQSENSE is set for this action. Otherwise, fail. 431 * 432 * Engines only. 433 */ 434 int 435 libscsi_action_set_senselen(libscsi_action_t *ap, size_t len) 436 { 437 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap; 438 439 if (!(aip->lsai_flags & LIBSCSI_AF_RQSENSE)) 440 return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS, 441 "sense data not supported: LIBSCSI_AF_RQSENSE is clear")); 442 443 if (len > UINT8_MAX) 444 return (libscsi_error(aip->lsai_hdl, ESCSI_BADLENGTH, 445 "sense length %lu exceeds allocated buffer capacity %lu", 446 (ulong_t)len, (ulong_t)UINT8_MAX)); 447 448 ASSERT(aip->lsai_sense_len == 0); 449 aip->lsai_sense_len = len; 450 451 return (0); 452 } 453 454 /* 455 * Allocate an action object. The object will contain a CDB area sufficiently 456 * large to hold a CDB for the given command, and the CDB's opcode will be 457 * filled in. A pointer to this CDB, the contents of which may be modified by 458 * the caller, may be obtained by a subsequent call to libscsi_action_cdb(). 459 * 460 * If flags includes LIBSCSI_AF_READ or LIBSCSI_AF_WRITE, buflen must be 461 * greater than zero. Otherwise, buflen must be 0 and buf must be NULL. 462 * If buflen is nonzero but buf is NULL, a suitably-sized buffer will be 463 * allocated; otherwise, the specified buffer will be used. In either case, 464 * a pointer to the buffer may be obtained via a subsequent call to 465 * libscsi_action_buffer(). 466 * 467 * If flags includes LIBSCSI_AF_RQSENSE, a REQUEST SENSE command will be 468 * issued immediately following the termination of the specified command. 469 * A buffer will be allocated to receive this sense data. Following successful 470 * execution of the action, a pointer to this buffer and the length of 471 * valid sense data may be obtained by a call to libscsi_action_sense(). 472 * If cmd is SPC3_CMD_REQUEST_SENSE, this flag must be clear. 473 */ 474 libscsi_action_t * 475 libscsi_action_alloc(libscsi_hdl_t *hp, spc3_cmd_t cmd, uint_t flags, 476 void *buf, size_t buflen) 477 { 478 libscsi_action_impl_t *aip; 479 size_t cdbsz, sz; 480 ptrdiff_t off; 481 482 /* 483 * If there's no buffer, it makes no sense to try to read or write 484 * data. Likewise, if we're neither reading nor writing data, we 485 * should not have a buffer. Both of these are programmer error. 486 */ 487 if (buflen == 0 && (flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE))) { 488 (void) libscsi_error(hp, ESCSI_NEEDBUF, "a buffer is " 489 "required when reading or writing"); 490 return (NULL); 491 } 492 if (buflen > 0 && !(flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE))) { 493 (void) libscsi_error(hp, ESCSI_BADFLAGS, "one of " 494 "LIBSCSI_AF_READ and LIBSCSI_AF_WRITE must be specified " 495 "in order to use a buffer"); 496 return (NULL); 497 } 498 if (cmd == SPC3_CMD_REQUEST_SENSE && (flags & LIBSCSI_AF_RQSENSE)) { 499 (void) libscsi_error(hp, ESCSI_BADFLAGS, "request sense " 500 "flag not allowed for request sense command"); 501 return (NULL); 502 } 503 504 if ((sz = cdbsz = libscsi_cmd_cdblen(hp, cmd)) == 0) 505 return (NULL); 506 507 /* 508 * If the caller has asked for a buffer but has not provided one, we 509 * will allocate it in our internal buffer along with the CDB and 510 * request sense space (if requested). 511 */ 512 if (buf == NULL) 513 sz += buflen; 514 515 if (flags & LIBSCSI_AF_RQSENSE) 516 sz += UINT8_MAX; 517 518 sz += offsetof(libscsi_action_impl_t, lsai_buf[0]); 519 520 if ((aip = libscsi_zalloc(hp, sz)) == NULL) 521 return (NULL); 522 523 aip->lsai_hdl = hp; 524 aip->lsai_flags = flags; 525 526 off = 0; 527 528 aip->lsai_cdb = aip->lsai_buf + off; 529 aip->lsai_cdb_len = cdbsz; 530 off += cdbsz; 531 aip->lsai_cdb[0] = (uint8_t)cmd; 532 533 if (buflen > 0) { 534 if (buf != NULL) { 535 aip->lsai_data = buf; 536 } else { 537 aip->lsai_data = aip->lsai_buf + off; 538 off += buflen; 539 } 540 aip->lsai_data_alloc = buflen; 541 if (flags & LIBSCSI_AF_WRITE) 542 aip->lsai_data_len = buflen; 543 } 544 545 if (flags & LIBSCSI_AF_RQSENSE) { 546 aip->lsai_sense_data = aip->lsai_buf + off; 547 off += UINT8_MAX; 548 } 549 550 aip->lsai_status = LIBSCSI_STATUS_INVALID; 551 552 return ((libscsi_action_t *)aip); 553 } 554 555 void 556 libscsi_action_free(libscsi_action_t *ap) 557 { 558 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap; 559 560 libscsi_free(aip->lsai_hdl, aip); 561 } 562 563 /* 564 * For testing purposes, we allow data to be corrupted via an environment 565 * variable setting. This helps ensure that higher level software can cope with 566 * arbitrarily broken targets. The mtbf value represents the number of bytes we 567 * will see, on average, in between each failure. Therefore, for each N bytes, 568 * we would expect to see (N / mtbf) bytes of corruption. 569 */ 570 static void 571 scsi_inject_errors(void *data, size_t len, uint_t mtbf) 572 { 573 char *buf = data; 574 double prob; 575 size_t index; 576 577 if (len == 0) 578 return; 579 580 prob = (double)len / mtbf; 581 582 while (prob > 1) { 583 index = lrand48() % len; 584 buf[index] = (lrand48() % 256); 585 prob -= 1; 586 } 587 588 if (drand48() <= prob) { 589 index = lrand48() % len; 590 buf[index] = (lrand48() % 256); 591 } 592 } 593 594 int 595 libscsi_exec(libscsi_action_t *ap, libscsi_target_t *tp) 596 { 597 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap; 598 libscsi_hdl_t *hp = aip->lsai_hdl; 599 int ret; 600 601 if (tp->lst_mtbf_write != 0 && 602 (aip->lsai_flags & LIBSCSI_AF_WRITE)) { 603 scsi_inject_errors(aip->lsai_data, aip->lsai_data_len, 604 tp->lst_mtbf_write); 605 } 606 607 if (tp->lst_mtbf_cdb != 0) { 608 scsi_inject_errors(aip->lsai_cdb, aip->lsai_cdb_len, 609 tp->lst_mtbf_cdb); 610 } 611 612 ret = tp->lst_engine->lse_ops->lseo_exec(hp, tp->lst_priv, ap); 613 614 if (ret == 0 && tp->lst_mtbf_read != 0 && 615 (aip->lsai_flags & LIBSCSI_AF_READ)) { 616 scsi_inject_errors(aip->lsai_data, aip->lsai_data_len, 617 tp->lst_mtbf_read); 618 } 619 620 return (ret); 621 } 622