1*275c9da8Seschrock /* 2*275c9da8Seschrock * CDDL HEADER START 3*275c9da8Seschrock * 4*275c9da8Seschrock * The contents of this file are subject to the terms of the 5*275c9da8Seschrock * Common Development and Distribution License (the "License"). 6*275c9da8Seschrock * You may not use this file except in compliance with the License. 7*275c9da8Seschrock * 8*275c9da8Seschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*275c9da8Seschrock * or http://www.opensolaris.org/os/licensing. 10*275c9da8Seschrock * See the License for the specific language governing permissions 11*275c9da8Seschrock * and limitations under the License. 12*275c9da8Seschrock * 13*275c9da8Seschrock * When distributing Covered Code, include this CDDL HEADER in each 14*275c9da8Seschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*275c9da8Seschrock * If applicable, add the following below this CDDL HEADER, with the 16*275c9da8Seschrock * fields enclosed by brackets "[]" replaced with your own identifying 17*275c9da8Seschrock * information: Portions Copyright [yyyy] [name of copyright owner] 18*275c9da8Seschrock * 19*275c9da8Seschrock * CDDL HEADER END 20*275c9da8Seschrock */ 21*275c9da8Seschrock 22*275c9da8Seschrock /* 23*275c9da8Seschrock * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*275c9da8Seschrock * Use is subject to license terms. 25*275c9da8Seschrock */ 26*275c9da8Seschrock 27*275c9da8Seschrock #pragma ident "%Z%%M% %I% %E% SMI" 28*275c9da8Seschrock 29*275c9da8Seschrock #include <scsi/libses.h> 30*275c9da8Seschrock #include "ses_impl.h" 31*275c9da8Seschrock 32*275c9da8Seschrock __thread ses_errno_t _ses_errno; 33*275c9da8Seschrock __thread char _ses_errmsg[1024]; 34*275c9da8Seschrock __thread char _ses_nverr_member[256]; 35*275c9da8Seschrock 36*275c9da8Seschrock static void ses_vpanic(const char *, va_list) __NORETURN; 37*275c9da8Seschrock 38*275c9da8Seschrock static void 39*275c9da8Seschrock ses_vpanic(const char *fmt, va_list ap) 40*275c9da8Seschrock { 41*275c9da8Seschrock int oserr = errno; 42*275c9da8Seschrock char msg[BUFSIZ]; 43*275c9da8Seschrock size_t len; 44*275c9da8Seschrock 45*275c9da8Seschrock (void) snprintf(msg, sizeof (msg), "ABORT: "); 46*275c9da8Seschrock len = strlen(msg); 47*275c9da8Seschrock (void) vsnprintf(msg + len, sizeof (msg) - len, fmt, ap); 48*275c9da8Seschrock 49*275c9da8Seschrock if (strchr(fmt, '\n') == NULL) { 50*275c9da8Seschrock len = strlen(msg); 51*275c9da8Seschrock (void) snprintf(msg + len, sizeof (msg) - len, ": %s\n", 52*275c9da8Seschrock strerror(oserr)); 53*275c9da8Seschrock } 54*275c9da8Seschrock 55*275c9da8Seschrock (void) write(STDERR_FILENO, msg, strlen(msg)); 56*275c9da8Seschrock 57*275c9da8Seschrock abort: 58*275c9da8Seschrock abort(); 59*275c9da8Seschrock _exit(1); 60*275c9da8Seschrock } 61*275c9da8Seschrock 62*275c9da8Seschrock /*PRINTFLIKE1*/ 63*275c9da8Seschrock void 64*275c9da8Seschrock ses_panic(const char *fmt, ...) 65*275c9da8Seschrock { 66*275c9da8Seschrock va_list ap; 67*275c9da8Seschrock 68*275c9da8Seschrock va_start(ap, fmt); 69*275c9da8Seschrock ses_vpanic(fmt, ap); 70*275c9da8Seschrock va_end(ap); 71*275c9da8Seschrock } 72*275c9da8Seschrock 73*275c9da8Seschrock int 74*275c9da8Seschrock ses_assert(const char *expr, const char *file, int line) 75*275c9da8Seschrock { 76*275c9da8Seschrock ses_panic("\"%s\", line %d: assertion failed: %s\n", file, line, expr); 77*275c9da8Seschrock 78*275c9da8Seschrock /*NOTREACHED*/ 79*275c9da8Seschrock return (0); 80*275c9da8Seschrock } 81*275c9da8Seschrock 82*275c9da8Seschrock int 83*275c9da8Seschrock nvlist_add_fixed_string(nvlist_t *nvl, const char *name, 84*275c9da8Seschrock const char *buf, size_t len) 85*275c9da8Seschrock { 86*275c9da8Seschrock char *str = alloca(len + 1); 87*275c9da8Seschrock bcopy(buf, str, len); 88*275c9da8Seschrock str[len] = '\0'; 89*275c9da8Seschrock 90*275c9da8Seschrock return (nvlist_add_string(nvl, name, str)); 91*275c9da8Seschrock } 92*275c9da8Seschrock 93*275c9da8Seschrock /* 94*275c9da8Seschrock * Like fixed_string, but clears any leading or trailing spaces. 95*275c9da8Seschrock */ 96*275c9da8Seschrock int 97*275c9da8Seschrock nvlist_add_fixed_string_trunc(nvlist_t *nvl, const char *name, 98*275c9da8Seschrock const char *buf, size_t len) 99*275c9da8Seschrock { 100*275c9da8Seschrock while (buf[0] == ' ' && len > 0) { 101*275c9da8Seschrock buf++; 102*275c9da8Seschrock len--; 103*275c9da8Seschrock } 104*275c9da8Seschrock 105*275c9da8Seschrock while (len > 0 && buf[len - 1] == ' ') 106*275c9da8Seschrock len--; 107*275c9da8Seschrock 108*275c9da8Seschrock return (nvlist_add_fixed_string(nvl, name, buf, len)); 109*275c9da8Seschrock } 110*275c9da8Seschrock 111*275c9da8Seschrock ses_errno_t 112*275c9da8Seschrock ses_errno(void) 113*275c9da8Seschrock { 114*275c9da8Seschrock return (_ses_errno); 115*275c9da8Seschrock } 116*275c9da8Seschrock 117*275c9da8Seschrock const char * 118*275c9da8Seschrock ses_errmsg(void) 119*275c9da8Seschrock { 120*275c9da8Seschrock if (_ses_errmsg[0] == '\0') 121*275c9da8Seschrock (void) snprintf(_ses_errmsg, sizeof (_ses_errmsg), "%s", 122*275c9da8Seschrock ses_strerror(_ses_errno)); 123*275c9da8Seschrock 124*275c9da8Seschrock return (_ses_errmsg); 125*275c9da8Seschrock } 126*275c9da8Seschrock 127*275c9da8Seschrock const char * 128*275c9da8Seschrock ses_nv_error_member(void) 129*275c9da8Seschrock { 130*275c9da8Seschrock if (_ses_nverr_member[0] != '\0') 131*275c9da8Seschrock return (_ses_nverr_member); 132*275c9da8Seschrock else 133*275c9da8Seschrock return (NULL); 134*275c9da8Seschrock } 135*275c9da8Seschrock 136*275c9da8Seschrock static int 137*275c9da8Seschrock __ses_set_errno(ses_errno_t err, const char *nvm) 138*275c9da8Seschrock { 139*275c9da8Seschrock if (nvm == NULL) { 140*275c9da8Seschrock _ses_nverr_member[0] = '\0'; 141*275c9da8Seschrock } else { 142*275c9da8Seschrock (void) strlcpy(_ses_nverr_member, nvm, 143*275c9da8Seschrock sizeof (_ses_nverr_member)); 144*275c9da8Seschrock } 145*275c9da8Seschrock _ses_errmsg[0] = '\0'; 146*275c9da8Seschrock _ses_errno = err; 147*275c9da8Seschrock 148*275c9da8Seschrock return (-1); 149*275c9da8Seschrock } 150*275c9da8Seschrock 151*275c9da8Seschrock int 152*275c9da8Seschrock ses_set_errno(ses_errno_t err) 153*275c9da8Seschrock { 154*275c9da8Seschrock return (__ses_set_errno(err, NULL)); 155*275c9da8Seschrock } 156*275c9da8Seschrock 157*275c9da8Seschrock int 158*275c9da8Seschrock ses_set_nverrno(int err, const char *member) 159*275c9da8Seschrock { 160*275c9da8Seschrock ses_errno_t se = (err == ENOMEM || err == EAGAIN) ? 161*275c9da8Seschrock ESES_NOMEM : ESES_NVL; 162*275c9da8Seschrock 163*275c9da8Seschrock /* 164*275c9da8Seschrock * If the error is ESES_NVL, then we should always have a member 165*275c9da8Seschrock * available. The only time 'member' is NULL is when nvlist_alloc() 166*275c9da8Seschrock * fails, which should only be possible if memory allocation fails. 167*275c9da8Seschrock */ 168*275c9da8Seschrock assert(se == ESES_NOMEM || member != NULL); 169*275c9da8Seschrock 170*275c9da8Seschrock return (__ses_set_errno(se, member)); 171*275c9da8Seschrock } 172*275c9da8Seschrock 173*275c9da8Seschrock static int 174*275c9da8Seschrock ses_verror(ses_errno_t err, const char *fmt, va_list ap) 175*275c9da8Seschrock { 176*275c9da8Seschrock int syserr = errno; 177*275c9da8Seschrock size_t n; 178*275c9da8Seschrock char *errmsg; 179*275c9da8Seschrock 180*275c9da8Seschrock errmsg = alloca(sizeof (_ses_errmsg)); 181*275c9da8Seschrock (void) vsnprintf(errmsg, sizeof (_ses_errmsg), fmt, ap); 182*275c9da8Seschrock (void) ses_set_errno(err); 183*275c9da8Seschrock 184*275c9da8Seschrock n = strlen(errmsg); 185*275c9da8Seschrock 186*275c9da8Seschrock while (n != 0 && errmsg[n - 1] == '\n') 187*275c9da8Seschrock errmsg[--n] = '\0'; 188*275c9da8Seschrock 189*275c9da8Seschrock bcopy(errmsg, _ses_errmsg, sizeof (_ses_errmsg)); 190*275c9da8Seschrock errno = syserr; 191*275c9da8Seschrock 192*275c9da8Seschrock return (-1); 193*275c9da8Seschrock } 194*275c9da8Seschrock 195*275c9da8Seschrock static int 196*275c9da8Seschrock ses_vnverror(int err, const char *member, const char *fmt, 197*275c9da8Seschrock va_list ap) 198*275c9da8Seschrock { 199*275c9da8Seschrock int syserr = errno; 200*275c9da8Seschrock size_t n; 201*275c9da8Seschrock char *errmsg; 202*275c9da8Seschrock 203*275c9da8Seschrock errmsg = alloca(sizeof (_ses_errmsg)); 204*275c9da8Seschrock (void) vsnprintf(errmsg, sizeof (_ses_errmsg), fmt, ap); 205*275c9da8Seschrock (void) ses_set_nverrno(err, member); 206*275c9da8Seschrock 207*275c9da8Seschrock n = strlen(errmsg); 208*275c9da8Seschrock 209*275c9da8Seschrock while (n != 0 && errmsg[n - 1] == '\n') 210*275c9da8Seschrock errmsg[--n] = '\0'; 211*275c9da8Seschrock 212*275c9da8Seschrock (void) snprintf(errmsg + n, sizeof (_ses_errmsg) - n, ": %s", 213*275c9da8Seschrock strerror(err)); 214*275c9da8Seschrock 215*275c9da8Seschrock bcopy(errmsg, _ses_errmsg, sizeof (_ses_errmsg)); 216*275c9da8Seschrock errno = syserr; 217*275c9da8Seschrock 218*275c9da8Seschrock return (-1); 219*275c9da8Seschrock } 220*275c9da8Seschrock 221*275c9da8Seschrock int 222*275c9da8Seschrock ses_error(ses_errno_t err, const char *fmt, ...) 223*275c9da8Seschrock { 224*275c9da8Seschrock va_list ap; 225*275c9da8Seschrock int rv; 226*275c9da8Seschrock 227*275c9da8Seschrock va_start(ap, fmt); 228*275c9da8Seschrock rv = ses_verror(err, fmt, ap); 229*275c9da8Seschrock va_end(ap); 230*275c9da8Seschrock 231*275c9da8Seschrock return (rv); 232*275c9da8Seschrock } 233*275c9da8Seschrock 234*275c9da8Seschrock int 235*275c9da8Seschrock ses_nverror(int err, const char *member, const char *fmt, ...) 236*275c9da8Seschrock { 237*275c9da8Seschrock va_list ap; 238*275c9da8Seschrock int rv; 239*275c9da8Seschrock 240*275c9da8Seschrock va_start(ap, fmt); 241*275c9da8Seschrock rv = ses_vnverror(err, member, fmt, ap); 242*275c9da8Seschrock va_end(ap); 243*275c9da8Seschrock 244*275c9da8Seschrock return (rv); 245*275c9da8Seschrock } 246*275c9da8Seschrock 247*275c9da8Seschrock int 248*275c9da8Seschrock ses_libscsi_error(libscsi_hdl_t *shp, const char *fmt, ...) 249*275c9da8Seschrock { 250*275c9da8Seschrock va_list ap; 251*275c9da8Seschrock char errmsg[LIBSES_ERRMSGLEN]; 252*275c9da8Seschrock libscsi_errno_t se = libscsi_errno(shp); 253*275c9da8Seschrock ses_errno_t e; 254*275c9da8Seschrock 255*275c9da8Seschrock switch (se) { 256*275c9da8Seschrock case ESCSI_NONE: 257*275c9da8Seschrock return (0); 258*275c9da8Seschrock case ESCSI_NOMEM: 259*275c9da8Seschrock e = ESES_NOMEM; 260*275c9da8Seschrock break; 261*275c9da8Seschrock case ESCSI_NOTSUP: 262*275c9da8Seschrock e = ESES_NOTSUP; 263*275c9da8Seschrock break; 264*275c9da8Seschrock case ESCSI_ZERO_LENGTH: 265*275c9da8Seschrock case ESCSI_VERSION: 266*275c9da8Seschrock case ESCSI_BADFLAGS: 267*275c9da8Seschrock case ESCSI_BOGUSFLAGS: 268*275c9da8Seschrock case ESCSI_BADLENGTH: 269*275c9da8Seschrock case ESCSI_NEEDBUF: 270*275c9da8Seschrock va_start(ap, fmt); 271*275c9da8Seschrock (void) vsnprintf(errmsg, sizeof (errmsg), fmt, ap); 272*275c9da8Seschrock va_end(ap); 273*275c9da8Seschrock ses_panic("%s: unexpected libscsi error %s: %s", errmsg, 274*275c9da8Seschrock libscsi_errname(se), libscsi_errmsg(shp)); 275*275c9da8Seschrock break; 276*275c9da8Seschrock case ESCSI_UNKNOWN: 277*275c9da8Seschrock e = ESES_UNKNOWN; 278*275c9da8Seschrock break; 279*275c9da8Seschrock default: 280*275c9da8Seschrock e = ESES_LIBSCSI; 281*275c9da8Seschrock break; 282*275c9da8Seschrock } 283*275c9da8Seschrock 284*275c9da8Seschrock va_start(ap, fmt); 285*275c9da8Seschrock (void) vsnprintf(errmsg, sizeof (errmsg), fmt, ap); 286*275c9da8Seschrock va_end(ap); 287*275c9da8Seschrock 288*275c9da8Seschrock return (ses_error(e, "%s: %s", errmsg, libscsi_errmsg(shp))); 289*275c9da8Seschrock } 290*275c9da8Seschrock 291*275c9da8Seschrock int 292*275c9da8Seschrock ses_scsi_error(libscsi_action_t *ap, const char *fmt, ...) 293*275c9da8Seschrock { 294*275c9da8Seschrock va_list args; 295*275c9da8Seschrock char errmsg[LIBSES_ERRMSGLEN]; 296*275c9da8Seschrock uint64_t asc = 0, ascq = 0, key = 0; 297*275c9da8Seschrock const char *code, *keystr; 298*275c9da8Seschrock 299*275c9da8Seschrock va_start(args, fmt); 300*275c9da8Seschrock (void) vsnprintf(errmsg, sizeof (errmsg), fmt, args); 301*275c9da8Seschrock va_end(args); 302*275c9da8Seschrock 303*275c9da8Seschrock if (libscsi_action_parse_sense(ap, &key, &asc, &ascq, NULL) != 0) 304*275c9da8Seschrock return (ses_error(ESES_LIBSCSI, 305*275c9da8Seschrock "%s: SCSI status %d (no sense data available)", errmsg, 306*275c9da8Seschrock libscsi_action_get_status(ap))); 307*275c9da8Seschrock 308*275c9da8Seschrock code = libscsi_sense_code_name(asc, ascq); 309*275c9da8Seschrock keystr = libscsi_sense_key_name(key); 310*275c9da8Seschrock 311*275c9da8Seschrock return (ses_error(ESES_LIBSCSI, "%s: SCSI status %d sense key %llu " 312*275c9da8Seschrock "(%s) additional sense code 0x%llx/0x%llx (%s)", errmsg, 313*275c9da8Seschrock libscsi_action_get_status(ap), key, keystr ? keystr : "<unknown>", 314*275c9da8Seschrock asc, ascq, code ? code : "<unknown>")); 315*275c9da8Seschrock } 316*275c9da8Seschrock 317*275c9da8Seschrock void * 318*275c9da8Seschrock ses_alloc(size_t sz) 319*275c9da8Seschrock { 320*275c9da8Seschrock void *p; 321*275c9da8Seschrock 322*275c9da8Seschrock if (sz == 0) 323*275c9da8Seschrock ses_panic("attempted zero-length allocation"); 324*275c9da8Seschrock 325*275c9da8Seschrock if ((p = malloc(sz)) == NULL) 326*275c9da8Seschrock (void) ses_set_errno(ESES_NOMEM); 327*275c9da8Seschrock 328*275c9da8Seschrock return (p); 329*275c9da8Seschrock } 330*275c9da8Seschrock 331*275c9da8Seschrock void * 332*275c9da8Seschrock ses_zalloc(size_t sz) 333*275c9da8Seschrock { 334*275c9da8Seschrock void *p; 335*275c9da8Seschrock 336*275c9da8Seschrock if ((p = ses_alloc(sz)) != NULL) 337*275c9da8Seschrock bzero(p, sz); 338*275c9da8Seschrock 339*275c9da8Seschrock return (p); 340*275c9da8Seschrock } 341*275c9da8Seschrock 342*275c9da8Seschrock char * 343*275c9da8Seschrock ses_strdup(const char *s) 344*275c9da8Seschrock { 345*275c9da8Seschrock char *p; 346*275c9da8Seschrock size_t len; 347*275c9da8Seschrock 348*275c9da8Seschrock if (s == NULL) 349*275c9da8Seschrock ses_panic("attempted zero-length allocation"); 350*275c9da8Seschrock 351*275c9da8Seschrock len = strlen(s) + 1; 352*275c9da8Seschrock 353*275c9da8Seschrock if ((p = ses_alloc(len)) != NULL) 354*275c9da8Seschrock bcopy(s, p, len); 355*275c9da8Seschrock 356*275c9da8Seschrock return (p); 357*275c9da8Seschrock } 358*275c9da8Seschrock 359*275c9da8Seschrock void * 360*275c9da8Seschrock ses_realloc(void *p, size_t sz) 361*275c9da8Seschrock { 362*275c9da8Seschrock if (sz == 0) 363*275c9da8Seschrock ses_panic("attempted zero-length allocation"); 364*275c9da8Seschrock 365*275c9da8Seschrock if ((p = realloc(p, sz)) == NULL) 366*275c9da8Seschrock (void) ses_set_errno(ESES_NOMEM); 367*275c9da8Seschrock 368*275c9da8Seschrock return (p); 369*275c9da8Seschrock } 370*275c9da8Seschrock 371*275c9da8Seschrock /*ARGSUSED*/ 372*275c9da8Seschrock void 373*275c9da8Seschrock ses_free(void *p) 374*275c9da8Seschrock { 375*275c9da8Seschrock free(p); 376*275c9da8Seschrock } 377