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