Re: [RFC] FC pass thru - Rev IV

FUJITA Tomonori
2008-11-27T07:03:42Z

On Tue, 18 Nov 2008 16:24:58 -0500
James Smart <James.Smart@Emulex.Com> 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@emulex.com>
>
> ---
>
> 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@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html