Blame sg.c

Packit Service 35c908
/*
Packit Service 35c908
 * Copyright (c) 2008, Intel Corporation.
Packit Service 35c908
 *
Packit Service 35c908
 * This program is free software; you can redistribute it and/or modify it
Packit Service 35c908
 * under the terms and conditions of the GNU Lesser General Public License,
Packit Service 35c908
 * version 2.1, as published by the Free Software Foundation.
Packit Service 35c908
 *
Packit Service 35c908
 * This program is distributed in the hope it will be useful, but WITHOUT
Packit Service 35c908
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Packit Service 35c908
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
Packit Service 35c908
 * for more details.
Packit Service 35c908
 *
Packit Service 35c908
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 35c908
 * along with this program; if not, write to the Free Software Foundation, Inc.,
Packit Service 35c908
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
Packit Service 35c908
 *
Packit Service 35c908
 */
Packit Service 35c908
Packit Service 35c908
#include <sys/ioctl.h>
Packit Service 35c908
#include "utils.h"
Packit Service 35c908
#include "api_lib.h"
Packit Service 35c908
#include "adapt_impl.h"
Packit Service 35c908
#include "fc_scsi.h"
Packit Service 35c908
Packit Service 35c908
/*
Packit Service 35c908
 * Perform INQUIRY of SCSI-generic device.
Packit Service 35c908
 */
Packit Service 35c908
HBA_STATUS
Packit Service 35c908
sg_issue_inquiry(const char *file, HBA_UINT8 cdb_byte1,
Packit Service 35c908
	       HBA_UINT8 cdb_byte2, void *buf, HBA_UINT32 *lenp,
Packit Service 35c908
	       HBA_UINT8 *statp, void *sense, HBA_UINT32 *sense_lenp)
Packit Service 35c908
{
Packit Service 35c908
	struct sg_io_hdr hdr;
Packit Service 35c908
	struct scsi_inquiry cmd;
Packit Service 35c908
	size_t len;
Packit Service 35c908
	HBA_UINT32 slen;
Packit Service 35c908
	int fd;
Packit Service 35c908
	int rc;
Packit Service 35c908
Packit Service 35c908
	len = *lenp;
Packit Service 35c908
	slen = *sense_lenp;
Packit Service 35c908
	if (slen > 255)
Packit Service 35c908
		slen = 255;   /* must fit in an 8-bit field */
Packit Service 35c908
	if (len > 255)
Packit Service 35c908
		len = 255;    /* sometimes must fit in 8-byte field */
Packit Service 35c908
	*lenp = 0;
Packit Service 35c908
	*statp = 0;
Packit Service 35c908
	fd = open(file, O_RDWR);
Packit Service 35c908
	if (fd < 0) {
Packit Service 35c908
		fprintf(stderr, "%s: open of %s failed, errno=0x%x\n",
Packit Service 35c908
			__func__, file, errno);
Packit Service 35c908
		return HBA_STATUS_ERROR;
Packit Service 35c908
	}
Packit Service 35c908
	memset(&hdr, 0, sizeof(hdr));
Packit Service 35c908
	memset(&cmd, 0, sizeof(cmd));
Packit Service 35c908
	memset(buf, 0, len);
Packit Service 35c908
Packit Service 35c908
	cmd.in_op = SCSI_OP_INQUIRY;
Packit Service 35c908
	cmd.in_flags = cdb_byte1;
Packit Service 35c908
	cmd.in_page_code = cdb_byte2;
Packit Service 35c908
	ua_net16_put(&cmd.in_alloc_len, len); /* field may actually be 8 bits */
Packit Service 35c908
Packit Service 35c908
	hdr.interface_id = 'S';
Packit Service 35c908
	hdr.dxfer_direction = SG_DXFER_FROM_DEV;
Packit Service 35c908
	hdr.cmd_len = sizeof(cmd);
Packit Service 35c908
	hdr.mx_sb_len = slen;
Packit Service 35c908
	hdr.dxfer_len = len;
Packit Service 35c908
	hdr.dxferp = (unsigned char *) buf;
Packit Service 35c908
	hdr.cmdp = (unsigned char *) &cm;;
Packit Service 35c908
	hdr.sbp = (unsigned char *) sense;
Packit Service 35c908
	hdr.timeout = 3000;                     /* mS to wait for result */
Packit Service 35c908
Packit Service 35c908
	rc = ioctl(fd, SG_IO, &hdr);
Packit Service 35c908
	if (rc < 0) {
Packit Service 35c908
		rc = errno;
Packit Service 35c908
		fprintf(stderr, "%s: SG_IO error. file %s, errno=0x%x\n",
Packit Service 35c908
			__func__, file, errno);
Packit Service 35c908
		close(fd);
Packit Service 35c908
		return HBA_STATUS_ERROR;
Packit Service 35c908
	}
Packit Service 35c908
	close(fd);
Packit Service 35c908
	*lenp = len - hdr.resid;
Packit Service 35c908
	*sense_lenp = hdr.sb_len_wr;
Packit Service 35c908
	*statp = hdr.status;
Packit Service 35c908
	return HBA_STATUS_OK;
Packit Service 35c908
}
Packit Service 35c908
Packit Service 35c908
static inline unsigned int
Packit Service 35c908
sg_get_id_type(struct scsi_inquiry_desc *dp)
Packit Service 35c908
{
Packit Service 35c908
	return dp->id_type_flags & SCSI_INQT_TYPE_MASK;
Packit Service 35c908
}
Packit Service 35c908
Packit Service 35c908
/*
Packit Service 35c908
 * Get device ID information for HBA-API.
Packit Service 35c908
 * See the spec.  We get the "best" information and leave the rest.
Packit Service 35c908
 * The buffer is left empty if nothing is gotten.
Packit Service 35c908
 */
