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