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.
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.
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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <scsi/libses.h>
32 __thread ses_errno_t _ses_errno
;
33 __thread
char _ses_errmsg
[1024];
34 __thread
char _ses_nverr_member
[256];
36 static void ses_vpanic(const char *, va_list) __NORETURN
;
39 ses_vpanic(const char *fmt
, va_list ap
)
45 (void) snprintf(msg
, sizeof (msg
), "ABORT: ");
47 (void) vsnprintf(msg
+ len
, sizeof (msg
) - len
, fmt
, ap
);
49 if (strchr(fmt
, '\n') == NULL
) {
51 (void) snprintf(msg
+ len
, sizeof (msg
) - len
, ": %s\n",
55 (void) write(STDERR_FILENO
, msg
, strlen(msg
));
64 ses_panic(const char *fmt
, ...)
74 ses_assert(const char *expr
, const char *file
, int line
)
76 ses_panic("\"%s\", line %d: assertion failed: %s\n", file
, line
, expr
);
83 nvlist_add_fixed_string(nvlist_t
*nvl
, const char *name
,
84 const char *buf
, size_t len
)
86 char *str
= alloca(len
+ 1);
90 return (nvlist_add_string(nvl
, name
, str
));
94 * Like fixed_string, but clears any leading or trailing spaces.
97 nvlist_add_fixed_string_trunc(nvlist_t
*nvl
, const char *name
,
98 const char *buf
, size_t len
)
100 while (buf
[0] == ' ' && len
> 0) {
105 while (len
> 0 && buf
[len
- 1] == ' ')
108 return (nvlist_add_fixed_string(nvl
, name
, buf
, len
));
120 if (_ses_errmsg
[0] == '\0')
121 (void) snprintf(_ses_errmsg
, sizeof (_ses_errmsg
), "%s",
122 ses_strerror(_ses_errno
));
124 return (_ses_errmsg
);
128 ses_nv_error_member(void)
130 if (_ses_nverr_member
[0] != '\0')
131 return (_ses_nverr_member
);
137 __ses_set_errno(ses_errno_t err
, const char *nvm
)
140 _ses_nverr_member
[0] = '\0';
142 (void) strlcpy(_ses_nverr_member
, nvm
,
143 sizeof (_ses_nverr_member
));
145 _ses_errmsg
[0] = '\0';
152 ses_set_errno(ses_errno_t err
)
154 return (__ses_set_errno(err
, NULL
));
158 ses_set_nverrno(int err
, const char *member
)
160 ses_errno_t se
= (err
== ENOMEM
|| err
== EAGAIN
) ?
161 ESES_NOMEM
: ESES_NVL
;
164 * If the error is ESES_NVL, then we should always have a member
165 * available. The only time 'member' is NULL is when nvlist_alloc()
166 * fails, which should only be possible if memory allocation fails.
168 assert(se
== ESES_NOMEM
|| member
!= NULL
);
170 return (__ses_set_errno(se
, member
));
174 ses_verror(ses_errno_t err
, const char *fmt
, va_list ap
)
180 errmsg
= alloca(sizeof (_ses_errmsg
));
181 (void) vsnprintf(errmsg
, sizeof (_ses_errmsg
), fmt
, ap
);
182 (void) ses_set_errno(err
);
186 while (n
!= 0 && errmsg
[n
- 1] == '\n')
189 bcopy(errmsg
, _ses_errmsg
, sizeof (_ses_errmsg
));
196 ses_vnverror(int err
, const char *member
, const char *fmt
,
203 errmsg
= alloca(sizeof (_ses_errmsg
));
204 (void) vsnprintf(errmsg
, sizeof (_ses_errmsg
), fmt
, ap
);
205 (void) ses_set_nverrno(err
, member
);
209 while (n
!= 0 && errmsg
[n
- 1] == '\n')
212 (void) snprintf(errmsg
+ n
, sizeof (_ses_errmsg
) - n
, ": %s",
215 bcopy(errmsg
, _ses_errmsg
, sizeof (_ses_errmsg
));
222 ses_error(ses_errno_t err
, const char *fmt
, ...)
228 rv
= ses_verror(err
, fmt
, ap
);
235 ses_nverror(int err
, const char *member
, const char *fmt
, ...)
241 rv
= ses_vnverror(err
, member
, fmt
, ap
);
248 ses_libscsi_error(libscsi_hdl_t
*shp
, const char *fmt
, ...)
251 char errmsg
[LIBSES_ERRMSGLEN
];
252 libscsi_errno_t se
= libscsi_errno(shp
);
264 case ESCSI_ZERO_LENGTH
:
267 case ESCSI_BOGUSFLAGS
:
268 case ESCSI_BADLENGTH
:
271 (void) vsnprintf(errmsg
, sizeof (errmsg
), fmt
, ap
);
273 ses_panic("%s: unexpected libscsi error %s: %s", errmsg
,
274 libscsi_errname(se
), libscsi_errmsg(shp
));
285 (void) vsnprintf(errmsg
, sizeof (errmsg
), fmt
, ap
);
288 return (ses_error(e
, "%s: %s", errmsg
, libscsi_errmsg(shp
)));
292 ses_scsi_error(libscsi_action_t
*ap
, const char *fmt
, ...)
295 char errmsg
[LIBSES_ERRMSGLEN
];
296 uint64_t asc
= 0, ascq
= 0, key
= 0;
297 const char *code
, *keystr
;
300 (void) vsnprintf(errmsg
, sizeof (errmsg
), fmt
, args
);
303 if (libscsi_action_parse_sense(ap
, &key
, &asc
, &ascq
, NULL
) != 0)
304 return (ses_error(ESES_LIBSCSI
,
305 "%s: SCSI status %d (no sense data available)", errmsg
,
306 libscsi_action_get_status(ap
)));
308 code
= libscsi_sense_code_name(asc
, ascq
);
309 keystr
= libscsi_sense_key_name(key
);
311 return (ses_error(ESES_LIBSCSI
, "%s: SCSI status %d sense key %llu "
312 "(%s) additional sense code 0x%llx/0x%llx (%s)", errmsg
,
313 libscsi_action_get_status(ap
), key
, keystr
? keystr
: "<unknown>",
314 asc
, ascq
, code
? code
: "<unknown>"));
323 ses_panic("attempted zero-length allocation");
325 if ((p
= malloc(sz
)) == NULL
)
326 (void) ses_set_errno(ESES_NOMEM
);
332 ses_zalloc(size_t sz
)
336 if ((p
= ses_alloc(sz
)) != NULL
)
343 ses_strdup(const char *s
)
349 ses_panic("attempted zero-length allocation");
353 if ((p
= ses_alloc(len
)) != NULL
)
360 ses_realloc(void *p
, size_t sz
)
363 ses_panic("attempted zero-length allocation");
365 if ((p
= realloc(p
, sz
)) == NULL
)
366 (void) ses_set_errno(ESES_NOMEM
);