Packit Service 35c908
void
Packit Service 35c908
sg_get_dev_id(const char *name, char *buf, size_t result_len)
Packit Service 35c908
{
Packit Service 35c908
	struct scsi_inquiry_dev_id *idp;
Packit Service 35c908
	struct scsi_inquiry_desc *dp;
Packit Service 35c908
	struct scsi_inquiry_desc *best = NULL;
Packit Service 35c908
	char sense[252];
Packit Service 35c908
	HBA_UINT32 len;
Packit Service 35c908
	HBA_UINT32 slen;
Packit Service 35c908
	u_char scsi_stat;
Packit Service 35c908
	size_t rlen;
Packit Service 35c908
	size_t dlen;
Packit Service 35c908
	unsigned int type;
Packit Service 35c908
Packit Service 35c908
	memset(buf, 0, result_len);
Packit Service 35c908
	len = result_len;
Packit Service 35c908
	slen = sizeof(sense);
Packit Service 35c908
	idp = (struct scsi_inquiry_dev_id *) buf;
Packit Service 35c908
	sg_issue_inquiry(name, SCSI_INQF_EVPD, SCSI_INQP_DEV_ID,
Packit Service 35c908
			buf, &len, &scsi_stat, sense, &slen);
Packit Service 35c908
	if (len < sizeof(*idp))
Packit Service 35c908
		return;
Packit Service 35c908
	if (idp->is_page_code != SCSI_INQP_DEV_ID)
Packit Service 35c908
		return;
Packit Service 35c908
	len -= sizeof(*idp);
Packit Service 35c908
	rlen = net16_get(&idp->is_page_len);
Packit Service 35c908
	if (rlen > len)
Packit Service 35c908
		rlen = len;
Packit Service 35c908
	dp = (struct scsi_inquiry_desc *) (idp + 1);
Packit Service 35c908
	for (; rlen >= sizeof(*dp);
Packit Service 35c908
	     rlen -= dlen,
Packit Service 35c908
	     dp = (struct scsi_inquiry_desc *) ((char *) dp + dlen)) {
Packit Service 35c908
		dlen = dp->id_designator_len + sizeof(*dp) -
Packit Service 35c908
		       sizeof(dp->id_designator[0]);
Packit Service 35c908
		if (dlen > rlen)
Packit Service 35c908
			break;
Packit Service 35c908
		type = sg_get_id_type(dp);
Packit Service 35c908
		if (type > SCSI_DTYPE_NAA)
Packit Service 35c908
			continue;
Packit Service 35c908
		if (best == NULL)
Packit Service 35c908
			best = dp;
Packit Service 35c908
		else if (type == sg_get_id_type(best) &&
Packit Service 35c908
			   (dp->id_designator_len < best->id_designator_len ||
Packit Service 35c908
			   (dp->id_designator_len == best->id_designator_len &&
Packit Service 35c908
			   memcmp(dp->id_designator, best->id_designator,
Packit Service 35c908
			   best->id_designator_len) < 0))) {
Packit Service 35c908
			best = dp;
Packit Service 35c908
		} else if (type > sg_get_id_type(best))
Packit Service 35c908
			best = dp;
Packit Service 35c908
	}
Packit Service 35c908
	if (best) {
Packit Service 35c908
		dp = best;
Packit Service 35c908
		dlen = dp->id_designator_len + sizeof(*dp) -
Packit Service 35c908
			sizeof(dp->id_designator[0]);
Packit Service 35c908
		if (dlen > result_len)
Packit Service 35c908
			dlen = 0;                       /* can't happen */
Packit Service 35c908
		else
Packit Service 35c908
			memmove(buf, dp, dlen);         /* areas may overlap */
Packit Service 35c908
		memset(buf +  dlen, 0, result_len - dlen);
Packit Service 35c908
	}
Packit Service 35c908
}
Packit Service 35c908
Packit Service 35c908
/*
Packit Service 35c908
 * Read Capacity for HBA-API.
Packit Service 35c908
 */
