public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] FC Pass Thru support
@ 2009-03-26 17:33 James Smart
  2009-03-27 14:00 ` Seokmann Ju
  2009-04-15 12:59 ` Christof Schmitt
  0 siblings, 2 replies; 4+ messages in thread
From: James Smart @ 2009-03-26 17:33 UTC (permalink / raw)
  To: linux-scsi


All,

Attached is the ELS/CT pass-thru patch for the FC Transport. The patch
creates a generic framework that lays on top of bsg and the SGIO v4 ioctl
in order to pass transaction requests to LLDD's.

The interface supports the following operations:
  On an fc_host basis:
    Request login to the specified N_Port_ID, creating an fc_rport.
    Request logout of the specified N_Port_ID, deleting an fc_rport
    Send ELS request to specified N_Port_ID w/o requiring a login, and
      wait for ELS response.
    Send CT request to specified N_Port_ID and wait for CT response.
      Login is required, but LLDD is allowed to manage login and decide
      whether it stays in place after the request is satisfied.
    Vendor-Unique request. Allows a LLDD-specific request to be passed
      to the LLDD, and the passing of a response back to the application.
  On an fc_rport basis:
    Send ELS request to nport and wait for ELS response.
    Send CT request to nport and wait for CT response.

The patch also exports several headers from include/scsi such that
they can be available to user-space applications:
  include/scsi/scsi.h
  include/scsi/scsi_netlink.h
  include/scsi/scsi_netlink_fc.h
  include/scsi/scsi_bsg_fc.h

For further information, refer to the last RFC:
http://marc.info/?l=linux-scsi&m=123436574018579&w=2


Hopefully, this still has time to make the 2.6.30 merge window.

Note: Documentation is still spotty and will be added later.

-- james s


 Signed-off-by: James Smart <james.smart@emulex.com>

 ---

 Documentation/scsi/scsi_fc_transport.txt |   14 
 Documentation/scsi/scsi_mid_low_api.txt  |    5 
 drivers/scsi/scsi_transport_fc.c         |  616 ++++++++++++++++++++++++++++++-
 include/Kbuild                           |    1 
 include/scsi/Kbuild                      |    4 
 include/scsi/scsi_bsg_fc.h               |  322 ++++++++++++++++
 include/scsi/scsi_host.h                 |    9 
 include/scsi/scsi_transport_fc.h         |   52 ++
 8 files changed, 1018 insertions(+), 5 deletions(-)


diff -upNr a/Documentation/scsi/scsi_fc_transport.txt b/Documentation/scsi/scsi_fc_transport.txt
--- a/Documentation/scsi/scsi_fc_transport.txt	2009-01-27 09:44:22.000000000 -0500
+++ b/Documentation/scsi/scsi_fc_transport.txt	2009-03-25 16:02:14.000000000 -0400
@@ -1,10 +1,11 @@
                              SCSI FC Tansport
                  =============================================
 
-Date:  4/12/2007
+Date:  11/18/2008
 Kernel Revisions for features:
   rports : <<TBS>>
-  vports : 2.6.22 (? TBD)
+  vports : 2.6.22
+  bsg support : 2.6.30 (?TBD?)
 
 
 Introduction
@@ -15,6 +16,7 @@ The FC transport can be found at:
   drivers/scsi/scsi_transport_fc.c
   include/scsi/scsi_transport_fc.h
   include/scsi/scsi_netlink_fc.h
+  include/scsi/scsi_bsg_fc.h
 
 This file is found at Documentation/scsi/scsi_fc_transport.txt
 
@@ -472,6 +474,14 @@ int
 fc_vport_terminate(struct fc_vport *vport)
 
 
+FC BSG support (CT & ELS passthru, and more)
+========================================================================
+<< To Be Supplied >>
+
+
+
+
+
 Credits
 =======
 The following people have contributed to this document:
diff -upNr a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt
--- a/Documentation/scsi/scsi_mid_low_api.txt	2008-09-23 15:11:57.000000000 -0400
+++ b/Documentation/scsi/scsi_mid_low_api.txt	2009-03-25 10:07:08.000000000 -0400
@@ -1271,6 +1271,11 @@ of interest:
     hostdata[0]  - area reserved for LLD at end of struct Scsi_Host. Size
                    is set by the second argument (named 'xtr_bytes') to
                    scsi_host_alloc() or scsi_register().
+    vendor_id    - a unique value that identifies the vendor supplying
+                   the LLD for the Scsi_Host.  Used most often in validating
+                   vendor-specific message requests.  Value consists of an
+                   identifier type and a vendor-specific value.
+                   See scsi_netlink.h for a description of valid formats.
 
 The scsi_host structure is defined in include/scsi/scsi_host.h
 
diff -upNr a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
--- a/drivers/scsi/scsi_transport_fc.c	2009-01-27 09:44:31.000000000 -0500
+++ b/drivers/scsi/scsi_transport_fc.c	2009-03-25 10:08:46.000000000 -0400
@@ -35,6 +35,7 @@
 #include <linux/netlink.h>
 #include <net/netlink.h>
 #include <scsi/scsi_netlink_fc.h>
+#include <scsi/scsi_bsg_fc.h>
 #include "scsi_priv.h"
 #include "scsi_transport_fc_internal.h"
 
@@ -43,6 +44,10 @@ static void fc_vport_sched_delete(struct
 static int fc_vport_setup(struct Scsi_Host *shost, int channel,
 	struct device *pdev, struct fc_vport_identifiers  *ids,
 	struct fc_vport **vport);
+static int fc_bsg_hostadd(struct Scsi_Host *, struct fc_host_attrs *);
+static int fc_bsg_rportadd(struct Scsi_Host *, struct fc_rport *);
+static void fc_bsg_remove(struct request_queue *);
+static void fc_bsg_goose_queue(struct fc_rport *);
 
 /*
  * Redefine so that we can have same named attributes in the
@@ -411,13 +416,26 @@ static int fc_host_setup(struct transpor
 		return -ENOMEM;
 	}
 
+	fc_bsg_hostadd(shost, fc_host);
+	/* ignore any bsg add error - we just can't do sgio */
+
+	return 0;
+}
+
+static int fc_host_remove(struct transport_container *tc, struct device *dev,
+			 struct device *cdev)
+{
+	struct Scsi_Host *shost = dev_to_shost(dev);
+	struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
+
+	fc_bsg_remove(fc_host->rqst_q);
 	return 0;
 }
 
 static DECLARE_TRANSPORT_CLASS(fc_host_class,
 			       "fc_host",
 			       fc_host_setup,
-			       NULL,
+			       fc_host_remove,
 			       NULL);
 
 /*
@@ -2383,6 +2401,7 @@ fc_rport_final_delete(struct work_struct
 		scsi_flush_work(shost);
 
 	fc_terminate_rport_io(rport);
+
 	/*
 	 * Cancel any outstanding timers. These should really exist
 	 * only when rmmod'ing the LLDD and we're asking for
@@ -2415,6 +2434,8 @@ fc_rport_final_delete(struct work_struct
 	    (i->f->dev_loss_tmo_callbk))
 		i->f->dev_loss_tmo_callbk(rport);
 
+	fc_bsg_remove(rport->rqst_q);
+
 	transport_remove_device(dev);
 	device_del(dev);
 	transport_destroy_device(dev);
@@ -2502,6 +2523,9 @@ fc_rport_create(struct Scsi_Host *shost,
 	transport_add_device(dev);
 	transport_configure_device(dev);
 
+	fc_bsg_rportadd(shost, rport);
+	/* ignore any bsg add error - we just can't do sgio */
+
 	if (rport->roles & FC_PORT_ROLE_FCP_TARGET) {
 		/* initiate a scan of the target */
 		rport->flags |= FC_RPORT_SCAN_PENDING;
@@ -2666,6 +2690,8 @@ fc_remote_port_add(struct Scsi_Host *sho
 					spin_unlock_irqrestore(shost->host_lock,
 							flags);
 
+				fc_bsg_goose_queue(rport);
+
 				return rport;
 			}
 		}
@@ -3351,6 +3377,594 @@ fc_vport_sched_delete(struct work_struct
 }
 
 
