xref: /illumos-gate/usr/src/lib/scsi/libscsi/common/scsi_engine.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/isa_defs.h>
31 #include <sys/systeminfo.h>
32 #include <sys/scsi/generic/commands.h>
33 #include <sys/scsi/impl/commands.h>
34 #include <sys/scsi/impl/uscsi.h>
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stddef.h>
39 #include <string.h>
40 #include <dlfcn.h>
41 #include <limits.h>
42 
43 #include <scsi/libscsi.h>
44 #include "libscsi_impl.h"
45 
46 static const libscsi_engine_t *
47 get_engine(libscsi_hdl_t *hp, const char *name)
48 {
49 	libscsi_engine_impl_t *eip;
50 	const libscsi_engine_t *ep;
51 	const char *engine_path, *p, *q;
52 	char engine_dir[MAXPATHLEN];
53 	char engine_lib[MAXPATHLEN];
54 	char init_name[MAXPATHLEN];
55 	void *dl_hdl;
56 	libscsi_engine_init_f init;
57 	boolean_t found_lib = B_FALSE, found_init = B_FALSE;
58 	int dirs_tried = 0;
59 	char isa[257];
60 
61 	for (eip = hp->lsh_engines; eip != NULL; eip = eip->lsei_next) {
62 		if (strcmp(eip->lsei_engine->lse_name, name) == 0)
63 			return (eip->lsei_engine);
64 	}
65 
66 	if ((engine_path = getenv("LIBSCSI_ENGINE_PATH")) == NULL)
67 		engine_path = LIBSCSI_DEFAULT_ENGINE_PATH;
68 
69 #if defined(_LP64)
70 	if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0)
71 		isa[0] = '\0';
72 #else
73 	isa[0] = '\0';
74 #endif
75 
76 	for (p = engine_path, q = strchr(p, ':'); p != NULL; p = q) {
77 		if (q != NULL) {
78 			ptrdiff_t len = q - p;
79 			(void) strncpy(engine_dir, p, len);
80 			engine_dir[len] = '\0';
81 			while (*q == ':')
82 				++q;
83 			if (*q == '\0')
84 				q = NULL;
85 			if (len == 0)
86 				continue;
87 		} else {
88 			(void) strcpy(engine_dir, p);
89 		}
90 		if (engine_dir[0] != '/')
91 			continue;
92 
93 		++dirs_tried;
94 
95 		(void) snprintf(engine_lib, MAXPATHLEN, "%s/%s/%s%s",
96 		    engine_dir, isa, name, LIBSCSI_ENGINE_EXT);
97 
98 		dl_hdl = dlopen(engine_lib,
99 		    RTLD_LOCAL | RTLD_LAZY | RTLD_PARENT);
100 		if (dl_hdl == NULL) {
101 			if (!found_lib)
102 				(void) libscsi_error(hp, ESCSI_NOENGINE,
103 				    "unable to dlopen %s: %s", engine_lib,
104 				    dlerror());
105 			continue;
106 		}
107 		found_lib = B_TRUE;
108 		(void) snprintf(init_name, MAXPATHLEN, "libscsi_%s_init", name);
109 		init = (libscsi_engine_init_f)dlsym(dl_hdl, init_name);
110 		if (init == NULL) {
111 			if (!found_init)
112 				(void) libscsi_error(hp, ESCSI_NOENGINE,
113 				    "failed to find %s in %s: %s", init_name,
114 				    engine_lib, dlerror());
115 			(void) dlclose(dl_hdl);
116 			continue;
117 		}
118 		if ((ep = init(hp)) == NULL) {
119 			(void) dlclose(dl_hdl);
120 			/*
121 			 * libscsi errno set by init.
122 			 */
123 			return (NULL);
124 		}
125 		if (ep->lse_libversion != hp->lsh_version) {
126 			(void) dlclose(dl_hdl);
127 			(void) libscsi_error(hp, ESCSI_ENGINE_VER, "engine "
128 			    "%s version %u does not match library version %u",
129 			    engine_lib, ep->lse_libversion, hp->lsh_version);
130 			return (NULL);
131 		}
132 
133 		eip = libscsi_zalloc(hp, sizeof (libscsi_engine_impl_t));
134 		if (eip == NULL) {
135 			(void) dlclose(dl_hdl);
136 			return (NULL);
137 		}
138 		eip->lsei_engine = ep;
139 		eip->lsei_dl_hdl = dl_hdl;
140 		eip->lsei_next = hp->lsh_engines;
141 		hp->lsh_engines = eip;
142 
143 		return (ep);
144 	}
145 
146 	if (dirs_tried == 0)
147 		(void) libscsi_error(hp, ESCSI_ENGINE_BADPATH, "no valid "
148 		    "directories found in engine path %s", engine_path);
149 
150 	return (NULL);
151 }
152 
153 static void
154 scsi_parse_mtbf(const char *envvar, uint_t *intp)
155 {
156 	const char *strval;
157 	int intval;
158 
159 	if ((strval = getenv(envvar)) != NULL &&
160 	    (intval = atoi(strval)) > 0) {
161 		srand48(gethrtime());
162 		*intp = intval;
163 	}
164 }
165 
166 libscsi_target_t *
167 libscsi_open(libscsi_hdl_t *hp, const char *engine, const void *target)
168 {
169 	const libscsi_engine_t *ep;
170 	libscsi_target_t *tp;
171 	void *private;
172 
173 	if (engine == NULL) {
174 		if ((engine = getenv("LIBSCSI_DEFAULT_ENGINE")) == NULL)
175 			engine = LIBSCSI_DEFAULT_ENGINE;
176 	}
177 
178 	if ((ep = get_engine(hp, engine)) == NULL)
179 		return (NULL);
180 
181 	if ((tp = libscsi_zalloc(hp, sizeof (libscsi_target_t))) == NULL)
182 		return (NULL);
183 
184 	if ((private = ep->lse_ops->lseo_open(hp, target)) == NULL) {
185 		libscsi_free(hp, tp);
186 		return (NULL);
187 	}
188 
189 	scsi_parse_mtbf("LIBSCSI_MTBF_CDB", &tp->lst_mtbf_cdb);
190 	scsi_parse_mtbf("LIBSCSI_MTBF_READ", &tp->lst_mtbf_read);
191 	scsi_parse_mtbf("LIBSCSI_MTBF_WRITE", &tp->lst_mtbf_write);
192 
193 	tp->lst_hdl = hp;
194 	tp->lst_engine = ep;
195 	tp->lst_priv = private;
196 
197 	++hp->lsh_targets;
198 
199 	if (libscsi_get_inquiry(hp, tp) != 0) {
200 		libscsi_close(hp, tp);
201 		return (NULL);
202 	}
203 
204 	return (tp);
205 }
206 
207 libscsi_hdl_t *
208 libscsi_get_handle(libscsi_target_t *tp)
209 {
210 	return (tp->lst_hdl);
211 }
212 
213 void
214 libscsi_close(libscsi_hdl_t *hp, libscsi_target_t *tp)
215 {
216 	tp->lst_engine->lse_ops->lseo_close(hp, tp->lst_priv);
217 	libscsi_free(hp, tp->lst_vendor);
218 	libscsi_free(hp, tp->lst_product);
219 	libscsi_free(hp, tp->lst_revision);
220 	libscsi_free(hp, tp);
221 	--hp->lsh_targets;
222 }
223 
224 sam4_status_t
225 libscsi_action_get_status(const libscsi_action_t *ap)
226 {
227 	const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
228 
229 	return (aip->lsai_status);
230 }
231 
232 /*
233  * Set the timeout in seconds for this action.  If no timeout is specified
234  * or if the timeout is set to 0, an implementation-specific timeout will be
235  * used (which may vary based on the target, command or other variables).
236  * Not all engines support all timeout values.  Setting the timeout to a value
237  * not supported by the engine will cause engine-defined behavior when the
238  * action is executed.
239  */
240 void
241 libscsi_action_set_timeout(libscsi_action_t *ap, uint32_t timeout)
242 {
243 	libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
244 
245 	aip->lsai_timeout = timeout;
246 }
247 
248 /*
249  * Obtain the timeout setting for this action.
250  */
251 uint32_t
252 libscsi_action_get_timeout(const libscsi_action_t *ap)
253 {
254 	const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
255 
256 	return (aip->lsai_timeout);
257 }
258 
259 /*
260  * Returns the flags associated with this action.  Never fails.
261  */
262 uint_t
263 libscsi_action_get_flags(const libscsi_action_t *ap)
264 {
265 	const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
266 
267 	return (aip->lsai_flags);
268 }
269 
270 /*
271  * Returns the address of the action's CDB.  The CDB buffer is guaranteed to
272  * be large enough to hold the complete CDB for the command specified when the
273  * action was allocated.  Therefore, changing the command/opcode portion of
274  * the CDB has undefined effects.  The remainder of the CDB may be modified.
275  */
276 uint8_t *
277 libscsi_action_get_cdb(const libscsi_action_t *ap)
278 {
279 	const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
280 
281 	return (aip->lsai_cdb);
282 }
283 
284 /*
285  * Places the address of the action buffer in the location pointed to by bp,
286  * if bp is not NULL.  If ap is not NULL, it will contain the allocated size
287  * of the buffer itself.  If vp is not NULL, it will contain the number of
288  * bytes of valid data currently stored in the buffer.
289  *
290  * If the action has LIBSCSI_AF_WRITE set and it has not yet been executed
291  * successfully, the entire buffer is assumed to contain valid data.
292  *
293  * If the action has LIBSCSI_AF_READ set and it has not yet been executed
294  * successfully, the amount of valid data is 0.
295  *
296  * If both LIBSCSI_AF_READ and LIBSCSI_AF_WRITE are clear, this function
297  * fails with ESCSI_BADFLAGS to indicate that the action flags are
298  * incompatible with the action data buffer.
299  */
300 int
301 libscsi_action_get_buffer(const libscsi_action_t *ap, uint8_t **bp,
302     size_t *sp, size_t *vp)
303 {
304 	const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
305 
306 	if ((aip->lsai_flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE)) == 0)
307 		return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS,
308 		    "data buffer not supported for actions with both "
309 		    "LIBSCSI_AF_READ and LIBSCSI_AF_WRITE clear"));
310 
311 	if ((aip->lsai_flags & LIBSCSI_AF_WRITE) &&
312 	    aip->lsai_status == LIBSCSI_STATUS_INVALID) {
313 		if (bp != NULL)
314 			*bp = aip->lsai_data;
315 		if (sp != NULL)
316 			*sp = aip->lsai_data_alloc;
317 		if (vp != NULL)
318 			*vp = aip->lsai_data_alloc;
319 
320 		return (0);
321 	}
322 
323 	if ((aip->lsai_flags & LIBSCSI_AF_READ) &&
324 	    aip->lsai_status != LIBSCSI_STATUS_INVALID) {
325 		if (bp != NULL)
326 			*bp = aip->lsai_data;
327 		if (sp != NULL)
328 			*sp = aip->lsai_data_alloc;
329 		if (vp != NULL)
330 			*vp = aip->lsai_data_len;
331 
332 		return (0);
333 	}
334 
335 	if (aip->lsai_flags & LIBSCSI_AF_WRITE) {
336 		if (bp != NULL)
337 			*bp = NULL;
338 		if (sp != NULL)
339 			*sp = NULL;
340 		if (vp != NULL)
341 			*vp = 0;
342 	} else {
343 		if (bp != NULL)
344 			*bp = aip->lsai_data;
345 		if (sp != NULL)
346 			*sp = aip->lsai_data_alloc;
347 		if (vp != NULL)
348 			*vp = 0;
349 	}
350 
351 	return (0);
352 }
353 
354 /*
355  * Obtain a pointer to the sense buffer for this action, if any, along with
356  * the size of the sense buffer and the amount of valid data it contains.
357  */
358 int
359 libscsi_action_get_sense(const libscsi_action_t *ap, uint8_t **bp,
360     size_t *sp, size_t *vp)
361 {
362 	const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
363 
364 	if (!(aip->lsai_flags & LIBSCSI_AF_RQSENSE))
365 		return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS,
366 		    "sense data unavailable: LIBSCSI_AF_RQSENSE is clear"));
367 
368 	if (vp != NULL) {
369 		if (aip->lsai_status == LIBSCSI_STATUS_INVALID)
370 			*vp = 0;
371 		else
372 			*vp = aip->lsai_sense_len;
373 	}
374 
375 	if (bp != NULL) {
376 		ASSERT(aip->lsai_sense_data != NULL);
377 		*bp = aip->lsai_sense_data;
378 	}
379 
380 	if (sp != NULL)
381 		*sp = UINT8_MAX;
382 
383 	return (0);
384 }
385 
386 /*
387  * Set the SCSI status of the action.
388  *
389  * Engines only.
390  */
391 void
392 libscsi_action_set_status(libscsi_action_t *ap, sam4_status_t status)
393 {
394 	libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
395 
396 	ASSERT(aip->lsai_status == LIBSCSI_STATUS_INVALID);
397 
398 	aip->lsai_status = status;
399 }
400 
401 /*
402  * Set the length of valid data returned by a READ action.  If the action is
403  * not a READ action, or the length exceeds the size of the buffer, an error
404  * results.
405  *
406  * Engines only.
407  */
408 int
409 libscsi_action_set_datalen(libscsi_action_t *ap, size_t len)
410 {
411 	libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
412 
413 	if ((aip->lsai_flags & LIBSCSI_AF_READ) == 0)
414 		return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS,
415 		    "data cannot be returned for actions with LIBSCSI_AF_READ "
416 		    "clear"));
417 	if (len > aip->lsai_data_alloc)
418 		return (libscsi_error(aip->lsai_hdl, ESCSI_BADLENGTH,
419 		    "data length %lu exceeds allocated buffer capacity %lu",
420 		    (ulong_t)len, (ulong_t)aip->lsai_data_alloc));
421 
422 	ASSERT(aip->lsai_data_len == 0);
423 	aip->lsai_data_len = len;
424 
425 	return (0);
426 }
427 
428 /*
429  * Set the length of the valid sense data returned following the command, if
430  * LIBSCSI_AF_RQSENSE is set for this action.  Otherwise, fail.
431  *
432  * Engines only.
433  */
434 int
435 libscsi_action_set_senselen(libscsi_action_t *ap, size_t len)
436 {
437 	libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
438 
439 	if (!(aip->lsai_flags & LIBSCSI_AF_RQSENSE))
440 		return (libscsi_error(aip->lsai_hdl, ESCSI_BADFLAGS,
441 		    "sense data not supported: LIBSCSI_AF_RQSENSE is clear"));
442 
443 	if (len > UINT8_MAX)
444 		return (libscsi_error(aip->lsai_hdl, ESCSI_BADLENGTH,
445 		    "sense length %lu exceeds allocated buffer capacity %lu",
446 		    (ulong_t)len, (ulong_t)UINT8_MAX));
447 
448 	ASSERT(aip->lsai_sense_len == 0);
449 	aip->lsai_sense_len = len;
450 
451 	return (0);
452 }
453 
454 /*
455  * Allocate an action object.  The object will contain a CDB area sufficiently
456  * large to hold a CDB for the given command, and the CDB's opcode will be
457  * filled in.  A pointer to this CDB, the contents of which may be modified by
458  * the caller, may be obtained by a subsequent call to libscsi_action_cdb().
459  *
460  * If flags includes LIBSCSI_AF_READ or LIBSCSI_AF_WRITE, buflen must be
461  * greater than zero.  Otherwise, buflen must be 0 and buf must be NULL.
462  * If buflen is nonzero but buf is NULL, a suitably-sized buffer will be
463  * allocated; otherwise, the specified buffer will be used.  In either case,
464  * a pointer to the buffer may be obtained via a subsequent call to
465  * libscsi_action_buffer().
466  *
467  * If flags includes LIBSCSI_AF_RQSENSE, a REQUEST SENSE command will be
468  * issued immediately following the termination of the specified command.
469  * A buffer will be allocated to receive this sense data.  Following successful
470  * execution of the action, a pointer to this buffer and the length of
471  * valid sense data may be obtained by a call to libscsi_action_sense().
472  * If cmd is SPC3_CMD_REQUEST_SENSE, this flag must be clear.
473  */
474 libscsi_action_t *
475 libscsi_action_alloc(libscsi_hdl_t *hp, spc3_cmd_t cmd, uint_t flags,
476     void *buf, size_t buflen)
477 {
478 	libscsi_action_impl_t *aip;
479 	size_t cdbsz, sz;
480 	ptrdiff_t off;
481 
482 	/*
483 	 * If there's no buffer, it makes no sense to try to read or write
484 	 * data.  Likewise, if we're neither reading nor writing data, we
485 	 * should not have a buffer.  Both of these are programmer error.
486 	 */
487 	if (buflen == 0 && (flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE))) {
488 		(void) libscsi_error(hp, ESCSI_NEEDBUF, "a buffer is "
489 		    "required when reading or writing");
490 		return (NULL);
491 	}
492 	if (buflen > 0 && !(flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE))) {
493 		(void) libscsi_error(hp, ESCSI_BADFLAGS, "one of "
494 		    "LIBSCSI_AF_READ and LIBSCSI_AF_WRITE must be specified "
495 		    "in order to use a buffer");
496 		return (NULL);
497 	}
498 	if (cmd == SPC3_CMD_REQUEST_SENSE && (flags & LIBSCSI_AF_RQSENSE)) {
499 		(void) libscsi_error(hp, ESCSI_BADFLAGS, "request sense "
500 		    "flag not allowed for request sense command");
501 		return (NULL);
502 	}
503 
504 	if ((sz = cdbsz = libscsi_cmd_cdblen(hp, cmd)) == 0)
505 		return (NULL);
506 
507 	/*
508 	 * If the caller has asked for a buffer but has not provided one, we
509 	 * will allocate it in our internal buffer along with the CDB and
510 	 * request sense space (if requested).
511 	 */
512 	if (buf == NULL)
513 		sz += buflen;
514 
515 	if (flags & LIBSCSI_AF_RQSENSE)
516 		sz += UINT8_MAX;
517 
518 	sz += offsetof(libscsi_action_impl_t, lsai_buf[0]);
519 
520 	if ((aip = libscsi_zalloc(hp, sz)) == NULL)
521 		return (NULL);
522 
523 	aip->lsai_hdl = hp;
524 	aip->lsai_flags = flags;
525 
526 	off = 0;
527 
528 	aip->lsai_cdb = aip->lsai_buf + off;
529 	aip->lsai_cdb_len = cdbsz;
530 	off += cdbsz;
531 	aip->lsai_cdb[0] = (uint8_t)cmd;
532 
533 	if (buflen > 0) {
534 		if (buf != NULL) {
535 			aip->lsai_data = buf;
536 		} else {
537 			aip->lsai_data = aip->lsai_buf + off;
538 			off += buflen;
539 		}
540 		aip->lsai_data_alloc = buflen;
541 		if (flags & LIBSCSI_AF_WRITE)
542 			aip->lsai_data_len = buflen;
543 	}
544 
545 	if (flags & LIBSCSI_AF_RQSENSE) {
546 		aip->lsai_sense_data = aip->lsai_buf + off;
547 		off += UINT8_MAX;
548 	}
549 
550 	aip->lsai_status = LIBSCSI_STATUS_INVALID;
551 
552 	return ((libscsi_action_t *)aip);
553 }
554 
555 void
556 libscsi_action_free(libscsi_action_t *ap)
557 {
558 	libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
559 
560 	libscsi_free(aip->lsai_hdl, aip);
561 }
562 
563 /*
564  * For testing purposes, we allow data to be corrupted via an environment
565  * variable setting.  This helps ensure that higher level software can cope with
566  * arbitrarily broken targets.  The mtbf value represents the number of bytes we
567  * will see, on average, in between each failure.  Therefore, for each N bytes,
568  * we would expect to see (N / mtbf) bytes of corruption.
569  */
570 static void
571 scsi_inject_errors(void *data, size_t len, uint_t mtbf)
572 {
573 	char *buf = data;
574 	double prob;
575 	size_t index;
576 
577 	if (len == 0)
578 		return;
579 
580 	prob = (double)len / mtbf;
581 
582 	while (prob > 1) {
583 		index = lrand48() % len;
584 		buf[index] = (lrand48() % 256);
585 		prob -= 1;
586 	}
587 
588 	if (drand48() <= prob) {
589 		index = lrand48() % len;
590 		buf[index] = (lrand48() % 256);
591 	}
592 }
593 
594 int
595 libscsi_exec(libscsi_action_t *ap, libscsi_target_t *tp)
596 {
597 	libscsi_action_impl_t *aip = (libscsi_action_impl_t *)ap;
598 	libscsi_hdl_t *hp = aip->lsai_hdl;
599 	int ret;
600 
601 	if (tp->lst_mtbf_write != 0 &&
602 	    (aip->lsai_flags & LIBSCSI_AF_WRITE)) {
603 		scsi_inject_errors(aip->lsai_data, aip->lsai_data_len,
604 		    tp->lst_mtbf_write);
605 	}
606 
607 	if (tp->lst_mtbf_cdb != 0) {
608 		scsi_inject_errors(aip->lsai_cdb, aip->lsai_cdb_len,
609 		    tp->lst_mtbf_cdb);
610 	}
611 
612 	ret = tp->lst_engine->lse_ops->lseo_exec(hp, tp->lst_priv, ap);
613 
614 	if (ret == 0 && tp->lst_mtbf_read != 0 &&
615 	    (aip->lsai_flags & LIBSCSI_AF_READ)) {
616 		scsi_inject_errors(aip->lsai_data, aip->lsai_data_len,
617 		    tp->lst_mtbf_read);
618 	}
619 
620 	return (ret);
621 }
622