Packit Service 35c908
HBA_STATUS
Packit Service 35c908
sg_issue_read_capacity(const char *file, void *resp, HBA_UINT32 *resp_lenp,
Packit Service 35c908
		HBA_UINT8 *statp, void *sense, HBA_UINT32 *sense_lenp)
Packit Service 35c908
{
Packit Service 35c908
	struct sg_io_hdr hdr;
Packit Service 35c908
	struct scsi_rcap10 cmd;
Packit Service 35c908
	struct scsi_rcap16 cmd_16;
Packit Service 35c908
	size_t len;
Packit Service 35c908
	int fd;
Packit Service 35c908
	int rc;
Packit Service 35c908
Packit Service 35c908
	len = *resp_lenp;
Packit Service 35c908
	*resp_lenp = 0;
Packit Service 35c908
	fd = open(file, O_RDWR);
Packit Service 35c908
	if (fd < 0) {
Packit Service 35c908
		fprintf(stderr, "%s: open of %s failed, errno=0x%x\n",
Packit Service 35c908
			__func__, file, errno);
Packit Service 35c908
		return errno;
Packit Service 35c908
	}
Packit Service 35c908
	memset(&hdr, 0, sizeof(hdr));
Packit Service 35c908
Packit Service 35c908
	/* If the response buffer size is enough to
Packit Service 35c908
	 * accomodate READ CAPACITY(16) response issue
Packit Service 35c908
	 * SCSI READ CAPACITY(16) else issue
Packit Service 35c908
	 * SCSI READ CAPACITY(10)
Packit Service 35c908
	 */
Packit Service 35c908
	if (len >= sizeof(struct scsi_rcap16_resp)) {
Packit Service 35c908
		memset(&cmd_16, 0, sizeof(cmd_16));
Packit Service 35c908
		cmd_16.rc_op = SCSI_OP_SA_IN_16;
Packit Service 35c908
		cmd_16.rc_sa = SCSI_SA_READ_CAP16;
Packit Service 35c908
		ua_net32_put(&cmd_16.rc_alloc_len, len);
Packit Service 35c908
		hdr.cmd_len = sizeof(cmd_16);
Packit Service 35c908
		hdr.cmdp = (unsigned char *) &cmd_16;
Packit Service 35c908
	} else {
Packit Service 35c908
		memset(&cmd, 0, sizeof(cmd));
Packit Service 35c908
		cmd.rc_op = SCSI_OP_READ_CAP10;
Packit Service 35c908
		hdr.cmd_len = sizeof(cmd);
Packit Service 35c908
		hdr.cmdp = (unsigned char *) &cm;;
Packit Service 35c908
	}
Packit Service 35c908
Packit Service 35c908
	hdr.interface_id = 'S';
Packit Service 35c908
	hdr.dxfer_direction = SG_DXFER_FROM_DEV;
Packit Service 35c908
	hdr.mx_sb_len = *sense_lenp;
Packit Service 35c908
	hdr.dxfer_len = len;
Packit Service 35c908
	hdr.dxferp = (unsigned char *) resp;
Packit Service 35c908
	hdr.sbp = (unsigned char *) sense;
Packit Service 35c908
	hdr.timeout = UINT_MAX;
Packit Service 35c908
	hdr.timeout = 3000;                     /* mS to wait for result */
Packit Service 35c908
Packit Service 35c908
	rc = ioctl(fd, SG_IO, &hdr);
Packit Service 35c908
	if (rc < 0) {
Packit Service 35c908
		rc = errno;
Packit Service 35c908
		fprintf(stderr, "%s: SG_IO error. file %s, errno=0x%x\n",
Packit Service 35c908
			__func__, file, errno);
Packit Service 35c908
		close(fd);
Packit Service 35c908
		return HBA_STATUS_ERROR;
Packit Service 35c908
	}
Packit Service 35c908
	close(fd);
Packit Service 35c908
	*resp_lenp = len - hdr.resid;
Packit Service 35c908
	*sense_lenp = hdr.sb_len_wr;
Packit Service 35c908
	*statp = hdr.status;
Packit Service 35c908
	return HBA_STATUS_OK;
Packit Service 35c908
}
Packit Service 35c908
Packit Service 35c908
/*
Packit Service 35c908
 * Report LUNs for HBA-API.
Packit Service 35c908
 */
