FUJITA Tomonori wrote: > 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; + unsigned bytes_requested = 0; >> + >> + 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. > > + /* + * tell blk layer all of the xmt data was sent. + * but set residual count to: requested - received + */ + + if (rsp) { + bytes_requested = blk_rq_bytes(rsp); + rsp->data_len = bytes_requested - job->reply->reply_payload_rcv_len; + } + + blk_end_bidi_request(job->req, err, blk_rq_bytes(job->req), bytes_requested); The residual count is left in req->data_len. Does bsg have a way to return the residual to user-mode? It must, since Pete was using that for sure. Note that you are looking for the bidi_read residual count. As was said by people. You must complete ALL bytes on both sides. Residual information is passed through req->data_len. Other wise the request is still active. (And yes blk_end_request uses blk_end_bidi_request internally) >> + 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. > I would suggest an fc_complete_request() defined that would do that. >> + 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 -- 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