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/scsi/generic/commands.h> 31*6316Seschrock #include <sys/scsi/impl/spc3_types.h> 32*6316Seschrock 33*6316Seschrock #include <stddef.h> 34*6316Seschrock #include <stdlib.h> 35*6316Seschrock #include <string.h> 36*6316Seschrock #include <strings.h> 37*6316Seschrock #include <alloca.h> 38*6316Seschrock #include <stdio.h> 39*6316Seschrock #include <unistd.h> 40*6316Seschrock #include <dlfcn.h> 41*6316Seschrock 42*6316Seschrock #include <scsi/libscsi.h> 43*6316Seschrock #include "libscsi_impl.h" 44*6316Seschrock 45*6316Seschrock int 46*6316Seschrock libscsi_assert(const char *expr, const char *file, int line) 47*6316Seschrock { 48*6316Seschrock char *msg; 49*6316Seschrock size_t len; 50*6316Seschrock 51*6316Seschrock len = snprintf(NULL, 0, 52*6316Seschrock "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr); 53*6316Seschrock 54*6316Seschrock msg = alloca(len + 1); 55*6316Seschrock 56*6316Seschrock (void) snprintf(msg, len + 1, 57*6316Seschrock "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr); 58*6316Seschrock 59*6316Seschrock (void) write(STDERR_FILENO, msg, strlen(msg)); 60*6316Seschrock 61*6316Seschrock abort(); 62*6316Seschrock _exit(1); 63*6316Seschrock 64*6316Seschrock /*NOTREACHED*/ 65*6316Seschrock return (0); 66*6316Seschrock } 67*6316Seschrock 68*6316Seschrock int 69*6316Seschrock libscsi_set_errno(libscsi_hdl_t *hp, libscsi_errno_t err) 70*6316Seschrock { 71*6316Seschrock hp->lsh_errno = err; 72*6316Seschrock hp->lsh_errmsg[0] = '\0'; 73*6316Seschrock 74*6316Seschrock return (-1); 75*6316Seschrock } 76*6316Seschrock 77*6316Seschrock /* 78*6316Seschrock * Internal routine for setting both _ue_errno and _ue_errmsg. We save 79*6316Seschrock * and restore the UNIX errno across this routing so the caller can use either 80*6316Seschrock * libscsi_set_errno(), libscsi_error(), or libscsi_verror() without this value 81*6316Seschrock * changing. 82*6316Seschrock */ 83*6316Seschrock int 84*6316Seschrock libscsi_verror(libscsi_hdl_t *hp, libscsi_errno_t err, const char *fmt, 85*6316Seschrock va_list ap) 86*6316Seschrock { 87*6316Seschrock size_t n; 88*6316Seschrock char *errmsg; 89*6316Seschrock 90*6316Seschrock /* 91*6316Seschrock * To allow the existing error message to itself be used in an error 92*6316Seschrock * message, we put the new error message into a buffer on the stack, 93*6316Seschrock * and then copy it into lsh_errmsg. We also need to set the errno, 94*6316Seschrock * but because the call to libscsi_set_errno() is destructive to 95*6316Seschrock * lsh_errmsg, we do this after we print into our temporary buffer 96*6316Seschrock * (in case _libscsi_errmsg is part of the error message) and before we 97*6316Seschrock * copy the temporary buffer on to _libscsi_errmsg (to prevent our new 98*6316Seschrock * message from being nuked by the call to libscsi_set_errno()). 99*6316Seschrock */ 100*6316Seschrock errmsg = alloca(sizeof (hp->lsh_errmsg)); 101*6316Seschrock (void) vsnprintf(errmsg, sizeof (hp->lsh_errmsg), fmt, ap); 102*6316Seschrock (void) libscsi_set_errno(hp, err); 103*6316Seschrock 104*6316Seschrock n = strlen(errmsg); 105*6316Seschrock 106*6316Seschrock if (n != 0 && errmsg[n - 1] == '\n') 107*6316Seschrock errmsg[n - 1] = '\0'; 108*6316Seschrock 109*6316Seschrock bcopy(errmsg, hp->lsh_errmsg, n + 1); 110*6316Seschrock 111*6316Seschrock return (-1); 112*6316Seschrock } 113*6316Seschrock 114*6316Seschrock /*PRINTFLIKE3*/ 115*6316Seschrock int 116*6316Seschrock libscsi_error(libscsi_hdl_t *hp, libscsi_errno_t err, const char *fmt, ...) 117*6316Seschrock { 118*6316Seschrock va_list ap; 119*6316Seschrock 120*6316Seschrock if (fmt == NULL) 121*6316Seschrock return (libscsi_set_errno(hp, err)); 122*6316Seschrock 123*6316Seschrock va_start(ap, fmt); 124*6316Seschrock err = libscsi_verror(hp, err, fmt, ap); 125*6316Seschrock va_end(ap); 126*6316Seschrock 127*6316Seschrock return (err); 128*6316Seschrock } 129*6316Seschrock 130*6316Seschrock libscsi_errno_t 131*6316Seschrock libscsi_errno(libscsi_hdl_t *hp) 132*6316Seschrock { 133*6316Seschrock return (hp->lsh_errno); 134*6316Seschrock } 135*6316Seschrock 136*6316Seschrock const char * 137*6316Seschrock libscsi_errmsg(libscsi_hdl_t *hp) 138*6316Seschrock { 139*6316Seschrock if (hp->lsh_errmsg[0] == '\0') 140*6316Seschrock (void) strlcpy(hp->lsh_errmsg, libscsi_strerror(hp->lsh_errno), 141*6316Seschrock sizeof (hp->lsh_errmsg)); 142*6316Seschrock 143*6316Seschrock return (hp->lsh_errmsg); 144*6316Seschrock } 145*6316Seschrock 146*6316Seschrock void * 147*6316Seschrock libscsi_alloc(libscsi_hdl_t *hp, size_t size) 148*6316Seschrock { 149*6316Seschrock void *mem; 150*6316Seschrock 151*6316Seschrock if (size == 0) { 152*6316Seschrock (void) libscsi_set_errno(hp, ESCSI_ZERO_LENGTH); 153*6316Seschrock return (NULL); 154*6316Seschrock } 155*6316Seschrock 156*6316Seschrock if ((mem = malloc(size)) == NULL) 157*6316Seschrock (void) libscsi_set_errno(hp, ESCSI_NOMEM); 158*6316Seschrock 159*6316Seschrock return (mem); 160*6316Seschrock } 161*6316Seschrock 162*6316Seschrock void * 163*6316Seschrock libscsi_zalloc(libscsi_hdl_t *hp, size_t size) 164*6316Seschrock { 165*6316Seschrock void *mem; 166*6316Seschrock 167*6316Seschrock if ((mem = libscsi_alloc(hp, size)) == NULL) 168*6316Seschrock return (NULL); 169*6316Seschrock 170*6316Seschrock bzero(mem, size); 171*6316Seschrock 172*6316Seschrock return (mem); 173*6316Seschrock } 174*6316Seschrock 175*6316Seschrock char * 176*6316Seschrock libscsi_strdup(libscsi_hdl_t *hp, const char *str) 177*6316Seschrock { 178*6316Seschrock size_t len = strlen(str); 179*6316Seschrock char *dup = libscsi_alloc(hp, len + 1); 180*6316Seschrock 181*6316Seschrock if (dup == NULL) 182*6316Seschrock return (NULL); 183*6316Seschrock 184*6316Seschrock return (strcpy(dup, str)); 185*6316Seschrock } 186*6316Seschrock 187*6316Seschrock /*ARGSUSED*/ 188*6316Seschrock void 189*6316Seschrock libscsi_free(libscsi_hdl_t *hp, void *ptr) 190*6316Seschrock { 191*6316Seschrock free(ptr); 192*6316Seschrock } 193*6316Seschrock 194*6316Seschrock libscsi_hdl_t * 195*6316Seschrock libscsi_init(uint_t version, libscsi_errno_t *errp) 196*6316Seschrock { 197*6316Seschrock libscsi_hdl_t *hp; 198*6316Seschrock 199*6316Seschrock if ((hp = malloc(sizeof (libscsi_hdl_t))) == NULL) { 200*6316Seschrock if (errp != NULL) 201*6316Seschrock *errp = ESCSI_NOMEM; 202*6316Seschrock return (NULL); 203*6316Seschrock } 204*6316Seschrock 205*6316Seschrock bzero(hp, sizeof (libscsi_hdl_t)); 206*6316Seschrock hp->lsh_version = version; 207*6316Seschrock 208*6316Seschrock return (hp); 209*6316Seschrock } 210*6316Seschrock 211*6316Seschrock void 212*6316Seschrock libscsi_fini(libscsi_hdl_t *hp) 213*6316Seschrock { 214*6316Seschrock libscsi_engine_impl_t *eip, *neip; 215*6316Seschrock 216*6316Seschrock if (hp == NULL) 217*6316Seschrock return; 218*6316Seschrock 219*6316Seschrock ASSERT(hp->lsh_targets == 0); 220*6316Seschrock 221*6316Seschrock for (eip = hp->lsh_engines; eip != NULL; eip = neip) { 222*6316Seschrock neip = eip->lsei_next; 223*6316Seschrock (void) dlclose(eip->lsei_dl_hdl); 224*6316Seschrock libscsi_free(hp, eip); 225*6316Seschrock } 226*6316Seschrock 227*6316Seschrock free(hp); 228*6316Seschrock } 229*6316Seschrock 230*6316Seschrock size_t 231*6316Seschrock libscsi_cmd_cdblen(libscsi_hdl_t *hp, uint8_t cmd) 232*6316Seschrock { 233*6316Seschrock size_t sz; 234*6316Seschrock 235*6316Seschrock switch (CDB_GROUPID(cmd)) { 236*6316Seschrock case CDB_GROUPID_0: 237*6316Seschrock sz = CDB_GROUP0; 238*6316Seschrock break; 239*6316Seschrock case CDB_GROUPID_1: 240*6316Seschrock sz = CDB_GROUP1; 241*6316Seschrock break; 242*6316Seschrock case CDB_GROUPID_2: 243*6316Seschrock sz = CDB_GROUP2; 244*6316Seschrock break; 245*6316Seschrock case CDB_GROUPID_3: 246*6316Seschrock sz = CDB_GROUP3; 247*6316Seschrock break; 248*6316Seschrock case CDB_GROUPID_4: 249*6316Seschrock sz = CDB_GROUP4; 250*6316Seschrock break; 251*6316Seschrock case CDB_GROUPID_5: 252*6316Seschrock sz = CDB_GROUP5; 253*6316Seschrock break; 254*6316Seschrock case CDB_GROUPID_6: 255*6316Seschrock sz = CDB_GROUP6; 256*6316Seschrock break; 257*6316Seschrock case CDB_GROUPID_7: 258*6316Seschrock sz = CDB_GROUP7; 259*6316Seschrock break; 260*6316Seschrock default: 261*6316Seschrock sz = 0; 262*6316Seschrock } 263*6316Seschrock 264*6316Seschrock if (sz == 0) 265*6316Seschrock (void) libscsi_error(hp, ESCSI_BADCMD, 266*6316Seschrock "unknown or unsupported command %u", cmd); 267*6316Seschrock 268*6316Seschrock return (sz); 269*6316Seschrock } 270*6316Seschrock 271*6316Seschrock static char * 272*6316Seschrock libscsi_process_inquiry_string(libscsi_hdl_t *hp, const char *raw, size_t len) 273*6316Seschrock { 274*6316Seschrock char *buf; 275*6316Seschrock 276*6316Seschrock buf = alloca(len + 1); 277*6316Seschrock bcopy(raw, buf, len); 278*6316Seschrock 279*6316Seschrock for (; len > 0; len--) { 280*6316Seschrock if (buf[len - 1] != ' ') 281*6316Seschrock break; 282*6316Seschrock } 283*6316Seschrock 284*6316Seschrock buf[len] = '\0'; 285*6316Seschrock 286*6316Seschrock return (libscsi_strdup(hp, buf)); 287*6316Seschrock } 288*6316Seschrock 289*6316Seschrock /* 290*6316Seschrock * As part of basic initialization, we always retrieve the INQUIRY information 291*6316Seschrock * to have the vendor/product/revision information available for all consumers. 292*6316Seschrock */ 293*6316Seschrock int 294*6316Seschrock libscsi_get_inquiry(libscsi_hdl_t *hp, libscsi_target_t *tp) 295*6316Seschrock { 296*6316Seschrock libscsi_action_t *ap; 297*6316Seschrock spc3_inquiry_cdb_t *cp; 298*6316Seschrock spc3_inquiry_data_t data; 299*6316Seschrock size_t len; 300*6316Seschrock 301*6316Seschrock if ((ap = libscsi_action_alloc(hp, SPC3_CMD_INQUIRY, 302*6316Seschrock LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE, &data, 303*6316Seschrock sizeof (data))) == NULL) 304*6316Seschrock return (-1); 305*6316Seschrock 306*6316Seschrock cp = (spc3_inquiry_cdb_t *)libscsi_action_get_cdb(ap); 307*6316Seschrock 308*6316Seschrock SCSI_WRITE16(&cp->ic_allocation_length, sizeof (data)); 309*6316Seschrock 310*6316Seschrock if (libscsi_exec(ap, tp) != 0 || 311*6316Seschrock libscsi_action_get_status(ap) != 0) { 312*6316Seschrock libscsi_action_free(ap); 313*6316Seschrock return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED)); 314*6316Seschrock } 315*6316Seschrock 316*6316Seschrock (void) libscsi_action_get_buffer(ap, NULL, NULL, &len); 317*6316Seschrock libscsi_action_free(ap); 318*6316Seschrock 319*6316Seschrock if (len < offsetof(spc3_inquiry_data_t, id_vs_36)) 320*6316Seschrock return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED)); 321*6316Seschrock 322*6316Seschrock if ((tp->lst_vendor = libscsi_process_inquiry_string(hp, 323*6316Seschrock data.id_vendor_id, sizeof (data.id_vendor_id))) == NULL || 324*6316Seschrock (tp->lst_product = libscsi_process_inquiry_string(hp, 325*6316Seschrock data.id_product_id, sizeof (data.id_product_id))) == NULL || 326*6316Seschrock (tp->lst_revision = libscsi_process_inquiry_string(hp, 327*6316Seschrock data.id_product_revision, 328*6316Seschrock sizeof (data.id_product_revision))) == NULL) { 329*6316Seschrock return (-1); 330*6316Seschrock } 331*6316Seschrock 332*6316Seschrock return (0); 333*6316Seschrock } 334*6316Seschrock 335*6316Seschrock const char * 336*6316Seschrock libscsi_vendor(libscsi_target_t *tp) 337*6316Seschrock { 338*6316Seschrock return (tp->lst_vendor); 339*6316Seschrock } 340*6316Seschrock 341*6316Seschrock const char * 342*6316Seschrock libscsi_product(libscsi_target_t *tp) 343*6316Seschrock { 344*6316Seschrock return (tp->lst_product); 345*6316Seschrock } 346*6316Seschrock 347*6316Seschrock const char * 348*6316Seschrock libscsi_revision(libscsi_target_t *tp) 349*6316Seschrock { 350*6316Seschrock return (tp->lst_revision); 351*6316Seschrock } 352