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