Re: [RFC] FC pass thru - Rev IV

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

 



On Tue, 18 Nov 2008 16:24:58 -0500
James Smart <James.Smart@xxxxxxxxxx> wrote:

> All,
> 
> I've reworked Seokmann's patch for the following items:
> - Add an fchost interface for bsg requests
> 
> - Formalized the request/response structures that I expect
>   to have us stuff into the bsg cmd/sense data areas. These
>   are now genericized so we can essentially pass any kind of
>   transaction. It can be a request that has no transmit or
>   receive payload, and simply returns a response.
> 
> - A new file was created, scsi_bsg_fc.h, which contains the
>   request/response data structures that should be shared
>   between the application and the kernel entities. 
> 
> - I stripped out some things that were in the request
>   structure that were actually LLD fields. Instead, I added
>   a dd_bsgsize structure to the template, so the transport
>   will allocate LLD work space along with the job structure.
>   I expect the missing fields to move to this area.
> 
> - I've made a strong attempt at ensuring that the request
>   has all the information necessary for the LLD, so that
>   there is no need to have the LLD remap the transmit payload
>   to figure things out. Granted, this comes at the cost of
>   replicating some data items.
> 
>   Sven, I've added the CT information you needed as part of this.
> 
> - I've renamed things quite a bit, hoping to make it clarity
>   better. The "service" struct is now a job. I still have
>   headaches with "request" (is it the blk request, or the job
>   request, or what..)
> 
> - The CT/ELS response is a bit funky. I've noted that the
>   way Emulex returns a response, vs Qlogic is a bit different,
>   thus the 2 ways to indicate "reject".
> 
> - fixed a couple of bugs in Seokmann's code, in the teardown,
>   error flows, request que dma settings, etc.
> 
> - I added a "vendor_id" field to the scsi_host_template to
>   use when verifying that the recipient knows how to decode
>   vendor-specific message. I didn't do this with the netlink
>   things as I was prepping it to not break kabi in existing
>   and older kernels. But, I believe this is a good time to
>   add it.
> 
> - I've started the Documentation/scsi/scsi_transport_fc.txt
>   documentation, but punted finishing it in lieu of sending
>   this RFC. I'm starting from Seokman's original emails and
>   will be updating for this reformat.
> 
> I'm only starting to debug this, so user beware.
> 
> I could really use some code review from Fujita or Boaz, to
> make sure I'm calling the right blk_xx completion functions
> relative to the setup flow, and to ensure that the "goose"
> when I jump out while the rport is blocked is correct.
> 
> Comments welcome
> 
> -- james s
> 
> 
> 
>  Signed-off-by: James Smart <james.smart@xxxxxxxxxx>
> 
>  ---
> 
>  Documentation/scsi/scsi_fc_transport.txt |   11 
>  Documentation/scsi/scsi_mid_low_api.txt  |    5 
>  drivers/scsi/scsi_transport_fc.c         |  581 ++++++++++++++++++++++++++++++-
>  include/scsi/scsi_bsg_fc.h               |  291 +++++++++++++++
>  include/scsi/scsi_host.h                 |    9 
>  include/scsi/scsi_transport_fc.h         |   53 ++
>  6 files changed, 946 insertions(+), 4 deletions(-)

(snip)

> +/**
> + * 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->next_rq;
> +	struct request *rsp = req->next_rq;
> +	unsigned long flags;
> +	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'll cheat: tell blk layer all of the xmt data was sent.
> +	 * but try to be honest about the amount of rcv data received
> +	 */
> +	if (rsp)
> +		blk_end_bidi_request(job->req, err, blk_rq_bytes(job->req),
> +	    			     job->reply->reply_payload_rcv_len);
> +	else
> +		blk_end_request(job->req, err, blk_rq_bytes(job->req));

I think that you can use blk_end_bidi_request() for non-bidi requests:

	blk_end_bidi_request(job->req, err, blk_rq_bytes(job->req),
			rsp ?
			 job->reply->reply_payload_rcv_len : 0);


I guess that it would be better to have one function to complete a
request, instead of blk_end_bidi_request and blk_end_request.


> +	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 void
> +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);

Needs to handle 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;
> +}
> +
> +
> +/**
> + * 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;
> +
> +	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)
> +		fc_bsg_map_buffer(&job->request_payload, req);
> +	if (rsp && rsp->bio)
> +		fc_bsg_map_buffer(&job->reply_payload, rsp);
> +	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;
> +}
> +
> +
> +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_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) {
> +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);
> +		/* fall thru */
> +	}
> +
> +	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:
> +	case FC_BSG_RPT_CT:
> +		cmdlen += sizeof(struct fc_bsg_rport_els);
> +		/* there better be a 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) {
> +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);
> +		/* fall thru */
> +	}
> +
> +	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;
> +			blk_complete_request(req);

I think that calling blk_complete_request() here crashes your kernel
since you don't set q->softirq_done_fn.

Calling blk_end_bidi_request should work here. Note that you need to
call spin_unlock_irq(q->queue_lock) before it.


> +			continue;
> +		}
> +
> +		spin_unlock_irq(q->queue_lock);
> +
> +		ret = fc_req_to_bsgjob(shost, rport, req);
> +		if (ret) {
> +			req->errors = ret;
> +			spin_lock_irq(q->queue_lock);
> +			blk_complete_request(req);

Ditto.

> +			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;
> +
> +	fc_host->rqst_q = NULL;
> +
> +	if (!i->f->bsg_request)
> +		return -ENOTSUPP;
> +
> +	snprintf(fc_host->bsg_name, sizeof(fc_host->bsg_name),
> +		 "fc_host%d", shost->host_no);

You don't need fc_host->bsg_name. bsg_register_queue() allocates
memory for the name.


> +	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, fc_host->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, dev->bus_id, NULL);

You don't need to pass dev->bus_id. It is used if you pass NULL.

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/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	2008-11-18 15:54:25.000000000 -0500
> @@ -0,0 +1,291 @@
> +/*
> + *  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>
> +#include <scsi/sg.h>

<scsi/sg.h> is necessary?


> +/*
> + * FC Transport SGIO v4 BSG Message Support
> + */
> +
> +/* Default BSG request timeout (in seconds) */
> +#define FC_DEFAULT_BSG_TIMEOUT		10

Should be (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_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_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_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	2008-11-18 15:54:25.000000000 -0500
> @@ -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	2008-10-18 10:32:54.000000000 -0400
> +++ b/include/scsi/scsi_transport_fc.h	2008-11-18 15:54:25.000000000 -0500
> @@ -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: */
> @@ -513,6 +513,10 @@ struct fc_host_attrs {
>  	struct workqueue_struct *work_q;
>  	char devloss_work_q_name[20];
>  	struct workqueue_struct *devloss_work_q;
> +
> +	/* bsg support */
> +	char bsg_name[20];
> +	struct request_queue *rqst_q;
>  };
>  
>  #define shost_to_fc_host(x) \
> @@ -578,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 *);
> @@ -613,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
> @@ -736,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@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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