[PATCH 4/4] RFC: iscsi class: add bsg support to iscsi class

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Mike Christie <michaelc@xxxxxxxxxxx>

This is just an initial conversion of Jay's patch to
the bsg lib. I disabled the code that copys the sg to
a buffer, because it was a little broken.

Patch is only compile tested.

Signed-off-by: Mike Christie <michaelc@xxxxxxxxxxx>
---
 drivers/scsi/scsi_transport_iscsi.c |  196 +++++++++++++++++++++++++++-
 include/scsi/Kbuild                 |    1 +
 include/scsi/scsi_bsg_iscsi.h       |  253 +++++++++++++++++++++++++++++++++++
 include/scsi/scsi_transport_iscsi.h |    6 +
 4 files changed, 455 insertions(+), 1 deletions(-)
 create mode 100644 include/scsi/scsi_bsg_iscsi.h

diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 1e6d479..48281ae 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -30,6 +30,9 @@
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_transport_iscsi.h>
 #include <scsi/iscsi_if.h>
+#include <scsi/scsi_bsg_iscsi.h>
+#include <scsi/scsi_bsg.h>
+#include <scsi/scsi_cmnd.h>
 
 #define ISCSI_SESSION_ATTRS 22
 #define ISCSI_CONN_ATTRS 13
@@ -269,6 +272,182 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
 }
 EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
 
