All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] RFC: Proposal for BSG Interface
@ 2010-03-17 18:06 Jayamohan Kallickal
  2010-03-18 12:55 ` Boaz Harrosh
  2010-05-10  0:37 ` Vikas Chaudhary
  0 siblings, 2 replies; 3+ messages in thread
From: Jayamohan Kallickal @ 2010-03-17 18:06 UTC (permalink / raw)
  To: linux-scsi; +Cc: James.Bottomley, michaelc, open-iscsi

  This patch contains the bsg interface based on
the bsg interface in FC.

Developed and submitted earlier by James Smart.

Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: Jayamohan Kallickal <jayamohank@serverengines.com>
---
 drivers/scsi/scsi_transport_iscsi.c |  459 ++++++++++++++++++++++++++++++++++-
 include/scsi/Kbuild                 |    1 +
 include/scsi/scsi_bsg_iscsi.h       |  253 +++++++++++++++++++
 include/scsi/scsi_transport_iscsi.h |   47 ++++
 4 files changed, 759 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 ea3892e..2b7218c 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -29,6 +29,8 @@
 #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_cmnd.h>
 
 #define ISCSI_SESSION_ATTRS 22
 #define ISCSI_CONN_ATTRS 13
@@ -268,6 +270,447 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
 }
 EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
 
