summaryrefslogtreecommitdiff
path: root/usr/src/lib/scsi/libses/common/ses_subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/scsi/libses/common/ses_subr.c')
-rw-r--r--usr/src/lib/scsi/libses/common/ses_subr.c376
1 files changed, 376 insertions, 0 deletions
diff --git a/usr/src/lib/scsi/libses/common/ses_subr.c b/usr/src/lib/scsi/libses/common/ses_subr.c
new file mode 100644
index 0000000000..aa1013e678
--- /dev/null
+++ b/usr/src/lib/scsi/libses/common/ses_subr.c
@@ -0,0 +1,376 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <scsi/libses.h>
+#include "ses_impl.h"
+
+__thread ses_errno_t _ses_errno;
+__thread char _ses_errmsg[1024];
+__thread char _ses_nverr_member[256];
+
+static void ses_vpanic(const char *, va_list) __NORETURN;
+
+static void
+ses_vpanic(const char *fmt, va_list ap)
+{
+ int oserr = errno;
+ char msg[BUFSIZ];
+ size_t len;
+
+ (void) snprintf(msg, sizeof (msg), "ABORT: ");
+ len = strlen(msg);
+ (void) vsnprintf(msg + len, sizeof (msg) - len, fmt, ap);
+
+ if (strchr(fmt, '\n') == NULL) {
+ len = strlen(msg);
+ (void) snprintf(msg + len, sizeof (msg) - len, ": %s\n",
+ strerror(oserr));
+ }
+
+ (void) write(STDERR_FILENO, msg, strlen(msg));
+
+abort:
+ abort();
+ _exit(1);
+}
+
+/*PRINTFLIKE1*/
+void
+ses_panic(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ ses_vpanic(fmt, ap);
+ va_end(ap);
+}
+
+int
+ses_assert(const char *expr, const char *file, int line)
+{
+ ses_panic("\"%s\", line %d: assertion failed: %s\n", file, line, expr);
+
+ /*NOTREACHED*/
+ return (0);
+}
+
+int
+nvlist_add_fixed_string(nvlist_t *nvl, const char *name,
+ const char *buf, size_t len)
+{
+ char *str = alloca(len + 1);
+ bcopy(buf, str, len);
+ str[len] = '\0';
+
+ return (nvlist_add_string(nvl, name, str));
+}
+
+/*
+ * Like fixed_string, but clears any leading or trailing spaces.
+ */
+int
+nvlist_add_fixed_string_trunc(nvlist_t *nvl, const char *name,
+ const char *buf, size_t len)
+{
+ while (buf[0] == ' ' && len > 0) {
+ buf++;
+ len--;
+ }
+
+ while (len > 0 && buf[len - 1] == ' ')
+ len--;
+
+ return (nvlist_add_fixed_string(nvl, name, buf, len));
+}
+
+ses_errno_t
+ses_errno(void)
+{
+ return (_ses_errno);
+}
+
+const char *
+ses_errmsg(void)
+{
+ if (_ses_errmsg[0] == '\0')
+ (void) snprintf(_ses_errmsg, sizeof (_ses_errmsg), "%s",
+ ses_strerror(_ses_errno));
+
+ return (_ses_errmsg);
+}
+
+const char *
+ses_nv_error_member(void)
+{
+ if (_ses_nverr_member[0] != '\0')
+ return (_ses_nverr_member);
+ else
+ return (NULL);
+}
+
+static int
+__ses_set_errno(ses_errno_t err, const char *nvm)
+{
+ if (nvm == NULL) {
+ _ses_nverr_member[0] = '\0';
+ } else {
+ (void) strlcpy(_ses_nverr_member, nvm,
+ sizeof (_ses_nverr_member));
+ }
+ _ses_errmsg[0] = '\0';
+ _ses_errno = err;
+
+ return (-1);
+}
+
+int
+ses_set_errno(ses_errno_t err)
+{
+ return (__ses_set_errno(err, NULL));
+}
+
+int
+ses_set_nverrno(int err, const char *member)
+{
+ ses_errno_t se = (err == ENOMEM || err == EAGAIN) ?
+ ESES_NOMEM : ESES_NVL;
+
+ /*
+ * If the error is ESES_NVL, then we should always have a member
+ * available. The only time 'member' is NULL is when nvlist_alloc()
+ * fails, which should only be possible if memory allocation fails.
+ */
+ assert(se == ESES_NOMEM || member != NULL);
+
+ return (__ses_set_errno(se, member));
+}
+
+static int
+ses_verror(ses_errno_t err, const char *fmt, va_list ap)
+{
+ int syserr = errno;
+ size_t n;
+ char *errmsg;
+
+ errmsg = alloca(sizeof (_ses_errmsg));
+ (void) vsnprintf(errmsg, sizeof (_ses_errmsg), fmt, ap);
+ (void) ses_set_errno(err);
+
+ n = strlen(errmsg);
+
+ while (n != 0 && errmsg[n - 1] == '\n')
+ errmsg[--n] = '\0';
+
+ bcopy(errmsg, _ses_errmsg, sizeof (_ses_errmsg));
+ errno = syserr;
+
+ return (-1);
+}
+
+static int
+ses_vnverror(int err, const char *member, const char *fmt,
+ va_list ap)
+{
+ int syserr = errno;
+ size_t n;
+ char *errmsg;
+
+ errmsg = alloca(sizeof (_ses_errmsg));
+ (void) vsnprintf(errmsg, sizeof (_ses_errmsg), fmt, ap);
+ (void) ses_set_nverrno(err, member);
+
+ n = strlen(errmsg);
+
+ while (n != 0 && errmsg[n - 1] == '\n')
+ errmsg[--n] = '\0';
+
+ (void) snprintf(errmsg + n, sizeof (_ses_errmsg) - n, ": %s",
+ strerror(err));
+
+ bcopy(errmsg, _ses_errmsg, sizeof (_ses_errmsg));
+ errno = syserr;
+
+ return (-1);
+}
+
+int
+ses_error(ses_errno_t err, const char *fmt, ...)
+{
+ va_list ap;
+ int rv;
+
+ va_start(ap, fmt);
+ rv = ses_verror(err, fmt, ap);
+ va_end(ap);
+
+ return (rv);
+}
+
+int
+ses_nverror(int err, const char *member, const char *fmt, ...)
+{
+ va_list ap;
+ int rv;
+
+ va_start(ap, fmt);
+ rv = ses_vnverror(err, member, fmt, ap);
+ va_end(ap);
+
+ return (rv);
+}
+
+int
+ses_libscsi_error(libscsi_hdl_t *shp, const char *fmt, ...)
+{
+ va_list ap;
+ char errmsg[LIBSES_ERRMSGLEN];
+ libscsi_errno_t se = libscsi_errno(shp);
+ ses_errno_t e;
+
+ switch (se) {
+ case ESCSI_NONE:
+ return (0);
+ case ESCSI_NOMEM:
+ e = ESES_NOMEM;
+ break;
+ case ESCSI_NOTSUP:
+ e = ESES_NOTSUP;
+ break;
+ case ESCSI_ZERO_LENGTH:
+ case ESCSI_VERSION:
+ case ESCSI_BADFLAGS:
+ case ESCSI_BOGUSFLAGS:
+ case ESCSI_BADLENGTH:
+ case ESCSI_NEEDBUF:
+ va_start(ap, fmt);
+ (void) vsnprintf(errmsg, sizeof (errmsg), fmt, ap);
+ va_end(ap);
+ ses_panic("%s: unexpected libscsi error %s: %s", errmsg,
+ libscsi_errname(se), libscsi_errmsg(shp));
+ break;
+ case ESCSI_UNKNOWN:
+ e = ESES_UNKNOWN;
+ break;
+ default:
+ e = ESES_LIBSCSI;
+ break;
+ }
+
+ va_start(ap, fmt);
+ (void) vsnprintf(errmsg, sizeof (errmsg), fmt, ap);
+ va_end(ap);
+
+ return (ses_error(e, "%s: %s", errmsg, libscsi_errmsg(shp)));
+}
+
+int
+ses_scsi_error(libscsi_action_t *ap, const char *fmt, ...)
+{
+ va_list args;
+ char errmsg[LIBSES_ERRMSGLEN];
+ uint64_t asc = 0, ascq = 0, key = 0;
+ const char *code, *keystr;
+
+ va_start(args, fmt);
+ (void) vsnprintf(errmsg, sizeof (errmsg), fmt, args);
+ va_end(args);
+
+ if (libscsi_action_parse_sense(ap, &key, &asc, &ascq, NULL) != 0)
+ return (ses_error(ESES_LIBSCSI,
+ "%s: SCSI status %d (no sense data available)", errmsg,
+ libscsi_action_get_status(ap)));
+
+ code = libscsi_sense_code_name(asc, ascq);
+ keystr = libscsi_sense_key_name(key);
+
+ return (ses_error(ESES_LIBSCSI, "%s: SCSI status %d sense key %llu "
+ "(%s) additional sense code 0x%llx/0x%llx (%s)", errmsg,
+ libscsi_action_get_status(ap), key, keystr ? keystr : "<unknown>",
+ asc, ascq, code ? code : "<unknown>"));
+}
+
+void *
+ses_alloc(size_t sz)
+{
+ void *p;
+
+ if (sz == 0)
+ ses_panic("attempted zero-length allocation");
+
+ if ((p = malloc(sz)) == NULL)
+ (void) ses_set_errno(ESES_NOMEM);
+
+ return (p);
+}
+
+void *
+ses_zalloc(size_t sz)
+{
+ void *p;
+
+ if ((p = ses_alloc(sz)) != NULL)
+ bzero(p, sz);
+
+ return (p);
+}
+
+char *
+ses_strdup(const char *s)
+{
+ char *p;
+ size_t len;
+
+ if (s == NULL)
+ ses_panic("attempted zero-length allocation");
+
+ len = strlen(s) + 1;
+
+ if ((p = ses_alloc(len)) != NULL)
+ bcopy(s, p, len);
+
+ return (p);
+}
+
+void *
+ses_realloc(void *p, size_t sz)
+{
+ if (sz == 0)
+ ses_panic("attempted zero-length allocation");
+
+ if ((p = realloc(p, sz)) == NULL)
+ (void) ses_set_errno(ESES_NOMEM);
+
+ return (p);
+}
+
+/*ARGSUSED*/
+void
+ses_free(void *p)
+{
+ free(p);
+}