Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 90eeb01a authored by Mike Christie's avatar Mike Christie Committed by James Bottomley
Browse files

[SCSI] iscsi class: add bsg support to iscsi class

This patch adds bsg support to the iscsi class. There is only
1 request, the host vendor one, supported. It is expected that
this would be used for things like flash updates.

This patch is made over this one
http://marc.info/?l=linux-scsi&m=131149780020992&w=2



Signed-off-by: default avatarMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 6ac73e8c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -309,6 +309,7 @@ config SCSI_FC_TGT_ATTRS
config SCSI_ISCSI_ATTRS
	tristate "iSCSI Transport Attributes"
	depends on SCSI && NET
	select BLK_DEV_BSGLIB
	help
	  If you wish to export transport-specific information about
	  each attached iSCSI device to sysfs, say Y.
+113 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/bsg-lib.h>
#include <net/tcp.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
@@ -31,6 +32,7 @@
#include <scsi/scsi_transport_iscsi.h>
#include <scsi/iscsi_if.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_bsg_iscsi.h>

#define ISCSI_TRANSPORT_VERSION "2.0-870"

@@ -447,6 +449,99 @@ void iscsi_destroy_iface(struct iscsi_iface *iface)
}
EXPORT_SYMBOL_GPL(iscsi_destroy_iface);

/*
 * BSG support
 */
/**
 * iscsi_bsg_host_dispatch - Dispatch command to LLD.
 * @job: bsg job to be processed
 */
static int iscsi_bsg_host_dispatch(struct bsg_job *job)
{
	struct Scsi_Host *shost = iscsi_job_to_shost(job);
	struct iscsi_bsg_request *req = job->request;
	struct iscsi_bsg_reply *reply = job->reply;
	struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
	int cmdlen = sizeof(uint32_t);	/* start with length of msgcode */
	int ret;

	/* check if we have the msgcode value at least */
	if (job->request_len < sizeof(uint32_t)) {
		ret = -ENOMSG;
		goto fail_host_msg;
	}

	/* Validate the host command */
	switch (req->msgcode) {
	case ISCSI_BSG_HST_VENDOR:
		cmdlen += sizeof(struct iscsi_bsg_host_vendor);
		if ((shost->hostt->vendor_id == 0L) ||
		    (req->rqst_data.h_vendor.vendor_id !=
			shost->hostt->vendor_id)) {
			ret = -ESRCH;
			goto fail_host_msg;
		}
		break;
	default:
		ret = -EBADR;
		goto fail_host_msg;
	}

	/* check if we really have all the request data needed */
	if (job->request_len < cmdlen) {
		ret = -ENOMSG;
		goto fail_host_msg;
	}

	ret = i->iscsi_transport->bsg_request(job);
	if (!ret)
		return 0;

fail_host_msg:
	/* return the errno failure code as the only status */
	BUG_ON(job->reply_len < sizeof(uint32_t));
	reply->reply_payload_rcv_len = 0;
	reply->result = ret;
	job->reply_len = sizeof(uint32_t);
	bsg_job_done(job, ret, 0);
	return 0;
}

/**
 * iscsi_bsg_host_add - Create and add the bsg hooks to receive requests
 * @shost: shost for iscsi_host
 * @cls_host: iscsi_cls_host adding the structures to
 */
static int
iscsi_bsg_host_add(struct Scsi_Host *shost, struct iscsi_cls_host *ihost)
{
	struct device *dev = &shost->shost_gendev;
	struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
	struct request_queue *q;
	char bsg_name[20];
	int ret;

	if (!i->iscsi_transport->bsg_request)
		return -ENOTSUPP;

	snprintf(bsg_name, sizeof(bsg_name), "iscsi_host%d", shost->host_no);

	q = __scsi_alloc_queue(shost, bsg_request_fn);
	if (!q)
		return -ENOMEM;

	ret = bsg_setup_queue(dev, q, bsg_name, iscsi_bsg_host_dispatch, 0);
	if (ret) {
		shost_printk(KERN_ERR, shost, "bsg interface failed to "
			     "initialize - no request queue\n");
		blk_cleanup_queue(q);
		return ret;
	}

	ihost->bsg_q = q;
	return 0;
}

static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
			    struct device *cdev)
{
@@ -456,13 +551,30 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
	memset(ihost, 0, sizeof(*ihost));
	atomic_set(&ihost->nr_scans, 0);
	mutex_init(&ihost->mutex);

