/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <sys/isa_defs.h>
#include <sys/systeminfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <dlfcn.h>
#include <limits.h>
#include "libscsi_impl.h"
static const libscsi_engine_t *
{
const char *engine_path, *p, *q;
void *dl_hdl;
int dirs_tried = 0;
return (eip->lsei_engine);
}
#if defined(_LP64)
isa[0] = '\0';
#else
isa[0] = '\0';
#endif
for (p = engine_path; p != NULL; p = q) {
while (*q == ':')
++q;
if (*q == '\0')
q = NULL;
if (len == 0)
continue;
} else {
(void) strcpy(engine_dir, p);
}
if (engine_dir[0] != '/')
continue;
++dirs_tried;
if (!found_lib)
"unable to dlopen %s: %s", engine_lib,
dlerror());
continue;
}
if (!found_init)
"failed to find %s in %s: %s", init_name,
engine_lib, dlerror());
continue;
}
/*
* libscsi errno set by init.
*/
return (NULL);
}
"%s version %u does not match library version %u",
return (NULL);
}
return (NULL);
}
return (ep);
}
if (dirs_tried == 0)
"directories found in engine path %s", engine_path);
return (NULL);
}
static void
{
const char *strval;
int intval;
}
}
{
void *private;
}
return (NULL);
return (NULL);
return (NULL);
}
++hp->lsh_targets;
return (NULL);
}
return (tp);
}
{
}
const char *
{
const char *target_name;
return (target_name);
}
void
{
--hp->lsh_targets;
}
{
return (aip->lsai_status);
}
{
return (aip->lsai_reason);
}
/*
* Set the timeout in seconds for this action. If no timeout is specified
* or if the timeout is set to 0, an implementation-specific timeout will be
* used (which may vary based on the target, command or other variables).
* Not all engines support all timeout values. Setting the timeout to a value
* not supported by the engine will cause engine-defined behavior when the
* action is executed.
*/
void
{
}
/*
* Obtain the timeout setting for this action.
*/
{
return (aip->lsai_timeout);
}
/*
* Returns the flags associated with this action. Never fails.
*/
{
return (aip->lsai_flags);
}
/*
* Returns the address of the action's CDB. The CDB buffer is guaranteed to
* be large enough to hold the complete CDB for the command specified when the
* the CDB has undefined effects. The remainder of the CDB may be modified.
*/
uint8_t *
{
}
/*
* Places the address of the action buffer in the location pointed to by bp,
* if bp is not NULL. If ap is not NULL, it will contain the allocated size
* of the buffer itself. If vp is not NULL, it will contain the number of
* bytes of valid data currently stored in the buffer.
*
* If the action has LIBSCSI_AF_WRITE set and it has not yet been executed
* successfully, the entire buffer is assumed to contain valid data.
*
* If the action has LIBSCSI_AF_READ set and it has not yet been executed
* successfully, the amount of valid data is 0.
*
* If both LIBSCSI_AF_READ and LIBSCSI_AF_WRITE are clear, this function
* fails with ESCSI_BADFLAGS to indicate that the action flags are
* incompatible with the action data buffer.
*/
int
{
"data buffer not supported for actions with both "
"LIBSCSI_AF_READ and LIBSCSI_AF_WRITE clear"));
return (0);
}
return (0);
}
*vp = 0;
} else {
*vp = 0;
}
return (0);
}
/*
* Obtain a pointer to the sense buffer for this action, if any, along with
* the size of the sense buffer and the amount of valid data it contains.
*/
int
{
"sense data unavailable: LIBSCSI_AF_RQSENSE is clear"));
*vp = 0;
else
}
}
return (0);
}
/*
* Set the SCSI status of the action.
*
* Engines only.
*/
void
{
}
/*
* Set the reason of the action.
*
* Engines only.
*/
void
{
}
/*
* Set the length of valid data returned by a READ action. If the action is
* not a READ action, or the length exceeds the size of the buffer, an error
* results.
*
* Engines only.
*/
int
{
"data cannot be returned for actions with LIBSCSI_AF_READ "
"clear"));
"data length %lu exceeds allocated buffer capacity %lu",
return (0);
}
/*
* Set the length of the valid sense data returned following the command, if
* LIBSCSI_AF_RQSENSE is set for this action. Otherwise, fail.
*
* Engines only.
*/
int
{
"sense data not supported: LIBSCSI_AF_RQSENSE is clear"));
"sense length %lu exceeds allocated buffer capacity %lu",
return (0);
}
/*
* Allocate an action object. The object will contain a CDB area sufficiently
* large to hold a CDB for the given command, and the CDB's opcode will be
* filled in. A pointer to this CDB, the contents of which may be modified by
* the caller, may be obtained by a subsequent call to libscsi_action_cdb().
*
* If flags includes LIBSCSI_AF_READ or LIBSCSI_AF_WRITE, buflen must be
* greater than zero. Otherwise, buflen must be 0 and buf must be NULL.
* If buflen is nonzero but buf is NULL, a suitably-sized buffer will be
* allocated; otherwise, the specified buffer will be used. In either case,
* a pointer to the buffer may be obtained via a subsequent call to
* libscsi_action_buffer().
*
* If flags includes LIBSCSI_AF_RQSENSE, a REQUEST SENSE command will be
* issued immediately following the termination of the specified command.
* A buffer will be allocated to receive this sense data. Following successful
* execution of the action, a pointer to this buffer and the length of
* valid sense data may be obtained by a call to libscsi_action_sense().
* If cmd is SPC3_CMD_REQUEST_SENSE, this flag must be clear.
*/
{
/*
* If there's no buffer, it makes no sense to try to read or write
* data. Likewise, if we're neither reading nor writing data, we
* should not have a buffer. Both of these are programmer error.
*/
"required when reading or writing");
return (NULL);
}
"LIBSCSI_AF_READ and LIBSCSI_AF_WRITE must be specified "
"in order to use a buffer");
return (NULL);
}
"flag not allowed for request sense command");
return (NULL);
}
return (NULL);
/*
* If the caller has asked for a buffer but has not provided one, we
* will allocate it in our internal buffer along with the CDB and
* request sense space (if requested).
*/
if (flags & LIBSCSI_AF_RQSENSE)
return (NULL);
off = 0;
if (buflen > 0) {
} else {
}
if (flags & LIBSCSI_AF_WRITE)
}
if (flags & LIBSCSI_AF_RQSENSE) {
}
return ((libscsi_action_t *)aip);
}
void
{
}
/*
* For testing purposes, we allow data to be corrupted via an environment
* variable setting. This helps ensure that higher level software can cope with
* arbitrarily broken targets. The mtbf value represents the number of bytes we
* will see, on average, in between each failure. Therefore, for each N bytes,
* we would expect to see (N / mtbf) bytes of corruption.
*/
static void
{
double prob;
if (len == 0)
return;
while (prob > 1) {
prob -= 1;
}
}
}
int
{
int ret;
if (tp->lst_mtbf_write != 0 &&
tp->lst_mtbf_write);
}
if (tp->lst_mtbf_cdb != 0) {
tp->lst_mtbf_cdb);
}
tp->lst_mtbf_read);
}
return (ret);
}