* [RFC] pass through support in fc transport: via bsg (block SG)
@ 2008-08-18 19:04 Seokmann Ju
2008-08-19 17:42 ` Seokmann Ju
0 siblings, 1 reply; 10+ messages in thread
From: Seokmann Ju @ 2008-08-18 19:04 UTC (permalink / raw)
To: James.Smart, Robert W Love
Cc: linux-scsi, Andrew Vasquez, Boaz Harrosh, Mike Christie
This is a patch for the FC transport in an effort to support pass
through services based on previous discussion as below,
http://marc.info/?t=121569558300005&r=1&w=2
Following are remarks for the changes,
- the SMP in the SAS transport has referenced, so the layout of the
changes are quite similar to it
- at this stage, the ELS/CT service packet serviced one at a time,
synchronously
- there is dedicated handler in the LLDD for ELS and CT, respectively
- the sense data area of the 'request' structure will hold service reply
- device files are created in following directories for each of
discovered initiator/targets,
= /sys/class/bsg/rport-<host_no>:<bus>-<id>
= /dev/rport-<host_no>:<bus>-<id>
And following are to-dos,
- abort mechanism
- asynchronous packet handling
- detailing error handling, etc.
The patch has created against scsi-misc.
With this patch, qla2xxx is under testing for the feature.
Thank you,
Seokmann
---
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/
scsi_transport_fc.c
index 56823fd..44f6a9e 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -40,6 +40,7 @@
static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
static void fc_vport_sched_delete(struct work_struct *work);
+static void fc_bsg_remove(struct Scsi_Host *, struct fc_rport *);
/*
* This is a temporary carrier for creating a vport. It will
eventually
@@ -67,6 +68,12 @@ struct fc_vport_identifiers {
static int fc_vport_create(struct Scsi_Host *shost, int channel,
struct device *pdev, struct fc_vport_identifiers *ids,
struct fc_vport **vport);
+static void fc_service_timedout(unsigned long);
+static void fc_service_done(struct fc_service *);
+static int
+fc_service_handler(struct Scsi_Host *, struct fc_rport *, struct
request *);
+
+struct kmem_cache *fc_service_cache;
/*
* Redefine so that we can have same named attributes in the
@@ -666,6 +673,11 @@ static __init int fc_transport_init(void)
error = transport_class_register(&fc_rport_class);
if (error)
return error;
+ fc_service_cache = kmem_cache_create("fc_service",
+ sizeof(struct fc_service),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!fc_service_cache)
+ return -ENOMEM;
return transport_class_register(&fc_transport_class);
}
@@ -675,6 +687,7 @@ static void __exit fc_transport_exit(void)
transport_class_unregister(&fc_rport_class);
transport_class_unregister(&fc_host_class);
transport_class_unregister(&fc_vport_class);
+ kmem_cache_destroy(fc_service_cache);
}
/*
@@ -2081,6 +2094,9 @@ fc_attach_transport(struct fc_function_template
*ft)
i->f = ft;
+ /* for FC services (FC-CT, ELS, etc.) */
+ i->f->fc_service_handler = fc_service_handler;
+
/* Transport uses the shost workq for scsi scanning */
i->t.create_work_queue = 1;
@@ -2430,12 +2446,234 @@ fc_rport_final_delete(struct work_struct *work)
transport_remove_device(dev);
device_del(dev);
+ fc_bsg_remove(shost, rport);
transport_destroy_device(dev);
put_device(&shost->shost_gendev); /* for fc_host->rport list */
put_device(dev); /* for self-reference */
}
+static void fc_service_timedout(unsigned long _service)
+{
+ struct fc_service *service = (void *) _service;
+ unsigned long flags;
+
+ spin_lock_irqsave(&service->service_state_lock, flags);
+ if (!(service->service_state_flags & FC_SERVICE_STATE_DONE))
+ service->service_state_flags |= FC_SERVICE_STATE_ABORTED;
+ spin_unlock_irqrestore(&service->service_state_lock, flags);
+
+ complete(&service->completion);
+}
+
+static void fc_service_done(struct fc_service *service)
+{
+ if (!del_timer(&service->timer))
+ return;
+ complete (&service->completion);
+}
+
+static int
+issue_fc_service(struct fc_rport *rport, void *req, int req_size,
+ void *resp, int resp_size, void *service_reply)
+{
+ int res, retry;
+ struct fc_service *service = NULL;
+ struct Scsi_Host *shost = rport_to_shost(rport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+ struct fc_frame_header *frame = req;
+
+ if ((frame->fh_type == FC_FRAME_TYPE_ELS) ||
+ (frame->fh_type == FC_FRAME_TYPE_FC_CT))
+ service->service_type = frame->fh_type;
+ else {
+ printk(KERN_ERR "invalid FC service type = %2x\n",
+ frame->fh_type);
+ return -EINVAL;
+ }
+
+ service = fc_alloc_service(GFP_KERNEL);
+ if (!service)
+ return -ENOMEM;
+
+ service->ct_frame = (struct fc_ct_frame *) req;
+ service->req_size = req_size;
+ service->response = resp;
+ service->resp_size = resp_size;
+ service->rport = rport;
+ /* sense area of the request structure */
+ service->reply = service_reply;
+ service->service_done = fc_service_done;
+
+ service->timer.data = (unsigned long) service;
+ service->timer.function = fc_service_timedout;
+ service->timer.expires = jiffies + FC_SERVICE_TIMEOUT*HZ;
+
+ add_timer(&service->timer);
+
+ if (service->service_type == FC_FRAME_TYPE_ELS)
+ res = i->f->execute_fc_els_service(service);
+ else if (service->service_type == FC_FRAME_TYPE_FC_CT)
+ res = i->f->execute_fc_ct_service(service);
+ else
+ printk(KERN_WARNING "%s: ERROR: invalid "
+ "FC service type = %2x\n", __func__,
+ service->service_type);
+
+ if (res) {
+ del_timer(&service->timer);
+ printk(KERN_ERR "executing FC service failed:%d\n", res);
+ goto ex_err;
+ }
+
+ wait_for_completion(&service->completion);
+
+ res = -ECOMM;
+ if ((service->service_state_flags & FC_SERVICE_STATE_ABORTED)) {
+ printk(KERN_ERR "FC service timed out or aborted\n");
+ i->f->abort_fc_service(service);
+ if (!(service->service_state_flags &
+ FC_SERVICE_STATE_DONE)) {
+ printk(KERN_ERR "FC service aborted and not done\n");
+ goto ex_err;
+ }
+ }
+ if (service->service_status.resp == FC_SERVICE_COMPLETE)
+ res = 0;
+ else {
+ printk(KERN_ERR "%s: FC service to rport %p"
+ " response: 0x%x", __func__, rport,
+ service->service_status.resp);
+ fc_free_service(service);
+ service = NULL;
+ }
+ex_err:
+ BUG_ON(retry == 3 && service != NULL);
+ if (service != NULL) {
+ fc_free_service(service);
+ }
+ return res;
+}
+
+static int
+fc_service_handler(struct Scsi_Host *shost, struct fc_rport *rport,
+ struct request *req)
+{
+ int ret;
+ struct request *rsp = req->next_rq;
+
+ if (!rsp) {
+ printk("%s: space for a FC service response is missing\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* do we need to support multiple segments? */
+ if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
+ printk("%s: multiple segments req %u %u, rsp %u %u\n",
+ __func__, req->bio->bi_vcnt, req->data_len,
+ rsp->bio->bi_vcnt, rsp->data_len);
+ return -EINVAL;
+ }
+
+ ret = issue_fc_service(rport, bio_data(req->bio), req->data_len,
+ bio_data(rsp->bio), rsp->data_len, req->sense);
+ if (ret > 0) {
+ /* positive number is the untransferred residual */
+ rsp->data_len = ret;
+ req->data_len = 0;
+ ret = 0;
+ } else if (ret == 0) {
+ rsp->data_len = 0;
+ req->data_len = 0;
+ }
+
+ return ret;
+}
+
+static void fc_service_request(struct request_queue *q)
+{
+ struct request *req;
+ struct fc_rport *rport = q->queuedata;
+ struct Scsi_Host *shost = rport_to_shost(rport);
+ int (*handler)(struct Scsi_Host *, struct fc_rport *,
+ struct request *);
+
+ while (!blk_queue_plugged(q)) {
+ req = elv_next_request(q);
+ if (!req)
+ break;
+
+ blkdev_dequeue_request(req);
+
+ spin_unlock_irq(q->queue_lock);
+
+ handler = to_fc_internal(shost->transportt)->f->fc_service_handler;
+ if (handler)
+ req->errors = handler(shost, rport, req);
+
+ spin_lock_irq(q->queue_lock);
+
+ req->end_io(req, req->errors);
+ }
+}
+
+static int
+fc_bsg_initialize(struct Scsi_Host *shost, struct fc_rport *rport)
+{
+ struct request_queue *q;
+ int error;
+ struct device *dev;
+ const char *name;
+ void (*release)(struct device *);
+
+ if (!to_fc_internal(shost->transportt)->f->fc_service_handler) {
+ printk("%s can't handle FC service requests\n", shost->hostt->name);
+ return 0;
+ }
+
+ if (!rport) {
+ printk(KERN_WARNING " ERROR: rport is NULL\n");
+ return -ENOMEM;
+ }
+
+ q = blk_init_queue(fc_service_request, NULL);
+ dev = &rport->dev;
+ name = dev->bus_id;
+ release = NULL;
+
+ if (!q)
+ return -ENOMEM;
+
+ error = bsg_register_queue(q, dev, name, release);
+ if (error) {
+ blk_cleanup_queue(q);
+ return -ENOMEM;
+ }
+
+ rport->q = q;
+
+ q->queuedata = rport;
+
+ queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
+
+ return 0;
+}
+
+static void
+fc_bsg_remove(struct Scsi_Host *shost, struct fc_rport *rport)
+{
+ struct request_queue *q = rport->q;
+
+ if (!q) {
+ printk(KERN_WARNING "%s: ERROR: invalid queue\n",
+ __func__);
+ return;
+ }
+
+ bsg_unregister_queue(q);
+}
+
/**
* fc_rport_create - allocates and creates a remote FC port.
* @shost: scsi host the remote port is connected to.
@@ -2495,6 +2733,7 @@ fc_rport_create(struct Scsi_Host *shost, int
channel,
else
rport->scsi_target_id = -1;
list_add_tail(&rport->peers, &fc_host->rports);
+
get_device(&shost->shost_gendev); /* for fc_host->rport list */
spin_unlock_irqrestore(shost->host_lock, flags);
@@ -2515,6 +2754,9 @@ fc_rport_create(struct Scsi_Host *shost, int
channel,
transport_add_device(dev);
transport_configure_device(dev);
+ if (fc_bsg_initialize(shost, rport))
+ printk("fail to a bsg device %s\n", rport->dev.bus_id);
+
if (rport->roles & FC_PORT_ROLE_FCP_TARGET) {
/* initiate a scan of the target */
rport->flags |= FC_RPORT_SCAN_PENDING;
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/
scsi_transport_fc.h
index 878373c..f54e067 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -32,7 +32,7 @@
#include <scsi/scsi_netlink.h>
struct scsi_transport_template;
-
+extern struct kmem_cache *fc_service_cache;
/*
* FC Port definitions - Following FC HBAAPI guidelines
@@ -333,6 +333,8 @@ struct fc_rport { /* aka fc_starget_attrs */
struct delayed_work fail_io_work;
struct work_struct stgt_delete_work;
struct work_struct rport_delete_work;
+
+ struct request_queue *q;
} __attribute__((aligned(sizeof(unsigned long))));
/* bit field values for struct fc_rport "flags" field: */
@@ -495,6 +497,129 @@ struct fc_host_attrs {
struct workqueue_struct *devloss_work_q;
};
+#define FC_STATUS_BUF_SIZE 96
+
+enum fc_frame_type {
+ FC_FRAME_TYPE_BS,
+ FC_FRAME_TYPE_ELS,
+ FC_FRAME_TYPE_IEC = 4,
+ FC_FRAME_TYPE_IP,
+ FC_FRAME_TYPE_FCP = 8,
+ FC_FRAME_TYPE_GPP,
+ FC_FRAME_TYPE_FC_CT = 0x20,
+};
+
+enum service_response {
+ FC_SERVICE_COMPLETE,
+ FC_SERVICE_UNDELIVERED = -1,
+};
+
+#define FC_SERVICE_STATE_PENDING 1
+#define FC_SERVICE_STATE_DONE 2
+#define FC_SERVICE_STATE_ABORTED 4
+#define FC_SERVICE_AT_INITIATOR 16
+
+struct fc_service_status {
+ enum service_response resp;
+ int buf_valid_size;
+
+ u8 buf[FC_STATUS_BUF_SIZE];
+
+ u32 residual;
+};
+
+/* NOTE - fc_frame_header is already defined in open-fcoe-upstream
branch */
+/*
+ * Frame header
+ */
+struct fc_frame_header {
+ __u8 fh_r_ctl; /* routing control */
+ __u8 fh_d_id[3]; /* Destination ID */
+
+ __u8 fh_cs_ctl; /* class of service control / pri */
+ __u8 fh_s_id[3]; /* Source ID */
+
+ __u8 fh_type; /* see enum fc_fh_type below */
+ __u8 fh_f_ctl[3]; /* frame control */
+
+ __u8 fh_seq_id; /* sequence ID */
+ __u8 fh_df_ctl; /* data field control */
+ __be16 fh_seq_cnt; /* sequence count */
+
+ __be16 fh_ox_id; /* originator exchange ID */
+ __be16 fh_rx_id; /* responder exchange ID */
+ __be32 fh_parm_offset; /* parameter or relative offset */
+};
+
+/* TBD - fc_els_hdr to move to ~/include/scsi/fc/fc_els.h */
+struct fc_els_hdr {
+ __u8 els_cmd;
+ __u8 els_param[3];
+};
+
+/* NOTE - fc_ct_hdr is already defined in open-fcoe-upstream branch */
+/*
+ * Fibre Channel Services - Common Transport.
+ * From T11.org FC-GS-2 Rev 5.3 November 1998.
+ */
+
+struct fc_ct_hdr {
+ __u8 ct_rev; /* revision */
+ __u8 ct_in_id[3]; /* N_Port ID of original requestor */
+ __u8 ct_fs_type; /* type of fibre channel service */
+ __u8 ct_fs_subtype; /* subtype */
+ __u8 ct_options;
+ __u8 _ct_resvd1;
+ __be16 ct_cmd; /* command / response code */
+ __be16 ct_mr_size; /* maximum / residual size */
+ __u8 _ct_resvd2;
+ __u8 ct_reason; /* reject reason */
+ __u8 ct_explan; /* reason code explanation */
+ __u8 ct_vendor; /* vendor unique data */
+};
+
+struct fc_ct_frame {
+ struct fc_frame_header fc_hdr;
+ struct fc_ct_hdr ct_hdr;
+ u32 ct_cmd[1];
+};
+
+struct fc_els_frame {
+ struct fc_frame_header fc_hdr;
+ struct fc_els_hdr els_hdr;
+ u32 els_cmd[4];
+};
+
+#define FC_SERVICE_TIMEOUT 10
+
+struct fc_service {
+ struct fc_rport *rport;
+ struct list_head list;
+
+ spinlock_t service_state_lock;
+ unsigned service_state_flags;
+
+ enum fc_frame_type service_type;
+
+ /* Used by the discovery code. */
+ struct timer_list timer;
+ struct completion completion;
+
+ union {
+ struct fc_ct_frame *ct_frame;
+ struct fc_els_frame *els_frame;
+ };
+ int req_size;
+ void *response;
+ int resp_size;
+
+ struct fc_service_status service_status;
+ void *reply; /* pointer to sense area of request */
+ void (*service_done)(struct fc_service *);
+
+ struct work_struct abort_work;
+};
+
#define shost_to_fc_host(x) \
((struct fc_host_attrs *)(x)->shost_data)
@@ -593,6 +718,14 @@ struct fc_function_template {
int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
int (* it_nexus_response)(struct Scsi_Host *, u64, int);
+ /* fibre-channel services */
+ int (*fc_service_handler)(struct Scsi_Host *,
+ struct fc_rport *rport,
+ struct request *);
+ int (*execute_fc_els_service)(struct fc_service *);
+ int (*execute_fc_ct_service)(struct fc_service *);
+ int (*abort_fc_service)(struct fc_service *);
+
/* allocation lengths for host-specific data */
u32 dd_fcrport_size;
u32 dd_fcvport_size;
@@ -713,6 +846,31 @@ fc_vport_set_state(struct fc_vport *vport, enum
fc_vport_state new_state)
vport->vport_state = new_state;
}
+static inline struct fc_service *
+fc_alloc_service(gfp_t flags)
+{
+ struct fc_service *service = kmem_cache_zalloc(fc_service_cache,
flags);
+
+ if (service) {
+ INIT_LIST_HEAD(&service->list);
+ spin_lock_init(&service->service_state_lock);
+ service->service_state_flags = FC_SERVICE_STATE_PENDING;
+ init_timer(&service->timer);
+ init_completion(&service->completion);
+ }
+
+ return service;
+}
+
+static inline void
+fc_free_service(struct fc_service *service)
+{
+ if (service) {
+ BUG_ON(!list_empty(&service->list));
+ kmem_cache_free(fc_service_cache, service);
+ }
+}
+
struct scsi_transport_template *fc_attach_transport(
struct fc_function_template *);
---
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [RFC] pass through support in fc transport: via bsg (block SG)
2008-08-18 19:04 [RFC] pass through support in fc transport: via bsg (block SG) Seokmann Ju
@ 2008-08-19 17:42 ` Seokmann Ju
2008-08-22 21:36 ` Seokmann Ju
0 siblings, 1 reply; 10+ messages in thread
From: Seokmann Ju @ 2008-08-19 17:42 UTC (permalink / raw)
To: James.Smart, Robert W Love
Cc: linux-scsi, Andrew Vasquez, Boaz Harrosh, Mike Christie
On Aug 18, 2008, at 12:04 PM, Seokmann Ju wrote:
> This is a patch for the FC transport in an effort to support pass
> through services based on previous discussion as below,
> http://marc.info/?t=121569558300005&r=1&w=2
>
> Following are remarks for the changes,
> - the SMP in the SAS transport has referenced, so the layout of the
> changes are quite similar to it
> - at this stage, the ELS/CT service packet serviced one at a time,
> synchronously
> - there is dedicated handler in the LLDD for ELS and CT, respectively
> - the sense data area of the 'request' structure will hold service
> reply
> - device files are created in following directories for each of
> discovered initiator/targets,
> = /sys/class/bsg/rport-<host_no>:<bus>-<id>
> = /dev/rport-<host_no>:<bus>-<id>
>
> And following are to-dos,
> - abort mechanism
> - asynchronous packet handling
> - detailing error handling, etc.
>
> The patch has created against scsi-misc.
> With this patch, qla2xxx is under testing for the feature.
Just realized that the one that submitted before is not the latest,
and here is the latest.
I apologize for any inconveniences.
Seokmann
---
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/
scsi_transport_fc.c
index 56823fd..a4cef16 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -40,6 +40,7 @@
static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
static void fc_vport_sched_delete(struct work_struct *work);
+static void fc_bsg_remove(struct Scsi_Host *, struct fc_rport *);
/*
* This is a temporary carrier for creating a vport. It will
eventually
@@ -67,6 +68,12 @@ struct fc_vport_identifiers {
static int fc_vport_create(struct Scsi_Host *shost, int channel,
struct device *pdev, struct fc_vport_identifiers *ids,
struct fc_vport **vport);
+static void fc_service_timedout(unsigned long);
+static void fc_service_done(struct fc_service *);
+static int
+fc_service_handler(struct Scsi_Host *, struct fc_rport *, struct
request *);
+
+struct kmem_cache *fc_service_cache;
/*
* Redefine so that we can have same named attributes in the
@@ -666,6 +673,11 @@ static __init int fc_transport_init(void)
error = transport_class_register(&fc_rport_class);
if (error)
return error;
+ fc_service_cache = kmem_cache_create("fc_service",
+ sizeof(struct fc_service),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!fc_service_cache)
+ return -ENOMEM;
return transport_class_register(&fc_transport_class);
}
@@ -675,6 +687,7 @@ static void __exit fc_transport_exit(void)
transport_class_unregister(&fc_rport_class);
transport_class_unregister(&fc_host_class);
transport_class_unregister(&fc_vport_class);
+ kmem_cache_destroy(fc_service_cache);
}
/*
@@ -2081,6 +2094,9 @@ fc_attach_transport(struct fc_function_template
*ft)
i->f = ft;
+ /* for FC services (FC-CT, ELS, etc.) */
+ i->f->fc_service_handler = fc_service_handler;
+
/* Transport uses the shost workq for scsi scanning */
i->t.create_work_queue = 1;
@@ -2430,12 +2446,240 @@ fc_rport_final_delete(struct work_struct *work)
transport_remove_device(dev);
device_del(dev);
+ fc_bsg_remove(shost, rport);
transport_destroy_device(dev);
put_device(&shost->shost_gendev); /* for fc_host->rport list */
put_device(dev); /* for self-reference */
}
+static void fc_service_timedout(unsigned long _service)
+{
+ struct fc_service *service = (void *) _service;
+ unsigned long flags;
+
+ spin_lock_irqsave(&service->service_state_lock, flags);
+ if (!(service->service_state_flags & FC_SERVICE_STATE_DONE))
+ service->service_state_flags |= FC_SERVICE_STATE_ABORTED;
+ spin_unlock_irqrestore(&service->service_state_lock, flags);
+
+ complete(&service->completion);
+}
+
+static void fc_service_done(struct fc_service *service)
+{
+ if (!del_timer(&service->timer))
+ return;
+ complete(&service->completion);
+}
+
+static int
+issue_fc_service(struct fc_rport *rport, void *req, int req_size,
+ void *resp, int resp_size, void *service_reply)
+{
+ int res = -ECOMM;
+ struct fc_service *service = NULL;
+ struct Scsi_Host *shost = rport_to_shost(rport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+ struct fc_frame_header *frame = req;
+
+ if (!((frame->fh_type == FC_FRAME_TYPE_ELS) ||
+ (frame->fh_type == FC_FRAME_TYPE_FC_CT))) {
+ printk(KERN_ERR "invalid FC service type = %2x\n",
+ frame->fh_type);
+ return -EINVAL;
+ }
+
+ service = fc_alloc_service(GFP_KERNEL);
+ if (!service)
+ return -ENOMEM;
+
+ service->service_type = frame->fh_type;
+ service->ct_frame = (struct fc_ct_frame *) req;
+ service->req_size = req_size;
+ service->response = resp;
+ service->resp_size = resp_size;
+ service->rport = rport;
+ /* sense area of the request structure */
+ service->reply_seq = service_reply;
+ service->service_done = fc_service_done;
+
+ service->timer.data = (unsigned long) service;
+ service->timer.function = fc_service_timedout;
+ service->timer.expires = jiffies + FC_SERVICE_TIMEOUT*HZ;
+
+ sg_init_one(&service->sg_req, req, req_size);
+ sg_init_one(&service->sg_resp, resp, resp_size);
+
+ add_timer(&service->timer);
+
+ if (service->service_type == FC_FRAME_TYPE_ELS) {
+ if (!i->f->execute_fc_els_service)
+ goto ex_err;
+ res = i->f->execute_fc_els_service(service);
+ } else if (service->service_type == FC_FRAME_TYPE_FC_CT) {
+ if (!i->f->execute_fc_ct_service)
+ goto ex_err;
+ res = i->f->execute_fc_ct_service(service);
+ } else
+ printk(KERN_WARNING "%s: ERROR: invalid "
+ "FC service type = %2x\n", __func__,
+ service->service_type);
+
+ if (res) {
+ del_timer(&service->timer);
+ printk(KERN_ERR "executing FC service failed:%d\n", res);
+ goto ex_err;
+ }
+
+ wait_for_completion(&service->completion);
+
+ if ((service->service_state_flags & FC_SERVICE_STATE_ABORTED)) {
+ printk(KERN_ERR "FC service timed out or aborted\n");
+ i->f->abort_fc_service(service);
+ if (!(service->service_state_flags &
+ FC_SERVICE_STATE_DONE)) {
+ printk(KERN_ERR "FC service aborted and not done\n");
+ goto ex_err;
+ }
+ }
+ if (service->service_status.resp == FC_SERVICE_COMPLETE)
+ res = 0;
+ else {
+ printk(KERN_ERR "%s: FC service to rport %p"
+ " response: 0x%x", __func__, rport,
+ service->service_status.resp);
+ fc_free_service(service);
+ service = NULL;
+ }
+ex_err:
+ BUG_ON(service == NULL);
+ if (service != NULL)
+ fc_free_service(service);
+
+ return res;
+}
+
+static int
+fc_service_handler(struct Scsi_Host *shost, struct fc_rport *rport,
+ struct request *req)
+{
+ int ret;
+ struct request *rsp = req->next_rq;
+
+ if (!rsp) {
+ printk(KERN_WARNING "%s: space for a FC service"
+ " response is missing\n", __func__);
+ return -EINVAL;
+ }
+
+ /* do we need to support multiple segments? */
+ if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
+ printk(KERN_WARNING "%s: multiple segments req %u %u,"
+ " rsp %u %u\n", __func__, req->bio->bi_vcnt,
+ req->data_len, rsp->bio->bi_vcnt, rsp->data_len);
+ return -EINVAL;
+ }
+
+ ret = issue_fc_service(rport, bio_data(req->bio), req->data_len,
+ bio_data(rsp->bio), rsp->data_len, req->sense);
+ if (ret > 0) {
+ /* positive number is the untransferred residual */
+ rsp->data_len = ret;
+ req->data_len = 0;
+ ret = 0;
+ } else if (ret == 0) {
+ rsp->data_len = 0;
+ req->data_len = 0;
+ }
+
+ return ret;
+}
+
+static void fc_service_request(struct request_queue *q)
+{
+ struct request *req;
+ struct fc_rport *rport = q->queuedata;
+ struct Scsi_Host *shost = rport_to_shost(rport);
+ int (*handler)(struct Scsi_Host *, struct fc_rport *,
+ struct request *);
+
+ while (!blk_queue_plugged(q)) {
+ req = elv_next_request(q);
+ if (!req)
+ break;
+
+ blkdev_dequeue_request(req);
+
+ spin_unlock_irq(q->queue_lock);
+
+ handler = to_fc_internal(shost->transportt)->f->fc_service_handler;
+ if (handler)
+ req->errors = handler(shost, rport, req);
+
+ spin_lock_irq(q->queue_lock);
+
+ req->end_io(req, req->errors);
+ }
+}
+
+static int
+fc_bsg_initialize(struct Scsi_Host *shost, struct fc_rport *rport)
+{
+ struct request_queue *q;
+ int error;
+ struct device *dev;
+ const char *name;
+ void (*release)(struct device *);
+
+ if (!to_fc_internal(shost->transportt)->f->fc_service_handler) {
+ printk(KERN_WARNING "%s can't handle FC service requests\n",
+ shost->hostt->name);
+ return 0;
+ }
+
+ if (!rport) {
+ printk(KERN_WARNING " ERROR: rport is NULL\n");
+ return -ENOMEM;
+ }
+
+ q = blk_init_queue(fc_service_request, NULL);
+ dev = &rport->dev;
+ name = dev->bus_id;
+ release = NULL;
+
+ if (!q)
+ return -ENOMEM;
+
+ error = bsg_register_queue(q, dev, name, release);
+ if (error) {
+ blk_cleanup_queue(q);
+ return -ENOMEM;
+ }
+
+ rport->q = q;
+
+ q->queuedata = rport;
+
+ queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
+
+ return 0;
+}
+
+static void
+fc_bsg_remove(struct Scsi_Host *shost, struct fc_rport *rport)
+{
+ struct request_queue *q = rport->q;
+
+ if (!q) {
+ printk(KERN_WARNING "%s: ERROR: invalid queue\n",
+ __func__);
+ return;
+ }
+
+ bsg_unregister_queue(q);
+}
+
/**
* fc_rport_create - allocates and creates a remote FC port.
* @shost: scsi host the remote port is connected to.
@@ -2495,6 +2739,7 @@ fc_rport_create(struct Scsi_Host *shost, int
channel,
else
rport->scsi_target_id = -1;
list_add_tail(&rport->peers, &fc_host->rports);
+
get_device(&shost->shost_gendev); /* for fc_host->rport list */
spin_unlock_irqrestore(shost->host_lock, flags);
@@ -2515,6 +2760,9 @@ fc_rport_create(struct Scsi_Host *shost, int
channel,
transport_add_device(dev);
transport_configure_device(dev);
+ if (fc_bsg_initialize(shost, rport))
+ printk(KERN_WARNING "fail to a bsg device %s\n", rport->dev.bus_id);
+
if (rport->roles & FC_PORT_ROLE_FCP_TARGET) {
/* initiate a scan of the target */
rport->flags |= FC_RPORT_SCAN_PENDING;
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/
scsi_transport_fc.h
index 878373c..3cb3847 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -32,7 +32,7 @@
#include <scsi/scsi_netlink.h>
struct scsi_transport_template;
-
+extern struct kmem_cache *fc_service_cache;
/*
* FC Port definitions - Following FC HBAAPI guidelines
@@ -333,6 +333,8 @@ struct fc_rport { /* aka fc_starget_attrs */
struct delayed_work fail_io_work;
struct work_struct stgt_delete_work;
struct work_struct rport_delete_work;
+
+ struct request_queue *q;
} __attribute__((aligned(sizeof(unsigned long))));
/* bit field values for struct fc_rport "flags" field: */
@@ -495,6 +497,132 @@ struct fc_host_attrs {
struct workqueue_struct *devloss_work_q;
};
+#define FC_STATUS_BUF_SIZE 96
+
+enum fc_frame_type {
+ FC_FRAME_TYPE_BS,
+ FC_FRAME_TYPE_ELS,
+ FC_FRAME_TYPE_IEC = 4,
+ FC_FRAME_TYPE_IP,
+ FC_FRAME_TYPE_FCP = 8,
+ FC_FRAME_TYPE_GPP,
+ FC_FRAME_TYPE_FC_CT = 0x20,
+};
+
+enum service_response {
+ FC_SERVICE_COMPLETE,
+ FC_SERVICE_UNDELIVERED = -1,
+};
+
+#define FC_SERVICE_STATE_PENDING 1
+#define FC_SERVICE_STATE_DONE 2
+#define FC_SERVICE_STATE_ABORTED 4
+#define FC_SERVICE_AT_INITIATOR 16
+
+struct fc_service_status {
+ enum service_response resp;
+ int buf_valid_size;
+
+ u8 buf[FC_STATUS_BUF_SIZE];
+
+ u32 residual;
+};
+
+/* NOTE - fc_frame_header is already defined in open-fcoe-upstream
branch */
+/*
+ * Frame header
+ */
+struct fc_frame_header {
+ __u8 fh_r_ctl; /* routing control */
+ __u8 fh_d_id[3]; /* Destination ID */
+
+ __u8 fh_cs_ctl; /* class of service control / pri */
+ __u8 fh_s_id[3]; /* Source ID */
+
+ __u8 fh_type; /* see enum fc_fh_type below */
+ __u8 fh_f_ctl[3]; /* frame control */
+
+ __u8 fh_seq_id; /* sequence ID */
+ __u8 fh_df_ctl; /* data field control */
+ __be16 fh_seq_cnt; /* sequence count */
+
+ __be16 fh_ox_id; /* originator exchange ID */
+ __be16 fh_rx_id; /* responder exchange ID */
+ __be32 fh_parm_offset; /* parameter or relative offset */
+};
+
+/* TBD - fc_els_hdr to move to ~/include/scsi/fc/fc_els.h */
+struct fc_els_hdr {
+ __u8 els_cmd;
+ __u8 els_param[3];
+};
+
+/* NOTE - fc_ct_hdr is already defined in open-fcoe-upstream branch */
+/*
+ * Fibre Channel Services - Common Transport.
+ * From T11.org FC-GS-2 Rev 5.3 November 1998.
+ */
+
+struct fc_ct_hdr {
+ __u8 ct_rev; /* revision */
+ __u8 ct_in_id[3]; /* N_Port ID of original requestor */
+ __u8 ct_fs_type; /* type of fibre channel service */
+ __u8 ct_fs_subtype; /* subtype */
+ __u8 ct_options;
+ __u8 _ct_resvd1;
+ __be16 ct_cmd; /* command / response code */
+ __be16 ct_mr_size; /* maximum / residual size */
+ __u8 _ct_resvd2;
+ __u8 ct_reason; /* reject reason */
+ __u8 ct_explan; /* reason code explanation */
+ __u8 ct_vendor; /* vendor unique data */
+};
+
+struct fc_els_frame {
+ struct fc_frame_header fc_hdr;
+ struct fc_els_hdr els_hdr;
+ u32 els_cmd[4];
+};
+
+struct fc_ct_frame {
+ struct fc_frame_header fc_hdr;
+ struct fc_ct_hdr ct_hdr;
+ u32 ct_cmd[1];
+};
+
+#define FC_SERVICE_TIMEOUT 10
+
+struct fc_service {
+ struct fc_rport *rport;
+ struct list_head list;
+
+ spinlock_t service_state_lock;
+ unsigned service_state_flags;
+
+ enum fc_frame_type service_type;
+
+ /* Used by the discovery code. */
+ struct timer_list timer;
+ struct completion completion;
+
+ union {
+ struct fc_ct_frame *ct_frame;
+ struct fc_els_frame *els_frame;
+ };
+ int req_size;
+ void *response;
+ int resp_size;
+
+ struct scatterlist sg_req;
+ struct scatterlist sg_resp;
+
+ struct fc_service_status service_status;
+ void *reply_seq; /* pointer to sense area of request */
+ void (*service_done)(struct fc_service *);
+
+ struct work_struct abort_work;
+};
+
#define shost_to_fc_host(x) \
((struct fc_host_attrs *)(x)->shost_data)
@@ -593,6 +721,14 @@ struct fc_function_template {
int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
int (* it_nexus_response)(struct Scsi_Host *, u64, int);
+ /* fibre-channel services */
+ int (*fc_service_handler)(struct Scsi_Host *,
+ struct fc_rport *rport,
+ struct request *);
+ int (*execute_fc_els_service)(struct fc_service *);
+ int (*execute_fc_ct_service)(struct fc_service *);
+ int (*abort_fc_service)(struct fc_service *);
+
/* allocation lengths for host-specific data */
u32 dd_fcrport_size;
u32 dd_fcvport_size;
@@ -713,6 +849,31 @@ fc_vport_set_state(struct fc_vport *vport, enum
fc_vport_state new_state)
vport->vport_state = new_state;
}
+static inline struct fc_service *
+fc_alloc_service(gfp_t flags)
+{
+ struct fc_service *service = kmem_cache_zalloc(fc_service_cache,
flags);
+
+ if (service) {
+ INIT_LIST_HEAD(&service->list);
+ spin_lock_init(&service->service_state_lock);
+ service->service_state_flags = FC_SERVICE_STATE_PENDING;
+ init_timer(&service->timer);
+ init_completion(&service->completion);
+ }
+
+ return service;
+}
+
+static inline void
+fc_free_service(struct fc_service *service)
+{
+ if (service) {
+ BUG_ON(!list_empty(&service->list));
+ kmem_cache_free(fc_service_cache, service);
+ }
+}
+
struct scsi_transport_template *fc_attach_transport(
struct fc_function_template *);
---
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [RFC] pass through support in fc transport: via bsg (block SG)
2008-08-19 17:42 ` Seokmann Ju
@ 2008-08-22 21:36 ` Seokmann Ju
2008-08-22 21:53 ` James Smart
0 siblings, 1 reply; 10+ messages in thread
From: Seokmann Ju @ 2008-08-22 21:36 UTC (permalink / raw)
To: James.Smart, Robert W Love
Cc: linux-scsi, Andrew Vasquez, Boaz Harrosh, Mike Christie
On Aug 19, 2008, at 10:42 AM, Seokmann Ju wrote:
>
> On Aug 18, 2008, at 12:04 PM, Seokmann Ju wrote:
>
>> This is a patch for the FC transport in an effort to support pass
>> through services based on previous discussion as below,
>> http://marc.info/?t=121569558300005&r=1&w=2
>>
>> Following are remarks for the changes,
>> - the SMP in the SAS transport has referenced, so the layout of the
>> changes are quite similar to it
>> - at this stage, the ELS/CT service packet serviced one at a time,
>> synchronously
>> - there is dedicated handler in the LLDD for ELS and CT, respectively
>> - the sense data area of the 'request' structure will hold service
>> reply
>> - device files are created in following directories for each of
>> discovered initiator/targets,
>> = /sys/class/bsg/rport-<host_no>:<bus>-<id>
>> = /dev/rport-<host_no>:<bus>-<id>
>>
>> And following are to-dos,
>> - abort mechanism
>> - asynchronous packet handling
>> - detailing error handling, etc.
>>
>> The patch has created against scsi-misc.
>> With this patch, qla2xxx is under testing for the feature.
> Just realized that the one that submitted before is not the latest,
> and here is the latest.
> I apologize for any inconveniences.
I just want to re-stroke this thread to make sure it is not skipped.
One question came to me while testing qla2xxx module with the changes.
When the application issues ELS/CT packet, should the packet include
the FC frame header?
And if the answer is 'yes', should the driver also include the FC
frame header when it returns response to the application (just like
any other frame exchanges in between two ports on the FC)?
The FC frame header has type field that identifies what type of the
payload (ELS / CT / etc.) the frame contains and the type field is
being checked by the FC transport layer before it calls LLDD's handler.
Thank you,
Seokmann
>
>
> Seokmann
> ---
> diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/
> scsi_transport_fc.c
> index 56823fd..a4cef16 100644
> --- a/drivers/scsi/scsi_transport_fc.c
> +++ b/drivers/scsi/scsi_transport_fc.c
> @@ -40,6 +40,7 @@
>
> static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
> static void fc_vport_sched_delete(struct work_struct *work);
> +static void fc_bsg_remove(struct Scsi_Host *, struct fc_rport *);
>
> /*
> * This is a temporary carrier for creating a vport. It will
> eventually
> @@ -67,6 +68,12 @@ struct fc_vport_identifiers {
> static int fc_vport_create(struct Scsi_Host *shost, int channel,
> struct device *pdev, struct fc_vport_identifiers *ids,
> struct fc_vport **vport);
> +static void fc_service_timedout(unsigned long);
> +static void fc_service_done(struct fc_service *);
> +static int
> +fc_service_handler(struct Scsi_Host *, struct fc_rport *, struct
> request *);
> +
> +struct kmem_cache *fc_service_cache;
>
> /*
> * Redefine so that we can have same named attributes in the
> @@ -666,6 +673,11 @@ static __init int fc_transport_init(void)
> error = transport_class_register(&fc_rport_class);
> if (error)
> return error;
> + fc_service_cache = kmem_cache_create("fc_service",
> + sizeof(struct fc_service),
> + 0, SLAB_HWCACHE_ALIGN, NULL);
> + if (!fc_service_cache)
> + return -ENOMEM;
> return transport_class_register(&fc_transport_class);
> }
>
> @@ -675,6 +687,7 @@ static void __exit fc_transport_exit(void)
> transport_class_unregister(&fc_rport_class);
> transport_class_unregister(&fc_host_class);
> transport_class_unregister(&fc_vport_class);
> + kmem_cache_destroy(fc_service_cache);
> }
>
> /*
> @@ -2081,6 +2094,9 @@ fc_attach_transport(struct
> fc_function_template *ft)
>
> i->f = ft;
>
> + /* for FC services (FC-CT, ELS, etc.) */
> + i->f->fc_service_handler = fc_service_handler;
> +
> /* Transport uses the shost workq for scsi scanning */
> i->t.create_work_queue = 1;
>
> @@ -2430,12 +2446,240 @@ fc_rport_final_delete(struct work_struct
> *work)
>
> transport_remove_device(dev);
> device_del(dev);
> + fc_bsg_remove(shost, rport);
> transport_destroy_device(dev);
> put_device(&shost->shost_gendev); /* for fc_host->rport list */
> put_device(dev); /* for self-reference */
> }
>
>
> +static void fc_service_timedout(unsigned long _service)
> +{
> + struct fc_service *service = (void *) _service;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&service->service_state_lock, flags);
> + if (!(service->service_state_flags & FC_SERVICE_STATE_DONE))
> + service->service_state_flags |= FC_SERVICE_STATE_ABORTED;
> + spin_unlock_irqrestore(&service->service_state_lock, flags);
> +
> + complete(&service->completion);
> +}
> +
> +static void fc_service_done(struct fc_service *service)
> +{
> + if (!del_timer(&service->timer))
> + return;
> + complete(&service->completion);
> +}
> +
> +static int
> +issue_fc_service(struct fc_rport *rport, void *req, int req_size,
> + void *resp, int resp_size, void *service_reply)
> +{
> + int res = -ECOMM;
> + struct fc_service *service = NULL;
> + struct Scsi_Host *shost = rport_to_shost(rport);
> + struct fc_internal *i = to_fc_internal(shost->transportt);
> + struct fc_frame_header *frame = req;
> +
> + if (!((frame->fh_type == FC_FRAME_TYPE_ELS) ||
> + (frame->fh_type == FC_FRAME_TYPE_FC_CT))) {
> + printk(KERN_ERR "invalid FC service type = %2x\n",
> + frame->fh_type);
> + return -EINVAL;
> + }
> +
> + service = fc_alloc_service(GFP_KERNEL);
> + if (!service)
> + return -ENOMEM;
> +
> + service->service_type = frame->fh_type;
> + service->ct_frame = (struct fc_ct_frame *) req;
> + service->req_size = req_size;
> + service->response = resp;
> + service->resp_size = resp_size;
> + service->rport = rport;
> + /* sense area of the request structure */
> + service->reply_seq = service_reply;
> + service->service_done = fc_service_done;
> +
> + service->timer.data = (unsigned long) service;
> + service->timer.function = fc_service_timedout;
> + service->timer.expires = jiffies + FC_SERVICE_TIMEOUT*HZ;
> +
> + sg_init_one(&service->sg_req, req, req_size);
> + sg_init_one(&service->sg_resp, resp, resp_size);
> +
> + add_timer(&service->timer);
> +
> + if (service->service_type == FC_FRAME_TYPE_ELS) {
> + if (!i->f->execute_fc_els_service)
> + goto ex_err;
> + res = i->f->execute_fc_els_service(service);
> + } else if (service->service_type == FC_FRAME_TYPE_FC_CT) {
> + if (!i->f->execute_fc_ct_service)
> + goto ex_err;
> + res = i->f->execute_fc_ct_service(service);
> + } else
> + printk(KERN_WARNING "%s: ERROR: invalid "
> + "FC service type = %2x\n", __func__,
> + service->service_type);
> +
> + if (res) {
> + del_timer(&service->timer);
> + printk(KERN_ERR "executing FC service failed:%d\n", res);
> + goto ex_err;
> + }
> +
> + wait_for_completion(&service->completion);
> +
> + if ((service->service_state_flags & FC_SERVICE_STATE_ABORTED)) {
> + printk(KERN_ERR "FC service timed out or aborted\n");
> + i->f->abort_fc_service(service);
> + if (!(service->service_state_flags &
> + FC_SERVICE_STATE_DONE)) {
> + printk(KERN_ERR "FC service aborted and not done\n");
> + goto ex_err;
> + }
> + }
> + if (service->service_status.resp == FC_SERVICE_COMPLETE)
> + res = 0;
> + else {
> + printk(KERN_ERR "%s: FC service to rport %p"
> + " response: 0x%x", __func__, rport,
> + service->service_status.resp);
> + fc_free_service(service);
> + service = NULL;
> + }
> +ex_err:
> + BUG_ON(service == NULL);
> + if (service != NULL)
> + fc_free_service(service);
> +
> + return res;
> +}
> +
> +static int
> +fc_service_handler(struct Scsi_Host *shost, struct fc_rport *rport,
> + struct request *req)
> +{
> + int ret;
> + struct request *rsp = req->next_rq;
> +
> + if (!rsp) {
> + printk(KERN_WARNING "%s: space for a FC service"
> + " response is missing\n", __func__);
> + return -EINVAL;
> + }
> +
> + /* do we need to support multiple segments? */
> + if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
> + printk(KERN_WARNING "%s: multiple segments req %u %u,"
> + " rsp %u %u\n", __func__, req->bio->bi_vcnt,
> + req->data_len, rsp->bio->bi_vcnt, rsp->data_len);
> + return -EINVAL;
> + }
> +
> + ret = issue_fc_service(rport, bio_data(req->bio), req->data_len,
> + bio_data(rsp->bio), rsp->data_len, req->sense);
> + if (ret > 0) {
> + /* positive number is the untransferred residual */
> + rsp->data_len = ret;
> + req->data_len = 0;
> + ret = 0;
> + } else if (ret == 0) {
> + rsp->data_len = 0;
> + req->data_len = 0;
> + }
> +
> + return ret;
> +}
> +
> +static void fc_service_request(struct request_queue *q)
> +{
> + struct request *req;
> + struct fc_rport *rport = q->queuedata;
> + struct Scsi_Host *shost = rport_to_shost(rport);
> + int (*handler)(struct Scsi_Host *, struct fc_rport *,
> + struct request *);
> +
> + while (!blk_queue_plugged(q)) {
> + req = elv_next_request(q);
> + if (!req)
> + break;
> +
> + blkdev_dequeue_request(req);
> +
> + spin_unlock_irq(q->queue_lock);
> +
> + handler = to_fc_internal(shost->transportt)->f->fc_service_handler;
> + if (handler)
> + req->errors = handler(shost, rport, req);
> +
> + spin_lock_irq(q->queue_lock);
> +
> + req->end_io(req, req->errors);
> + }
> +}
> +
> +static int
> +fc_bsg_initialize(struct Scsi_Host *shost, struct fc_rport *rport)
> +{
> + struct request_queue *q;
> + int error;
> + struct device *dev;
> + const char *name;
> + void (*release)(struct device *);
> +
> + if (!to_fc_internal(shost->transportt)->f->fc_service_handler) {
> + printk(KERN_WARNING "%s can't handle FC service requests\n",
> + shost->hostt->name);
> + return 0;
> + }
> +
> + if (!rport) {
> + printk(KERN_WARNING " ERROR: rport is NULL\n");
> + return -ENOMEM;
> + }
> +
> + q = blk_init_queue(fc_service_request, NULL);
> + dev = &rport->dev;
> + name = dev->bus_id;
> + release = NULL;
> +
> + if (!q)
> + return -ENOMEM;
> +
> + error = bsg_register_queue(q, dev, name, release);
> + if (error) {
> + blk_cleanup_queue(q);
> + return -ENOMEM;
> + }
> +
> + rport->q = q;
> +
> + q->queuedata = rport;
> +
> + queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
> +
> + return 0;
> +}
> +
> +static void
> +fc_bsg_remove(struct Scsi_Host *shost, struct fc_rport *rport)
> +{
> + struct request_queue *q = rport->q;
> +
> + if (!q) {
> + printk(KERN_WARNING "%s: ERROR: invalid queue\n",
> + __func__);
> + return;
> + }
> +
> + bsg_unregister_queue(q);
> +}
> +
> /**
> * fc_rport_create - allocates and creates a remote FC port.
> * @shost: scsi host the remote port is connected to.
> @@ -2495,6 +2739,7 @@ fc_rport_create(struct Scsi_Host *shost, int
> channel,
> else
> rport->scsi_target_id = -1;
> list_add_tail(&rport->peers, &fc_host->rports);
> +
> get_device(&shost->shost_gendev); /* for fc_host->rport list */
>
> spin_unlock_irqrestore(shost->host_lock, flags);
> @@ -2515,6 +2760,9 @@ fc_rport_create(struct Scsi_Host *shost, int
> channel,
> transport_add_device(dev);
> transport_configure_device(dev);
>
> + if (fc_bsg_initialize(shost, rport))
> + printk(KERN_WARNING "fail to a bsg device %s\n", rport-
> >dev.bus_id);
> +
> if (rport->roles & FC_PORT_ROLE_FCP_TARGET) {
> /* initiate a scan of the target */
> rport->flags |= FC_RPORT_SCAN_PENDING;
> diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/
> scsi_transport_fc.h
> index 878373c..3cb3847 100644
> --- a/include/scsi/scsi_transport_fc.h
> +++ b/include/scsi/scsi_transport_fc.h
> @@ -32,7 +32,7 @@
> #include <scsi/scsi_netlink.h>
>
> struct scsi_transport_template;
> -
> +extern struct kmem_cache *fc_service_cache;
>
> /*
> * FC Port definitions - Following FC HBAAPI guidelines
> @@ -333,6 +333,8 @@ struct fc_rport { /* aka fc_starget_attrs */
> struct delayed_work fail_io_work;
> struct work_struct stgt_delete_work;
> struct work_struct rport_delete_work;
> +
> + struct request_queue *q;
> } __attribute__((aligned(sizeof(unsigned long))));
>
> /* bit field values for struct fc_rport "flags" field: */
> @@ -495,6 +497,132 @@ struct fc_host_attrs {
> struct workqueue_struct *devloss_work_q;
> };
>
> +#define FC_STATUS_BUF_SIZE 96
> +
> +enum fc_frame_type {
> + FC_FRAME_TYPE_BS,
> + FC_FRAME_TYPE_ELS,
> + FC_FRAME_TYPE_IEC = 4,
> + FC_FRAME_TYPE_IP,
> + FC_FRAME_TYPE_FCP = 8,
> + FC_FRAME_TYPE_GPP,
> + FC_FRAME_TYPE_FC_CT = 0x20,
> +};
> +
> +enum service_response {
> + FC_SERVICE_COMPLETE,
> + FC_SERVICE_UNDELIVERED = -1,
> +};
> +
> +#define FC_SERVICE_STATE_PENDING 1
> +#define FC_SERVICE_STATE_DONE 2
> +#define FC_SERVICE_STATE_ABORTED 4
> +#define FC_SERVICE_AT_INITIATOR 16
> +
> +struct fc_service_status {
> + enum service_response resp;
> + int buf_valid_size;
> +
> + u8 buf[FC_STATUS_BUF_SIZE];
> +
> + u32 residual;
> +};
> +
> +/* NOTE - fc_frame_header is already defined in open-fcoe-upstream
> branch */
> +/*
> + * Frame header
> + */
> +struct fc_frame_header {
> + __u8 fh_r_ctl; /* routing control */
> + __u8 fh_d_id[3]; /* Destination ID */
> +
> + __u8 fh_cs_ctl; /* class of service control / pri */
> + __u8 fh_s_id[3]; /* Source ID */
> +
> + __u8 fh_type; /* see enum fc_fh_type below */
> + __u8 fh_f_ctl[3]; /* frame control */
> +
> + __u8 fh_seq_id; /* sequence ID */
> + __u8 fh_df_ctl; /* data field control */
> + __be16 fh_seq_cnt; /* sequence count */
> +
> + __be16 fh_ox_id; /* originator exchange ID */
> + __be16 fh_rx_id; /* responder exchange ID */
> + __be32 fh_parm_offset; /* parameter or relative offset */
> +};
> +
> +/* TBD - fc_els_hdr to move to ~/include/scsi/fc/fc_els.h */
> +struct fc_els_hdr {
> + __u8 els_cmd;
> + __u8 els_param[3];
> +};
> +
> +/* NOTE - fc_ct_hdr is already defined in open-fcoe-upstream branch
> */
> +/*
> + * Fibre Channel Services - Common Transport.
> + * From T11.org FC-GS-2 Rev 5.3 November 1998.
> + */
> +
> +struct fc_ct_hdr {
> + __u8 ct_rev; /* revision */
> + __u8 ct_in_id[3]; /* N_Port ID of original requestor */
> + __u8 ct_fs_type; /* type of fibre channel service */
> + __u8 ct_fs_subtype; /* subtype */
> + __u8 ct_options;
> + __u8 _ct_resvd1;
> + __be16 ct_cmd; /* command / response code */
> + __be16 ct_mr_size; /* maximum / residual size */
> + __u8 _ct_resvd2;
> + __u8 ct_reason; /* reject reason */
> + __u8 ct_explan; /* reason code explanation */
> + __u8 ct_vendor; /* vendor unique data */
> +};
> +
> +struct fc_els_frame {
> + struct fc_frame_header fc_hdr;
> + struct fc_els_hdr els_hdr;
> + u32 els_cmd[4];
> +};
> +
> +struct fc_ct_frame {
> + struct fc_frame_header fc_hdr;
> + struct fc_ct_hdr ct_hdr;
> + u32 ct_cmd[1];
> +};
> +
> +#define FC_SERVICE_TIMEOUT 10
> +
> +struct fc_service {
> + struct fc_rport *rport;
> + struct list_head list;
> +
> + spinlock_t service_state_lock;
> + unsigned service_state_flags;
> +
> + enum fc_frame_type service_type;
> +
> + /* Used by the discovery code. */
> + struct timer_list timer;
> + struct completion completion;
> +
> + union {
> + struct fc_ct_frame *ct_frame;
> + struct fc_els_frame *els_frame;
> + };
> + int req_size;
> + void *response;
> + int resp_size;
> +
> + struct scatterlist sg_req;
> + struct scatterlist sg_resp;
> +
> + struct fc_service_status service_status;
> + void *reply_seq; /* pointer to sense area of request */
> + void (*service_done)(struct fc_service *);
> +
> + struct work_struct abort_work;
> +};
> +
> #define shost_to_fc_host(x) \
> ((struct fc_host_attrs *)(x)->shost_data)
>
> @@ -593,6 +721,14 @@ struct fc_function_template {
> int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
> int (* it_nexus_response)(struct Scsi_Host *, u64, int);
>
> + /* fibre-channel services */
> + int (*fc_service_handler)(struct Scsi_Host *,
> + struct fc_rport *rport,
> + struct request *);
> + int (*execute_fc_els_service)(struct fc_service *);
> + int (*execute_fc_ct_service)(struct fc_service *);
> + int (*abort_fc_service)(struct fc_service *);
> +
> /* allocation lengths for host-specific data */
> u32 dd_fcrport_size;
> u32 dd_fcvport_size;
> @@ -713,6 +849,31 @@ fc_vport_set_state(struct fc_vport *vport, enum
> fc_vport_state new_state)
> vport->vport_state = new_state;
> }
>
> +static inline struct fc_service *
> +fc_alloc_service(gfp_t flags)
> +{
> + struct fc_service *service = kmem_cache_zalloc(fc_service_cache,
> flags);
> +
> + if (service) {
> + INIT_LIST_HEAD(&service->list);
> + spin_lock_init(&service->service_state_lock);
> + service->service_state_flags = FC_SERVICE_STATE_PENDING;
> + init_timer(&service->timer);
> + init_completion(&service->completion);
> + }
> +
> + return service;
> +}
> +
> +static inline void
> +fc_free_service(struct fc_service *service)
> +{
> + if (service) {
> + BUG_ON(!list_empty(&service->list));
> + kmem_cache_free(fc_service_cache, service);
> + }
> +}
> +
>
> struct scsi_transport_template *fc_attach_transport(
> struct fc_function_template *);
> ---
> --
> To unsubscribe from this list: send the line "unsubscribe linux-
> scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] pass through support in fc transport: via bsg (block SG)
2008-08-22 21:36 ` Seokmann Ju
@ 2008-08-22 21:53 ` James Smart
2008-08-22 22:09 ` Andrew Vasquez
2008-09-11 13:25 ` Seokmann Ju
0 siblings, 2 replies; 10+ messages in thread
From: James Smart @ 2008-08-22 21:53 UTC (permalink / raw)
To: Seokmann Ju
Cc: Robert W Love, linux-scsi@vger.kernel.org, Andrew Vasquez,
Boaz Harrosh, Mike Christie
Nope - not forgotten, just a lot of different things to get to.
I don't know of anything in the header that needs to be specified.
Everything is either fixed because it is an ELS/CT request, or what
needs to be specified (usually S_ID/D_ID) comes from the object the bsg
reference is to. CS_CTL is the only one that is a maybe - but that's a
whole different story, and we should just ignore it for now. So I'm
against a header.
Additionally, we have to be careful about what kind of interface we
believe the LLD's support. If they expected a raw frame transmit, I
don't know how many support that, especially as adapters very much
control XID's, etc. Create Exchange, w/ Send/Receive, sequence is
prefered, but even that might be too low. At best, there is explicit
els or ct assist interfaces - which means the LLD/adapter is likely
handling all the header and segmentation, and the interface is just
passing payload buffers.
So in general it's a request, w/ xmt payload, buffer for response, and a
completion status (which I would assume is more than just an int and a
couple of #defines - we have to cover the F_RJT/P_RJT/ABORT cases..)
-- james s
Seokmann Ju wrote:
> I just want to re-stroke this thread to make sure it is not skipped.
>
> One question came to me while testing qla2xxx module with the changes.
> When the application issues ELS/CT packet, should the packet include
> the FC frame header?
> And if the answer is 'yes', should the driver also include the FC
> frame header when it returns response to the application (just like
> any other frame exchanges in between two ports on the FC)?
> The FC frame header has type field that identifies what type of the
> payload (ELS / CT / etc.) the frame contains and the type field is
> being checked by the FC transport layer before it calls LLDD's handler.
>
> Thank you,
> Seokmann
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] pass through support in fc transport: via bsg (block SG)
2008-08-22 21:53 ` James Smart
@ 2008-08-22 22:09 ` Andrew Vasquez
2008-08-22 22:35 ` Chris Leech
2008-08-23 14:43 ` James Smart
2008-09-11 13:25 ` Seokmann Ju
1 sibling, 2 replies; 10+ messages in thread
From: Andrew Vasquez @ 2008-08-22 22:09 UTC (permalink / raw)
To: James Smart
Cc: Seokmann Ju, Robert W Love, linux-scsi@vger.kernel.org,
Boaz Harrosh, Mike Christie
On Fri, 22 Aug 2008, James Smart wrote:
> Nope - not forgotten, just a lot of different things to get to.
>
> I don't know of anything in the header that needs to be specified.
> Everything is either fixed because it is an ELS/CT request, or what needs
> to be specified (usually S_ID/D_ID) comes from the object the bsg reference
> is to. CS_CTL is the only one that is a maybe - but that's a whole
> different story, and we should just ignore it for now. So I'm against a
> header.
>
> Additionally, we have to be careful about what kind of interface we believe
> the LLD's support. If they expected a raw frame transmit, I don't know how
> many support that, especially as adapters very much control XID's, etc.
> Create Exchange, w/ Send/Receive, sequence is prefered, but even that might
> be too low. At best, there is explicit els or ct assist interfaces - which
> means the LLD/adapter is likely handling all the header and segmentation,
> and the interface is just passing payload buffers.
That's essentially what prompted this inquiry. Sure, for hardware
CNA/HBA solutions, access to something like a raw-frame header seems
unnecessary. What about software FCoE? Would the openfcoe want this
export/expose these raw-frame data?
> So in general it's a request, w/ xmt payload, buffer for response, and a
> completion status (which I would assume is more than just an int and a
> couple of #defines - we have to cover the F_RJT/P_RJT/ABORT cases..)
--
av
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] pass through support in fc transport: via bsg (block SG)
2008-08-22 22:09 ` Andrew Vasquez
@ 2008-08-22 22:35 ` Chris Leech
2008-08-22 22:48 ` Andrew Vasquez
2008-08-23 14:43 ` James Smart
1 sibling, 1 reply; 10+ messages in thread
From: Chris Leech @ 2008-08-22 22:35 UTC (permalink / raw)
To: Andrew Vasquez
Cc: James Smart, Seokmann Ju, Robert W Love,
linux-scsi@vger.kernel.org, Boaz Harrosh, Mike Christie
On Fri, Aug 22, 2008 at 3:09 PM, Andrew Vasquez
<andrew.vasquez@qlogic.com> wrote:
> On Fri, 22 Aug 2008, James Smart wrote:
>
>> Nope - not forgotten, just a lot of different things to get to.
>>
>> I don't know of anything in the header that needs to be specified.
>> Everything is either fixed because it is an ELS/CT request, or what needs
>> to be specified (usually S_ID/D_ID) comes from the object the bsg reference
>> is to. CS_CTL is the only one that is a maybe - but that's a whole
>> different story, and we should just ignore it for now. So I'm against a
>> header.
>>
>> Additionally, we have to be careful about what kind of interface we believe
>> the LLD's support. If they expected a raw frame transmit, I don't know how
>> many support that, especially as adapters very much control XID's, etc.
>> Create Exchange, w/ Send/Receive, sequence is prefered, but even that might
>> be too low. At best, there is explicit els or ct assist interfaces - which
>> means the LLD/adapter is likely handling all the header and segmentation,
>> and the interface is just passing payload buffers.
>
> That's essentially what prompted this inquiry. Sure, for hardware
> CNA/HBA solutions, access to something like a raw-frame header seems
> unnecessary. What about software FCoE? Would the openfcoe want this
> export/expose these raw-frame data?
It's easy enough to provide software assists for lower level devices,
so I'd say focus on what will work for HBAs and we'll make software
FCoE work around that interface. I don't see a reason to expose any
extra level of detail here, if you want to see the full frame data in
the software FCoE case you can always just capture the network
traffic.
- Chris
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] pass through support in fc transport: via bsg (block SG)
2008-08-22 22:35 ` Chris Leech
@ 2008-08-22 22:48 ` Andrew Vasquez
0 siblings, 0 replies; 10+ messages in thread
From: Andrew Vasquez @ 2008-08-22 22:48 UTC (permalink / raw)
To: Chris Leech
Cc: James Smart, Seokmann Ju, Robert W Love,
linux-scsi@vger.kernel.org, Boaz Harrosh, Mike Christie
On Fri, 22 Aug 2008, Chris Leech wrote:
> > That's essentially what prompted this inquiry. Sure, for hardware
> > CNA/HBA solutions, access to something like a raw-frame header seems
> > unnecessary. What about software FCoE? Would the openfcoe want this
> > export/expose these raw-frame data?
>
> It's easy enough to provide software assists for lower level devices,
> so I'd say focus on what will work for HBAs and we'll make software
> FCoE work around that interface. I don't see a reason to expose any
> extra level of detail here, if you want to see the full frame data in
> the software FCoE case you can always just capture the network
> traffic.
Fair enough...
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] pass through support in fc transport: via bsg (block SG)
2008-08-22 22:09 ` Andrew Vasquez
2008-08-22 22:35 ` Chris Leech
@ 2008-08-23 14:43 ` James Smart
1 sibling, 0 replies; 10+ messages in thread
From: James Smart @ 2008-08-23 14:43 UTC (permalink / raw)
To: Andrew Vasquez
Cc: Seokmann Ju, Robert W Love, linux-scsi@vger.kernel.org,
Boaz Harrosh, Mike Christie
Andrew Vasquez wrote:
>> Additionally, we have to be careful about what kind of interface we believe
>> the LLD's support. If they expected a raw frame transmit, I don't know how
>> many support that, especially as adapters very much control XID's, etc.
>> Create Exchange, w/ Send/Receive, sequence is prefered, but even that might
>> be too low. At best, there is explicit els or ct assist interfaces - which
>> means the LLD/adapter is likely handling all the header and segmentation,
>> and the interface is just passing payload buffers.
>
> That's essentially what prompted this inquiry. Sure, for hardware
> CNA/HBA solutions, access to something like a raw-frame header seems
> unnecessary. What about software FCoE? Would the openfcoe want this
> export/expose these raw-frame data?
Well - if it's an interface that really needs to be supported by
everything, we should focus on the common denominator. CT/ELS passthru,
in so much as needed by HBAAPI (or whatever generic tools we create like
fcping), is one of those "by everything" cases.
We can always have additional interfaces, which are similar, and less
supported by definition, that can go lower in the stack. I would also
justify the separate interfaces as it's ambiguous to have an interface
that says "sometimes this information is relevant, and sometimes its
not, depending on who receives it". The consumer of the interface can't
depend on it.
-- james
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] pass through support in fc transport: via bsg (block SG)
2008-08-22 21:53 ` James Smart
2008-08-22 22:09 ` Andrew Vasquez
@ 2008-09-11 13:25 ` Seokmann Ju
2008-09-11 13:44 ` James Smart
1 sibling, 1 reply; 10+ messages in thread
From: Seokmann Ju @ 2008-09-11 13:25 UTC (permalink / raw)
To: James Smart
Cc: Robert W Love, linux-scsi@vger.kernel.org, Andrew Vasquez,
Boaz Harrosh, Mike Christie
On Aug 22, 2008, at 2:53 PM, James Smart wrote:
> Nope - not forgotten, just a lot of different things to get to.
>
> I don't know of anything in the header that needs to be specified.
> Everything is either fixed because it is an ELS/CT request, or what
> needs to be specified (usually S_ID/D_ID) comes from the object the
> bsg reference is to. CS_CTL is the only one that is a maybe - but
> that's a whole different story, and we should just ignore it for
> now. So I'm against a header.
>
> Additionally, we have to be careful about what kind of interface we
> believe the LLD's support. If they expected a raw frame transmit, I
> don't know how many support that, especially as adapters very much
> control XID's, etc. Create Exchange, w/ Send/Receive, sequence is
> prefered, but even that might be too low. At best, there is
> explicit els or ct assist interfaces - which means the LLD/adapter
> is likely handling all the header and segmentation, and the
> interface is just passing payload buffers.
>
> So in general it's a request, w/ xmt payload, buffer for response,
> and a completion status (which I would assume is more than just an
> int and a couple of #defines - we have to cover the F_RJT/P_RJT/
> ABORT cases..)
I actually had missed the point at that time and now I'm getting it as
I read one more time.
So, in this case, how to identify whether the request is ELS or CT if
the application issues the request without the frame header?
Seokmann
>
>
> -- james s
>
> Seokmann Ju wrote:
>> I just want to re-stroke this thread to make sure it is not skipped.
>> One question came to me while testing qla2xxx module with the
>> changes.
>> When the application issues ELS/CT packet, should the packet include
>> the FC frame header?
>> And if the answer is 'yes', should the driver also include the FC
>> frame header when it returns response to the application (just like
>> any other frame exchanges in between two ports on the FC)?
>> The FC frame header has type field that identifies what type of the
>> payload (ELS / CT / etc.) the frame contains and the type field is
>> being checked by the FC transport layer before it calls LLDD's
>> handler.
>> Thank you,
>> Seokmann
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] pass through support in fc transport: via bsg (block SG)
2008-09-11 13:25 ` Seokmann Ju
@ 2008-09-11 13:44 ` James Smart
0 siblings, 0 replies; 10+ messages in thread
From: James Smart @ 2008-09-11 13:44 UTC (permalink / raw)
To: Seokmann Ju
Cc: Robert W Love, linux-scsi@vger.kernel.org, Andrew Vasquez,
Boaz Harrosh, Mike Christie
Seokmann,
I apologize for the late review. I'm going over it now. (PS: ping me
next time if you want to makre sure I've looked at it). I should have
comments within the day.
Seokmann Ju wrote:
> I actually had missed the point at that time and now I'm getting it as
> I read one more time.
> So, in this case, how to identify whether the request is ELS or CT if
> the application issues the request without the frame header?
Whether it's ELS or CT should be part of the metadata of the request (a
flag, a request type opcode, or similar). There should be no reason for
a frame header.
-- james s
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2008-09-11 13:44 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-18 19:04 [RFC] pass through support in fc transport: via bsg (block SG) Seokmann Ju
2008-08-19 17:42 ` Seokmann Ju
2008-08-22 21:36 ` Seokmann Ju
2008-08-22 21:53 ` James Smart
2008-08-22 22:09 ` Andrew Vasquez
2008-08-22 22:35 ` Chris Leech
2008-08-22 22:48 ` Andrew Vasquez
2008-08-23 14:43 ` James Smart
2008-09-11 13:25 ` Seokmann Ju
2008-09-11 13:44 ` James Smart
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox