move 32-bit libs to lib/i386 subdirs & 64-bit libs to lib/
[unleashed.git] / usr / src / lib / scsi / libscsi / common / scsi_engine.c
blobd82c498f71382af3281740c1f4926995209cd122
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2017, Joyent, Inc.
27 #include <sys/types.h>
28 #include <sys/isa_defs.h>
29 #include <sys/systeminfo.h>
30 #include <sys/scsi/generic/commands.h>
31 #include <sys/scsi/impl/commands.h>
32 #include <sys/scsi/impl/uscsi.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <stddef.h>
37 #include <string.h>
38 #include <dlfcn.h>
39 #include <limits.h>
41 #include <scsi/libscsi.h>
42 #include "libscsi_impl.h"
44 static const libscsi_engine_t *
45 get_engine(libscsi_hdl_t *hp, const char *name)
47 libscsi_engine_impl_t *eip;
48 const libscsi_engine_t *ep;
49 const char *engine_path, *p, *q;
50 char engine_dir[MAXPATHLEN];
51 char engine_lib[MAXPATHLEN];
52 char init_name[MAXPATHLEN];
53 void *dl_hdl;
54 libscsi_engine_init_f init;
55 boolean_t found_lib = B_FALSE, found_init = B_FALSE;
56 int dirs_tried = 0;
57 char isa[257];
59 for (eip = hp->lsh_engines; eip != NULL; eip = eip->lsei_next) {
60 if (strcmp(eip->lsei_engine->lse_name, name) == 0)
61 return (eip->lsei_engine);
64 if ((engine_path = getenv("LIBSCSI_ENGINE_PATH")) == NULL)
65 engine_path = LIBSCSI_DEFAULT_ENGINE_PATH;
67 #if defined(_LP64)
68 isa[0] = '\0';
69 #else
70 strcpy(isa, "i386");
71 #endif
73 for (p = engine_path; p != NULL; p = q) {
74 if ((q = strchr(p, ':')) != NULL) {
75 ptrdiff_t len = q - p;
76 (void) strncpy(engine_dir, p, len);
77 engine_dir[len] = '\0';
78 while (*q == ':')
79 ++q;
80 if (*q == '\0')
81 q = NULL;
82 if (len == 0)
83 continue;
84 } else {
85 (void) strcpy(engine_dir, p);
87 if (engine_dir[0] != '/')
88 continue;
90 ++dirs_tried;
92 (void) snprintf(engine_lib, MAXPATHLEN, "%s/%s/%s%s",
93 engine_dir, isa, name, LIBSCSI_ENGINE_EXT);
95 dl_hdl = dlopen(engine_lib,
96 RTLD_LOCAL | RTLD_LAZY | RTLD_PARENT);
97 if (dl_hdl == NULL) {
98 if (!found_lib)
99 (void) libscsi_error(hp, ESCSI_NOENGINE,
100 "unable to dlopen %s: %s", engine_lib,
101 dlerror());
102 continue;
104 found_lib = B_TRUE;
105 (void) snprintf(init_name, MAXPATHLEN, "libscsi_%s_init", name);
106 init = (libscsi_engine_init_f)dlsym(dl_hdl, init_name);
107 if (init == NULL) {
108 if (!found_init)
109 (void) libscsi_error(hp, ESCSI_NOENGINE,
110 "failed to find %s in %s: %s", init_name,
111 engine_lib, dlerror());
112 (void) dlclose(dl_hdl);
113 continue;
115 if ((ep = init(hp)) == NULL) {
116 (void) dlclose(dl_hdl);
118 * libscsi errno set by init.
120 return (NULL);
122 if (ep->lse_libversion != hp->lsh_version) {
123 (void) dlclose(dl_hdl);
124 (void) libscsi_error(hp, ESCSI_ENGINE_VER, "engine "
125 "%s version %u does not match library version %u",
126 engine_lib, ep->lse_libversion, hp->lsh_version);
127 return (NULL);
130 eip = libscsi_zalloc(hp, sizeof (libscsi_engine_impl_t));
131 if (eip == NULL) {
132 (void) dlclose(dl_hdl);
133 return (NULL);
135 eip->lsei_engine = ep;
136 eip->lsei_dl_hdl = dl_hdl;
137 eip->lsei_next = hp->lsh_engines;
138 hp->lsh_engines = eip;
140 return (ep);
143 if (dirs_tried == 0)
144 (void) libscsi_error(hp, ESCSI_ENGINE_BADPATH, "no valid "
145 "directories found in engine path %s", engine_path);
147 return (NULL);
150 static void
151 scsi_parse_mtbf(const char *envvar, uint_t *intp)
153 const char *strval;
154 int intval;
156 if ((strval = getenv(envvar)) != NULL &&
157 (intval = atoi(strval)) > 0) {
158 srand48(gethrtime());
159 *intp = intval;
163 libscsi_target_t *
164 libscsi_open(libscsi_hdl_t *hp, const char *engine, const void *target)
166 const libscsi_engine_t *ep;
167 libscsi_target_t *tp;
168 void *private;
170 if (engine == NULL) {
171 if ((engine = getenv("LIBSCSI_DEFAULT_ENGINE")) == NULL)
172 engine = LIBSCSI_DEFAULT_ENGINE;
175 if ((ep = get_engine(hp, engine)) == NULL)
176 return (NULL);
178 if ((tp = libscsi_zalloc(hp, sizeof (libscsi_target_t))) == NULL)
179 return (NULL);
181 if ((private = ep->lse_ops->lseo_open(hp, target)) == NULL) {
182 libscsi_free(hp, tp);
183 return (NULL);
186 scsi_parse_mtbf("LIBSCSI_MTBF_CDB", &tp->lst_mtbf_cdb);
187 scsi_parse_mtbf("LIBSCSI_MTBF_READ", &tp->lst_mtbf_read);
188 scsi_parse_mtbf("LIBSCSI_MTBF_WRITE", &tp->lst_mtbf_write);
190 tp->lst_hdl = hp;
191 tp->lst_engine = ep;
192 tp->lst_priv = private;
194 ++hp->lsh_targets;
196 if (libscsi_get_inquiry(hp, tp) != 0) {
197 libscsi_close(hp, tp);
198 return (NULL);
201 return (tp);
204 libscsi_hdl_t *
205 libscsi_get_handle(libscsi_target_t *tp)
207 return (tp->lst_hdl);
210 void
211 libscsi_close(libscsi_hdl_t *hp, libscsi_target_t *tp)
213 tp->lst_engine->lse_ops->lseo_close(hp, tp->lst_priv);
214 libscsi_free(hp, tp->lst_vendor);
215 libscsi_free(hp, tp->lst_product);
216 libscsi_free(hp, tp->lst_revision);
217 libscsi_free(hp, tp);
218 --hp->lsh_targets;
221 sam4_status_t
222 libscsi_action_get_status(const libscsi_action_t *ap)
224 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
226 return (aip->lsai_status);
230 * Set the timeout in seconds for this action. If no timeout is specified
231 * or if the timeout is set to 0, an implementation-specific timeout will be
232 * used (which may vary based on the target, command or other variables).
233 * Not all engines support all timeout values. Setting the timeout to a value
234 * not supported by the engine will cause engine-defined behavior when the
235 * action is executed.
237 void
238 libscsi_action_set_timeout(libscsi_action_t *ap, uint32_t timeout)
240 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
242 aip->lsai_timeout = timeout;
246 * Obtain the timeout setting for this action.
248 uint32_t
249 libscsi_action_get_timeout(const libscsi_action_t *ap)
251 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
253 return (aip->lsai_timeout);
257 * Returns the flags associated with this action. Never fails.
259 uint_t
260 libscsi_action_get_flags(const libscsi_action_t *ap)
262 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
264 return (aip->lsai_flags);
268 * Return the length of the CDB buffer associated with this action. Never
269 * fails.
271 size_t
272 libscsi_action_get_cdblen(const libscsi_action_t *ap)
274 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
276 return (aip->lsai_cdb_len);
280 * Returns the address of the action's CDB. The CDB buffer is guaranteed to
281 * be large enough to hold the complete CDB for the command specified when the
282 * action was allocated. Therefore, changing the command/opcode portion of
283 * the CDB has undefined effects. The remainder of the CDB may be modified.
285 uint8_t *
286 libscsi_action_get_cdb(const libscsi_action_t *ap)
288 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
290 return (aip->lsai_cdb);
294 * Places the address of the action buffer in the location pointed to by bp,
295 * if bp is not NULL. If ap is not NULL, it will contain the allocated size
296 * of the buffer itself. If vp is not NULL, it will contain the number of
297 * bytes of valid data currently stored in the buffer.
299 * If the action has LIBSCSI_AF_WRITE set and it has not yet been executed
300 * successfully, the entire buffer is assumed to contain valid data.
302 * If the action has LIBSCSI_AF_READ set and it has not yet been executed
303 * successfully, the amount of valid data is 0.
305 * If both LIBSCSI_AF_READ and LIBSCSI_AF_WRITE are clear, this function
306 * fails with ESCSI_BADFLAGS to indicate that the action flags are
307 * incompatible with the action data buffer.
310 libscsi_action_get_buffer(const libscsi_action_t *ap, uint8_t **bp,
311 size_t *sp, size_t *vp)
313 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
315 if ((aip->lsai_flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE)) == 0)
316 return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS,
317 "data buffer not supported for actions with both "
318 "LIBSCSI_AF_READ and LIBSCSI_AF_WRITE clear"));
320 if ((aip->lsai_flags & LIBSCSI_AF_WRITE) &&
321 aip->lsai_status == LIBSCSI_STATUS_INVALID) {
322 if (bp != NULL)
323 *bp = aip->lsai_data;
324 if (sp != NULL)
325 *sp = aip->lsai_data_alloc;
326 if (vp != NULL)
327 *vp = aip->lsai_data_alloc;
329 return (0);
332 if ((aip->lsai_flags & LIBSCSI_AF_READ) &&
333 aip->lsai_status != LIBSCSI_STATUS_INVALID) {
334 if (bp != NULL)
335 *bp = aip->lsai_data;
336 if (sp != NULL)
337 *sp = aip->lsai_data_alloc;
338 if (vp != NULL)
339 *vp = aip->lsai_data_len;
341 return (0);
344 if (aip->lsai_flags & LIBSCSI_AF_WRITE) {
345 if (bp != NULL)
346 *bp = NULL;
347 if (sp != NULL)
348 *sp = 0;
349 if (vp != NULL)
350 *vp = 0;
351 } else {
352 if (bp != NULL)
353 *bp = aip->lsai_data;
354 if (sp != NULL)
355 *sp = aip->lsai_data_alloc;
356 if (vp != NULL)
357 *vp = 0;
360 return (0);
364 * Obtain a pointer to the sense buffer for this action, if any, along with
365 * the size of the sense buffer and the amount of valid data it contains.
368 libscsi_action_get_sense(const libscsi_action_t *ap, uint8_t **bp,
369 size_t *sp, size_t *vp)
371 const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
373 if (!(aip->lsai_flags & LIBSCSI_AF_RQSENSE))
374 return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS,
375 "sense data unavailable: LIBSCSI_AF_RQSENSE is clear"));
377 if (vp != NULL) {
378 if (aip->lsai_status == LIBSCSI_STATUS_INVALID)
379 *vp = 0;
380 else
381 *vp = aip->lsai_sense_len;
384 if (bp != NULL) {
385 ASSERT(aip->lsai_sense_data != NULL);
386 *bp = aip->lsai_sense_data;
389 if (sp != NULL)
390 *sp = UINT8_MAX;
392 return (0);
396 * Set the SCSI status of the action.
398 * Engines only.
400 void
401 libscsi_action_set_status(libscsi_action_t *ap, sam4_status_t status)
403 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
405 ASSERT(aip->lsai_status == LIBSCSI_STATUS_INVALID);
407 aip->lsai_status = status;
411 * Set the length of valid data returned by a READ action. If the action is
412 * not a READ action, or the length exceeds the size of the buffer, an error
413 * results.
415 * Engines only.
418 libscsi_action_set_datalen(libscsi_action_t *ap, size_t len)
420 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
422 if ((aip->lsai_flags & LIBSCSI_AF_READ) == 0)
423 return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS,
424 "data cannot be returned for actions with LIBSCSI_AF_READ "
425 "clear"));
426 if (len > aip->lsai_data_alloc)
427 return (libscsi_error(aip->lsai_hdl, ESCSI_BADLENGTH,
428 "data length %lu exceeds allocated buffer capacity %lu",
429 (ulong_t)len, (ulong_t)aip->lsai_data_alloc));
431 ASSERT(aip->lsai_data_len == 0);
432 aip->lsai_data_len = len;
434 return (0);
438 * Set the length of the valid sense data returned following the command, if
439 * LIBSCSI_AF_RQSENSE is set for this action. Otherwise, fail.
441 * Engines only.
444 libscsi_action_set_senselen(libscsi_action_t *ap, size_t len)
446 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
448 if (!(aip->lsai_flags & LIBSCSI_AF_RQSENSE))
449 return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS,
450 "sense data not supported: LIBSCSI_AF_RQSENSE is clear"));
452 if (len > UINT8_MAX)
453 return (libscsi_error(aip->lsai_hdl, ESCSI_BADLENGTH,
454 "sense length %lu exceeds allocated buffer capacity %lu",
455 (ulong_t)len, (ulong_t)UINT8_MAX));
457 ASSERT(aip->lsai_sense_len == 0);
458 aip->lsai_sense_len = len;
460 return (0);
464 * Allocate an action object. The object will contain a CDB area sufficiently
465 * large to hold a CDB for the given command, and the CDB's opcode will be
466 * filled in. A pointer to this CDB, the contents of which may be modified by
467 * the caller, may be obtained by a subsequent call to libscsi_action_cdb().
469 * If flags includes LIBSCSI_AF_READ or LIBSCSI_AF_WRITE, buflen must be
470 * greater than zero. Otherwise, buflen must be 0 and buf must be NULL.
471 * If buflen is nonzero but buf is NULL, a suitably-sized buffer will be
472 * allocated; otherwise, the specified buffer will be used. In either case,
473 * a pointer to the buffer may be obtained via a subsequent call to
474 * libscsi_action_buffer().
476 * If flags includes LIBSCSI_AF_RQSENSE, a REQUEST SENSE command will be
477 * issued immediately following the termination of the specified command.
478 * A buffer will be allocated to receive this sense data. Following successful
479 * execution of the action, a pointer to this buffer and the length of
480 * valid sense data may be obtained by a call to libscsi_action_sense().
481 * If cmd is SPC3_CMD_REQUEST_SENSE, this flag must be clear.
483 libscsi_action_t *
484 libscsi_action_alloc_vendor(libscsi_hdl_t *hp, spc3_cmd_t cmd, size_t cdbsz,
485 uint_t flags, void *buf, size_t buflen)
487 libscsi_action_impl_t *aip;
488 size_t sz;
489 ptrdiff_t off;
492 * If there's no buffer, it makes no sense to try to read or write
493 * data. Likewise, if we're neither reading nor writing data, we
494 * should not have a buffer. Both of these are programmer error.
496 if (buflen == 0 && (flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE))) {
497 (void) libscsi_error(hp, ESCSI_NEEDBUF, "a buffer is "
498 "required when reading or writing");
499 return (NULL);
501 if (buflen > 0 && !(flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE))) {
502 (void) libscsi_error(hp, ESCSI_BADFLAGS, "one of "
503 "LIBSCSI_AF_READ and LIBSCSI_AF_WRITE must be specified "
504 "in order to use a buffer");
505 return (NULL);
508 if (cdbsz == 0) {
509 (void) libscsi_error(hp, ESCSI_BADLENGTH, "the supplied CDB "
510 "buffer size has an invalid length, it must be non-zero.");
511 return (NULL);
514 sz = cdbsz;
517 * If the caller has asked for a buffer but has not provided one, we
518 * will allocate it in our internal buffer along with the CDB and
519 * request sense space (if requested).
521 if (buf == NULL)
522 sz += buflen;
524 if (flags & LIBSCSI_AF_RQSENSE)
525 sz += UINT8_MAX;
527 sz += offsetof(libscsi_action_impl_t, lsai_buf[0]);
529 if ((aip = libscsi_zalloc(hp, sz)) == NULL)
530 return (NULL);
532 aip->lsai_hdl = hp;
533 aip->lsai_flags = flags;
535 off = 0;
537 aip->lsai_cdb = aip->lsai_buf + off;
538 aip->lsai_cdb_len = cdbsz;
539 off += cdbsz;
540 aip->lsai_cdb[0] = (uint8_t)cmd;
542 if (buflen > 0) {
543 if (buf != NULL) {
544 aip->lsai_data = buf;
545 } else {
546 aip->lsai_data = aip->lsai_buf + off;
547 off += buflen;
549 aip->lsai_data_alloc = buflen;
550 if (flags & LIBSCSI_AF_WRITE)
551 aip->lsai_data_len = buflen;
554 if (flags & LIBSCSI_AF_RQSENSE) {
555 aip->lsai_sense_data = aip->lsai_buf + off;
556 off += UINT8_MAX;
559 aip->lsai_status = LIBSCSI_STATUS_INVALID;
561 return ((libscsi_action_t *)aip);
564 libscsi_action_t *
565 libscsi_action_alloc(libscsi_hdl_t *hp, spc3_cmd_t cmd, uint_t flags,
566 void *buf, size_t buflen)
568 size_t cdbsz;
570 if (cmd == SPC3_CMD_REQUEST_SENSE && (flags & LIBSCSI_AF_RQSENSE)) {
571 (void) libscsi_error(hp, ESCSI_BADFLAGS, "request sense "
572 "flag not allowed for request sense command");
573 return (NULL);
576 if ((cdbsz = libscsi_cmd_cdblen(hp, cmd)) == 0)
577 return (NULL);
579 return (libscsi_action_alloc_vendor(hp, cmd, cdbsz, flags, buf,
580 buflen));
583 void
584 libscsi_action_free(libscsi_action_t *ap)
586 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
588 libscsi_free(aip->lsai_hdl, aip);
592 * For testing purposes, we allow data to be corrupted via an environment
593 * variable setting. This helps ensure that higher level software can cope with
594 * arbitrarily broken targets. The mtbf value represents the number of bytes we
595 * will see, on average, in between each failure. Therefore, for each N bytes,
596 * we would expect to see (N / mtbf) bytes of corruption.
598 static void
599 scsi_inject_errors(void *data, size_t len, uint_t mtbf)
601 char *buf = data;
602 double prob;
603 size_t index;
605 if (len == 0)
606 return;
608 prob = (double)len / mtbf;
610 while (prob > 1) {
611 index = lrand48() % len;
612 buf[index] = (lrand48() % 256);
613 prob -= 1;
616 if (drand48() <= prob) {
617 index = lrand48() % len;
618 buf[index] = (lrand48() % 256);
623 libscsi_exec(libscsi_action_t *ap, libscsi_target_t *tp)
625 libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
626 libscsi_hdl_t *hp = aip->lsai_hdl;
627 int ret;
629 if (tp->lst_mtbf_write != 0 &&
630 (aip->lsai_flags & LIBSCSI_AF_WRITE)) {
631 scsi_inject_errors(aip->lsai_data, aip->lsai_data_len,
632 tp->lst_mtbf_write);
635 if (tp->lst_mtbf_cdb != 0) {
636 scsi_inject_errors(aip->lsai_cdb, aip->lsai_cdb_len,
637 tp->lst_mtbf_cdb);
640 ret = tp->lst_engine->lse_ops->lseo_exec(hp, tp->lst_priv, ap);
642 if (ret == 0 && tp->lst_mtbf_read != 0 &&
643 (aip->lsai_flags & LIBSCSI_AF_READ)) {
644 scsi_inject_errors(aip->lsai_data, aip->lsai_data_len,
645 tp->lst_mtbf_read);
648 return (ret);