+
+/*
+ * BSG support
+ */
+
+/**
+ * iscsi_bsg_job_timeout - handler for when a bsg request timesout
+ * @req:	request that timed out
+ */
+static enum blk_eh_timer_return iscsi_bsg_job_timeout(struct request *req)
+{
+	struct scsi_bsg_job *job = req->special;
+	struct Scsi_Host *shost = job->shost;
+	struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
+	int err = 0;
+
+	if (i->iscsi_transport->bsg_timeout)
+		err = i->iscsi_transport->bsg_timeout(job);
+	return err;
+}
+
+static int iscsi_req_to_bsg_job(struct Scsi_Host *shost, struct device *dev,
+				struct request *req)
+{
+	return scsi_bsg_req_to_job(shost, dev, req, 0, 0);
+}
+
+/**
+ * iscsi_bsg_host_dispatch - process bsg requests and dispatch to LLD
+ * @q:		iscsi host request queue
+ * @shost:	scsi host request queue attached to
+ * @job:	bsg job to be processed
+ */
+static enum scsi_dispatch_result
+iscsi_bsg_host_dispatch(struct request_queue *q, struct Scsi_Host *shost,
+			 struct scsi_bsg_job *job)
+{
+	unsigned char *pdata;
+	struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
+	int cmdlen = sizeof(uint32_t);	/* start with length of msgcode */
+	int ret, num;
+	unsigned int tot_len = 0;
+	struct scatterlist *sge = NULL;
+	struct iscsi_bsg_request *bsg_req = job->request;
+	struct iscsi_bsg_reply *bsg_reply = job->reply;
+
+	/* 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 (bsg_req->msgcode) {
+	case ISCSI_BSG_HST_NET_CONFIG:
+		cmdlen += sizeof(struct iscsi_bsg_host_net_config);
+		/*
+		 * Validate set ops have a request payload.
+		 * Get ops are allowed to have none/partial/all reply payloads
+		 */
+		if ((bsg_req->rqst_data.h_netconfig.set_op) &&
+		    (!job->request_payload.payload_len)) {
+			ret = -EINVAL;
+			goto fail_host_msg;
+		}
+#if 0
+This should be using kmap instead of sg_virt
+
+Should also move this to a new function so other cmds can use it
+
+		tot_len = 0;
+		for_each_sg(job->request_payload.sg_list, sge,
+			    job->request_payload.sg_cnt, num) {
+			tot_len += sge->length;
+		}
+
+		job->request_payload.va =  kmalloc(tot_len, GFP_KERNEL);
+		if (job->request_payload.va == NULL) {
+			ret = -EINVAL;
+			goto fail_host_msg;
+		}
+		pdata = job->request_payload.va;
+		job->request_payload.size = tot_len;
+		for_each_sg(job->request_payload.sg_list, sge,
+				 job->request_payload.sg_cnt, num) {
+			memcpy(pdata, sg_virt(sge), sge->length);
+			pdata += sge->length;
+
+		}
+#endif
+		break;
+
+	case ISCSI_BSG_HST_VENDOR:
+#if 0
+		cmdlen += sizeof(struct iscsi_bsg_host_vendor);
+		if ((shost->hostt->vendor_id == 0L) ||
+		    (bsg_req->rqst_data.h_vendor.vendor_id !=
+			shost->hostt->vendor_id)) {
+			ret = -ESRCH;
+			goto fail_host_msg;
+		}
+		break;
+#endif
+	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 SCSI_DISPATCH_UNLOCKED;
+
+fail_host_msg:
+	/* return the errno failure code as the only status */
+	BUG_ON(job->reply_len < sizeof(uint32_t));
+	bsg_reply->reply_payload_rcv_len = 0;
+	bsg_reply->result = ret;
+	job->reply_len = sizeof(uint32_t);
+	scsi_bsg_job_done(job, ret, 0);
+	return SCSI_DISPATCH_UNLOCKED;
+}
+
+/**
+ * iscsi_bsg_host_handler - handler for bsg requests for a iscsi host
+ * @q: iscsi host request queue
+ */
+static void
+iscsi_bsg_host_handler(struct request_queue *q)
+{
+	struct Scsi_Host *shost = q->queuedata;
+
+	scsi_bsg_request_handler(q, shost, &shost->shost_gendev,
+				 iscsi_req_to_bsg_job,
+				 iscsi_bsg_host_dispatch);
+}
+
+/**
+ * iscsi_bsg_host_add - Create and add the bsg hooks so we can 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];
+
+	ihost->rqst_q = NULL;
+
+	if (!i->iscsi_transport->bsg_request)
+		return -ENOTSUPP;
+
+	snprintf(bsg_name, sizeof(bsg_name),
+		 "iscsi_host%d", shost->host_no);
+
+	q = scsi_bsg_add(shost, dev, bsg_name, iscsi_bsg_host_handler);
+	if (!q) {
+		printk(KERN_ERR "iscsi_host%d: bsg interface failed to "
+				"initialize - no request queue\n",
+				 shost->host_no);
+		return -ENOMEM;
+	}
+
+	q->queuedata = shost;
+	ihost->rqst_q = q;
+	return 0;
+}
+
 static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
 			    struct device *cdev)
 {
@@ -278,13 +457,27 @@ 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;
+
+	scsi_bsg_remove(ihost->rqst_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,
@@ -1930,6 +2123,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
 	priv->iscsi_transport = tt;
 	priv->t.user_scan = iscsi_user_scan;
 	priv->t.create_work_queue = 1;
+	priv->t.eh_bsg_timed_out = iscsi_bsg_job_timeout;
 
 	priv->dev.class = &iscsi_transport_class;
 	dev_set_name(&priv->dev, "%s", tt->name);
diff --git a/include/scsi/Kbuild b/include/scsi/Kbuild
index b3a0ee6..f513500 100644
--- a/include/scsi/Kbuild
+++ b/include/scsi/Kbuild
@@ -2,4 +2,5 @@ header-y += scsi.h
 header-y += scsi_netlink.h
 header-y += scsi_netlink_fc.h
 header-y += scsi_bsg_fc.h
+header-y += scsi_bsg_iscsi.h
 header-y += fc/
diff --git a/include/scsi/scsi_bsg_iscsi.h b/include/scsi/scsi_bsg_iscsi.h
new file mode 100644
index 0000000..7c723a7
--- /dev/null
+++ b/include/scsi/scsi_bsg_iscsi.h
@@ -0,0 +1,253 @@
+/*
+ *  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_NET_CONFIG	(ISCSI_BSG_HST_MASK | 0x00000001)
+#define ISCSI_BSG_HST_VENDOR		(ISCSI_BSG_HST_MASK | 0x000000FF)
+
+#define ISCSI_SET_IP_ADDR		1
+#define ISCSI_SET_DEFAULT_GATEWAY	2
+#define ISCSI_SET_VLAN			3
+#define ISCSI_SET_HBA_NAME		4
+#define ISCSI_CONFIGURE_STATELESS_IP	5
+#define ISCSI_GET_HBA_NAME		6
+#define ISCSI_GET_IF_INFO		7
+#define ISCSI_GET_DEFAULT_GATEWAY	8
+#define ISCSI_GET_MAC_ADDRESS           9
+
+/*
+ * iSCSI Host Messages
+ */
+
+struct ip_address_subnet_format {
+	u16 sizeofstructure;
+	u8  iptype;
+	u8  ipv6_prefix_length;
+	u8  ipaddress[16];
+	u8  subnetmask[16];
+	u32 rsvd0;
+} __packed;
+
+struct iscsi_ip_addr_record {
+	u32  action;
+	u32  interface_hndl;
+	struct ip_address_subnet_format ip_address;
+	u32  status;
+} __packed;
+
+struct iscsi_ip_addr_record_params {
+	u32 record_entry_count;
+	struct iscsi_ip_addr_record ip_record[1];
+} __packed;
+
+struct ip_address_format {
+	u16	sizeofstructure;
+	u8	reserved;
+	u8	ip_type;
+	u8	ip_address[16];
+	u32	rsvd0;
+} __packed;
+
+struct iscsi_bsg_common_format {
+	u8 opcode;		/* dword 0 */
+	u8 subsystem;		/* dword 0 */
+	u8 port_number;		/* dword 0 */
+	u8 domain;		/* dword 0 */
+	u32 timeout;		/* dword 1 */
+	u32 request_length;	/* dword 2 */
+	u32 rsvd0;		/* dword 3 */
+	u32    action;
+	struct ip_address_format gateway;
+	u32  interface_hndl;
+	u32  vlan_priority;
+	u32  flags;
+	u8   iscsiname[224];
+	u8   iscsialias[32];
+	u32  ip_type;
+	u32  retry_count;
+	struct iscsi_ip_addr_record_params ip_params;
+} __packed;
+
+/* ISCSI_BSG_HST_NET_CONFIG : */
+
+/* bsg network parameter ids */
+enum iscsi_bsg_netparam {
+	BSG_NETPARAM_UNKNOWN		= 0x00000000,
+	BSG_NETPARAM_MAC		= BSG_NETPARAM_UNKNOWN + 1,
+	BSG_NETPARAM_MTU		= BSG_NETPARAM_UNKNOWN + 2,
+	BSG_NETPARAM_VLAN		= BSG_NETPARAM_UNKNOWN + 3,
+	BSG_NETPARAM_BOOTPROTO		= BSG_NETPARAM_UNKNOWN + 4,
+	BSG_NETPARAM_IPV4_ADDR		= BSG_NETPARAM_UNKNOWN + 5,
+	BSG_NETPARAM_IPV4_MASK		= BSG_NETPARAM_UNKNOWN + 6,
+	BSG_NETPARAM_IPV4_GW		= BSG_NETPARAM_UNKNOWN + 7,
+	BSG_NETPARAM_IPV6_ADDR		= BSG_NETPARAM_UNKNOWN + 8,
+	BSG_NETPARAM_IPV6_MASK		= BSG_NETPARAM_UNKNOWN + 9,
+	BSG_NETPARAM_IPV6_GW		= BSG_NETPARAM_UNKNOWN + 10,
+	BSG_NETPARAM_IPV6_AUTO_PARAM	= BSG_NETPARAM_UNKNOWN + 11,
+};
+
+/* network parameter TLV (type, length, value) structure */
+struct iscsi_bsg_netparam_tlv {
+	uint32_t	netparam;
+	uint32_t	length;
+	uint8_t		value[1];
+};
+
+/* Request:
+ * This message sets or gets Network configuration parameters on/from the
+ * iscsi host network interface.
+ *
+ * On set operations, the request payload buffer contains a set of
+ * netparam tlv's with the values to be set.
+ *
+ * On get operations, the request payload is unused.
+ */
+struct iscsi_bsg_host_net_config {
+	/*
+	 * Specifies the operation type:  0x0 = GET;  0x1 = SET
+	 */
+	uint8_t		set_op;
+
+	/*
+	 * If SET operation, contains the total number of netparam tlv's
+	 * in the request payload.
+	 */
+	uint8_t		netparam_count;
+};
+
+/* Response:
+ *
+ * On set operations, the response structure will specify the number of
+ * successfully processed netparam TLVs from the request payload.
+ * The reply payload will contain (as many as can fit) the successfully
+ * processed TLVs and their new values.
+ *
+ * On get operations, the response structure will specify the total
+ * number of netparam TLVs supported on the iscsi host network interface,
+ * and the reply payload size that is required to obtain the entire
+ * TLV list.  The reply payload will contain (as many as can fit) the
+ * TLV's supported on the iscsi host network interface.
+ *
+ * Note: Reply payloads will be truncated to whole TLVs that fit within
+ * the specified reply payload size.
+ *
+ */
+struct iscsi_bsg_host_net_config_reply {
+	/*
+	 * On SET operations: contains the number of successfully
+	 * processed netparam TLV elements.
+	 *
+	 * On GET operations: contains the total number of netparams
+	 * that are supported on the iscsi host network interface.
+	 */
+	uint8_t		netparam_count;
+
+	/*
+	 * On GET operations: specifies the size of the reply payload
+	 * that is required to obtain the entire list of netparam TLVs.
+	 */
+	uint32_t	netparam_payload_len;
+};
+
+
+/* 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_net_config	h_netconfig;
+		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;
+		struct iscsi_bsg_host_net_config_reply	h_netconfig_reply;
+	} reply_data;
+};
+
+
+#endif /* SCSI_BSG_ISCSI_H */
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 349c7f3..354091f 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -36,6 +36,7 @@ struct iscsi_cls_conn;
 struct iscsi_conn;
 struct iscsi_task;
 struct sockaddr;
+struct scsi_bsg_job;
 
 /**
  * struct iscsi_transport - iSCSI Transport template
@@ -134,6 +135,10 @@ struct iscsi_transport {
 	int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type,
 			  uint32_t enable, struct sockaddr *dst_addr);
 	int (*set_path) (struct Scsi_Host *shost, struct iscsi_path *params);
+
+	/* bsg support */
+	int (*bsg_request)(struct scsi_bsg_job *job);
+	int (*bsg_timeout)(struct scsi_bsg_job *job);
 };
 
 /*
@@ -212,6 +217,7 @@ struct iscsi_cls_session {
 struct iscsi_cls_host {
 	atomic_t nr_scans;
 	struct mutex mutex;
+	struct request_queue *rqst_q;	/* bsg support */
 };
 
 extern void iscsi_host_for_each_session(struct Scsi_Host *shost,
-- 
1.6.6.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux