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