275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock/*
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * CDDL HEADER START
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * The contents of this file are subject to the terms of the
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * Common Development and Distribution License (the "License").
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * You may not use this file except in compliance with the License.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * or http://www.opensolaris.org/os/licensing.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * See the License for the specific language governing permissions
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * and limitations under the License.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * When distributing Covered Code, include this CDDL HEADER in each
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * If applicable, add the following below this CDDL HEADER, with the
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * fields enclosed by brackets "[]" replaced with your own identifying
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * information: Portions Copyright [yyyy] [name of copyright owner]
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * CDDL HEADER END
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock/*
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * Use is subject to license terms.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#pragma ident "%Z%%M% %I% %E% SMI"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <sys/types.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <sys/scsi/impl/uscsi.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <sys/scsi/generic/commands.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <unistd.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <fcntl.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <errno.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <string.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <strings.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <stdio.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <limits.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <scsi/libscsi.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "libscsi_impl.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstruct uscsi_dev {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int fd;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char *dev;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock};
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic void *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockuscsi_open(libscsi_hdl_t *hp, const void *target)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock struct uscsi_dev *dp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const char *target_name = (const char *)target;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((dp = libscsi_zalloc(hp, sizeof (struct uscsi_dev))) == NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((dp->dev = libscsi_strdup(hp, target_name)) == NULL) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock libscsi_free(hp, dp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((dp->fd = open(target_name, O_RDONLY)) < 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) libscsi_error(hp, ESCSI_BADTARGET, "failed to open %s "
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "for reading: %s", target_name, strerror(errno));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock libscsi_free(hp, dp->dev);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock libscsi_free(hp, dp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (dp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic void
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockuscsi_close(libscsi_hdl_t *hp, void *private)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock struct uscsi_dev *dp = (struct uscsi_dev *)private;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (dp == NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (dp->fd > 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) close(dp->fd);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock libscsi_free(hp, dp->dev);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock libscsi_free(hp, dp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockxlate_flags(libscsi_hdl_t *hp, uint_t flags, int *uf)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint_t f;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int i;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock f = 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (i = 0; i < sizeof (flags) * 8; i++) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock switch (flags & (1 << i)) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock case 0:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock continue;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock case LIBSCSI_AF_READ:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock f |= USCSI_READ;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock break;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock case LIBSCSI_AF_WRITE:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock f |= USCSI_WRITE;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock break;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock case LIBSCSI_AF_SILENT:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock f |= USCSI_SILENT;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock break;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock case LIBSCSI_AF_DIAGNOSE:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock f |= USCSI_DIAGNOSE;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock break;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock case LIBSCSI_AF_ISOLATE:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock f = USCSI_ISOLATE;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock break;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock case LIBSCSI_AF_RQSENSE:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock f = USCSI_RQENABLE;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock break;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock default:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (libscsi_error(hp, ESCSI_BOGUSFLAGS,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "flag 0x%x is unknown", 1 << i));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock *uf = f;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (0);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockuscsi_exec(libscsi_hdl_t *hp, void *private, libscsi_action_t *ap)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock struct uscsi_dev *dp = (struct uscsi_dev *)private;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock struct uscsi_cmd cmd;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock size_t data_a, data_v;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint8_t *cp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint_t flags;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock bzero(&cmd, sizeof (cmd));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cp = libscsi_action_get_cdb(ap);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (cp == NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (-1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock flags = libscsi_action_get_flags(ap);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (xlate_flags(hp, flags, &cmd.uscsi_flags) != 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (-1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cmd.uscsi_status = (short)-1;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cmd.uscsi_timeout = (short)libscsi_action_get_timeout(ap);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cmd.uscsi_cdb = (caddr_t)cp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cmd.uscsi_cdblen = libscsi_cmd_cdblen(hp, *cp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (cmd.uscsi_cdblen == 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (-1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (flags & (LIBSCSI_AF_READ | LIBSCSI_AF_WRITE)) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (libscsi_action_get_buffer(ap,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (uint8_t **)&cmd.uscsi_bufaddr, &data_a, &data_v) != 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (-1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (flags & LIBSCSI_AF_READ)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cmd.uscsi_buflen = data_a;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock else
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cmd.uscsi_buflen = data_v;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (flags & LIBSCSI_AF_RQSENSE) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (libscsi_action_get_sense(ap, (uint8_t **)&cmd.uscsi_rqbuf,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock &data_a, NULL) != 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (-1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (data_a > UCHAR_MAX)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock data_a = UCHAR_MAX;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cmd.uscsi_rqlen = (uchar_t)data_a;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cmd.uscsi_rqstatus = (uchar_t)-1;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (ioctl(dp->fd, USCSICMD, &cmd) < 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ASSERT(errno != EFAULT);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock switch (errno) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock case EINVAL:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (libscsi_error(hp, ESCSI_BADCMD, "internal "
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "uscsi error"));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock case EPERM:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (libscsi_error(hp, ESCSI_PERM, "insufficient "
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "privileges "));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock case EIO:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock /* Command never executed at all */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (cmd.uscsi_status == (short)-1)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (libscsi_error(hp, ESCSI_IO, "I/O "
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "error", strerror(errno)));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock break;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock default:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (libscsi_error(hp, ESCSI_SYS, "uscsi ioctl "
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "failed: %s", strerror(errno)));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock libscsi_action_set_status(ap, cmd.uscsi_status);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((flags & LIBSCSI_AF_READ) && libscsi_action_set_datalen(ap,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cmd.uscsi_buflen - cmd.uscsi_resid) != 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (-1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((flags & LIBSCSI_AF_RQSENSE) && libscsi_action_set_senselen(ap,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cmd.uscsi_rqlen - cmd.uscsi_rqresid) != 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (-1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (0);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock/*ARGSUSED*/
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic void
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockuscsi_target_name(libscsi_hdl_t *hp, void *private, char *buf, size_t len)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock struct uscsi_dev *dp = (struct uscsi_dev *)private;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) snprintf(buf, len, "%s", dp->dev);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic const libscsi_engine_ops_t uscsi_ops = {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock .lseo_open = uscsi_open,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock .lseo_close = uscsi_close,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock .lseo_exec = uscsi_exec,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock .lseo_target_name = uscsi_target_name
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock};
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic const libscsi_engine_t uscsi_engine = {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock .lse_name = "uscsi",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock .lse_libversion = LIBSCSI_VERSION,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock .lse_ops = &uscsi_ops
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock};
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock/*ARGSUSED*/
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockconst libscsi_engine_t *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrocklibscsi_uscsi_init(libscsi_hdl_t *hp)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (&uscsi_engine);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}