+/*
+ * BSG support
+ */
+
+
+/**
+ * fc_destroy_bsgjob - routine to teardown/delete a fc bsg job
+ * @job:	fc_bsg_job that is to be torn down
+ */
+static void
+fc_destroy_bsgjob(struct fc_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);
+}
+
+
+/**
+ * fc_bsg_jobdone - completion routine for bsg requests that the LLD has
+ *                  completed
+ * @job:	fc_bsg_job that is complete
+ */
+static void
+fc_bsg_jobdone(struct fc_bsg_job *job)
+{
+	struct request *req = job->req;
+	struct request *rsp = req->next_rq;
+	unsigned long flags;
+	unsigned rsp_len = 0, req_len = blk_rq_bytes(req);
+	int err;
+
+	spin_lock_irqsave(&job->job_lock, flags);
+	job->state_flags |= FC_RQST_STATE_DONE;
+	job->ref_cnt--;
+	spin_unlock_irqrestore(&job->job_lock, flags);
+
+	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->data_len = 0;
+
+	if (rsp) {
+		rsp_len = blk_rq_bytes(rsp);
+		BUG_ON(job->reply->reply_payload_rcv_len > rsp_len);
+		/* set reply (bidi) residual */
+		rsp->data_len = (rsp_len - job->reply->reply_payload_rcv_len);
+	}
+
+	blk_end_bidi_request(req, err, req_len, rsp_len);
+
+	fc_destroy_bsgjob(job);
+}
+
+
+/**
+ * fc_bsg_job_timeout - handler for when a bsg request timesout
+ * @req:	request that timed out
+ */
+static enum blk_eh_timer_return
+fc_bsg_job_timeout(struct request *req)
+{
+	struct fc_bsg_job *job = (void *) req->special;
+	struct Scsi_Host *shost = job->shost;
+	struct fc_internal *i = to_fc_internal(shost->transportt);
+	unsigned long flags;
+	int err = 0, done = 0;
+
+	if (job->rport && job->rport->port_state == FC_PORTSTATE_BLOCKED)
+		return BLK_EH_RESET_TIMER;
+
+	spin_lock_irqsave(&job->job_lock, flags);
+	if (job->state_flags & FC_RQST_STATE_DONE)
+		done = 1;
+	else
+		job->ref_cnt++;
+	spin_unlock_irqrestore(&job->job_lock, flags);
+
+	if (!done && i->f->bsg_timeout) {
+		/* call LLDD to abort the i/o as it has timed out */
+		err = i->f->bsg_timeout(job);
+		if (err)
+			printk(KERN_ERR "ERROR: FC BSG request timeout - LLD "
+				"abort failed with status %d\n", err);
+	}
+
+	if (!done) {
+		spin_lock_irqsave(&job->job_lock, flags);
+		job->ref_cnt--;
+		spin_unlock_irqrestore(&job->job_lock, flags);
+		fc_destroy_bsgjob(job);
+	}
+
+	/* the blk_end_sync_io() doesn't check the error */
+	return BLK_EH_HANDLED;
+}
+
+
+
+static int
+fc_bsg_map_buffer(struct fc_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 = req->data_len;
+	return 0;
+}
+
+
+/**
+ * fc_req_to_bsgjob - Allocate/create the fc_bsg_job structure for the
+ *                   bsg request
+ * @shost:	SCSI Host corresponding to the bsg object
+ * @rport:	(optional) FC Remote Port corresponding to the bsg object
+ * @req:	BSG request that needs a job structure
+ */
+static int
+fc_req_to_bsgjob(struct Scsi_Host *shost, struct fc_rport *rport,
+	struct request *req)
+{
+	struct fc_internal *i = to_fc_internal(shost->transportt);
+	struct request *rsp = req->next_rq;
+	struct fc_bsg_job *job;
+	int ret;
+
+	BUG_ON(req->special);
+
+	job = kzalloc(sizeof(struct fc_bsg_job) + i->f->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 fc 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->rport = rport;
+	job->req = req;
+	if (i->f->dd_bsg_size)
+		job->dd_data = (void *)&job[1];
+	spin_lock_init(&job->job_lock);
+	job->request = (struct fc_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 = fc_bsg_map_buffer(&job->request_payload, req);
+		if (ret)
+			goto failjob_rls_job;
+	}
+	if (rsp && rsp->bio) {
+		ret = fc_bsg_map_buffer(&job->reply_payload, rsp);
+		if (ret)
+			goto failjob_rls_rqst_payload;
+	}
+	job->job_done = fc_bsg_jobdone;
+	if (rport)
+		job->dev = &rport->dev;
+	else
+		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 fc_dispatch_result {
+	FC_DISPATCH_BREAK,	/* on return, q is locked, break from q loop */
+	FC_DISPATCH_LOCKED,	/* on return, q is locked, continue on */
+	FC_DISPATCH_UNLOCKED,	/* on return, q is unlocked, continue on */
+};
+
+
+/**
+ * fc_bsg_host_dispatch - process fc host bsg requests and dispatch to LLDD
+ * @shost:	scsi host rport attached to
+ * @job:	bsg job to be processed
+ */
+static enum fc_dispatch_result
+fc_bsg_host_dispatch(struct request_queue *q, struct Scsi_Host *shost,
+			 struct fc_bsg_job *job)
+{
+	struct fc_internal *i = to_fc_internal(shost->transportt);
+	int cmdlen = sizeof(uint32_t);	/* start with length of msgcode */
+	int ret;
+
+	/* Validate the host command */
+	switch (job->request->msgcode) {
+	case FC_BSG_HST_ADD_RPORT:
+		cmdlen += sizeof(struct fc_bsg_host_add_rport);
+		break;
+
+	case FC_BSG_HST_DEL_RPORT:
+		cmdlen += sizeof(struct fc_bsg_host_del_rport);
+		break;
+
+	case FC_BSG_HST_ELS_NOLOGIN:
+		cmdlen += sizeof(struct fc_bsg_host_els);
+		/* there better be a xmt and rcv payloads */
+		if ((!job->request_payload.payload_len) ||
+		    (!job->reply_payload.payload_len)) {
+			ret = -EINVAL;
+			goto fail_host_msg;
+		}
+		break;
+
+	case FC_BSG_HST_CT:
+		cmdlen += sizeof(struct fc_bsg_host_ct);
+		/* there better be xmt and rcv payloads */
+		if ((!job->request_payload.payload_len) ||
+		    (!job->reply_payload.payload_len)) {
+			ret = -EINVAL;
+			goto fail_host_msg;
+		}
+		break;
+
+	case FC_BSG_HST_VENDOR:
+		cmdlen += sizeof(struct fc_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->f->bsg_request(job);
+	if (!ret)
+		return FC_DISPATCH_UNLOCKED;
+
+fail_host_msg:
+	/* return the errno failure code as the only status */
+	BUG_ON(job->reply_len < sizeof(uint32_t));
+	job->reply->result = ret;
+	job->reply_len = sizeof(uint32_t);
+	fc_bsg_jobdone(job);
+	return FC_DISPATCH_UNLOCKED;
+}
+
+
+/*
+ * fc_bsg_goose_queue - restart rport queue in case it was stopped
+ * @rport:	rport to be restarted
+ */
+static void
+fc_bsg_goose_queue(struct fc_rport *rport)
+{
+	int flagset;
+
+	if (!rport->rqst_q)
+		return;
+
+	get_device(&rport->dev);
+
+	spin_lock(rport->rqst_q->queue_lock);
+	flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags) &&
+		  !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags);
+	if (flagset)
+		queue_flag_set(QUEUE_FLAG_REENTER, rport->rqst_q);
+	__blk_run_queue(rport->rqst_q);
+	if (flagset)
+		queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q);
+	spin_unlock(rport->rqst_q->queue_lock);
+
+	put_device(&rport->dev);
+}
+
+
+/**
+ * fc_bsg_rport_dispatch - process rport bsg requests and dispatch to LLDD
+ * @shost:	scsi host rport attached to
+ * @rport:	rport request destined to
+ * @job:	bsg job to be processed
+ */
+static enum fc_dispatch_result
+fc_bsg_rport_dispatch(struct request_queue *q, struct Scsi_Host *shost,
+			 struct fc_rport *rport, struct fc_bsg_job *job)
+{
+	struct fc_internal *i = to_fc_internal(shost->transportt);
+	int cmdlen = sizeof(uint32_t);	/* start with length of msgcode */
+	int ret;
+
+	/* Validate the rport command */
+	switch (job->request->msgcode) {
+	case FC_BSG_RPT_ELS:
+		cmdlen += sizeof(struct fc_bsg_rport_els);
+		goto check_bidi;
+
+	case FC_BSG_RPT_CT:
+		cmdlen += sizeof(struct fc_bsg_rport_ct);
+check_bidi:
+		/* there better be xmt and rcv payloads */
+		if ((!job->request_payload.payload_len) ||
+		    (!job->reply_payload.payload_len)) {
+			ret = -EINVAL;
+			goto fail_rport_msg;
+		}
+		break;
+	default:
+		ret = -EBADR;
+		goto fail_rport_msg;
+	}
+
+	/* check if we really have all the request data needed */
+	if (job->request_len < cmdlen) {
+		ret = -ENOMSG;
+		goto fail_rport_msg;
+	}
+
+	ret = i->f->bsg_request(job);
+	if (!ret)
+		return FC_DISPATCH_UNLOCKED;
+
+fail_rport_msg:
+	/* return the errno failure code as the only status */
+	BUG_ON(job->reply_len < sizeof(uint32_t));
+	job->reply->result = ret;
+	job->reply_len = sizeof(uint32_t);
+	fc_bsg_jobdone(job);
+	return FC_DISPATCH_UNLOCKED;
+}
+
+
+/**
+ * fc_bsg_request_handler - generic handler for bsg requests
+ * @q:		request queue to manage
+ * @shost:	Scsi_Host related to the bsg object
+ * @rport:	FC remote port related to the bsg object (optional)
+ * @dev:	device structure for bsg object
+ */
+static void
+fc_bsg_request_handler(struct request_queue *q, struct Scsi_Host *shost,
+		       struct fc_rport *rport, struct device *dev)
+{
+	struct request *req;
+	struct fc_bsg_job *job;
+	enum fc_dispatch_result ret;
+
+	if (!get_device(dev))
+		return;
+
+	while (!blk_queue_plugged(q)) {
+		req = elv_next_request(q);
+		if (!req)
+			break;
+
+		if (rport && (rport->port_state == FC_PORTSTATE_BLOCKED))
+				break;
+
+		blkdev_dequeue_request(req);
+
+		if (rport && (rport->port_state != FC_PORTSTATE_ONLINE)) {
+			req->errors = -ENXIO;
+			spin_unlock_irq(q->queue_lock);
+			blk_end_request(req, -ENXIO, blk_rq_bytes(req));
+			spin_lock_irq(q->queue_lock);
+			continue;
+		}
+
+		spin_unlock_irq(q->queue_lock);
+
+		ret = fc_req_to_bsgjob(shost, rport, req);
+		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->result = -ENOMSG;
+			job->reply_len = sizeof(uint32_t);
+			fc_bsg_jobdone(job);
+			spin_lock_irq(q->queue_lock);
+			continue;
+		}
+
+		/* the dispatch routines will unlock the queue_lock */
+		if (rport)
+			ret = fc_bsg_rport_dispatch(q, shost, rport, job);
+		else
+			ret = fc_bsg_host_dispatch(q, shost, job);
+
+		/* did dispatcher hit state that can't process any more */
+		if (ret == FC_DISPATCH_BREAK)
+			break;
+
+		/* did dispatcher had released the lock */
+		if (ret == FC_DISPATCH_UNLOCKED)
+			spin_lock_irq(q->queue_lock);
+	}
+
+	spin_unlock_irq(q->queue_lock);
+	put_device(dev);
+	spin_lock_irq(q->queue_lock);
+}
+
+
+/**
+ * fc_bsg_host_handler - handler for bsg requests for a fc host
+ * @q:		fc host request queue
+ */
+static void
+fc_bsg_host_handler(struct request_queue *q)
+{
+	struct Scsi_Host *shost = q->queuedata;
+
+	fc_bsg_request_handler(q, shost, NULL, &shost->shost_gendev);
+}
+
+
+/**
+ * fc_bsg_rport_handler - handler for bsg requests for a fc rport
+ * @q:		rport request queue
+ */
+static void
+fc_bsg_rport_handler(struct request_queue *q)
+{
+	struct fc_rport *rport = q->queuedata;
+	struct Scsi_Host *shost = rport_to_shost(rport);
+
+	fc_bsg_request_handler(q, shost, rport, &rport->dev);
+}
+
+
+/**
+ * fc_bsg_hostadd - Create and add the bsg hooks so we can receive requests
+ * @shost:	shost for fc_host
+ * @fc_host:	fc_host adding the structures to
+ */
+static int
+fc_bsg_hostadd(struct Scsi_Host *shost, struct fc_host_attrs *fc_host)
+{
+	struct device *dev = &shost->shost_gendev;
+	struct fc_internal *i = to_fc_internal(shost->transportt);
+	struct request_queue *q;
+	int err;
+	char bsg_name[BUS_ID_SIZE]; /*20*/
+
+	fc_host->rqst_q = NULL;
+
+	if (!i->f->bsg_request)
+		return -ENOTSUPP;
+
+	snprintf(bsg_name, sizeof(bsg_name),
+		 "fc_host%d", shost->host_no);
+
+	q = __scsi_alloc_queue(shost, fc_bsg_host_handler);
+	if (!q) {
+		printk(KERN_ERR "fc_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_rq_timed_out(q, fc_bsg_job_timeout);
+	blk_queue_rq_timeout(q, FC_DEFAULT_BSG_TIMEOUT);
+
+	err = bsg_register_queue(q, dev, bsg_name, NULL);
+	if (err) {
+		printk(KERN_ERR "fc_host%d: bsg interface failed to "
+				"initialize - register queue\n",
+				shost->host_no);
+		blk_cleanup_queue(q);
+		return err;
+	}
+
+	fc_host->rqst_q = q;
+	return 0;
+}
+
+
+/**
+ * fc_bsg_rportadd - Create and add the bsg hooks so we can receive requests
+ * @shost:	shost that rport is attached to
+ * @rport:	rport that the bsg hooks are being attached to
+ */
+static int
+fc_bsg_rportadd(struct Scsi_Host *shost, struct fc_rport *rport)
+{
+	struct device *dev = &rport->dev;
+	struct fc_internal *i = to_fc_internal(shost->transportt);
+	struct request_queue *q;
+	int err;
+
+	rport->rqst_q = NULL;
+
+	if (!i->f->bsg_request)
+		return -ENOTSUPP;
+
+	q = __scsi_alloc_queue(shost, fc_bsg_rport_handler);
+	if (!q) {
+		printk(KERN_ERR "%s: bsg interface failed to "
+				"initialize - no request queue\n",
+				 dev->bus_id);
+		return -ENOMEM;
+	}
+
+	q->queuedata = rport;
+	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
+	blk_queue_rq_timed_out(q, fc_bsg_job_timeout);
+	blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
+
+	err = bsg_register_queue(q, dev, NULL, NULL);
+	if (err) {
+		printk(KERN_ERR "%s: bsg interface failed to "
+				"initialize - register queue\n",
+				 dev->bus_id);
+		blk_cleanup_queue(q);
+		return err;
+	}
+
+	rport->rqst_q = q;
+	return 0;
+}
+
+
+/**
+ * fc_bsg_remove - Deletes the bsg hooks on fchosts/rports
+ * @q:	the request_queue that is to be torn down.
+ */
+static void
+fc_bsg_remove(struct request_queue *q)
+{
+	if (q) {
+		bsg_unregister_queue(q);
+		blk_cleanup_queue(q);
+	}
+}
+
+
 /* Original Author:  Martin Hicks */
 MODULE_AUTHOR("James Smart");
 MODULE_DESCRIPTION("FC Transport Attributes");
diff -upNr a/include/Kbuild b/include/Kbuild
--- a/include/Kbuild	2009-03-25 10:24:22.000000000 -0400
+++ b/include/Kbuild	2009-03-25 10:24:48.000000000 -0400
@@ -8,3 +8,4 @@ header-y += mtd/
 header-y += rdma/
 header-y += video/
 header-y += drm/
+header-y += scsi/
diff -upNr a/include/scsi/Kbuild b/include/scsi/Kbuild
--- a/include/scsi/Kbuild	1969-12-31 19:00:00.000000000 -0500
+++ b/include/scsi/Kbuild	2009-03-25 10:21:50.000000000 -0400
@@ -0,0 +1,4 @@
+header-y += scsi.h
+header-y += scsi_netlink.h
+header-y += scsi_netlink_fc.h
+header-y += scsi_bsg_fc.h
diff -upNr a/include/scsi/scsi_bsg_fc.h b/include/scsi/scsi_bsg_fc.h
--- a/include/scsi/scsi_bsg_fc.h	1969-12-31 19:00:00.000000000 -0500
+++ b/include/scsi/scsi_bsg_fc.h	2009-03-25 10:07:08.000000000 -0400
@@ -0,0 +1,322 @@
+/*
+ *  FC Transport BSG Interface
+ *
+ *  Copyright (C) 2008   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_FC_H
+#define SCSI_BSG_FC_H
+
+/*
+ * This file intended to be included by both kernel and user space
+ */
+
+#include <scsi/scsi.h>
+
+/*
+ * FC Transport SGIO v4 BSG Message Support
+ */
+
+/* Default BSG request timeout (in seconds) */
+#define FC_DEFAULT_BSG_TIMEOUT		(10 * HZ)
+
+
+/*
+ * Request Message Codes supported by the FC Transport
+ */
+
+/* define the class masks for the message codes */
+#define FC_BSG_CLS_MASK		0xF0000000	/* find object class */
+#define FC_BSG_HST_MASK		0x80000000	/* fc host class */
+#define FC_BSG_RPT_MASK		0x40000000	/* fc rport class */
+
+	/* fc_host Message Codes */
+#define FC_BSG_HST_ADD_RPORT		(FC_BSG_HST_MASK | 0x00000001)
+#define FC_BSG_HST_DEL_RPORT		(FC_BSG_HST_MASK | 0x00000002)
+#define FC_BSG_HST_ELS_NOLOGIN		(FC_BSG_HST_MASK | 0x00000003)
+#define FC_BSG_HST_CT			(FC_BSG_HST_MASK | 0x00000004)
+#define FC_BSG_HST_VENDOR		(FC_BSG_HST_MASK | 0x000000FF)
+
+	/* fc_rport Message Codes */
+#define FC_BSG_RPT_ELS			(FC_BSG_RPT_MASK | 0x00000001)
+#define FC_BSG_RPT_CT			(FC_BSG_RPT_MASK | 0x00000002)
+
+
+
+/*
+ * FC Address Identifiers in Message Structures :
+ *
+ *   Whenever a command payload contains a FC Address Identifier
+ *   (aka port_id), the value is effectively in big-endian
+ *   order, thus the array elements are decoded as follows:
+ *     element [0] is bits 23:16 of the FC Address Identifier
+ *     element [1] is bits 15:8 of the FC Address Identifier
+ *     element [2] is bits 7:0 of the FC Address Identifier
+ */
+
+
+/*
+ * FC Host Messages
+ */
+
+/* FC_BSG_HST_ADDR_PORT : */
+
+/* Request:
+ * This message requests the FC host to login to the remote port
+ * at the specified N_Port_Id.  The remote port is to be enumerated
+ * with the transport upon completion of the login.
+ */
+struct fc_bsg_host_add_rport {
+	uint8_t		reserved;
+
+	/* FC Address Identier of the remote port to login to */
+	uint8_t		port_id[3];
+};
+
+/* Response:
+ * There is no additional response data - fc_bsg_reply->result is sufficient
+ */
+
+
+/* FC_BSG_HST_DEL_RPORT : */
+
+/* Request:
+ * This message requests the FC host to remove an enumerated
+ * remote port and to terminate the login to it.
+ *
+ * Note: The driver is free to reject this request if it desires to
+ * remain logged in with the remote port.
+ */
+struct fc_bsg_host_del_rport {
+	uint8_t		reserved;
+
+	/* FC Address Identier of the remote port to logout of */
+	uint8_t		port_id[3];
+};
+
+/* Response:
+ * There is no additional response data - fc_bsg_reply->result is sufficient
+ */
+
+
+/* FC_BSG_HST_ELS_NOLOGIN : */
+
+/* Request:
+ * This message requests the FC_Host to send an ELS to a specific
+ * N_Port_ID. The host does not need to log into the remote port,
+ * nor does it need to enumerate the rport for further traffic
+ * (although, the FC host is free to do so if it desires).
+ */
+struct fc_bsg_host_els {
+	/*
+	 * ELS Command Code being sent (must be the same as byte 0
+	 * of the payload)
+	 */
+	uint8_t 	command_code;
+
+	/* FC Address Identier of the remote port to send the ELS to */
+	uint8_t		port_id[3];
+};
+
+/* Response:
+ */
+/* fc_bsg_ctels_reply->status values */
+#define FC_CTELS_STATUS_OK	0x00000000
+#define FC_CTELS_STATUS_REJECT	0x00000001
+#define FC_CTELS_STATUS_P_RJT	0x00000002
+#define FC_CTELS_STATUS_F_RJT	0x00000003
+#define FC_CTELS_STATUS_P_BSY	0x00000004
+#define FC_CTELS_STATUS_F_BSY	0x00000006
+struct fc_bsg_ctels_reply {
+	/*
+	 * Note: An ELS LS_RJT may be reported in 2 ways:
+	 *  a) A status of FC_CTELS_STATUS_OK is returned. The caller
+	 *     is to look into the ELS receive payload to determine
+	 *     LS_ACC or LS_RJT (by contents of word 0). The reject
+	 *     data will be in word 1.
+	 *  b) A status of FC_CTELS_STATUS_REJECT is returned, The
+	 *     rjt_data field will contain valid data.
+	 *
+	 * Note: ELS LS_ACC is determined by an FC_CTELS_STATUS_OK, and
+	 *   the receive payload word 0 indicates LS_ACC
+	 *   (e.g. value is 0x02xxxxxx).
+	 *
+	 * Note: Similarly, a CT Reject may be reported in 2 ways:
+	 *  a) A status of FC_CTELS_STATUS_OK is returned. The caller
+	 *     is to look into the CT receive payload to determine
+	 *     Accept or Reject (by contents of word 2). The reject
+	 *     data will be in word 3.
+	 *  b) A status of FC_CTELS_STATUS_REJECT is returned, The
+	 *     rjt_data field will contain valid data.
+	 *
+	 * Note: x_RJT/BSY status will indicae that the rjt_data field
+	 *   is valid and contains the reason/explanation values.
+	 */
+	uint32_t	status;		/* See FC_CTELS_STATUS_xxx */
+
+	/* valid if status is not FC_CTELS_STATUS_OK */
+	struct	{
+		uint8_t	action;		/* fragment_id for CT REJECT */
+		uint8_t	reason_code;
+		uint8_t	reason_explanation;
+		uint8_t	vendor_unique;
+	} rjt_data;
+};
+
+
+/* FC_BSG_HST_CT : */
+
+/* Request:
+ * This message requests that a CT Request be performed with the
+ * indicated N_Port_ID. The driver is responsible for logging in with
+ * the fabric and/or N_Port_ID, etc as per FC rules. This request does
+ * not mandate that the driver must enumerate the destination in the
+ * transport. The driver is allowed to decide whether to enumerate it,
+ * and whether to tear it down after the request.
+ */
+struct fc_bsg_host_ct {
+	uint8_t		reserved;
+
+	/* FC Address Identier of the remote port to send the ELS to */
+	uint8_t		port_id[3];
+
+	/*
+	 * We need words 0-2 of the generic preamble for the LLD's
+	 */
+	uint32_t	preamble_word0;	/* revision & IN_ID */
+	uint32_t	preamble_word1;	/* GS_Type, GS_SubType, Options, Rsvd */
+	uint32_t	preamble_word2;	/* Cmd Code, Max Size */
+
+};
+/* Response:
+ *
+ * The reply structure is an fc_bsg_ctels_reply structure
+ */
+
+
+/* FC_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 fc_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 fc_bsg_host_vendor_reply {
+	/* start of vendor response area */
+	uint32_t vendor_rsp[0];
+};
+
+
+
+/*
+ * FC Remote Port Messages
+ */
+
+/* FC_BSG_RPT_ELS : */
+
+/* Request:
+ * This message requests that an ELS be performed with the rport.
+ */
+struct fc_bsg_rport_els {
+	/*
+	 * ELS Command Code being sent (must be the same as
+	 * byte 0 of the payload)
+	 */
+	uint8_t els_code;
+};
+
+/* Response:
+ *
+ * The reply structure is an fc_bsg_ctels_reply structure
+ */
+
+
+/* FC_BSG_RPT_CT : */
+
+/* Request:
+ * This message requests that a CT Request be performed with the rport.
+ */
+struct fc_bsg_rport_ct {
+	/*
+	 * We need words 0-2 of the generic preamble for the LLD's
+	 */
+	uint32_t	preamble_word0;	/* revision & IN_ID */
+	uint32_t	preamble_word1;	/* GS_Type, GS_SubType, Options, Rsvd */
+	uint32_t	preamble_word2;	/* Cmd Code, Max Size */
+};
+/* Response:
+ *
+ * The reply structure is an fc_bsg_ctels_reply structure
+ */
+
+
+
+
+/* request (CDB) structure of the sg_io_v4 */
+struct fc_bsg_request {
+	uint32_t msgcode;
+	union {
+		struct fc_bsg_host_add_rport	h_addrport;
+		struct fc_bsg_host_del_rport	h_delrport;
+		struct fc_bsg_host_els		h_els;
+		struct fc_bsg_host_ct		h_ct;
+		struct fc_bsg_host_vendor	h_vendor;
+
+		struct fc_bsg_rport_els		r_els;
+		struct fc_bsg_rport_ct		r_ct;
+	} rqst_data;
+};
+
+
+/* response (request sense data) structure of the sg_io_v4 */
+struct fc_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 fc_bsg_host_vendor_reply		vendor_reply;
+
+		struct fc_bsg_ctels_reply		ctels_reply;
+	} reply_data;
+};
+
+
+#endif /* SCSI_BSG_FC_H */
+
diff -upNr a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
--- a/include/scsi/scsi_host.h	2008-10-18 10:32:54.000000000 -0400
+++ b/include/scsi/scsi_host.h	2009-03-25 10:07:08.000000000 -0400
@@ -478,6 +478,15 @@ struct scsi_host_template {
 	 * module_init/module_exit.
 	 */
 	struct list_head legacy_hosts;
+
+	/*
+	 * Vendor Identifier associated with the host
+	 *
+	 * Note: When specifying vendor_id, be sure to read the
+	 *   Vendor Type and ID formatting requirements specified in
+	 *   scsi_netlink.h
+	 */
+	u64 vendor_id;
 };
 
 /*
diff -upNr a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
--- a/include/scsi/scsi_transport_fc.h	2009-01-27 09:44:40.000000000 -0500
+++ b/include/scsi/scsi_transport_fc.h	2009-03-25 10:07:08.000000000 -0400
@@ -33,7 +33,6 @@
 
 struct scsi_transport_template;
 
-
 /*
  * FC Port definitions - Following FC HBAAPI guidelines
  *
@@ -352,6 +351,7 @@ struct fc_rport {	/* aka fc_starget_attr
  	struct delayed_work fail_io_work;
  	struct work_struct stgt_delete_work;
 	struct work_struct rport_delete_work;
+	struct request_queue *rqst_q;	/* bsg support */
 } __attribute__((aligned(sizeof(unsigned long))));
 
 /* bit field values for struct fc_rport "flags" field: */
