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