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