Packit Service 35c908
HBA_STATUS
Packit Service 35c908
sg_issue_report_luns(const char *file, void *resp, HBA_UINT32 *resp_lenp,
Packit Service 35c908
		   HBA_UINT8 *statp, void *sense, HBA_UINT32 *sense_lenp)
Packit Service 35c908
{
Packit Service 35c908
	struct sg_io_hdr hdr;
Packit Service 35c908
	struct scsi_report_luns cmd;
Packit Service 35c908
	size_t len;
Packit Service 35c908
	int fd;
Packit Service 35c908
	int rc;
Packit Service 35c908
Packit Service 35c908
	len = *resp_lenp;
Packit Service 35c908
	*resp_lenp = 0;
Packit Service 35c908
	fd = open(file, O_RDWR);
Packit Service 35c908
	if (fd < 0) {
Packit Service 35c908
		fprintf(stderr, "%s: open of %s failed, errno=0x%x\n",
Packit Service 35c908
			__func__, file, errno);
Packit Service 35c908
		return errno;
Packit Service 35c908
	}
Packit Service 35c908
	memset(&hdr, 0, sizeof(hdr));
Packit Service 35c908
	memset(&cmd, 0, sizeof(cmd));
Packit Service 35c908
Packit Service 35c908
	cmd.rl_op = SCSI_OP_REPORT_LUNS;
Packit Service 35c908
	ua_net32_put(&cmd.rl_alloc_len, len);
Packit Service 35c908
Packit Service 35c908
	hdr.interface_id = 'S';
Packit Service 35c908
	hdr.dxfer_direction = SG_DXFER_FROM_DEV;
Packit Service 35c908
	hdr.cmd_len = sizeof(cmd);
Packit Service 35c908
	hdr.mx_sb_len = *sense_lenp;
Packit Service 35c908
	hdr.dxfer_len = len;
Packit Service 35c908
	hdr.dxferp = (unsigned char *) resp;
Packit Service 35c908
	hdr.cmdp = (unsigned char *) &cm;;
Packit Service 35c908
	hdr.sbp = (unsigned char *) sense;
Packit Service 35c908
	hdr.timeout = UINT_MAX;
Packit Service 35c908
	hdr.timeout = 3000;                     /* mS to wait for result */
Packit Service 35c908
Packit Service 35c908
	rc = ioctl(fd, SG_IO, &hdr);
Packit Service 35c908
	if (rc < 0) {
Packit Service 35c908
		rc = errno;
Packit Service 35c908
		fprintf(stderr, "%s: SG_IO error. file %s, errno=0x%x\n",
Packit Service 35c908
			__func__, file, errno);
Packit Service 35c908
		close(fd);
Packit Service 35c908
		return HBA_STATUS_ERROR;
Packit Service 35c908
	}
Packit Service 35c908
	close(fd);
Packit Service 35c908
	*resp_lenp = len - hdr.resid;
Packit Service 35c908
	*sense_lenp = hdr.sb_len_wr;
Packit Service 35c908
	*statp = hdr.status;
Packit Service 35c908
	return HBA_STATUS_OK;
Packit Service 35c908
}
Packit Service 35c908