@@ -514,6 +514,9 @@ struct fc_host_attrs {
 	struct workqueue_struct *work_q;
 	char devloss_work_q_name[20];
 	struct workqueue_struct *devloss_work_q;
+
+	/* bsg support */
+	struct request_queue *rqst_q;
 };
 
 #define shost_to_fc_host(x) \
@@ -579,6 +582,47 @@ struct fc_host_attrs {
 	(((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q)
 
 
+struct fc_bsg_buffer {
+	unsigned int payload_len;
+	int sg_cnt;
+	struct scatterlist *sg_list;
+};
+
+/* Values for fc_bsg_job->state_flags (bitflags) */
+#define FC_RQST_STATE_INPROGRESS	0
+#define FC_RQST_STATE_DONE		1
+
+struct fc_bsg_job {
+	struct Scsi_Host *shost;
+	struct fc_rport *rport;
+	struct device *dev;
+	struct request *req;
+	spinlock_t job_lock;
+	unsigned int state_flags;
+	unsigned int ref_cnt;
+	void (*job_done)(struct fc_bsg_job *);
+
+	struct fc_bsg_request *request;
+	struct fc_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 fc_bsg_buffer request_payload;
+	struct fc_bsg_buffer reply_payload;
+
+	void *dd_data;			/* Used for driver-specific storage */
+};
+
+
 /* The functions by which the transport class and the driver communicate */
 struct fc_function_template {
 	void    (*get_rport_dev_loss_tmo)(struct fc_rport *);
@@ -614,9 +658,14 @@ struct fc_function_template {
 	int     (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
 	int     (* it_nexus_response)(struct Scsi_Host *, u64, int);
 
+	/* bsg support */
+	int	(*bsg_request)(struct fc_bsg_job *);
+	int	(*bsg_timeout)(struct fc_bsg_job *);
+
 	/* allocation lengths for host-specific data */
 	u32	 			dd_fcrport_size;
 	u32	 			dd_fcvport_size;
+	u32				dd_bsg_size;
 
 	/*
 	 * The driver sets these to tell the transport class it
@@ -737,7 +786,6 @@ fc_vport_set_state(struct fc_vport *vpor
 	vport->vport_state = new_state;
 }
 
-
 struct scsi_transport_template *fc_attach_transport(
 			struct fc_function_template *);
 void fc_release_transport(struct scsi_transport_template *);



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

* Re: [PATCH] FC Pass Thru support
  2009-03-26 17:33 [PATCH] FC Pass Thru support James Smart
@ 2009-03-27 14:00 ` Seokmann Ju
  2009-04-15 12:59 ` Christof Schmitt
  1 sibling, 0 replies; 4+ messages in thread
From: Seokmann Ju @ 2009-03-27 14:00 UTC (permalink / raw)
  To: James.Smart@Emulex.Com; +Cc: linux-scsi@vger.kernel.org


On Mar 26, 2009, at 10:33 AM, James Smart wrote:

>
> All,
>
> Attached is the ELS/CT pass-thru patch for the FC Transport. The patch
> creates a generic framework that lays on top of bsg and the SGIO v4  
> ioctl
> in order to pass transaction requests to LLDD's.
Thanks for the updated patch.
I'm working on the LLD for full support.

>
>
> The interface supports the following operations:
>  On an fc_host basis:
>    Request login to the specified N_Port_ID, creating an fc_rport.
>    Request logout of the specified N_Port_ID, deleting an fc_rport
>    Send ELS request to specified N_Port_ID w/o requiring a login, and
>      wait for ELS response.
>    Send CT request to specified N_Port_ID and wait for CT response.
>      Login is required, but LLDD is allowed to manage login and decide
>      whether it stays in place after the request is satisfied.
>    Vendor-Unique request. Allows a LLDD-specific request to be passed
>      to the LLDD, and the passing of a response back to the  
> application.
>  On an fc_rport basis:
>    Send ELS request to nport and wait for ELS response.
>    Send CT request to nport and wait for CT response.
>
> The patch also exports several headers from include/scsi such that
> they can be available to user-space applications:
>  include/scsi/scsi.h
>  include/scsi/scsi_netlink.h
>  include/scsi/scsi_netlink_fc.h
>  include/scsi/scsi_bsg_fc.h
>
> For further information, refer to the last RFC:
> http://marc.info/?l=linux-scsi&m=123436574018579&w=2
>
>
> Hopefully, this still has time to make the 2.6.30 merge window.
Yes, I also would like to see this on 2.6.30.

Thank you,
Seokmann

>
>
> Note: Documentation is still spotty and will be added later.
>
> -- james s
>
>
> Signed-off-by: James Smart <james.smart@emulex.com>
>
> ---
>
> Documentation/scsi/scsi_fc_transport.txt |   14
> Documentation/scsi/scsi_mid_low_api.txt  |    5
> drivers/scsi/scsi_transport_fc.c         |  616 +++++++++++++++++++++ 
> +++++++++-
> include/Kbuild                           |    1
> include/scsi/Kbuild                      |    4
> include/scsi/scsi_bsg_fc.h               |  322 ++++++++++++++++
> include/scsi/scsi_host.h                 |    9
> include/scsi/scsi_transport_fc.h         |   52 ++
> 8 files changed, 1018 insertions(+), 5 deletions(-)
>
>
> diff -upNr a/Documentation/scsi/scsi_fc_transport.txt b/ 
> Documentation/scsi/scsi_fc_transport.txt
> --- a/Documentation/scsi/scsi_fc_transport.txt  2009-01-27  
> 09:44:22.000000000 -0500
> +++ b/Documentation/scsi/scsi_fc_transport.txt  2009-03-25  
> 16:02:14.000000000 -0400
> @@ -1,10 +1,11 @@
>                              SCSI FC Tansport
>                  =============================================
>
> -Date:  4/12/2007
> +Date:  11/18/2008
> Kernel Revisions for features:
>   rports : <<TBS>>
> -  vports : 2.6.22 (? TBD)
> +  vports : 2.6.22
> +  bsg support : 2.6.30 (?TBD?)
>
>
> Introduction
> @@ -15,6 +16,7 @@ The FC transport can be found at:
>   drivers/scsi/scsi_transport_fc.c
>   include/scsi/scsi_transport_fc.h
>   include/scsi/scsi_netlink_fc.h
> +  include/scsi/scsi_bsg_fc.h
>
> This file is found at Documentation/scsi/scsi_fc_transport.txt
>
> @@ -472,6 +474,14 @@ int
> fc_vport_terminate(struct fc_vport *vport)
>
>
> +FC BSG support (CT & ELS passthru, and more)
> + 
> = 
> = 
> ======================================================================
> +<< To Be Supplied >>
> +
> +
> +
> +
> +
> Credits
> =======
> The following people have contributed to this document:
> diff -upNr a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/ 
> scsi/scsi_mid_low_api.txt
> --- a/Documentation/scsi/scsi_mid_low_api.txt   2008-09-23  
> 15:11:57.000000000 -0400
> +++ b/Documentation/scsi/scsi_mid_low_api.txt   2009-03-25  
> 10:07:08.000000000 -0400
> @@ -1271,6 +1271,11 @@ of interest:
>     hostdata[0]  - area reserved for LLD at end of struct Scsi_Host.  
> Size
>                    is set by the second argument (named 'xtr_bytes')  
> to
>                    scsi_host_alloc() or scsi_register().
> +    vendor_id    - a unique value that identifies the vendor  
> supplying
> +                   the LLD for the Scsi_Host.  Used most often in  
> validating
> +                   vendor-specific message requests.  Value  
> consists of an
> +                   identifier type and a vendor-specific value.
> +                   See scsi_netlink.h for a description of valid  
> formats.
>
> The scsi_host structure is defined in include/scsi/scsi_host.h
>
> diff -upNr a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/ 
> scsi_transport_fc.c
> --- a/drivers/scsi/scsi_transport_fc.c  2009-01-27  
> 09:44:31.000000000 -0500
> +++ b/drivers/scsi/scsi_transport_fc.c  2009-03-25  
> 10:08:46.000000000 -0400
> @@ -35,6 +35,7 @@
> #include <linux/netlink.h>
> #include <net/netlink.h>
> #include <scsi/scsi_netlink_fc.h>
> +#include <scsi/scsi_bsg_fc.h>
> #include "scsi_priv.h"
> #include "scsi_transport_fc_internal.h"
>
> @@ -43,6 +44,10 @@ static void fc_vport_sched_delete(struct
> static int fc_vport_setup(struct Scsi_Host *shost, int channel,
>        struct device *pdev, struct fc_vport_identifiers  *ids,
>        struct fc_vport **vport);
> +static int fc_bsg_hostadd(struct Scsi_Host *, struct fc_host_attrs  
> *);
> +static int fc_bsg_rportadd(struct Scsi_Host *, struct fc_rport *);
> +static void fc_bsg_remove(struct request_queue *);
> +static void fc_bsg_goose_queue(struct fc_rport *);
>
> /*
>  * Redefine so that we can have same named attributes in the
> @@ -411,13 +416,26 @@ static int fc_host_setup(struct transpor
>                return -ENOMEM;
>        }
>
> +       fc_bsg_hostadd(shost, fc_host);
> +       /* ignore any bsg add error - we just can't do sgio */
> +
> +       return 0;
> +}
> +
> +static int fc_host_remove(struct transport_container *tc, struct  
> device *dev,
> +                        struct device *cdev)
> +{
> +       struct Scsi_Host *shost = dev_to_shost(dev);
> +       struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
> +
> +       fc_bsg_remove(fc_host->rqst_q);
>        return 0;
> }
>
> static DECLARE_TRANSPORT_CLASS(fc_host_class,
>                               "fc_host",
>                               fc_host_setup,
> -                              NULL,
> +                              fc_host_remove,
>                               NULL);
>
> /*
> @@ -2383,6 +2401,7 @@ fc_rport_final_delete(struct work_struct
>                scsi_flush_work(shost);
>
>        fc_terminate_rport_io(rport);
> +
>        /*
>         * Cancel any outstanding timers. These should really exist
>         * only when rmmod'ing the LLDD and we're asking for
> @@ -2415,6 +2434,8 @@ fc_rport_final_delete(struct work_struct
>            (i->f->dev_loss_tmo_callbk))
>                i->f->dev_loss_tmo_callbk(rport);
>
> +       fc_bsg_remove(rport->rqst_q);
> +
>        transport_remove_device(dev);
>        device_del(dev);
>        transport_destroy_device(dev);
> @@ -2502,6 +2523,9 @@ fc_rport_create(struct Scsi_Host *shost,
>        transport_add_device(dev);
>        transport_configure_device(dev);
>
> +       fc_bsg_rportadd(shost, rport);
> +       /* ignore any bsg add error - we just can't do sgio */
> +
>        if (rport->roles & FC_PORT_ROLE_FCP_TARGET) {
>                /* initiate a scan of the target */
>                rport->flags |= FC_RPORT_SCAN_PENDING;
> @@ -2666,6 +2690,8 @@ fc_remote_port_add(struct Scsi_Host *sho
>                                        spin_unlock_irqrestore(shost- 
> >host_lock,
>                                                        flags);
>
> +                               fc_bsg_goose_queue(rport);
> +
>                                return rport;
>                        }
>                }
> @@ -3351,6 +3377,594 @@ fc_vport_sched_delete(struct work_struct
> }
>
>
> +/*
> + * BSG support
> + */
> +
> +
> +/**
> + * fc_destroy_bsgjob - routine to teardown/delete a fc bsg job
> + * @job:       fc_bsg_job that is to be torn down
> + */
> +static void
> +fc_destroy_bsgjob(struct fc_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);
> +}
> +
> +
> +/**
> + * fc_bsg_jobdone - completion routine for bsg requests that the  
> LLD has
> + *                  completed
> + * @job:       fc_bsg_job that is complete
> + */
> +static void
> +fc_bsg_jobdone(struct fc_bsg_job *job)
> +{
> +       struct request *req = job->req;
> +       struct request *rsp = req->next_rq;
> +       unsigned long flags;
> +       unsigned rsp_len = 0, req_len = blk_rq_bytes(req);
> +       int err;
> +
> +       spin_lock_irqsave(&job->job_lock, flags);
> +       job->state_flags |= FC_RQST_STATE_DONE;
> +       job->ref_cnt--;
> +       spin_unlock_irqrestore(&job->job_lock, flags);
> +
> +       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->data_len = 0;
> +
> +       if (rsp) {
> +               rsp_len = blk_rq_bytes(rsp);
> +               BUG_ON(job->reply->reply_payload_rcv_len > rsp_len);
> +               /* set reply (bidi) residual */
> +               rsp->data_len = (rsp_len - job->reply- 
> >reply_payload_rcv_len);
> +       }
> +
> +       blk_end_bidi_request(req, err, req_len, rsp_len);
> +
> +       fc_destroy_bsgjob(job);
> +}
> +
> +
> +/**
> + * fc_bsg_job_timeout - handler for when a bsg request timesout
> + * @req:       request that timed out
> + */
> +static enum blk_eh_timer_return
> +fc_bsg_job_timeout(struct request *req)
> +{
> +       struct fc_bsg_job *job = (void *) req->special;
> +       struct Scsi_Host *shost = job->shost;
> +       struct fc_internal *i = to_fc_internal(shost->transportt);
> +       unsigned long flags;
> +       int err = 0, done = 0;
> +
> +       if (job->rport && job->rport->port_state ==  
> FC_PORTSTATE_BLOCKED)
> +               return BLK_EH_RESET_TIMER;
> +
> +       spin_lock_irqsave(&job->job_lock, flags);
> +       if (job->state_flags & FC_RQST_STATE_DONE)
> +               done = 1;
> +       else
> +               job->ref_cnt++;
> +       spin_unlock_irqrestore(&job->job_lock, flags);
> +
> +       if (!done && i->f->bsg_timeout) {
> +               /* call LLDD to abort the i/o as it has timed out */
> +               err = i->f->bsg_timeout(job);
> +               if (err)
> +                       printk(KERN_ERR "ERROR: FC BSG request  
> timeout - LLD "
> +                               "abort failed with status %d\n", err);
> +       }
> +
> +       if (!done) {
> +               spin_lock_irqsave(&job->job_lock, flags);
> +               job->ref_cnt--;
> +               spin_unlock_irqrestore(&job->job_lock, flags);
> +               fc_destroy_bsgjob(job);
> +       }
> +
> +       /* the blk_end_sync_io() doesn't check the error */
> +       return BLK_EH_HANDLED;
> +}
> +
> +
> +
> +static int
> +fc_bsg_map_buffer(struct fc_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 = req->data_len;
> +       return 0;
> +}
> +
> +
> +/**
> + * fc_req_to_bsgjob - Allocate/create the fc_bsg_job structure for  
> the
> + *                   bsg request
> + * @shost:     SCSI Host corresponding to the bsg object
> + * @rport:     (optional) FC Remote Port corresponding to the bsg  
> object
> + * @req:       BSG request that needs a job structure
> + */
> +static int
> +fc_req_to_bsgjob(struct Scsi_Host *shost, struct fc_rport *rport,
> +       struct request *req)
> +{
> +       struct fc_internal *i = to_fc_internal(shost->transportt);
> +       struct request *rsp = req->next_rq;
> +       struct fc_bsg_job *job;
> +       int ret;
> +
> +       BUG_ON(req->special);
> +
> +       job = kzalloc(sizeof(struct fc_bsg_job) + i->f->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 fc 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->rport = rport;
> +       job->req = req;
> +       if (i->f->dd_bsg_size)
> +               job->dd_data = (void *)&job[1];
> +       spin_lock_init(&job->job_lock);
> +       job->request = (struct fc_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 = fc_bsg_map_buffer(&job->request_payload, req);
> +               if (ret)
> +                       goto failjob_rls_job;
> +       }
> +       if (rsp && rsp->bio) {
> +               ret = fc_bsg_map_buffer(&job->reply_payload, rsp);
> +               if (ret)
> +                       goto failjob_rls_rqst_payload;
> +       }
> +       job->job_done = fc_bsg_jobdone;
> +       if (rport)
> +               job->dev = &rport->dev;
> +       else
> +               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 fc_dispatch_result {
> +       FC_DISPATCH_BREAK,      /* on return, q is locked, break  
> from q loop */
> +       FC_DISPATCH_LOCKED,     /* on return, q is locked, continue  
> on */
> +       FC_DISPATCH_UNLOCKED,   /* on return, q is unlocked,  
> continue on */
> +};
> +
> +
> +/**
> + * fc_bsg_host_dispatch - process fc host bsg requests and dispatch  
> to LLDD
> + * @shost:     scsi host rport attached to
> + * @job:       bsg job to be processed
> + */
> +static enum fc_dispatch_result
> +fc_bsg_host_dispatch(struct request_queue *q, struct Scsi_Host  
> *shost,
> +                        struct fc_bsg_job *job)
> +{
> +       struct fc_internal *i = to_fc_internal(shost->transportt);
> +       int cmdlen = sizeof(uint32_t);  /* start with length of  
> msgcode */
> +       int ret;
> +
> +       /* Validate the host command */
> +       switch (job->request->msgcode) {
> +       case FC_BSG_HST_ADD_RPORT:
> +               cmdlen += sizeof(struct fc_bsg_host_add_rport);
> +               break;
> +
> +       case FC_BSG_HST_DEL_RPORT:
> +               cmdlen += sizeof(struct fc_bsg_host_del_rport);
> +               break;
> +
> +       case FC_BSG_HST_ELS_NOLOGIN:
> +               cmdlen += sizeof(struct fc_bsg_host_els);
> +               /* there better be a xmt and rcv payloads */
> +               if ((!job->request_payload.payload_len) ||
> +                   (!job->reply_payload.payload_len)) {
> +                       ret = -EINVAL;
> +                       goto fail_host_msg;
> +               }
> +               break;
> +
> +       case FC_BSG_HST_CT:
> +               cmdlen += sizeof(struct fc_bsg_host_ct);
> +               /* there better be xmt and rcv payloads */
> +               if ((!job->request_payload.payload_len) ||
> +                   (!job->reply_payload.payload_len)) {
> +                       ret = -EINVAL;
> +                       goto fail_host_msg;
> +               }
> +               break;
> +
> +       case FC_BSG_HST_VENDOR:
> +               cmdlen += sizeof(struct fc_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->f->bsg_request(job);
> +       if (!ret)
> +               return FC_DISPATCH_UNLOCKED;
> +
> +fail_host_msg:
> +       /* return the errno failure code as the only status */
> +       BUG_ON(job->reply_len < sizeof(uint32_t));
> +       job->reply->result = ret;
> +       job->reply_len = sizeof(uint32_t);
> +       fc_bsg_jobdone(job);
> +       return FC_DISPATCH_UNLOCKED;
> +}
> +
> +
> +/*
> + * fc_bsg_goose_queue - restart rport queue in case it was stopped
> + * @rport:     rport to be restarted
> + */
> +static void
> +fc_bsg_goose_queue(struct fc_rport *rport)
> +{
> +       int flagset;
> +
> +       if (!rport->rqst_q)
> +               return;
> +
> +       get_device(&rport->dev);
> +
> +       spin_lock(rport->rqst_q->queue_lock);
> +       flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q- 
> >queue_flags) &&
> +                 !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q- 
> >queue_flags);
> +       if (flagset)
> +               queue_flag_set(QUEUE_FLAG_REENTER, rport->rqst_q);
> +       __blk_run_queue(rport->rqst_q);
> +       if (flagset)
> +               queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q);
> +       spin_unlock(rport->rqst_q->queue_lock);
> +
> +       put_device(&rport->dev);
> +}
> +
> +
> +/**
> + * fc_bsg_rport_dispatch - process rport bsg requests and dispatch  
> to LLDD
> + * @shost:     scsi host rport attached to
> + * @rport:     rport request destined to
> + * @job:       bsg job to be processed
> + */
> +static enum fc_dispatch_result
> +fc_bsg_rport_dispatch(struct request_queue *q, struct Scsi_Host  
> *shost,
> +                        struct fc_rport *rport, struct fc_bsg_job  
> *job)
> +{
> +       struct fc_internal *i = to_fc_internal(shost->transportt);
> +       int cmdlen = sizeof(uint32_t);  /* start with length of  
> msgcode */
> +       int ret;
> +
> +       /* Validate the rport command */
> +       switch (job->request->msgcode) {
> +       case FC_BSG_RPT_ELS:
> +               cmdlen += sizeof(struct fc_bsg_rport_els);
> +               goto check_bidi;
> +
> +       case FC_BSG_RPT_CT:
> +               cmdlen += sizeof(struct fc_bsg_rport_ct);
> +check_bidi:
> +               /* there better be xmt and rcv payloads */
> +               if ((!job->request_payload.payload_len) ||
> +                   (!job->reply_payload.payload_len)) {
> +                       ret = -EINVAL;
> +                       goto fail_rport_msg;
> +               }
> +               break;
> +       default:
> +               ret = -EBADR;
> +               goto fail_rport_msg;
> +       }
> +
> +       /* check if we really have all the request data needed */
> +       if (job->request_len < cmdlen) {
> +               ret = -ENOMSG;
> +               goto fail_rport_msg;
> +       }
> +
> +       ret = i->f->bsg_request(job);
> +       if (!ret)
> +               return FC_DISPATCH_UNLOCKED;
> +
> +fail_rport_msg:
> +       /* return the errno failure code as the only status */
> +       BUG_ON(job->reply_len < sizeof(uint32_t));
> +       job->reply->result = ret;
> +       job->reply_len = sizeof(uint32_t);
> +       fc_bsg_jobdone(job);
> +       return FC_DISPATCH_UNLOCKED;
> +}
> +
> +
> +/**
> + * fc_bsg_request_handler - generic handler for bsg requests
> + * @q:         request queue to manage
> + * @shost:     Scsi_Host related to the bsg object
> + * @rport:     FC remote port related to the bsg object (optional)
> + * @dev:       device structure for bsg object
> + */
> +static void
> +fc_bsg_request_handler(struct request_queue *q, struct Scsi_Host  
> *shost,
> +                      struct fc_rport *rport, struct device *dev)
> +{
> +       struct request *req;
> +       struct fc_bsg_job *job;
> +       enum fc_dispatch_result ret;
> +
> +       if (!get_device(dev))
> +               return;
> +
> +       while (!blk_queue_plugged(q)) {
> +               req = elv_next_request(q);
> +               if (!req)
> +                       break;
> +
> +               if (rport && (rport->port_state ==  
> FC_PORTSTATE_BLOCKED))
> +                               break;
> +
> +               blkdev_dequeue_request(req);
> +
> +               if (rport && (rport->port_state !=  
> FC_PORTSTATE_ONLINE)) {
> +                       req->errors = -ENXIO;
> +                       spin_unlock_irq(q->queue_lock);
> +                       blk_end_request(req, -ENXIO,  
> blk_rq_bytes(req));
> +                       spin_lock_irq(q->queue_lock);
> +                       continue;
> +               }
> +
> +               spin_unlock_irq(q->queue_lock);
> +
> +               ret = fc_req_to_bsgjob(shost, rport, req);
> +               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->result = -ENOMSG;
> +                       job->reply_len = sizeof(uint32_t);
> +                       fc_bsg_jobdone(job);
> +                       spin_lock_irq(q->queue_lock);
> +                       continue;
> +               }
> +
> +               /* the dispatch routines will unlock the queue_lock */
> +               if (rport)
> +                       ret = fc_bsg_rport_dispatch(q, shost, rport,  
> job);
> +               else
> +                       ret = fc_bsg_host_dispatch(q, shost, job);
> +
> +               /* did dispatcher hit state that can't process any  
> more */
> +               if (ret == FC_DISPATCH_BREAK)
> +                       break;
> +
> +               /* did dispatcher had released the lock */
> +               if (ret == FC_DISPATCH_UNLOCKED)
> +                       spin_lock_irq(q->queue_lock);
> +       }
> +
> +       spin_unlock_irq(q->queue_lock);
> +       put_device(dev);
> +       spin_lock_irq(q->queue_lock);
> +}
> +
> +
> +/**
> + * fc_bsg_host_handler - handler for bsg requests for a fc host
> + * @q:         fc host request queue
> + */
> +static void
> +fc_bsg_host_handler(struct request_queue *q)
> +{
> +       struct Scsi_Host *shost = q->queuedata;
> +
> +       fc_bsg_request_handler(q, shost, NULL, &shost->shost_gendev);
> +}
> +
> +
> +/**
> + * fc_bsg_rport_handler - handler for bsg requests for a fc rport
> + * @q:         rport request queue
> + */
> +static void
> +fc_bsg_rport_handler(struct request_queue *q)
> +{
> +       struct fc_rport *rport = q->queuedata;
> +       struct Scsi_Host *shost = rport_to_shost(rport);
> +
> +       fc_bsg_request_handler(q, shost, rport, &rport->dev);
> +}
> +
> +
> +/**
> + * fc_bsg_hostadd - Create and add the bsg hooks so we can receive  
> requests
> + * @shost:     shost for fc_host
> + * @fc_host:   fc_host adding the structures to
> + */
> +static int
> +fc_bsg_hostadd(struct Scsi_Host *shost, struct fc_host_attrs  
> *fc_host)
> +{
> +       struct device *dev = &shost->shost_gendev;
> +       struct fc_internal *i = to_fc_internal(shost->transportt);
> +       struct request_queue *q;
> +       int err;
> +       char bsg_name[BUS_ID_SIZE]; /*20*/
> +
> +       fc_host->rqst_q = NULL;
> +
> +       if (!i->f->bsg_request)
> +               return -ENOTSUPP;
> +
> +       snprintf(bsg_name, sizeof(bsg_name),
> +                "fc_host%d", shost->host_no);
> +
> +       q = __scsi_alloc_queue(shost, fc_bsg_host_handler);
> +       if (!q) {
> +               printk(KERN_ERR "fc_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_rq_timed_out(q, fc_bsg_job_timeout);
> +       blk_queue_rq_timeout(q, FC_DEFAULT_BSG_TIMEOUT);
> +
> +       err = bsg_register_queue(q, dev, bsg_name, NULL);
> +       if (err) {
> +               printk(KERN_ERR "fc_host%d: bsg interface failed to "
> +                               "initialize - register queue\n",
> +                               shost->host_no);
> +               blk_cleanup_queue(q);
> +               return err;
> +       }
> +
> +       fc_host->rqst_q = q;
> +       return 0;
> +}
> +
> +
> +/**
> + * fc_bsg_rportadd - Create and add the bsg hooks so we can receive  
> requests
> + * @shost:     shost that rport is attached to
> + * @rport:     rport that the bsg hooks are being attached to
> + */
> +static int
> +fc_bsg_rportadd(struct Scsi_Host *shost, struct fc_rport *rport)
> +{
> +       struct device *dev = &rport->dev;
> +       struct fc_internal *i = to_fc_internal(shost->transportt);
> +       struct request_queue *q;
> +       int err;
> +
> +       rport->rqst_q = NULL;
> +
> +       if (!i->f->bsg_request)
> +               return -ENOTSUPP;
> +
> +       q = __scsi_alloc_queue(shost, fc_bsg_rport_handler);
> +       if (!q) {
> +               printk(KERN_ERR "%s: bsg interface failed to "
> +                               "initialize - no request queue\n",
> +                                dev->bus_id);
> +               return -ENOMEM;
> +       }
> +
> +       q->queuedata = rport;
> +       queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
> +       blk_queue_rq_timed_out(q, fc_bsg_job_timeout);
> +       blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
> +
> +       err = bsg_register_queue(q, dev, NULL, NULL);
> +       if (err) {
> +               printk(KERN_ERR "%s: bsg interface failed to "
> +                               "initialize - register queue\n",
> +                                dev->bus_id);
> +               blk_cleanup_queue(q);
> +               return err;
> +       }
> +
> +       rport->rqst_q = q;
> +       return 0;
> +}
> +
> +
> +/**
> + * fc_bsg_remove - Deletes the bsg hooks on fchosts/rports
> + * @q: the request_queue that is to be torn down.
> + */
> +static void
> +fc_bsg_remove(struct request_queue *q)
> +{
> +       if (q) {
> +               bsg_unregister_queue(q);
> +               blk_cleanup_queue(q);
> +       }
> +}
> +
> +
> /* Original Author:  Martin Hicks */
> MODULE_AUTHOR("James Smart");
> MODULE_DESCRIPTION("FC Transport Attributes");
> diff -upNr a/include/Kbuild b/include/Kbuild
> --- a/include/Kbuild    2009-03-25 10:24:22.000000000 -0400
> +++ b/include/Kbuild    2009-03-25 10:24:48.000000000 -0400
> @@ -8,3 +8,4 @@ header-y += mtd/
> header-y += rdma/
> header-y += video/
> header-y += drm/
> +header-y += scsi/
> diff -upNr a/include/scsi/Kbuild b/include/scsi/Kbuild
> --- a/include/scsi/Kbuild       1969-12-31 19:00:00.000000000 -0500
> +++ b/include/scsi/Kbuild       2009-03-25 10:21:50.000000000 -0400
> @@ -0,0 +1,4 @@
> +header-y += scsi.h
> +header-y += scsi_netlink.h
> +header-y += scsi_netlink_fc.h
> +header-y += scsi_bsg_fc.h
> diff -upNr a/include/scsi/scsi_bsg_fc.h b/include/scsi/scsi_bsg_fc.h
> --- a/include/scsi/scsi_bsg_fc.h        1969-12-31  
> 19:00:00.000000000 -0500
> +++ b/include/scsi/scsi_bsg_fc.h        2009-03-25  
> 10:07:08.000000000 -0400
> @@ -0,0 +1,322 @@
> +/*
> + *  FC Transport BSG Interface
> + *
> + *  Copyright (C) 2008   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_FC_H
> +#define SCSI_BSG_FC_H
> +
> +/*
> + * This file intended to be included by both kernel and user space
> + */
> +
> +#include <scsi/scsi.h>
> +
> +/*
> + * FC Transport SGIO v4 BSG Message Support
> + */
> +
> +/* Default BSG request timeout (in seconds) */
> +#define FC_DEFAULT_BSG_TIMEOUT         (10 * HZ)
> +
> +
> +/*
> + * Request Message Codes supported by the FC Transport
> + */
> +
> +/* define the class masks for the message codes */
> +#define FC_BSG_CLS_MASK                0xF0000000      /* find  
> object class */
> +#define FC_BSG_HST_MASK                0x80000000      /* fc host  
> class */
> +#define FC_BSG_RPT_MASK                0x40000000      /* fc rport  
> class */
> +
> +       /* fc_host Message Codes */
> +#define FC_BSG_HST_ADD_RPORT           (FC_BSG_HST_MASK | 0x00000001)
> +#define FC_BSG_HST_DEL_RPORT           (FC_BSG_HST_MASK | 0x00000002)
> +#define FC_BSG_HST_ELS_NOLOGIN         (FC_BSG_HST_MASK | 0x00000003)
> +#define FC_BSG_HST_CT                  (FC_BSG_HST_MASK | 0x00000004)
> +#define FC_BSG_HST_VENDOR              (FC_BSG_HST_MASK | 0x000000FF)
> +
> +       /* fc_rport Message Codes */
> +#define FC_BSG_RPT_ELS                 (FC_BSG_RPT_MASK | 0x00000001)
> +#define FC_BSG_RPT_CT                  (FC_BSG_RPT_MASK | 0x00000002)
> +
> +
> +
> +/*
> + * FC Address Identifiers in Message Structures :
> + *
> + *   Whenever a command payload contains a FC Address Identifier
> + *   (aka port_id), the value is effectively in big-endian
> + *   order, thus the array elements are decoded as follows:
> + *     element [0] is bits 23:16 of the FC Address Identifier
> + *     element [1] is bits 15:8 of the FC Address Identifier
> + *     element [2] is bits 7:0 of the FC Address Identifier
> + */
> +
> +
> +/*
> + * FC Host Messages
> + */
> +
> +/* FC_BSG_HST_ADDR_PORT : */
> +
> +/* Request:
> + * This message requests the FC host to login to the remote port
> + * at the specified N_Port_Id.  The remote port is to be enumerated
> + * with the transport upon completion of the login.
> + */
> +struct fc_bsg_host_add_rport {
> +       uint8_t         reserved;
> +
> +       /* FC Address Identier of the remote port to login to */
> +       uint8_t         port_id[3];
> +};
> +
> +/* Response:
> + * There is no additional response data - fc_bsg_reply->result is  
> sufficient
> + */
> +
> +
> +/* FC_BSG_HST_DEL_RPORT : */
> +
> +/* Request:
> + * This message requests the FC host to remove an enumerated
> + * remote port and to terminate the login to it.
> + *
> + * Note: The driver is free to reject this request if it desires to
> + * remain logged in with the remote port.
> + */
> +struct fc_bsg_host_del_rport {
> +       uint8_t         reserved;
> +
> +       /* FC Address Identier of the remote port to logout of */
> +       uint8_t         port_id[3];
> +};
> +
> +/* Response:
> + * There is no additional response data - fc_bsg_reply->result is  
> sufficient
> + */
> +
> +
> +/* FC_BSG_HST_ELS_NOLOGIN : */
> +
> +/* Request:
> + * This message requests the FC_Host to send an ELS to a specific
> + * N_Port_ID. The host does not need to log into the remote port,
> + * nor does it need to enumerate the rport for further traffic
> + * (although, the FC host is free to do so if it desires).
> + */
> +struct fc_bsg_host_els {
> +       /*
> +        * ELS Command Code being sent (must be the same as byte 0
> +        * of the payload)
> +        */
> +       uint8_t         command_code;
> +
> +       /* FC Address Identier of the remote port to send the ELS to  
> */
> +       uint8_t         port_id[3];
> +};
> +
> +/* Response:
> + */
> +/* fc_bsg_ctels_reply->status values */
> +#define FC_CTELS_STATUS_OK     0x00000000
> +#define FC_CTELS_STATUS_REJECT 0x00000001
> +#define FC_CTELS_STATUS_P_RJT  0x00000002
> +#define FC_CTELS_STATUS_F_RJT  0x00000003
> +#define FC_CTELS_STATUS_P_BSY  0x00000004
> +#define FC_CTELS_STATUS_F_BSY  0x00000006
> +struct fc_bsg_ctels_reply {
> +       /*
> +        * Note: An ELS LS_RJT may be reported in 2 ways:
> +        *  a) A status of FC_CTELS_STATUS_OK is returned. The caller
> +        *     is to look into the ELS receive payload to determine
> +        *     LS_ACC or LS_RJT (by contents of word 0). The reject
> +        *     data will be in word 1.
> +        *  b) A status of FC_CTELS_STATUS_REJECT is returned, The
> +        *     rjt_data field will contain valid data.
> +        *
> +        * Note: ELS LS_ACC is determined by an FC_CTELS_STATUS_OK,  
> and
> +        *   the receive payload word 0 indicates LS_ACC
> +        *   (e.g. value is 0x02xxxxxx).
> +        *
> +        * Note: Similarly, a CT Reject may be reported in 2 ways:
> +        *  a) A status of FC_CTELS_STATUS_OK is returned. The caller
> +        *     is to look into the CT receive payload to determine
> +        *     Accept or Reject (by contents of word 2). The reject
> +        *     data will be in word 3.
> +        *  b) A status of FC_CTELS_STATUS_REJECT is returned, The
> +        *     rjt_data field will contain valid data.
> +        *
> +        * Note: x_RJT/BSY status will indicae that the rjt_data field
> +        *   is valid and contains the reason/explanation values.
> +        */
> +       uint32_t        status;         /* See FC_CTELS_STATUS_xxx */
> +
> +       /* valid if status is not FC_CTELS_STATUS_OK */
> +       struct  {
> +               uint8_t action;         /* fragment_id for CT REJECT  
> */
> +               uint8_t reason_code;
> +               uint8_t reason_explanation;
> +               uint8_t vendor_unique;
> +       } rjt_data;
> +};
> +
> +
> +/* FC_BSG_HST_CT : */
> +
> +/* Request:
> + * This message requests that a CT Request be performed with the
> + * indicated N_Port_ID. The driver is responsible for logging in with
> + * the fabric and/or N_Port_ID, etc as per FC rules. This request  
> does
> + * not mandate that the driver must enumerate the destination in the
> + * transport. The driver is allowed to decide whether to enumerate  
> it,
> + * and whether to tear it down after the request.
> + */
> +struct fc_bsg_host_ct {
> +       uint8_t         reserved;
> +
> +       /* FC Address Identier of the remote port to send the ELS to  
> */
> +       uint8_t         port_id[3];
> +
> +       /*
> +        * We need words 0-2 of the generic preamble for the LLD's
> +        */
> +       uint32_t        preamble_word0; /* revision & IN_ID */
> +       uint32_t        preamble_word1; /* GS_Type, GS_SubType,  
> Options, Rsvd */
> +       uint32_t        preamble_word2; /* Cmd Code, Max Size */
> +
> +};
> +/* Response:
> + *
> + * The reply structure is an fc_bsg_ctels_reply structure
> + */
> +
> +
> +/* FC_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 fc_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 fc_bsg_host_vendor_reply {
> +       /* start of vendor response area */
> +       uint32_t vendor_rsp[0];
> +};
> +
> +
> +
> +/*
> + * FC Remote Port Messages
> + */
> +
> +/* FC_BSG_RPT_ELS : */
> +
> +/* Request:
> + * This message requests that an ELS be performed with the rport.
> + */
> +struct fc_bsg_rport_els {
> +       /*
> +        * ELS Command Code being sent (must be the same as
> +        * byte 0 of the payload)
> +        */
> +       uint8_t els_code;
> +};
> +
> +/* Response:
> + *
> + * The reply structure is an fc_bsg_ctels_reply structure
> + */
> +
> +
> +/* FC_BSG_RPT_CT : */
> +
> +/* Request:
> + * This message requests that a CT Request be performed with the  
> rport.
> + */
> +struct fc_bsg_rport_ct {
> +       /*
> +        * We need words 0-2 of the generic preamble for the LLD's
> +        */
> +       uint32_t        preamble_word0; /* revision & IN_ID */
> +       uint32_t        preamble_word1; /* GS_Type, GS_SubType,  
> Options, Rsvd */
> +       uint32_t        preamble_word2; /* Cmd Code, Max Size */
> +};
> +/* Response:
> + *
> + * The reply structure is an fc_bsg_ctels_reply structure
> + */
> +
> +
> +
> +
> +/* request (CDB) structure of the sg_io_v4 */
> +struct fc_bsg_request {
> +       uint32_t msgcode;
> +       union {
> +               struct fc_bsg_host_add_rport    h_addrport;
> +               struct fc_bsg_host_del_rport    h_delrport;
> +               struct fc_bsg_host_els          h_els;
> +               struct fc_bsg_host_ct           h_ct;
> +               struct fc_bsg_host_vendor       h_vendor;
> +
> +               struct fc_bsg_rport_els         r_els;
> +               struct fc_bsg_rport_ct          r_ct;
> +       } rqst_data;
> +};
> +
> +
> +/* response (request sense data) structure of the sg_io_v4 */
> +struct fc_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 fc_bsg_host_vendor_reply         vendor_reply;
> +
> +               struct fc_bsg_ctels_reply               ctels_reply;
> +       } reply_data;
> +};
> +
> +
> +#endif /* SCSI_BSG_FC_H */
> +
> diff -upNr a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
> --- a/include/scsi/scsi_host.h  2008-10-18 10:32:54.000000000 -0400
> +++ b/include/scsi/scsi_host.h  2009-03-25 10:07:08.000000000 -0400
> @@ -478,6 +478,15 @@ struct scsi_host_template {
>         * module_init/module_exit.
>         */
>        struct list_head legacy_hosts;
> +
> +       /*
> +        * Vendor Identifier associated with the host
> +        *
> +        * Note: When specifying vendor_id, be sure to read the
> +        *   Vendor Type and ID formatting requirements specified in
> +        *   scsi_netlink.h
> +        */
> +       u64 vendor_id;
> };
>
> /*
> diff -upNr a/include/scsi/scsi_transport_fc.h b/include/scsi/ 
> scsi_transport_fc.h
> --- a/include/scsi/scsi_transport_fc.h  2009-01-27  
> 09:44:40.000000000 -0500
> +++ b/include/scsi/scsi_transport_fc.h  2009-03-25  
> 10:07:08.000000000 -0400
> @@ -33,7 +33,6 @@
>
> struct scsi_transport_template;
>
> -
> /*
>  * FC Port definitions - Following FC HBAAPI guidelines
>  *
> @@ -352,6 +351,7 @@ struct fc_rport {   /* aka fc_starget_attr
>        struct delayed_work fail_io_work;
>        struct work_struct stgt_delete_work;
>        struct work_struct rport_delete_work;
> +       struct request_queue *rqst_q;   /* bsg support */
> } __attribute__((aligned(sizeof(unsigned long))));
>
> /* bit field values for struct fc_rport "flags" field: */
> @@ -514,6 +514,9 @@ struct fc_host_attrs {
>        struct workqueue_struct *work_q;
>        char devloss_work_q_name[20];
>        struct workqueue_struct *devloss_work_q;
> +
> +       /* bsg support */
> +       struct request_queue *rqst_q;
> };
>
> #define shost_to_fc_host(x) \
> @@ -579,6 +582,47 @@ struct fc_host_attrs {
>        (((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q)
>
>
> +struct fc_bsg_buffer {
> +       unsigned int payload_len;
> +       int sg_cnt;
> +       struct scatterlist *sg_list;
> +};
> +
> +/* Values for fc_bsg_job->state_flags (bitflags) */
> +#define FC_RQST_STATE_INPROGRESS       0
> +#define FC_RQST_STATE_DONE             1
> +
> +struct fc_bsg_job {
> +       struct Scsi_Host *shost;
> +       struct fc_rport *rport;
> +       struct device *dev;
> +       struct request *req;
> +       spinlock_t job_lock;
> +       unsigned int state_flags;
> +       unsigned int ref_cnt;
> +       void (*job_done)(struct fc_bsg_job *);
> +
> +       struct fc_bsg_request *request;
> +       struct fc_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 fc_bsg_buffer request_payload;
> +       struct fc_bsg_buffer reply_payload;
> +
> +       void *dd_data;                  /* Used for driver-specific  
> storage */
> +};
> +
> +
> /* The functions by which the transport class and the driver  
> communicate */
> struct fc_function_template {
>        void    (*get_rport_dev_loss_tmo)(struct fc_rport *);
> @@ -614,9 +658,14 @@ struct fc_function_template {
>        int     (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64,  
> int);
>        int     (* it_nexus_response)(struct Scsi_Host *, u64, int);
>
> +       /* bsg support */
> +       int     (*bsg_request)(struct fc_bsg_job *);
> +       int     (*bsg_timeout)(struct fc_bsg_job *);
> +
>        /* allocation lengths for host-specific data */
>        u32                             dd_fcrport_size;
>        u32                             dd_fcvport_size;
> +       u32                             dd_bsg_size;
>
>        /*
>         * The driver sets these to tell the transport class it
> @@ -737,7 +786,6 @@ fc_vport_set_state(struct fc_vport *vpor
>        vport->vport_state = new_state;
> }
>
> -
> struct scsi_transport_template *fc_attach_transport(
>                        struct fc_function_template *);
> void fc_release_transport(struct scsi_transport_template *);
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux- 
> scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH] FC Pass Thru support
  2009-03-26 17:33 [PATCH] FC Pass Thru support James Smart
  2009-03-27 14:00 ` Seokmann Ju
@ 2009-04-15 12:59 ` Christof Schmitt
  2009-04-16 14:15   ` James Smart
  1 sibling, 1 reply; 4+ messages in thread
From: Christof Schmitt @ 2009-04-15 12:59 UTC (permalink / raw)
  To: James Smart; +Cc: linux-scsi

On Thu, Mar 26, 2009 at 01:33:19PM -0400, James Smart wrote:
> 
> All,
> 
> Attached is the ELS/CT pass-thru patch for the FC Transport. The patch
> creates a generic framework that lays on top of bsg and the SGIO v4 ioctl
> in order to pass transaction requests to LLDD's.
> 
> The interface supports the following operations:
>   On an fc_host basis:
>     Request login to the specified N_Port_ID, creating an fc_rport.
>     Request logout of the specified N_Port_ID, deleting an fc_rport
>     Send ELS request to specified N_Port_ID w/o requiring a login, and
>       wait for ELS response.
>     Send CT request to specified N_Port_ID and wait for CT response.
>       Login is required, but LLDD is allowed to manage login and decide
>       whether it stays in place after the request is satisfied.
>     Vendor-Unique request. Allows a LLDD-specific request to be passed
>       to the LLDD, and the passing of a response back to the application.
>   On an fc_rport basis:
>     Send ELS request to nport and wait for ELS response.
>     Send CT request to nport and wait for CT response.
> 
> The patch also exports several headers from include/scsi such that
> they can be available to user-space applications:
>   include/scsi/scsi.h
>   include/scsi/scsi_netlink.h
>   include/scsi/scsi_netlink_fc.h
>   include/scsi/scsi_bsg_fc.h
> 
> For further information, refer to the last RFC:
> http://marc.info/?l=linux-scsi&m=123436574018579&w=2

This patch triggers the warning WARN_ON(!irqs_disabled()) in
blk_remove_plug, and the description of __blk_run_queue states:

/**
 * __blk_run_queue - run a single device queue
 * @q:  The queue to run
 *
 * Description:
 *    See @blk_run_queue. This variant must be called with the queue
 *    lock held and interrupts disabled.
 *
 */

I assume to get this right, fc_bsg_goose_queue should disable
interrupts when taking the queue lock. See patch below.

Christof
---
 drivers/scsi/scsi_transport_fc.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

--- a/drivers/scsi/scsi_transport_fc.c	2009-04-14 14:29:25.000000000 +0200
+++ b/drivers/scsi/scsi_transport_fc.c	2009-04-14 14:31:41.000000000 +0200
@@ -3707,13 +3707,14 @@ static void
 fc_bsg_goose_queue(struct fc_rport *rport)
 {
 	int flagset;
+	unsigned long flags;
 
 	if (!rport->rqst_q)
 		return;
 
 	get_device(&rport->dev);
 
-	spin_lock(rport->rqst_q->queue_lock);
+	spin_lock_irqsave(rport->rqst_q->queue_lock, flags);
 	flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags) &&
 		  !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags);
 	if (flagset)
@@ -3721,7 +3722,7 @@ fc_bsg_goose_queue(struct fc_rport *rpor
 	__blk_run_queue(rport->rqst_q);
 	if (flagset)
 		queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q);
-	spin_unlock(rport->rqst_q->queue_lock);
+	spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags);
 
 	put_device(&rport->dev);
 }

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

* Re: [PATCH] FC Pass Thru support
  2009-04-15 12:59 ` Christof Schmitt
@ 2009-04-16 14:15   ` James Smart
  0 siblings, 0 replies; 4+ messages in thread
From: James Smart @ 2009-04-16 14:15 UTC (permalink / raw)
  To: Christof Schmitt; +Cc: linux-scsi@vger.kernel.org

Thanks Christof.  I'll add it to the patch.

-- james s


Christof Schmitt wrote:
> On Thu, Mar 26, 2009 at 01:33:19PM -0400, James Smart wrote:
>   
>> All,
>>
>> Attached is the ELS/CT pass-thru patch for the FC Transport. The patch
>> creates a generic framework that lays on top of bsg and the SGIO v4 ioctl
>> in order to pass transaction requests to LLDD's.
>>
>> The interface supports the following operations:
>>   On an fc_host basis:
>>     Request login to the specified N_Port_ID, creating an fc_rport.
>>     Request logout of the specified N_Port_ID, deleting an fc_rport
>>     Send ELS request to specified N_Port_ID w/o requiring a login, and
>>       wait for ELS response.
>>     Send CT request to specified N_Port_ID and wait for CT response.
>>       Login is required, but LLDD is allowed to manage login and decide
>>       whether it stays in place after the request is satisfied.
>>     Vendor-Unique request. Allows a LLDD-specific request to be passed
>>       to the LLDD, and the passing of a response back to the application.
>>   On an fc_rport basis:
>>     Send ELS request to nport and wait for ELS response.
>>     Send CT request to nport and wait for CT response.
>>
>> The patch also exports several headers from include/scsi such that
>> they can be available to user-space applications:
>>   include/scsi/scsi.h
>>   include/scsi/scsi_netlink.h
>>   include/scsi/scsi_netlink_fc.h
>>   include/scsi/scsi_bsg_fc.h
>>
>> For further information, refer to the last RFC:
>> http://marc.info/?l=linux-scsi&m=123436574018579&w=2
>>     
>
> This patch triggers the warning WARN_ON(!irqs_disabled()) in
> blk_remove_plug, and the description of __blk_run_queue states:
>
> /**
>  * __blk_run_queue - run a single device queue
>  * @q:  The queue to run
>  *
>  * Description:
>  *    See @blk_run_queue. This variant must be called with the queue
>  *    lock held and interrupts disabled.
>  *
>  */
>
> I assume to get this right, fc_bsg_goose_queue should disable
> interrupts when taking the queue lock. See patch below.
>
> Christof
> ---
>  drivers/scsi/scsi_transport_fc.c |    5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
>
> --- a/drivers/scsi/scsi_transport_fc.c	2009-04-14 14:29:25.000000000 +0200
> +++ b/drivers/scsi/scsi_transport_fc.c	2009-04-14 14:31:41.000000000 +0200
> @@ -3707,13 +3707,14 @@ static void
>  fc_bsg_goose_queue(struct fc_rport *rport)
>  {
>  	int flagset;
> +	unsigned long flags;
>  
>  	if (!rport->rqst_q)
>  		return;
>  
>  	get_device(&rport->dev);
>  
> -	spin_lock(rport->rqst_q->queue_lock);
> +	spin_lock_irqsave(rport->rqst_q->queue_lock, flags);
>  	flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags) &&
>  		  !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags);
>  	if (flagset)
> @@ -3721,7 +3722,7 @@ fc_bsg_goose_queue(struct fc_rport *rpor
>  	__blk_run_queue(rport->rqst_q);
>  	if (flagset)
>  		queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q);
> -	spin_unlock(rport->rqst_q->queue_lock);
> +	spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags);
>  
>  	put_device(&rport->dev);
>  }
>
>   

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

end of thread, other threads:[~2009-04-16 14:21 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-26 17:33 [PATCH] FC Pass Thru support James Smart
2009-03-27 14:00 ` Seokmann Ju
2009-04-15 12:59 ` Christof Schmitt
2009-04-16 14:15   ` James Smart

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox