* [PATCH 1/2] FC pass through support - revised III
@ 2008-10-31 15:34 Seokmann Ju
2008-11-11 9:41 ` FUJITA Tomonori
0 siblings, 1 reply; 4+ messages in thread
From: Seokmann Ju @ 2008-10-31 15:34 UTC (permalink / raw)
To: James Smart, James Bottomley, FUJITA Tomonori, Boaz Harrosh
Cc: linux-scsi, Andrew Vasquez, Mike Christie, Robert W Love
[-- Attachment #1: Type: text/plain, Size: 11409 bytes --]
Attachment is also available at the bottom.
---
From 47f113766853dcabec329013fd1c2eb9e04f8c92 Mon Sep 17 00:00:00 2001
From: root <root@linux-atl-00.qlogic.com>
Date: Fri, 31 Oct 2008 08:13:15 -0700
Subject: [PATCH] scsi_transport_fc: FC pass through support
This patch will add FC pass through support.
The FC pass through support is service request handling mechanism
for FC specification defined services including,
- Link Services (Basic LS, Extended LS)
- Generic Services (FC-CT - Common Transport)
The support utilize BSG (Block layer SCSI Generic) interface with
bidi (bi-directional) nature in handling the service requests.
This patch added following featues in the support
- FC service structure has defined to transport service requests
- Handles the service request in asynchronous manner - LLD
- Timeout capability
- Abort capability
Signed-off-by: Seokmann Ju <seokmann.ju@qlogic.com>
---
drivers/scsi/scsi_transport_fc.c | 212 +++++++++++++++++++++++++++++
++++++++-
include/scsi/scsi_transport_fc.h | 79 ++++++++++++++-
2 files changed, 288 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/
scsi_transport_fc.c
index 1e71abf..a0c1430 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -43,6 +43,11 @@ static void fc_vport_sched_delete(struct
work_struct *work);
static int fc_vport_setup(struct Scsi_Host *shost, int channel,
struct device *pdev, struct fc_vport_identifiers *ids,
struct fc_vport **vport);
+static enum blk_eh_timer_return fc_service_timeout(struct request
*req);
+static void fc_service_done(struct fc_service *);
+static int fc_service_handler(struct Scsi_Host *, struct fc_rport *,
+ struct request *, struct request_queue *);
+static void fc_bsg_remove(struct Scsi_Host *, struct fc_rport *);
/*
* Redefine so that we can have same named attributes in the
@@ -2413,11 +2418,214 @@ 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 enum blk_eh_timer_return fc_service_timeout(struct request *req)
+{
+ struct fc_service *service = (void *) req->special;
+ struct Scsi_Host *shost = rport_to_shost(service->rport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+ unsigned long flags;
+ int res = 0;
+
+ if (service->rport->port_state == FC_PORTSTATE_BLOCKED)
+ return BLK_EH_RESET_TIMER;
+
+ spin_lock_irqsave(&service->service_state_lock, flags);
+ if (!(service->service_state_flag & FC_SERVICE_STATE_DONE))
+ service->service_state_flag |= FC_SERVICE_STATE_TIMEOUT;
+ spin_unlock_irqrestore(&service->service_state_lock, flags);
+
+ if (i->f->abort_fc_service)
+ res = i->f->abort_fc_service(service);
+
+ if (res) {
+ printk(KERN_ERR "ERROR: issuing FC service to the LLD "
+ "failed with status %d\n", res);
+ fc_service_done(service);
+ }
+
+ /* the blk_end_sync_io() doesn't check the error */
+ return BLK_EH_NOT_HANDLED;
+}
+
+static void fc_service_done(struct fc_service *service)
+{
+
+ if (service->service_state_flag != FC_SERVICE_STATE_DONE) {
+ if (service->service_state_flag == FC_SERVICE_STATE_TIMEOUT)
+ printk(KERN_ERR "ERROR: FC service timed out\n");
+ else if (service->service_state_flag ==
+ FC_SERVICE_STATE_ABORTED)
+ printk(KERN_ERR "ERROR: FC service aborted\n");
+ else
+ printk(KERN_ERR "ERROR: FC service not finished\n");
+ }
+
+ if (service->srv_reply.status != FC_SERVICE_COMPLETE) {
+ printk(KERN_ERR "ERROR: FC service to rport %p failed with"
+ " status 0x%x\n", service->rport,
+ service->srv_reply.status);
+ }
+
+ service->req->errors = service->srv_reply.status;
+
+ blk_end_bidi_request(service->req,
+ service->srv_reply.status ? -EIO : 0, blk_rq_bytes(service->req),
+ service->req->next_rq ? blk_rq_bytes(service->req->next_rq) : 0);
+
+ kfree(service->sg_req);
+ kfree(service->sg_rsp);
+ kfree(service);
+}
+
+static int
+issue_fc_service(struct fc_rport *rport, struct request *req,
+ struct request *rsp, struct request_queue *q)
+{
+ int res = -ECOMM;
+ struct fc_service *service;
+ struct Scsi_Host *shost = rport_to_shost(rport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+ struct fc_service_request *srv_request = (struct fc_service_request *)
+ req->cmd;
+
+ service = kzalloc(sizeof(struct fc_service), GFP_KERNEL);
+ if (!service)
+ return -ENOMEM;
+
+ req->special = service;
+ service->rport = rport;
+ service->req = req;
+ service->q = q;
+ service->srv_request = srv_request;
+
+ service->sg_req =
+ kzalloc(sizeof(struct scatterlist) * req->nr_phys_segments,
+ GFP_KERNEL);
+ sg_init_table(service->sg_req, req->nr_phys_segments);
+ service->req_sg_cnt =
+ blk_rq_map_sg(q, req, service->sg_req);
+ service->req_size = req->data_len;
+
+ service->sg_rsp =
+ kzalloc(sizeof(struct scatterlist) * rsp->nr_phys_segments,
+ GFP_KERNEL);
+ sg_init_table(service->sg_rsp, rsp->nr_phys_segments);
+ service->rsp_sg_cnt =
+ blk_rq_map_sg(q, rsp, service->sg_rsp);
+ service->rsp_size = rsp->data_len;
+
+ /* sense area of the request structure */
+ service->reply_seq = req->sense;
+ service->service_done = fc_service_done;
+ service->service_state_flag = FC_SERVICE_STATE_PENDING;
+
+ if (i->f->execute_fc_service)
+ res = i->f->execute_fc_service(service);
+
+ if (res) {
+ printk(KERN_ERR "ERROR: issuing FC service to the LLD "
+ "failed with status %d\n", res);
+ fc_service_done(service);
+ return res;
+ }
+
+ return 0;
+}
+
+static int
+fc_service_handler(struct Scsi_Host *shost, struct fc_rport *rport,
+ struct request *req, struct request_queue *q)
+{
+ int ret;
+ struct request *rsp = req->next_rq;
+
+ if (!rsp) {
+ printk(KERN_ERR "ERROR: space for a FC service"
+ " response is missing\n");
+ return -EINVAL;
+ }
+
+ ret = issue_fc_service(rport, req, rsp, q);
+
+ return ret;
+}
+
+static void fc_service_dispatch(struct request_queue *q)
+{
+ struct request *req;
+ struct fc_rport *rport = q->queuedata;
+ struct Scsi_Host *shost = rport_to_shost(rport);
+
+ while (!blk_queue_plugged(q)) {
+ req = elv_next_request(q);
+ if (!req)
+ break;
+
+ blkdev_dequeue_request(req);
+ spin_unlock_irq(q->queue_lock);
+
+ fc_service_handler(shost, rport, req, q);
+
+ spin_lock_irq(q->queue_lock);
+ }
+}
+
+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 (!rport) {
+ printk(KERN_ERR "ERROR: rport is NULL\n");
+ return -ENOMEM;
+ }
+
+ q = blk_init_queue(fc_service_dispatch, NULL);
+ if (!q)
+ return -ENOMEM;
+
+ dev = &rport->dev;
+ name = dev->bus_id;
+ release = NULL;
+
+ error = bsg_register_queue(q, dev, name, release);
+ if (error) {
+ blk_cleanup_queue(q);
+ return -ENOMEM;
+ }
+
+ blk_queue_max_hw_segments(q, shost->sg_tablesize);
+ blk_queue_max_phys_segments(q, SCSI_MAX_SG_CHAIN_SEGMENTS);
+ blk_queue_rq_timed_out(q, fc_service_timeout);
+ blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
+
+ 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)
+ return;
+
+ bsg_unregister_queue(q);
+}
/**
* fc_rport_create - allocates and creates a remote FC port.
@@ -2478,8 +2686,8 @@ 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 */
+ get_device(&shost->shost_gendev); /* for fc_host->rport list */
spin_unlock_irqrestore(shost->host_lock, flags);
dev = &rport->dev;
@@ -2498,6 +2706,8 @@ fc_rport_create(struct Scsi_Host *shost, int
channel,
transport_add_device(dev);
transport_configure_device(dev);
+ fc_bsg_initialize(shost, rport);
+
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 49d8913..8367d48 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -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_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: */
@@ -515,6 +515,78 @@ 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 fc_service_status {
+ FC_SERVICE_COMPLETE,
+ FC_SERVICE_TIMEOUT,
+ FC_SERVICE_ABORT,
+ FC_SERVICE_UNSUPPORTED,
+ FC_SERVICE_ERROR = -1,
+};
+
+#define FC_SERVICE_STATE_PENDING 1
+#define FC_SERVICE_STATE_DONE 2
+#define FC_SERVICE_STATE_ABORTED 4
+#define FC_SERVICE_STATE_TIMEOUT 8
+
+#define FC_SERVICE_TIMEOUT 10
+
+/* request (CDB) structure of the sg_io_v4 */
+struct fc_service_request {
+ u8 request_type;
+ u8 reserved0;
+ u8 reserved1;
+ u8 reserved2;
+ u32 reserved3[3];
+};
+
+/* response (request sense data) structure of the sg_io_v4 */
+struct fc_service_reply {
+ enum fc_service_status status;
+ u16 error_code;
+ u16 additional_error_code;
+ u32 residual;
+};
+
+struct fc_service {
+ struct fc_rport *rport;
+ struct list_head list;
+
+ spinlock_t service_state_lock;
+ unsigned service_state_flag;
+
+ struct request *req;
+ struct request_queue *q;
+
+ /* Used by the discovery code. */
+ struct completion completion;
+
+ struct fc_service_request *srv_request;
+ struct scatterlist *sg_req;
+ int req_sg_cnt;
+ int req_size;
+ struct scatterlist *sg_rsp;
+ int rsp_sg_cnt;
+ int rsp_size;
+
+ struct fc_service_reply srv_reply;
+ void *reply_seq; /* pointer to sense area of request */
+ void (*service_done)(struct fc_service *);
+
+ void *lld_pkt;
+};
+
#define shost_to_fc_host(x) \
((struct fc_host_attrs *)(x)->shost_data)
@@ -613,6 +685,10 @@ struct fc_function_template {
int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
int (* it_nexus_response)(struct Scsi_Host *, u64, int);
+ /* fc service handler */
+ int (*execute_fc_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;
@@ -736,7 +812,6 @@ fc_vport_set_state(struct fc_vport *vport, enum
fc_vport_state new_state)
vport->vport_state = new_state;
}
-
struct scsi_transport_template *fc_attach_transport(
struct fc_function_template *);
void fc_release_transport(struct scsi_transport_template *);
--
1.6.0.2
[-- Attachment #2: 0001-scsi_transport_fc-FC-pass-through-support.patch --]
[-- Type: application/octet-stream, Size: 11705 bytes --]
From 47f113766853dcabec329013fd1c2eb9e04f8c92 Mon Sep 17 00:00:00 2001
From: root <root@linux-atl-00.qlogic.com>
Date: Fri, 31 Oct 2008 08:13:15 -0700
Subject: [PATCH] scsi_transport_fc: FC pass through support
This patch will add FC pass through support.
The FC pass through support is service request handling mechanism
for FC specification defined services including,
- Link Services (Basic LS, Extended LS)
- Generic Services (FC-CT - Common Transport)
The support utilize BSG (Block layer SCSI Generic) interface with
bidi (bi-directional) nature in handling the service requests.
This patch added following featues in the support
- FC service structure has defined to transport service requests
- Handles the service request in asynchronous manner - LLD
- Timeout capability
- Abort capability
Signed-off-by: Seokmann Ju <seokmann.ju@qlogic.com>
---
drivers/scsi/scsi_transport_fc.c | 212 +++++++++++++++++++++++++++++++++++++-
include/scsi/scsi_transport_fc.h | 79 ++++++++++++++-
2 files changed, 288 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 1e71abf..a0c1430 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -43,6 +43,11 @@ static void fc_vport_sched_delete(struct work_struct *work);
static int fc_vport_setup(struct Scsi_Host *shost, int channel,
struct device *pdev, struct fc_vport_identifiers *ids,
struct fc_vport **vport);
+static enum blk_eh_timer_return fc_service_timeout(struct request *req);
+static void fc_service_done(struct fc_service *);
+static int fc_service_handler(struct Scsi_Host *, struct fc_rport *,
+ struct request *, struct request_queue *);
+static void fc_bsg_remove(struct Scsi_Host *, struct fc_rport *);
/*
* Redefine so that we can have same named attributes in the
@@ -2413,11 +2418,214 @@ 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 enum blk_eh_timer_return fc_service_timeout(struct request *req)
+{
+ struct fc_service *service = (void *) req->special;
+ struct Scsi_Host *shost = rport_to_shost(service->rport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+ unsigned long flags;
+ int res = 0;
+
+ if (service->rport->port_state == FC_PORTSTATE_BLOCKED)
+ return BLK_EH_RESET_TIMER;
+
+ spin_lock_irqsave(&service->service_state_lock, flags);
+ if (!(service->service_state_flag & FC_SERVICE_STATE_DONE))
+ service->service_state_flag |= FC_SERVICE_STATE_TIMEOUT;
+ spin_unlock_irqrestore(&service->service_state_lock, flags);
+
+ if (i->f->abort_fc_service)
+ res = i->f->abort_fc_service(service);
+
+ if (res) {
+ printk(KERN_ERR "ERROR: issuing FC service to the LLD "
+ "failed with status %d\n", res);
+ fc_service_done(service);
+ }
+
+ /* the blk_end_sync_io() doesn't check the error */
+ return BLK_EH_NOT_HANDLED;
+}
+
+static void fc_service_done(struct fc_service *service)
+{
+
+ if (service->service_state_flag != FC_SERVICE_STATE_DONE) {
+ if (service->service_state_flag == FC_SERVICE_STATE_TIMEOUT)
+ printk(KERN_ERR "ERROR: FC service timed out\n");
+ else if (service->service_state_flag ==
+ FC_SERVICE_STATE_ABORTED)
+ printk(KERN_ERR "ERROR: FC service aborted\n");
+ else
+ printk(KERN_ERR "ERROR: FC service not finished\n");
+ }
+
+ if (service->srv_reply.status != FC_SERVICE_COMPLETE) {
+ printk(KERN_ERR "ERROR: FC service to rport %p failed with"
+ " status 0x%x\n", service->rport,
+ service->srv_reply.status);
+ }
+
+ service->req->errors = service->srv_reply.status;
+
+ blk_end_bidi_request(service->req,
+ service->srv_reply.status ? -EIO : 0, blk_rq_bytes(service->req),
+ service->req->next_rq ? blk_rq_bytes(service->req->next_rq) : 0);
+
+ kfree(service->sg_req);
+ kfree(service->sg_rsp);
+ kfree(service);
+}
+
+static int
+issue_fc_service(struct fc_rport *rport, struct request *req,
+ struct request *rsp, struct request_queue *q)
+{
+ int res = -ECOMM;
+ struct fc_service *service;
+ struct Scsi_Host *shost = rport_to_shost(rport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+ struct fc_service_request *srv_request = (struct fc_service_request *)
+ req->cmd;
+
+ service = kzalloc(sizeof(struct fc_service), GFP_KERNEL);
+ if (!service)
+ return -ENOMEM;
+
+ req->special = service;
+ service->rport = rport;
+ service->req = req;
+ service->q = q;
+ service->srv_request = srv_request;
+
+ service->sg_req =
+ kzalloc(sizeof(struct scatterlist) * req->nr_phys_segments,
+ GFP_KERNEL);
+ sg_init_table(service->sg_req, req->nr_phys_segments);
+ service->req_sg_cnt =
+ blk_rq_map_sg(q, req, service->sg_req);
+ service->req_size = req->data_len;
+
+ service->sg_rsp =
+ kzalloc(sizeof(struct scatterlist) * rsp->nr_phys_segments,
+ GFP_KERNEL);
+ sg_init_table(service->sg_rsp, rsp->nr_phys_segments);
+ service->rsp_sg_cnt =
+ blk_rq_map_sg(q, rsp, service->sg_rsp);
+ service->rsp_size = rsp->data_len;
+
+ /* sense area of the request structure */
+ service->reply_seq = req->sense;
+ service->service_done = fc_service_done;
+ service->service_state_flag = FC_SERVICE_STATE_PENDING;
+
+ if (i->f->execute_fc_service)
+ res = i->f->execute_fc_service(service);
+
+ if (res) {
+ printk(KERN_ERR "ERROR: issuing FC service to the LLD "
+ "failed with status %d\n", res);
+ fc_service_done(service);
+ return res;
+ }
+
+ return 0;
+}
+
+static int
+fc_service_handler(struct Scsi_Host *shost, struct fc_rport *rport,
+ struct request *req, struct request_queue *q)
+{
+ int ret;
+ struct request *rsp = req->next_rq;
+
+ if (!rsp) {
+ printk(KERN_ERR "ERROR: space for a FC service"
+ " response is missing\n");
+ return -EINVAL;
+ }
+
+ ret = issue_fc_service(rport, req, rsp, q);
+
+ return ret;
+}
+
+static void fc_service_dispatch(struct request_queue *q)
+{
+ struct request *req;
+ struct fc_rport *rport = q->queuedata;
+ struct Scsi_Host *shost = rport_to_shost(rport);
+
+ while (!blk_queue_plugged(q)) {
+ req = elv_next_request(q);
+ if (!req)
+ break;
+
+ blkdev_dequeue_request(req);
+ spin_unlock_irq(q->queue_lock);
+
+ fc_service_handler(shost, rport, req, q);
+
+ spin_lock_irq(q->queue_lock);
+ }
+}
+
+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 (!rport) {
+ printk(KERN_ERR "ERROR: rport is NULL\n");
+ return -ENOMEM;
+ }
+
+ q = blk_init_queue(fc_service_dispatch, NULL);
+ if (!q)
+ return -ENOMEM;
+
+ dev = &rport->dev;
+ name = dev->bus_id;
+ release = NULL;
+
+ error = bsg_register_queue(q, dev, name, release);
+ if (error) {
+ blk_cleanup_queue(q);
+ return -ENOMEM;
+ }
+
+ blk_queue_max_hw_segments(q, shost->sg_tablesize);
+ blk_queue_max_phys_segments(q, SCSI_MAX_SG_CHAIN_SEGMENTS);
+ blk_queue_rq_timed_out(q, fc_service_timeout);
+ blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
+
+ 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)
+ return;
+
+ bsg_unregister_queue(q);
+}
/**
* fc_rport_create - allocates and creates a remote FC port.
@@ -2478,8 +2686,8 @@ 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 */
+ get_device(&shost->shost_gendev); /* for fc_host->rport list */
spin_unlock_irqrestore(shost->host_lock, flags);
dev = &rport->dev;
@@ -2498,6 +2706,8 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
transport_add_device(dev);
transport_configure_device(dev);
+ fc_bsg_initialize(shost, rport);
+
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 49d8913..8367d48 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -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_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: */
@@ -515,6 +515,78 @@ 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 fc_service_status {
+ FC_SERVICE_COMPLETE,
+ FC_SERVICE_TIMEOUT,
+ FC_SERVICE_ABORT,
+ FC_SERVICE_UNSUPPORTED,
+ FC_SERVICE_ERROR = -1,
+};
+
+#define FC_SERVICE_STATE_PENDING 1
+#define FC_SERVICE_STATE_DONE 2
+#define FC_SERVICE_STATE_ABORTED 4
+#define FC_SERVICE_STATE_TIMEOUT 8
+
+#define FC_SERVICE_TIMEOUT 10
+
+/* request (CDB) structure of the sg_io_v4 */
+struct fc_service_request {
+ u8 request_type;
+ u8 reserved0;
+ u8 reserved1;
+ u8 reserved2;
+ u32 reserved3[3];
+};
+
+/* response (request sense data) structure of the sg_io_v4 */
+struct fc_service_reply {
+ enum fc_service_status status;
+ u16 error_code;
+ u16 additional_error_code;
+ u32 residual;
+};
+
+struct fc_service {
+ struct fc_rport *rport;
+ struct list_head list;
+
+ spinlock_t service_state_lock;
+ unsigned service_state_flag;
+
+ struct request *req;
+ struct request_queue *q;
+
+ /* Used by the discovery code. */
+ struct completion completion;
+
+ struct fc_service_request *srv_request;
+ struct scatterlist *sg_req;
+ int req_sg_cnt;
+ int req_size;
+ struct scatterlist *sg_rsp;
+ int rsp_sg_cnt;
+ int rsp_size;
+
+ struct fc_service_reply srv_reply;
+ void *reply_seq; /* pointer to sense area of request */
+ void (*service_done)(struct fc_service *);
+
+ void *lld_pkt;
+};
+
#define shost_to_fc_host(x) \
((struct fc_host_attrs *)(x)->shost_data)
@@ -613,6 +685,10 @@ struct fc_function_template {
int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
int (* it_nexus_response)(struct Scsi_Host *, u64, int);
+ /* fc service handler */
+ int (*execute_fc_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;
@@ -736,7 +812,6 @@ fc_vport_set_state(struct fc_vport *vport, enum fc_vport_state new_state)
vport->vport_state = new_state;
}
-
struct scsi_transport_template *fc_attach_transport(
struct fc_function_template *);
void fc_release_transport(struct scsi_transport_template *);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH 1/2] FC pass through support - revised III
2008-10-31 15:34 [PATCH 1/2] FC pass through support - revised III Seokmann Ju
@ 2008-11-11 9:41 ` FUJITA Tomonori
2008-11-11 14:35 ` Seokmann Ju
0 siblings, 1 reply; 4+ messages in thread
From: FUJITA Tomonori @ 2008-11-11 9:41 UTC (permalink / raw)
To: seokmann.ju
Cc: James.Smart, James.Bottomley, fujita.tomonori, bharrosh,
linux-scsi, andrew.vasquez, michaelc, robert.w.love
On Fri, 31 Oct 2008 08:34:35 -0700
Seokmann Ju <seokmann.ju@qlogic.com> wrote:
> Attachment is also available at the bottom.
> ---
> From 47f113766853dcabec329013fd1c2eb9e04f8c92 Mon Sep 17 00:00:00 2001
> From: root <root@linux-atl-00.qlogic.com>
> Date: Fri, 31 Oct 2008 08:13:15 -0700
> Subject: [PATCH] scsi_transport_fc: FC pass through support
>
> This patch will add FC pass through support.
> The FC pass through support is service request handling mechanism
> for FC specification defined services including,
> - Link Services (Basic LS, Extended LS)
> - Generic Services (FC-CT - Common Transport)
> The support utilize BSG (Block layer SCSI Generic) interface with
> bidi (bi-directional) nature in handling the service requests.
>
> This patch added following featues in the support
> - FC service structure has defined to transport service requests
> - Handles the service request in asynchronous manner - LLD
> - Timeout capability
> - Abort capability
>
> Signed-off-by: Seokmann Ju <seokmann.ju@qlogic.com>
> ---
> drivers/scsi/scsi_transport_fc.c | 212 +++++++++++++++++++++++++++++
> ++++++++-
> include/scsi/scsi_transport_fc.h | 79 ++++++++++++++-
> 2 files changed, 288 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/
> scsi_transport_fc.c
> index 1e71abf..a0c1430 100644
> --- a/drivers/scsi/scsi_transport_fc.c
> +++ b/drivers/scsi/scsi_transport_fc.c
> @@ -43,6 +43,11 @@ static void fc_vport_sched_delete(struct
> work_struct *work);
> static int fc_vport_setup(struct Scsi_Host *shost, int channel,
> struct device *pdev, struct fc_vport_identifiers *ids,
> struct fc_vport **vport);
> +static enum blk_eh_timer_return fc_service_timeout(struct request
> *req);
> +static void fc_service_done(struct fc_service *);
> +static int fc_service_handler(struct Scsi_Host *, struct fc_rport *,
> + struct request *, struct request_queue *);
> +static void fc_bsg_remove(struct Scsi_Host *, struct fc_rport *);
>
> /*
> * Redefine so that we can have same named attributes in the
> @@ -2413,11 +2418,214 @@ 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 enum blk_eh_timer_return fc_service_timeout(struct request *req)
> +{
> + struct fc_service *service = (void *) req->special;
> + struct Scsi_Host *shost = rport_to_shost(service->rport);
> + struct fc_internal *i = to_fc_internal(shost->transportt);
> + unsigned long flags;
> + int res = 0;
> +
> + if (service->rport->port_state == FC_PORTSTATE_BLOCKED)
> + return BLK_EH_RESET_TIMER;
> +
> + spin_lock_irqsave(&service->service_state_lock, flags);
> + if (!(service->service_state_flag & FC_SERVICE_STATE_DONE))
> + service->service_state_flag |= FC_SERVICE_STATE_TIMEOUT;
> + spin_unlock_irqrestore(&service->service_state_lock, flags);
> +
> + if (i->f->abort_fc_service)
> + res = i->f->abort_fc_service(service);
> +
> + if (res) {
> + printk(KERN_ERR "ERROR: issuing FC service to the LLD "
> + "failed with status %d\n", res);
> + fc_service_done(service);
> + }
> +
> + /* the blk_end_sync_io() doesn't check the error */
> + return BLK_EH_NOT_HANDLED;
> +}
> +
> +static void fc_service_done(struct fc_service *service)
> +{
> +
> + if (service->service_state_flag != FC_SERVICE_STATE_DONE) {
> + if (service->service_state_flag == FC_SERVICE_STATE_TIMEOUT)
> + printk(KERN_ERR "ERROR: FC service timed out\n");
> + else if (service->service_state_flag ==
> + FC_SERVICE_STATE_ABORTED)
> + printk(KERN_ERR "ERROR: FC service aborted\n");
> + else
> + printk(KERN_ERR "ERROR: FC service not finished\n");
> + }
> +
> + if (service->srv_reply.status != FC_SERVICE_COMPLETE) {
> + printk(KERN_ERR "ERROR: FC service to rport %p failed with"
> + " status 0x%x\n", service->rport,
> + service->srv_reply.status);
> + }
> +
> + service->req->errors = service->srv_reply.status;
> +
> + blk_end_bidi_request(service->req,
> + service->srv_reply.status ? -EIO : 0, blk_rq_bytes(service->req),
> + service->req->next_rq ? blk_rq_bytes(service->req->next_rq) : 0);
> +
> + kfree(service->sg_req);
> + kfree(service->sg_rsp);
> + kfree(service);
> +}
> +
> +static int
> +issue_fc_service(struct fc_rport *rport, struct request *req,
> + struct request *rsp, struct request_queue *q)
> +{
> + int res = -ECOMM;
> + struct fc_service *service;
> + struct Scsi_Host *shost = rport_to_shost(rport);
> + struct fc_internal *i = to_fc_internal(shost->transportt);
> + struct fc_service_request *srv_request = (struct fc_service_request *)
> + req->cmd;
> +
> + service = kzalloc(sizeof(struct fc_service), GFP_KERNEL);
> + if (!service)
> + return -ENOMEM;
> +
> + req->special = service;
> + service->rport = rport;
> + service->req = req;
> + service->q = q;
> + service->srv_request = srv_request;
> +
> + service->sg_req =
> + kzalloc(sizeof(struct scatterlist) * req->nr_phys_segments,
> + GFP_KERNEL);
Needs to check the allocation failure.
> + sg_init_table(service->sg_req, req->nr_phys_segments);
> + service->req_sg_cnt =
> + blk_rq_map_sg(q, req, service->sg_req);
> + service->req_size = req->data_len;
> +
> + service->sg_rsp =
> + kzalloc(sizeof(struct scatterlist) * rsp->nr_phys_segments,
> + GFP_KERNEL);
Ditto.
> + sg_init_table(service->sg_rsp, rsp->nr_phys_segments);
> + service->rsp_sg_cnt =
> + blk_rq_map_sg(q, rsp, service->sg_rsp);
> + service->rsp_size = rsp->data_len;
> +
> + /* sense area of the request structure */
> + service->reply_seq = req->sense;
> + service->service_done = fc_service_done;
> + service->service_state_flag = FC_SERVICE_STATE_PENDING;
> +
> + if (i->f->execute_fc_service)
> + res = i->f->execute_fc_service(service);
> +
> + if (res) {
> + printk(KERN_ERR "ERROR: issuing FC service to the LLD "
> + "failed with status %d\n", res);
> + fc_service_done(service);
> + return res;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +fc_service_handler(struct Scsi_Host *shost, struct fc_rport *rport,
> + struct request *req, struct request_queue *q)
> +{
> + int ret;
> + struct request *rsp = req->next_rq;
> +
> + if (!rsp) {
> + printk(KERN_ERR "ERROR: space for a FC service"
> + " response is missing\n");
> + return -EINVAL;
Needs to complete the request unless the request leaks, I think.
> + }
> +
> + ret = issue_fc_service(rport, req, rsp, q);
> +
> + return ret;
> +}
> +
> +static void fc_service_dispatch(struct request_queue *q)
> +{
> + struct request *req;
> + struct fc_rport *rport = q->queuedata;
> + struct Scsi_Host *shost = rport_to_shost(rport);
> +
> + while (!blk_queue_plugged(q)) {
> + req = elv_next_request(q);
> + if (!req)
> + break;
> +
> + blkdev_dequeue_request(req);
> + spin_unlock_irq(q->queue_lock);
> +
> + fc_service_handler(shost, rport, req, q);
> +
> + spin_lock_irq(q->queue_lock);
> + }
> +}
> +
> +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 *);
Not necessary.
> + if (!rport) {
> + printk(KERN_ERR "ERROR: rport is NULL\n");
> + return -ENOMEM;
> + }
> +
> + q = blk_init_queue(fc_service_dispatch, NULL);
> + if (!q)
> + return -ENOMEM;
> +
> + dev = &rport->dev;
> + name = dev->bus_id;
> + release = NULL;
> +
> + error = bsg_register_queue(q, dev, name, release);
You can just use NULL here.
error = bsg_register_queue(q, dev, name, NULL);
> + if (error) {
> + blk_cleanup_queue(q);
> + return -ENOMEM;
> + }
> +
> + blk_queue_max_hw_segments(q, shost->sg_tablesize);
> + blk_queue_max_phys_segments(q, SCSI_MAX_SG_CHAIN_SEGMENTS);
> + blk_queue_rq_timed_out(q, fc_service_timeout);
> + blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
> +
> + 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)
> + return;
> +
> + bsg_unregister_queue(q);
> +}
>
> /**
> * fc_rport_create - allocates and creates a remote FC port.
> @@ -2478,8 +2686,8 @@ 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 */
>
> + get_device(&shost->shost_gendev); /* for fc_host->rport list */
> spin_unlock_irqrestore(shost->host_lock, flags);
>
> dev = &rport->dev;
> @@ -2498,6 +2706,8 @@ fc_rport_create(struct Scsi_Host *shost, int
> channel,
> transport_add_device(dev);
> transport_configure_device(dev);
>
> + fc_bsg_initialize(shost, rport);
> +
> 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 49d8913..8367d48 100644
> --- a/include/scsi/scsi_transport_fc.h
> +++ b/include/scsi/scsi_transport_fc.h
> @@ -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_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: */
> @@ -515,6 +515,78 @@ 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 fc_service_status {
> + FC_SERVICE_COMPLETE,
> + FC_SERVICE_TIMEOUT,
> + FC_SERVICE_ABORT,
> + FC_SERVICE_UNSUPPORTED,
> + FC_SERVICE_ERROR = -1,
> +};
> +
> +#define FC_SERVICE_STATE_PENDING 1
> +#define FC_SERVICE_STATE_DONE 2
> +#define FC_SERVICE_STATE_ABORTED 4
> +#define FC_SERVICE_STATE_TIMEOUT 8
> +
> +#define FC_SERVICE_TIMEOUT 10
> +
> +/* request (CDB) structure of the sg_io_v4 */
> +struct fc_service_request {
> + u8 request_type;
> + u8 reserved0;
> + u8 reserved1;
> + u8 reserved2;
> + u32 reserved3[3];
> +};
> +
> +/* response (request sense data) structure of the sg_io_v4 */
> +struct fc_service_reply {
> + enum fc_service_status status;
> + u16 error_code;
> + u16 additional_error_code;
> + u32 residual;
> +};
> +
> +struct fc_service {
> + struct fc_rport *rport;
> + struct list_head list;
> +
> + spinlock_t service_state_lock;
> + unsigned service_state_flag;
> +
> + struct request *req;
> + struct request_queue *q;
> +
> + /* Used by the discovery code. */
> + struct completion completion;
> +
> + struct fc_service_request *srv_request;
> + struct scatterlist *sg_req;
> + int req_sg_cnt;
> + int req_size;
> + struct scatterlist *sg_rsp;
> + int rsp_sg_cnt;
> + int rsp_size;
> +
> + struct fc_service_reply srv_reply;
> + void *reply_seq; /* pointer to sense area of request */
> + void (*service_done)(struct fc_service *);
> +
> + void *lld_pkt;
> +};
> +
> #define shost_to_fc_host(x) \
> ((struct fc_host_attrs *)(x)->shost_data)
>
> @@ -613,6 +685,10 @@ struct fc_function_template {
> int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
> int (* it_nexus_response)(struct Scsi_Host *, u64, int);
>
> + /* fc service handler */
> + int (*execute_fc_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;
> @@ -736,7 +812,6 @@ fc_vport_set_state(struct fc_vport *vport, enum
> fc_vport_state new_state)
> vport->vport_state = new_state;
> }
>
> -
> struct scsi_transport_template *fc_attach_transport(
> struct fc_function_template *);
> void fc_release_transport(struct scsi_transport_template *);
> --
> 1.6.0.2
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/2] FC pass through support - revised III
2008-11-11 9:41 ` FUJITA Tomonori
@ 2008-11-11 14:35 ` Seokmann Ju
2008-11-11 15:30 ` James Smart
0 siblings, 1 reply; 4+ messages in thread
From: Seokmann Ju @ 2008-11-11 14:35 UTC (permalink / raw)
To: FUJITA Tomonori, James Smart
Cc: James Bottomley, Boaz Harrosh, linux-scsi, Andrew Vasquez,
Mike Christie, Robert W Love
Thanks for the comments, Tomonori.
As I responded next to each of your comments, I will make changes
accordingly.
James, would you want me to send you patch reflecting the changes only?
Or, if you'd prefer, I will send you another patch contains 'revised
III + these changes'.
Please let me know.
Thank you,
Seokmann
On Nov 11, 2008, at 1:41 AM, FUJITA Tomonori wrote:
> On Fri, 31 Oct 2008 08:34:35 -0700
> Seokmann Ju <seokmann.ju@qlogic.com> wrote:
>
>> Attachment is also available at the bottom.
>> ---
>> From 47f113766853dcabec329013fd1c2eb9e04f8c92 Mon Sep 17 00:00:00
>> 2001
>> From: root <root@linux-atl-00.qlogic.com>
>> Date: Fri, 31 Oct 2008 08:13:15 -0700
>> Subject: [PATCH] scsi_transport_fc: FC pass through support
>>
>> This patch will add FC pass through support.
>> The FC pass through support is service request handling mechanism
>> for FC specification defined services including,
>> - Link Services (Basic LS, Extended LS)
>> - Generic Services (FC-CT - Common Transport)
>> The support utilize BSG (Block layer SCSI Generic) interface with
>> bidi (bi-directional) nature in handling the service requests.
>>
>> This patch added following featues in the support
>> - FC service structure has defined to transport service requests
>> - Handles the service request in asynchronous manner - LLD
>> - Timeout capability
>> - Abort capability
>>
>> Signed-off-by: Seokmann Ju <seokmann.ju@qlogic.com>
>> ---
>> drivers/scsi/scsi_transport_fc.c | 212 +++++++++++++++++++++++++++
>> ++
>> ++++++++-
>> include/scsi/scsi_transport_fc.h | 79 ++++++++++++++-
>> 2 files changed, 288 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/
>> scsi_transport_fc.c
>> index 1e71abf..a0c1430 100644
>> --- a/drivers/scsi/scsi_transport_fc.c
>> +++ b/drivers/scsi/scsi_transport_fc.c
>> @@ -43,6 +43,11 @@ static void fc_vport_sched_delete(struct
>> work_struct *work);
>> static int fc_vport_setup(struct Scsi_Host *shost, int channel,
>> struct device *pdev, struct fc_vport_identifiers *ids,
>> struct fc_vport **vport);
>> +static enum blk_eh_timer_return fc_service_timeout(struct request
>> *req);
>> +static void fc_service_done(struct fc_service *);
>> +static int fc_service_handler(struct Scsi_Host *, struct fc_rport *,
>> + struct request *, struct request_queue *);
>> +static void fc_bsg_remove(struct Scsi_Host *, struct fc_rport *);
>>
>> /*
>> * Redefine so that we can have same named attributes in the
>> @@ -2413,11 +2418,214 @@ 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 enum blk_eh_timer_return fc_service_timeout(struct request
>> *req)
>> +{
>> + struct fc_service *service = (void *) req->special;
>> + struct Scsi_Host *shost = rport_to_shost(service->rport);
>> + struct fc_internal *i = to_fc_internal(shost->transportt);
>> + unsigned long flags;
>> + int res = 0;
>> +
>> + if (service->rport->port_state == FC_PORTSTATE_BLOCKED)
>> + return BLK_EH_RESET_TIMER;
>> +
>> + spin_lock_irqsave(&service->service_state_lock, flags);
>> + if (!(service->service_state_flag & FC_SERVICE_STATE_DONE))
>> + service->service_state_flag |= FC_SERVICE_STATE_TIMEOUT;
>> + spin_unlock_irqrestore(&service->service_state_lock, flags);
>> +
>> + if (i->f->abort_fc_service)
>> + res = i->f->abort_fc_service(service);
>> +
>> + if (res) {
>> + printk(KERN_ERR "ERROR: issuing FC service to the LLD "
>> + "failed with status %d\n", res);
>> + fc_service_done(service);
>> + }
>> +
>> + /* the blk_end_sync_io() doesn't check the error */
>> + return BLK_EH_NOT_HANDLED;
>> +}
>> +
>> +static void fc_service_done(struct fc_service *service)
>> +{
>> +
>> + if (service->service_state_flag != FC_SERVICE_STATE_DONE) {
>> + if (service->service_state_flag == FC_SERVICE_STATE_TIMEOUT)
>> + printk(KERN_ERR "ERROR: FC service timed out\n");
>> + else if (service->service_state_flag ==
>> + FC_SERVICE_STATE_ABORTED)
>> + printk(KERN_ERR "ERROR: FC service aborted\n");
>> + else
>> + printk(KERN_ERR "ERROR: FC service not finished\n");
>> + }
>> +
>> + if (service->srv_reply.status != FC_SERVICE_COMPLETE) {
>> + printk(KERN_ERR "ERROR: FC service to rport %p failed with"
>> + " status 0x%x\n", service->rport,
>> + service->srv_reply.status);
>> + }
>> +
>> + service->req->errors = service->srv_reply.status;
>> +
>> + blk_end_bidi_request(service->req,
>> + service->srv_reply.status ? -EIO : 0, blk_rq_bytes(service-
>> >req),
>> + service->req->next_rq ? blk_rq_bytes(service->req->next_rq) :
>> 0);
>> +
>> + kfree(service->sg_req);
>> + kfree(service->sg_rsp);
>> + kfree(service);
>> +}
>> +
>> +static int
>> +issue_fc_service(struct fc_rport *rport, struct request *req,
>> + struct request *rsp, struct request_queue *q)
>> +{
>> + int res = -ECOMM;
>> + struct fc_service *service;
>> + struct Scsi_Host *shost = rport_to_shost(rport);
>> + struct fc_internal *i = to_fc_internal(shost->transportt);
>> + struct fc_service_request *srv_request = (struct
>> fc_service_request *)
>> + req->cmd;
>> +
>> + service = kzalloc(sizeof(struct fc_service), GFP_KERNEL);
>> + if (!service)
>> + return -ENOMEM;
>> +
>> + req->special = service;
>> + service->rport = rport;
>> + service->req = req;
>> + service->q = q;
>> + service->srv_request = srv_request;
>> +
>> + service->sg_req =
>> + kzalloc(sizeof(struct scatterlist) * req->nr_phys_segments,
>> + GFP_KERNEL);
>
> Needs to check the allocation failure.
OK. checker will be added.
>
>
>
>> + sg_init_table(service->sg_req, req->nr_phys_segments);
>> + service->req_sg_cnt =
>> + blk_rq_map_sg(q, req, service->sg_req);
>> + service->req_size = req->data_len;
>> +
>> + service->sg_rsp =
>> + kzalloc(sizeof(struct scatterlist) * rsp->nr_phys_segments,
>> + GFP_KERNEL);
>
> Ditto.
OK.
>
>
>
>> + sg_init_table(service->sg_rsp, rsp->nr_phys_segments);
>> + service->rsp_sg_cnt =
>> + blk_rq_map_sg(q, rsp, service->sg_rsp);
>> + service->rsp_size = rsp->data_len;
>> +
>> + /* sense area of the request structure */
>> + service->reply_seq = req->sense;
>> + service->service_done = fc_service_done;
>> + service->service_state_flag = FC_SERVICE_STATE_PENDING;
>> +
>> + if (i->f->execute_fc_service)
>> + res = i->f->execute_fc_service(service);
>> +
>> + if (res) {
>> + printk(KERN_ERR "ERROR: issuing FC service to the LLD "
>> + "failed with status %d\n", res);
>> + fc_service_done(service);
>> + return res;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int
>> +fc_service_handler(struct Scsi_Host *shost, struct fc_rport *rport,
>> + struct request *req, struct request_queue *q)
>> +{
>> + int ret;
>> + struct request *rsp = req->next_rq;
>> +
>> + if (!rsp) {
>> + printk(KERN_ERR "ERROR: space for a FC service"
>> + " response is missing\n");
>> + return -EINVAL;
>
> Needs to complete the request unless the request leaks, I think.
You are right. There are some other places where need to be fixed as
well.
>
>
>
>> + }
>> +
>> + ret = issue_fc_service(rport, req, rsp, q);
>> +
>> + return ret;
>> +}
>> +
>> +static void fc_service_dispatch(struct request_queue *q)
>> +{
>> + struct request *req;
>> + struct fc_rport *rport = q->queuedata;
>> + struct Scsi_Host *shost = rport_to_shost(rport);
>> +
>> + while (!blk_queue_plugged(q)) {
>> + req = elv_next_request(q);
>> + if (!req)
>> + break;
>> +
>> + blkdev_dequeue_request(req);
>> + spin_unlock_irq(q->queue_lock);
>> +
>> + fc_service_handler(shost, rport, req, q);
>> +
>> + spin_lock_irq(q->queue_lock);
>> + }
>> +}
>> +
>> +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 *);
>
> Not necessary.
>
>
>> + if (!rport) {
>> + printk(KERN_ERR "ERROR: rport is NULL\n");
>> + return -ENOMEM;
>> + }
>> +
>> + q = blk_init_queue(fc_service_dispatch, NULL);
>> + if (!q)
>> + return -ENOMEM;
>> +
>> + dev = &rport->dev;
>> + name = dev->bus_id;
>> + release = NULL;
>> +
>> + error = bsg_register_queue(q, dev, name, release);
>
> You can just use NULL here.
>
>
> error = bsg_register_queue(q, dev, name, NULL);
OK.
>
>
>
>> + if (error) {
>> + blk_cleanup_queue(q);
>> + return -ENOMEM;
>> + }
>> +
>> + blk_queue_max_hw_segments(q, shost->sg_tablesize);
>> + blk_queue_max_phys_segments(q, SCSI_MAX_SG_CHAIN_SEGMENTS);
>> + blk_queue_rq_timed_out(q, fc_service_timeout);
>> + blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
>> +
>> + 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)
>> + return;
>> +
>> + bsg_unregister_queue(q);
>> +}
>>
>> /**
>> * fc_rport_create - allocates and creates a remote FC port.
>> @@ -2478,8 +2686,8 @@ 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 */
>>
>> + get_device(&shost->shost_gendev); /* for fc_host->rport list */
>> spin_unlock_irqrestore(shost->host_lock, flags);
>>
>> dev = &rport->dev;
>> @@ -2498,6 +2706,8 @@ fc_rport_create(struct Scsi_Host *shost, int
>> channel,
>> transport_add_device(dev);
>> transport_configure_device(dev);
>>
>> + fc_bsg_initialize(shost, rport);
>> +
>> 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 49d8913..8367d48 100644
>> --- a/include/scsi/scsi_transport_fc.h
>> +++ b/include/scsi/scsi_transport_fc.h
>> @@ -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_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: */
>> @@ -515,6 +515,78 @@ 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 fc_service_status {
>> + FC_SERVICE_COMPLETE,
>> + FC_SERVICE_TIMEOUT,
>> + FC_SERVICE_ABORT,
>> + FC_SERVICE_UNSUPPORTED,
>> + FC_SERVICE_ERROR = -1,
>> +};
>> +
>> +#define FC_SERVICE_STATE_PENDING 1
>> +#define FC_SERVICE_STATE_DONE 2
>> +#define FC_SERVICE_STATE_ABORTED 4
>> +#define FC_SERVICE_STATE_TIMEOUT 8
>> +
>> +#define FC_SERVICE_TIMEOUT 10
>> +
>> +/* request (CDB) structure of the sg_io_v4 */
>> +struct fc_service_request {
>> + u8 request_type;
>> + u8 reserved0;
>> + u8 reserved1;
>> + u8 reserved2;
>> + u32 reserved3[3];
>> +};
>> +
>> +/* response (request sense data) structure of the sg_io_v4 */
>> +struct fc_service_reply {
>> + enum fc_service_status status;
>> + u16 error_code;
>> + u16 additional_error_code;
>> + u32 residual;
>> +};
>> +
>> +struct fc_service {
>> + struct fc_rport *rport;
>> + struct list_head list;
>> +
>> + spinlock_t service_state_lock;
>> + unsigned service_state_flag;
>> +
>> + struct request *req;
>> + struct request_queue *q;
>> +
>> + /* Used by the discovery code. */
>> + struct completion completion;
>> +
>> + struct fc_service_request *srv_request;
>> + struct scatterlist *sg_req;
>> + int req_sg_cnt;
>> + int req_size;
>> + struct scatterlist *sg_rsp;
>> + int rsp_sg_cnt;
>> + int rsp_size;
>> +
>> + struct fc_service_reply srv_reply;
>> + void *reply_seq; /* pointer to sense area of request */
>> + void (*service_done)(struct fc_service *);
>> +
>> + void *lld_pkt;
>> +};
>> +
>> #define shost_to_fc_host(x) \
>> ((struct fc_host_attrs *)(x)->shost_data)
>>
>> @@ -613,6 +685,10 @@ struct fc_function_template {
>> int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
>> int (* it_nexus_response)(struct Scsi_Host *, u64, int);
>>
>> + /* fc service handler */
>> + int (*execute_fc_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;
>> @@ -736,7 +812,6 @@ fc_vport_set_state(struct fc_vport *vport, enum
>> fc_vport_state new_state)
>> vport->vport_state = new_state;
>> }
>>
>> -
>> struct scsi_transport_template *fc_attach_transport(
>> struct fc_function_template *);
>> void fc_release_transport(struct scsi_transport_template *);
>> --
>> 1.6.0.2
>>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/2] FC pass through support - revised III
2008-11-11 14:35 ` Seokmann Ju
@ 2008-11-11 15:30 ` James Smart
0 siblings, 0 replies; 4+ messages in thread
From: James Smart @ 2008-11-11 15:30 UTC (permalink / raw)
To: Seokmann Ju
Cc: FUJITA Tomonori, James Bottomley, Boaz Harrosh,
linux-scsi@vger.kernel.org, Andrew Vasquez, Mike Christie,
Robert W Love
fyi - I'm working on a rework IV that genericizes it more, and have been
talking to Seokman about it.
Don't worry about the patch 1 comments. I've dealt with most of these
already. But, I'm sure I'll introduce some things that Fujita/Boaz can
correct for me.
As for the patch2 comments, hold off until you see the IV rework. When
you revise for the RFC, you can pick them up.
-- james
Seokmann Ju wrote:
> Thanks for the comments, Tomonori.
> As I responded next to each of your comments, I will make changes
> accordingly.
>
> James, would you want me to send you patch reflecting the changes only?
> Or, if you'd prefer, I will send you another patch contains 'revised
> III + these changes'.
>
> Please let me know.
>
> Thank you,
> Seokmann
>
> On Nov 11, 2008, at 1:41 AM, FUJITA Tomonori wrote:
>
>> On Fri, 31 Oct 2008 08:34:35 -0700
>> Seokmann Ju <seokmann.ju@qlogic.com> wrote:
>>
>>> Attachment is also available at the bottom.
>>> ---
>>> From 47f113766853dcabec329013fd1c2eb9e04f8c92 Mon Sep 17 00:00:00
>>> 2001
>>> From: root <root@linux-atl-00.qlogic.com>
>>> Date: Fri, 31 Oct 2008 08:13:15 -0700
>>> Subject: [PATCH] scsi_transport_fc: FC pass through support
>>>
>>> This patch will add FC pass through support.
>>> The FC pass through support is service request handling mechanism
>>> for FC specification defined services including,
>>> - Link Services (Basic LS, Extended LS)
>>> - Generic Services (FC-CT - Common Transport)
>>> The support utilize BSG (Block layer SCSI Generic) interface with
>>> bidi (bi-directional) nature in handling the service requests.
>>>
>>> This patch added following featues in the support
>>> - FC service structure has defined to transport service requests
>>> - Handles the service request in asynchronous manner - LLD
>>> - Timeout capability
>>> - Abort capability
>>>
>>> Signed-off-by: Seokmann Ju <seokmann.ju@qlogic.com>
>>> ---
>>> drivers/scsi/scsi_transport_fc.c | 212 +++++++++++++++++++++++++++
>>> ++
>>> ++++++++-
>>> include/scsi/scsi_transport_fc.h | 79 ++++++++++++++-
>>> 2 files changed, 288 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/
>>> scsi_transport_fc.c
>>> index 1e71abf..a0c1430 100644
>>> --- a/drivers/scsi/scsi_transport_fc.c
>>> +++ b/drivers/scsi/scsi_transport_fc.c
>>> @@ -43,6 +43,11 @@ static void fc_vport_sched_delete(struct
>>> work_struct *work);
>>> static int fc_vport_setup(struct Scsi_Host *shost, int channel,
>>> struct device *pdev, struct fc_vport_identifiers *ids,
>>> struct fc_vport **vport);
>>> +static enum blk_eh_timer_return fc_service_timeout(struct request
>>> *req);
>>> +static void fc_service_done(struct fc_service *);
>>> +static int fc_service_handler(struct Scsi_Host *, struct fc_rport *,
>>> + struct request *, struct request_queue *);
>>> +static void fc_bsg_remove(struct Scsi_Host *, struct fc_rport *);
>>>
>>> /*
>>> * Redefine so that we can have same named attributes in the
>>> @@ -2413,11 +2418,214 @@ 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 enum blk_eh_timer_return fc_service_timeout(struct request
>>> *req)
>>> +{
>>> + struct fc_service *service = (void *) req->special;
>>> + struct Scsi_Host *shost = rport_to_shost(service->rport);
>>> + struct fc_internal *i = to_fc_internal(shost->transportt);
>>> + unsigned long flags;
>>> + int res = 0;
>>> +
>>> + if (service->rport->port_state == FC_PORTSTATE_BLOCKED)
>>> + return BLK_EH_RESET_TIMER;
>>> +
>>> + spin_lock_irqsave(&service->service_state_lock, flags);
>>> + if (!(service->service_state_flag & FC_SERVICE_STATE_DONE))
>>> + service->service_state_flag |= FC_SERVICE_STATE_TIMEOUT;
>>> + spin_unlock_irqrestore(&service->service_state_lock, flags);
>>> +
>>> + if (i->f->abort_fc_service)
>>> + res = i->f->abort_fc_service(service);
>>> +
>>> + if (res) {
>>> + printk(KERN_ERR "ERROR: issuing FC service to the LLD "
>>> + "failed with status %d\n", res);
>>> + fc_service_done(service);
>>> + }
>>> +
>>> + /* the blk_end_sync_io() doesn't check the error */
>>> + return BLK_EH_NOT_HANDLED;
>>> +}
>>> +
>>> +static void fc_service_done(struct fc_service *service)
>>> +{
>>> +
>>> + if (service->service_state_flag != FC_SERVICE_STATE_DONE) {
>>> + if (service->service_state_flag == FC_SERVICE_STATE_TIMEOUT)
>>> + printk(KERN_ERR "ERROR: FC service timed out\n");
>>> + else if (service->service_state_flag ==
>>> + FC_SERVICE_STATE_ABORTED)
>>> + printk(KERN_ERR "ERROR: FC service aborted\n");
>>> + else
>>> + printk(KERN_ERR "ERROR: FC service not finished\n");
>>> + }
>>> +
>>> + if (service->srv_reply.status != FC_SERVICE_COMPLETE) {
>>> + printk(KERN_ERR "ERROR: FC service to rport %p failed with"
>>> + " status 0x%x\n", service->rport,
>>> + service->srv_reply.status);
>>> + }
>>> +
>>> + service->req->errors = service->srv_reply.status;
>>> +
>>> + blk_end_bidi_request(service->req,
>>> + service->srv_reply.status ? -EIO : 0, blk_rq_bytes(service-
>>>> req),
>>> + service->req->next_rq ? blk_rq_bytes(service->req->next_rq) :
>>> 0);
>>> +
>>> + kfree(service->sg_req);
>>> + kfree(service->sg_rsp);
>>> + kfree(service);
>>> +}
>>> +
>>> +static int
>>> +issue_fc_service(struct fc_rport *rport, struct request *req,
>>> + struct request *rsp, struct request_queue *q)
>>> +{
>>> + int res = -ECOMM;
>>> + struct fc_service *service;
>>> + struct Scsi_Host *shost = rport_to_shost(rport);
>>> + struct fc_internal *i = to_fc_internal(shost->transportt);
>>> + struct fc_service_request *srv_request = (struct
>>> fc_service_request *)
>>> + req->cmd;
>>> +
>>> + service = kzalloc(sizeof(struct fc_service), GFP_KERNEL);
>>> + if (!service)
>>> + return -ENOMEM;
>>> +
>>> + req->special = service;
>>> + service->rport = rport;
>>> + service->req = req;
>>> + service->q = q;
>>> + service->srv_request = srv_request;
>>> +
>>> + service->sg_req =
>>> + kzalloc(sizeof(struct scatterlist) * req->nr_phys_segments,
>>> + GFP_KERNEL);
>> Needs to check the allocation failure.
> OK. checker will be added.
>>
>>
>>> + sg_init_table(service->sg_req, req->nr_phys_segments);
>>> + service->req_sg_cnt =
>>> + blk_rq_map_sg(q, req, service->sg_req);
>>> + service->req_size = req->data_len;
>>> +
>>> + service->sg_rsp =
>>> + kzalloc(sizeof(struct scatterlist) * rsp->nr_phys_segments,
>>> + GFP_KERNEL);
>> Ditto.
> OK.
>>
>>
>>> + sg_init_table(service->sg_rsp, rsp->nr_phys_segments);
>>> + service->rsp_sg_cnt =
>>> + blk_rq_map_sg(q, rsp, service->sg_rsp);
>>> + service->rsp_size = rsp->data_len;
>>> +
>>> + /* sense area of the request structure */
>>> + service->reply_seq = req->sense;
>>> + service->service_done = fc_service_done;
>>> + service->service_state_flag = FC_SERVICE_STATE_PENDING;
>>> +
>>> + if (i->f->execute_fc_service)
>>> + res = i->f->execute_fc_service(service);
>>> +
>>> + if (res) {
>>> + printk(KERN_ERR "ERROR: issuing FC service to the LLD "
>>> + "failed with status %d\n", res);
>>> + fc_service_done(service);
>>> + return res;
>>> + }
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int
>>> +fc_service_handler(struct Scsi_Host *shost, struct fc_rport *rport,
>>> + struct request *req, struct request_queue *q)
>>> +{
>>> + int ret;
>>> + struct request *rsp = req->next_rq;
>>> +
>>> + if (!rsp) {
>>> + printk(KERN_ERR "ERROR: space for a FC service"
>>> + " response is missing\n");
>>> + return -EINVAL;
>> Needs to complete the request unless the request leaks, I think.
> You are right. There are some other places where need to be fixed as
> well.
>
>>
>>
>>> + }
>>> +
>>> + ret = issue_fc_service(rport, req, rsp, q);
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +static void fc_service_dispatch(struct request_queue *q)
>>> +{
>>> + struct request *req;
>>> + struct fc_rport *rport = q->queuedata;
>>> + struct Scsi_Host *shost = rport_to_shost(rport);
>>> +
>>> + while (!blk_queue_plugged(q)) {
>>> + req = elv_next_request(q);
>>> + if (!req)
>>> + break;
>>> +
>>> + blkdev_dequeue_request(req);
>>> + spin_unlock_irq(q->queue_lock);
>>> +
>>> + fc_service_handler(shost, rport, req, q);
>>> +
>>> + spin_lock_irq(q->queue_lock);
>>> + }
>>> +}
>>> +
>>> +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 *);
>> Not necessary.
>>
>>
>>> + if (!rport) {
>>> + printk(KERN_ERR "ERROR: rport is NULL\n");
>>> + return -ENOMEM;
>>> + }
>>> +
>>> + q = blk_init_queue(fc_service_dispatch, NULL);
>>> + if (!q)
>>> + return -ENOMEM;
>>> +
>>> + dev = &rport->dev;
>>> + name = dev->bus_id;
>>> + release = NULL;
>>> +
>>> + error = bsg_register_queue(q, dev, name, release);
>> You can just use NULL here.
>>
>>
>> error = bsg_register_queue(q, dev, name, NULL);
> OK.
>>
>>
>>> + if (error) {
>>> + blk_cleanup_queue(q);
>>> + return -ENOMEM;
>>> + }
>>> +
>>> + blk_queue_max_hw_segments(q, shost->sg_tablesize);
>>> + blk_queue_max_phys_segments(q, SCSI_MAX_SG_CHAIN_SEGMENTS);
>>> + blk_queue_rq_timed_out(q, fc_service_timeout);
>>> + blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
>>> +
>>> + 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)
>>> + return;
>>> +
>>> + bsg_unregister_queue(q);
>>> +}
>>>
>>> /**
>>> * fc_rport_create - allocates and creates a remote FC port.
>>> @@ -2478,8 +2686,8 @@ 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 */
>>>
>>> + get_device(&shost->shost_gendev); /* for fc_host->rport list */
>>> spin_unlock_irqrestore(shost->host_lock, flags);
>>>
>>> dev = &rport->dev;
>>> @@ -2498,6 +2706,8 @@ fc_rport_create(struct Scsi_Host *shost, int
>>> channel,
>>> transport_add_device(dev);
>>> transport_configure_device(dev);
>>>
>>> + fc_bsg_initialize(shost, rport);
>>> +
>>> 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 49d8913..8367d48 100644
>>> --- a/include/scsi/scsi_transport_fc.h
>>> +++ b/include/scsi/scsi_transport_fc.h
>>> @@ -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_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: */
>>> @@ -515,6 +515,78 @@ 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 fc_service_status {
>>> + FC_SERVICE_COMPLETE,
>>> + FC_SERVICE_TIMEOUT,
>>> + FC_SERVICE_ABORT,
>>> + FC_SERVICE_UNSUPPORTED,
>>> + FC_SERVICE_ERROR = -1,
>>> +};
>>> +
>>> +#define FC_SERVICE_STATE_PENDING 1
>>> +#define FC_SERVICE_STATE_DONE 2
>>> +#define FC_SERVICE_STATE_ABORTED 4
>>> +#define FC_SERVICE_STATE_TIMEOUT 8
>>> +
>>> +#define FC_SERVICE_TIMEOUT 10
>>> +
>>> +/* request (CDB) structure of the sg_io_v4 */
>>> +struct fc_service_request {
>>> + u8 request_type;
>>> + u8 reserved0;
>>> + u8 reserved1;
>>> + u8 reserved2;
>>> + u32 reserved3[3];
>>> +};
>>> +
>>> +/* response (request sense data) structure of the sg_io_v4 */
>>> +struct fc_service_reply {
>>> + enum fc_service_status status;
>>> + u16 error_code;
>>> + u16 additional_error_code;
>>> + u32 residual;
>>> +};
>>> +
>>> +struct fc_service {
>>> + struct fc_rport *rport;
>>> + struct list_head list;
>>> +
>>> + spinlock_t service_state_lock;
>>> + unsigned service_state_flag;
>>> +
>>> + struct request *req;
>>> + struct request_queue *q;
>>> +
>>> + /* Used by the discovery code. */
>>> + struct completion completion;
>>> +
>>> + struct fc_service_request *srv_request;
>>> + struct scatterlist *sg_req;
>>> + int req_sg_cnt;
>>> + int req_size;
>>> + struct scatterlist *sg_rsp;
>>> + int rsp_sg_cnt;
>>> + int rsp_size;
>>> +
>>> + struct fc_service_reply srv_reply;
>>> + void *reply_seq; /* pointer to sense area of request */
>>> + void (*service_done)(struct fc_service *);
>>> +
>>> + void *lld_pkt;
>>> +};
>>> +
>>> #define shost_to_fc_host(x) \
>>> ((struct fc_host_attrs *)(x)->shost_data)
>>>
>>> @@ -613,6 +685,10 @@ struct fc_function_template {
>>> int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
>>> int (* it_nexus_response)(struct Scsi_Host *, u64, int);
>>>
>>> + /* fc service handler */
>>> + int (*execute_fc_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;
>>> @@ -736,7 +812,6 @@ fc_vport_set_state(struct fc_vport *vport, enum
>>> fc_vport_state new_state)
>>> vport->vport_state = new_state;
>>> }
>>>
>>> -
>>> struct scsi_transport_template *fc_attach_transport(
>>> struct fc_function_template *);
>>> void fc_release_transport(struct scsi_transport_template *);
>>> --
>>> 1.6.0.2
>>>
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2008-11-11 15:29 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-10-31 15:34 [PATCH 1/2] FC pass through support - revised III Seokmann Ju
2008-11-11 9:41 ` FUJITA Tomonori
2008-11-11 14:35 ` Seokmann Ju
2008-11-11 15:30 ` James Smart
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.