+
+/*
+ * BSG support
+ */
+
+/**
+ * iscsi_destroy_bsgjob - routine to teardown/delete a iscsi bsg job
+ * @job:	iscsi_bsg_job that is to be torn down
+ */
+static void
+iscsi_destroy_bsgjob(struct iscsi_bsg_job *job)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&job->job_lock, flags);
+	if (job->ref_cnt) {
+		spin_unlock_irqrestore(&job->job_lock, flags);
+		return;
+	}
+	spin_unlock_irqrestore(&job->job_lock, flags);
+
+	put_device(job->dev);	/* release reference for the request */
+
+	kfree(job->request_payload.sg_list);
+	kfree(job->reply_payload.sg_list);
+	kfree(job);
+}
+
+/**
+ * iscsi_bsg_jobdone - completion routine for bsg requests that the LLD has
+ *                  completed
+ * @job:	iscsi_bsg_job that is complete
+ */
+static void
+iscsi_bsg_jobdone(struct iscsi_bsg_job *job)
+{
+	struct request *req = job->req;
+	struct request *rsp = req->next_rq;
+	int err;
+
+	err = job->req->errors = job->reply->result;
+
+	if (err < 0)
+		/* we're only returning the result field in the reply */
+		job->req->sense_len = sizeof(uint32_t);
+	else
+		job->req->sense_len = job->reply_len;
+
+	/* we assume all request payload was transferred, residual == 0 */
+	req->resid_len = 0;
+
+	if (rsp) {
+		WARN_ON(job->reply->reply_payload_rcv_len > rsp->resid_len);
+
+		/* set reply (bidi) residual */
+		rsp->resid_len -= min(job->reply->reply_payload_rcv_len,
+				      rsp->resid_len);
+	}
+	blk_complete_request(req);
+}
+
+/**
+ * iscsi_bsg_softirq_done - softirq done routine for destroying the bsg requests
+ * @rq:        BSG request that holds the job to be destroyed
+ */
+static void
+iscsi_bsg_softirq_done(struct request *rq)
+{
+	struct iscsi_bsg_job *job = rq->special;
+	unsigned long flags;
+
+	spin_lock_irqsave(&job->job_lock, flags);
+	job->state_flags |= ISCSI_RQST_STATE_DONE;
+	job->ref_cnt--;
+	spin_unlock_irqrestore(&job->job_lock, flags);
+
+	blk_end_request_all(rq, rq->errors);
+	iscsi_destroy_bsgjob(job);
+}
+
+/**
+ * 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 iscsi_bsg_job *job = (void *) req->special;
+	struct Scsi_Host *shost = job->shost;
+	struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
+	unsigned long flags;
+	int err = 0, done = 0;
+
+	spin_lock_irqsave(&job->job_lock, flags);
+	if (job->state_flags & ISCSI_RQST_STATE_DONE)
+		done = 1;
+	else
+		job->ref_cnt++;
+	spin_unlock_irqrestore(&job->job_lock, flags);
+
+	if (!done && i->iscsi_transport->bsg_timeout) {
+		/* call LLDD to abort the i/o as it has timed out */
+		err = i->iscsi_transport->bsg_timeout(job);
+		if (err == -EAGAIN) {
+			job->ref_cnt--;
+			return BLK_EH_RESET_TIMER;
+		} else if (err)
+			printk(KERN_ERR "ERROR: iSCSI BSG request timeout - "
+				"LLD abort failed with status %d\n", err);
+	}
+
+	/* the blk_end_sync_io() doesn't check the error */
+	if (done)
+		return BLK_EH_NOT_HANDLED;
+	else
+		return BLK_EH_HANDLED;
+}
+
+static int
+iscsi_bsg_map_buffer(struct iscsi_bsg_buffer *buf, struct request *req)
+{
+	size_t sz = (sizeof(struct scatterlist) * req->nr_phys_segments);
+
+	BUG_ON(!req->nr_phys_segments);
+
+	buf->sg_list = kzalloc(sz, GFP_KERNEL);
+	if (!buf->sg_list)
+		return -ENOMEM;
+	sg_init_table(buf->sg_list, req->nr_phys_segments);
+	buf->sg_cnt = blk_rq_map_sg(req->q, req, buf->sg_list);
+	buf->payload_len = blk_rq_bytes(req);
+	return 0;
+}
+
+/**
+ * iscsi_req_to_bsgjob - Allocate/create the iscsi_bsg_job structure for the
+ *                   bsg request
+ * @req:	BSG request that needs a job structure
+ * @shost:	SCSI Host corresponding to the bsg object
+ */
+static int
+iscsi_req_to_bsgjob(struct request *req, struct Scsi_Host *shost)
+{
+	struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
+	struct request *rsp = req->next_rq;
+	struct iscsi_bsg_job *job;
+	int ret;
+
+	BUG_ON(req->special);
+
+	job = kzalloc(sizeof(struct iscsi_bsg_job) +
+				 i->iscsi_transport->dd_bsg_size, GFP_KERNEL);
+	if (!job)
+		return -ENOMEM;
+
+	/*
+	 * Note: this is a bit silly.
+	 * The request gets formatted as a SGIO v4 ioctl request, which
+	 * then gets reformatted as a blk request, which then gets
+	 * reformatted as a iscsi bsg request. And on completion, we have
+	 * to wrap return results such that SGIO v4 thinks it was a scsi
+	 * status.  I hope this was all worth it.
+	 */
+
+	req->special = job;
+	job->shost = shost;
+	job->req = req;
+	if (i->iscsi_transport->dd_bsg_size)
+		job->dd_data = (void *)&job[1];
+	spin_lock_init(&job->job_lock);
+	job->request = (struct iscsi_bsg_request *)req->cmd;
+	job->request_len = req->cmd_len;
+	job->reply = req->sense;
+	job->reply_len = SCSI_SENSE_BUFFERSIZE;	/* Size of sense buffer
+						 * allocated */
+	if (req->bio) {
+		ret = iscsi_bsg_map_buffer(&job->request_payload, req);
+		if (ret)
+			goto failjob_rls_job;
+	}
+	if (rsp && rsp->bio) {
+		ret = iscsi_bsg_map_buffer(&job->reply_payload, rsp);
+		if (ret)
+			goto failjob_rls_rqst_payload;
+	}
+	job->job_done = iscsi_bsg_jobdone;
+	job->dev = &shost->shost_gendev;
+	get_device(job->dev);		/* take a reference for the request */
+
+	job->ref_cnt = 1;
+
+	return 0;
+
+
+failjob_rls_rqst_payload:
+	kfree(job->request_payload.sg_list);
+failjob_rls_job:
+	kfree(job);
+	return -ENOMEM;
+}
+
+
+enum iscsi_dispatch_result {
+	DISPATCH_BREAK,		/* on return, q is locked, break from q loop */
+	DISPATCH_LOCKED,	/* on return, q is locked, continue on */
+	DISPATCH_UNLOCKED,	/* on return, q is unlocked, continue on */
+};
+
+/**
+ * iscsi_bsg_host_dispatch - process iscsi host bsg requests and
+ *                           dispatch to LLDD
+ * @q:		iscsi host request queue
+ * @shost:	scsi host request queue attached to
+ * @job:	bsg job to be processed
+ */
+static enum iscsi_dispatch_result
+iscsi_bsg_host_dispatch(struct request_queue *q, struct Scsi_Host *shost,
+			 struct iscsi_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;
+
+	/* Validate the host command */
+	job->request_payload.va = NULL;
+	switch (job->request->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 ((job->request->rqst_data.h_netconfig.set_op) &&
+		    (!job->request_payload.payload_len)) {
+			ret = -EINVAL;
+			goto fail_host_msg;
+		}
+		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;
+
+		}
+		break;
+
+	case ISCSI_BSG_HST_VENDOR:
+		cmdlen += sizeof(struct iscsi_bsg_host_vendor);
+		if ((shost->hostt->vendor_id == 0L) ||
+		    (job->request->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) {
+		kfree(job->request_payload.va);
+		return DISPATCH_UNLOCKED;
+	}
+
+fail_host_msg:
+	kfree(job->request_payload.va);
+
+	/* return the errno failure code as the only status */
+	BUG_ON(job->reply_len < sizeof(uint32_t));
+	job->reply->reply_payload_rcv_len = 0;
+	job->reply->result = ret;
+	job->reply_len = sizeof(uint32_t);
+	iscsi_bsg_jobdone(job);
+	return DISPATCH_UNLOCKED;
+}
+
+/**
+ * iscsi_bsg_request_handler - generic handler for bsg requests
+ * @q:		request queue to manage
+ * @shost:	Scsi_Host related to the bsg object
+ * @dev:	device structure for bsg object
+ *
+ * NOTE: only shost messages are expected
+ */
+static void
+iscsi_bsg_request_handler(struct request_queue *q, struct Scsi_Host *shost,
+			struct device *dev)
+{
+	struct request *req;
+	struct iscsi_bsg_job *job;
+	enum iscsi_dispatch_result ret;
+
+	if (!get_device(dev))
+		return;
+
+	while (!blk_queue_plugged(q)) {
+
+		req = blk_fetch_request(q);
+		if (!req)
+			break;
+
+		spin_unlock_irq(q->queue_lock);
+
+		ret = iscsi_req_to_bsgjob(req, shost);
+		if (ret) {
+			req->errors = ret;
+			blk_end_request(req, ret, blk_rq_bytes(req));
+			spin_lock_irq(q->queue_lock);
+			continue;
+		}
+
+		job = req->special;
+
+		/* check if we have the msgcode value at least */
+		if (job->request_len < sizeof(uint32_t)) {
+			BUG_ON(job->reply_len < sizeof(uint32_t));
+			job->reply->reply_payload_rcv_len = 0;
+			job->reply->result = -ENOMSG;
+			job->reply_len = sizeof(uint32_t);
+			iscsi_bsg_jobdone(job);
+			spin_lock_irq(q->queue_lock);
+			continue;
+		}
+
+		/* the dispatch routines will unlock the queue_lock */
+		ret = iscsi_bsg_host_dispatch(q, shost, job);
+
+		/* did dispatcher hit state that can't process any more */
+		if (ret == DISPATCH_BREAK)
+			break;
+
+		/* did dispatcher had released the lock */
+		if (ret == DISPATCH_UNLOCKED)
+			spin_lock_irq(q->queue_lock);
+	}
+
+	spin_unlock_irq(q->queue_lock);
+	put_device(dev);
+	spin_lock_irq(q->queue_lock);
+}
+
+/**
+ * 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;
+
+	iscsi_bsg_request_handler(q, shost, &shost->shost_gendev);
+}
+
+/**
+ * iscsi_bsg_hostadd - 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_hostadd(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;
+	int err;
+	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_alloc_queue(shost, 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;
+	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
+	blk_queue_softirq_done(q, iscsi_bsg_softirq_done);
+	blk_queue_rq_timed_out(q, iscsi_bsg_job_timeout);
+	blk_queue_rq_timeout(q, ISCSI_DEFAULT_BSG_TIMEOUT);
+
+	err = bsg_register_queue(q, dev, bsg_name, NULL);
+	if (err) {
+		printk(KERN_ERR "iscsi_host%d: bsg interface failed to "
+				"initialize - register queue\n",
+				shost->host_no);
+		blk_cleanup_queue(q);
+		return err;
+	}
+
+	ihost->rqst_q = q;
+	return 0;
+}
+
+/**
+ * iscsi_bsg_remove - Deletes the bsg hooks on iscsi objects
+ * @q:	the request_queue that is to be torn down.
+ */
+static void
+iscsi_bsg_remove(struct request_queue *q)
+{
+	if (q) {
+		bsg_unregister_queue(q);
+		blk_cleanup_queue(q);
+	}
+}
+
+/* End BSG routines */
+
 static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
 			    struct device *cdev)
 {
@@ -277,13 +720,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_hostadd(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;
+
+	iscsi_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,
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..10c91c3
--- /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
+
+/*
+ * 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..30a07ee 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -37,6 +37,47 @@ struct iscsi_conn;
 struct iscsi_task;
 struct sockaddr;
 
+struct iscsi_bsg_buffer {
+	unsigned int payload_len;
+	int sg_cnt;
+	struct scatterlist *sg_list;
+	void *va;
+	unsigned int size;
+};
+
+/* Values for iscsi_bsg_job->state_flags (bitflags) */
+#define ISCSI_RQST_STATE_INPROGRESS	0
+#define ISCSI_RQST_STATE_DONE		1
+
+struct iscsi_bsg_job {
+	struct Scsi_Host *shost;
+	struct device *dev;
+	struct request *req;
+	spinlock_t job_lock;
+	unsigned int state_flags;
+	unsigned int ref_cnt;
+	void (*job_done)(struct iscsi_bsg_job *);
+
+	struct iscsi_bsg_request *request;
+	struct iscsi_bsg_reply *reply;
+	unsigned int request_len;
+	unsigned int reply_len;
+	/*
+	 * On entry : reply_len indicates the buffer size allocated for
+	 * the reply.
+	 *
+	 * Upon completion : the message handler must set reply_len
+	 *  to indicates the size of the reply to be returned to the
+	 *  caller.
+	 */
+
+	/* DMA payloads for the request/response */
+	struct iscsi_bsg_buffer request_payload;
+	struct iscsi_bsg_buffer reply_payload;
+
+	void *dd_data;			/* Used for driver-specific storage */
+};
+
 /**
  * struct iscsi_transport - iSCSI Transport template
  *
@@ -134,6 +175,11 @@ 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 iscsi_bsg_job *);
+	int	(*bsg_timeout)(struct iscsi_bsg_job *);
+	u32	dd_bsg_size;	/* allocation length for host-specific data */
 };
 
 /*
@@ -212,6 +258,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.4


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH 1/2] RFC: Proposal for BSG Interface
  2010-03-17 18:06 [PATCH 1/2] RFC: Proposal for BSG Interface Jayamohan Kallickal
@ 2010-03-18 12:55 ` Boaz Harrosh
  2010-05-10  0:37 ` Vikas Chaudhary
  1 sibling, 0 replies; 3+ messages in thread
From: Boaz Harrosh @ 2010-03-18 12:55 UTC (permalink / raw)
  To: open-iscsi; +Cc: Jayamohan Kallickal, linux-scsi, James.Bottomley, michaelc

On 03/17/2010 08:06 PM, Jayamohan Kallickal wrote:
>   This patch contains the bsg interface based on
> the bsg interface in FC.
> 

What? where? who? how? why? w*\? ...

You are proposing a new Kernel ABI/API here right. I think it is not acceptable
without a detailed documentation, including every little bit. Nothing missing.

If lots of it is already written for FC then grate most of your job is done.

But for us mortals please put some text on an introductory message. I use iscsi
everyday for 4 years, your mail should answer the question: "what am I missing?"

> Developed and submitted earlier by James Smart.
> 
> Signed-off-by: James Smart <james.smart@emulex.com>
> Signed-off-by: Jayamohan Kallickal <jayamohank@serverengines.com>

Boaz

^ permalink raw reply	[flat|nested] 3+ messages in thread

* RE: [PATCH 1/2] RFC: Proposal for BSG Interface
  2010-03-17 18:06 [PATCH 1/2] RFC: Proposal for BSG Interface Jayamohan Kallickal
  2010-03-18 12:55 ` Boaz Harrosh
@ 2010-05-10  0:37 ` Vikas Chaudhary
  1 sibling, 0 replies; 3+ messages in thread
From: Vikas Chaudhary @ 2010-05-10  0:37 UTC (permalink / raw)
  To: open-iscsi, linux-scsi; +Cc: James.Bottomley, michaelc, Jayamohan Kallickal

Sorry for late response. Please see our comments inline.
We are trying to figure out how we can leverage this interface
for our offload solution.

Thanks,
Vikas.


>+/*
>+ * iSCSI Host Messages
>+ */
>+
>+struct ip_address_subnet_format {
>+	u16 sizeofstructure;

Why do we need this field ?

>+	u8  iptype;
>+	u8  ipv6_prefix_length;
>+	u8  ipaddress[16];
>+	u8  subnetmask[16];
>+	u32 rsvd0;
>+} __packed;
>+
>+struct iscsi_ip_addr_record {
>+	u32  action;

What's does this field implies ? Looks like be2iscsi specific ?

>+	u32  interface_hndl;

Again what this interface handle for ?

>+	struct ip_address_subnet_format ip_address;
>+	u32  status;

Why do we need *status* ? And its status of what ?

>+} __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;
>+

So this structure is needed to distinguish between IPV4 and IPV6. Correct ?
Once we have a better understanding we can really assess whether it will
work for our interface or not, or it will require further changes to make it generic
so that it will work for us.

>+struct iscsi_bsg_common_format {
>+	u8 opcode;		/* dword 0 */
>+	u8 subsystem;		/* dword 0 */
>+	u8 port_number;		/* dword 0 */
>+	u8 domain;		/* dword 0 */

What does *port_number* and *domain* indicate ?

>+	u32 timeout;		/* dword 1 */

Is it bsg command time out?

>+	u32 request_length;	/* dword 2 */
>+	u32 rsvd0;		/* dword 3 */

Why *rsvd0* here? Why not at end of struct.

>+	u32    action;

What is expected data here ? So at the app's level what *action*
is supposed to be set to ?

>+	struct ip_address_format gateway;
>+	u32  interface_hndl;

What is expected data here? Why we need *interface_hndl* here.
We also have a *port_number* as struct member.

>+	u32  vlan_priority;
>+	u32  flags;

Again *flags* is supposed to be set to what ?

>+	u8   iscsiname[224];
>+	u8   iscsialias[32];
>+	u32  ip_type;
>+	u32  retry_count;
>+	struct iscsi_ip_addr_record_params ip_params;

Can we add *u32 vendor_data[0]* for vendor specific data?

>+} __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];
>+};

So *value[1]* you mean *value[0]*, just to be consistent ? Also the idea behind
this TLV is for App's to set whatever network param needs to be set or get in one
or multiple shot, can be configured and passed back & forth ? Is that how
you guys envisioned it ?

>+
>+/* 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;

Looking at the implementation, looks like *set_op*  is set to ISCSI_SET_IP_ADDR
for ex, ? Basically not consistent  as outlined in the comment.

>+
>+	/*
>+	 * If SET operation, contains the total number of netparam tlv's
>+	 * in the request payload.
>+	 */
>+	uint8_t		netparam_count;
>+};


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2010-05-10  0:37 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-17 18:06 [PATCH 1/2] RFC: Proposal for BSG Interface Jayamohan Kallickal
2010-03-18 12:55 ` Boaz Harrosh
2010-05-10  0:37 ` Vikas Chaudhary

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.