	iscsi_bsg_host_add(shost, ihost);
	/* ignore any bsg add error - we just can't do sgio */

	return 0;
}

static int iscsi_remove_host(struct transport_container *tc,
			     struct device *dev, struct device *cdev)
{
	struct Scsi_Host *shost = dev_to_shost(dev);
	struct iscsi_cls_host *ihost = shost->shost_data;

	if (ihost->bsg_q) {
		bsg_remove_queue(ihost->bsg_q);
		blk_cleanup_queue(ihost->bsg_q);
	}
	return 0;
}

static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
			       "iscsi_host",
			       iscsi_setup_host,
			       NULL,
			       iscsi_remove_host,
			       NULL);

static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
+110 −0
Original line number Diff line number Diff line
/*
 *  iSCSI Transport BSG Interface
 *
 *  Copyright (C) 2009   James Smart, Emulex Corporation
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#ifndef SCSI_BSG_ISCSI_H
#define SCSI_BSG_ISCSI_H

/*
 * This file intended to be included by both kernel and user space
 */

#include <scsi/scsi.h>

/*
 * iSCSI Transport SGIO v4 BSG Message Support
 */

/* Default BSG request timeout (in seconds) */
#define ISCSI_DEFAULT_BSG_TIMEOUT      (10 * HZ)


/*
 * Request Message Codes supported by the iSCSI Transport
 */

/* define the class masks for the message codes */
#define ISCSI_BSG_CLS_MASK     0xF0000000      /* find object class */
#define ISCSI_BSG_HST_MASK     0x80000000      /* iscsi host class */

/* iscsi host Message Codes */
#define ISCSI_BSG_HST_VENDOR           (ISCSI_BSG_HST_MASK | 0x000000FF)


/*
 * iSCSI Host Messages
 */

/* ISCSI_BSG_HST_VENDOR : */

/* Request:
 * Note: When specifying vendor_id, be sure to read the Vendor Type and ID
 *   formatting requirements specified in scsi_netlink.h
 */
struct iscsi_bsg_host_vendor {
	/*
	 * Identifies the vendor that the message is formatted for. This
	 * should be the recipient of the message.
	 */
	uint64_t vendor_id;

	/* start of vendor command area */
	uint32_t vendor_cmd[0];
};

/* Response:
 */
struct iscsi_bsg_host_vendor_reply {
	/* start of vendor response area */
	uint32_t vendor_rsp[0];
};


/* request (CDB) structure of the sg_io_v4 */
struct iscsi_bsg_request {
	uint32_t msgcode;
	union {
		struct iscsi_bsg_host_vendor    h_vendor;
	} rqst_data;
} __attribute__((packed));


/* response (request sense data) structure of the sg_io_v4 */
struct iscsi_bsg_reply {
	/*
	 * The completion result. Result exists in two forms:
	 * if negative, it is an -Exxx system errno value. There will
	 * be no further reply information supplied.
	 * else, it's the 4-byte scsi error result, with driver, host,
	 * msg and status fields. The per-msgcode reply structure
	 * will contain valid data.
	 */
	uint32_t result;

	/* If there was reply_payload, how much was recevied ? */
	uint32_t reply_payload_rcv_len;

	union {
		struct iscsi_bsg_host_vendor_reply      vendor_reply;
	} reply_data;
};


#endif /* SCSI_BSG_ISCSI_H */
+6 −1
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ struct iscsi_conn;
struct iscsi_task;
struct sockaddr;
struct iscsi_iface;
struct bsg_job;

/**
 * struct iscsi_transport - iSCSI Transport template
@@ -141,9 +142,9 @@ struct iscsi_transport {
				enum iscsi_param_type param_type,
				int param, char *buf);
	mode_t (*attr_is_visible)(int param_type, int param);
	int (*bsg_request)(struct bsg_job *job);
};


/*
 * transport registration upcalls
 */
@@ -227,8 +228,12 @@ struct iscsi_cls_session {
struct iscsi_cls_host {
	atomic_t nr_scans;
	struct mutex mutex;
	struct request_queue *bsg_q;
};

#define iscsi_job_to_shost(_job) \
        dev_to_shost(_job->dev)

extern void iscsi_host_for_each_session(struct Scsi_Host *shost,
				void (*fn)(struct iscsi_cls_session *));