From: Chandra Seetharaman <sekharan@us.ibm.com>
To: linux-scsi@vger.kernel.org
Cc: dm-devel@redhat.com, babu.moger@lsi.com, michaelc@cs.wisc.edu,
Benoit_Arthur@emc.com, Eddie.Williams@steeleye.com,
berthiaume_wayne@emc.com,
Chandra Seetharaman <sekharan@us.ibm.com>
Subject: [PATCH 2/4] scsi_dh: rdac handler: Make rdac hardware handler async
Date: Tue, 29 Sep 2009 19:08:23 -0700 [thread overview]
Message-ID: <20090930020823.11455.23935.sendpatchset@chandra-ubuntu> (raw)
In-Reply-To: <20090930020811.11455.59565.sendpatchset@chandra-ubuntu>
Batch up MODE_SELECT in rdac device handler.
LSI RDAC storage has the capability of handling mode selects for
multiple luns in a same command. Make use of that ability to send
as few MODE SELECTs as possible to the storage controller as possible.
This patch creates a work queue and queues up activate requests
when a MODE SELECT is sent down the wire. When that MODE SELECT
completes, it compiles queued up activate requests for multiple
luns into a single MODE SELECT.
This reduces the time to do failover/failback of large number of LUNS.
Signed-off-by: Babu Moger <babu.moger@lsi.com>
Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
---
drivers/scsi/device_handler/scsi_dh_rdac.c | 117 ++++++++++++++++++++++++++---
1 file changed, 104 insertions(+), 13 deletions(-)
Index: linux-2.6.31/drivers/scsi/device_handler/scsi_dh_rdac.c
===================================================================
--- linux-2.6.31.orig/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ linux-2.6.31/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -22,6 +22,7 @@
#include <scsi/scsi.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_dh.h>
+#include <linux/workqueue.h>
#define RDAC_NAME "rdac"
#define RDAC_RETRY_COUNT 5
@@ -135,6 +136,11 @@ struct rdac_controller {
struct rdac_pg_legacy legacy;
struct rdac_pg_expanded expanded;
} mode_select;
+ spinlock_t ms_lock;
+ int ms_queued;
+ struct work_struct ms_work;
+ struct scsi_device *ms_sdev;
+ struct list_head ms_head;
};
struct c8_inquiry {
u8 peripheral_info;
@@ -195,8 +201,17 @@ static const char *lun_state[] =
"owned (AVT mode)",
};
+struct rdac_queue_data {
+ struct list_head entry;
+ struct rdac_dh_data *h;
+ activate_complete callback_fn;
+ void *callback_data;
+};
+
static LIST_HEAD(ctlr_list);
static DEFINE_SPINLOCK(list_lock);
+static struct workqueue_struct *kmpath_rdacd;
+static void send_mode_select(struct work_struct *work);
static inline struct rdac_dh_data *get_rdac_data(struct scsi_device *sdev)
{
@@ -253,7 +268,6 @@ static struct request *rdac_failover_get
rdac_pg->subpage_code = 0x1;
rdac_pg->page_len[0] = 0x01;
rdac_pg->page_len[1] = 0x28;
- rdac_pg->lun_table[h->lun] = 0x81;
} else {
struct rdac_pg_legacy *rdac_pg;
@@ -263,7 +277,6 @@ static struct request *rdac_failover_get
common = &rdac_pg->common;
rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER;
rdac_pg->page_len = 0x68;
- rdac_pg->lun_table[h->lun] = 0x81;
}
common->rdac_mode[1] = RDAC_MODE_TRANSFER_SPECIFIED_LUNS;
common->quiescence_timeout = RDAC_QUIESCENCE_TIME;
@@ -297,6 +310,7 @@ static void release_controller(struct kr
struct rdac_controller *ctlr;
ctlr = container_of(kref, struct rdac_controller, kref);
+ flush_workqueue(kmpath_rdacd);
spin_lock(&list_lock);
list_del(&ctlr->node);
spin_unlock(&list_lock);
@@ -326,6 +340,11 @@ static struct rdac_controller *get_contr
memcpy(ctlr->slot_id, slot_id, SLOT_ID_LEN);
kref_init(&ctlr->kref);
ctlr->use_ms10 = -1;
+ ctlr->ms_queued = 0;
+ ctlr->ms_sdev = NULL;
+ spin_lock_init(&ctlr->ms_lock);
+ INIT_WORK(&ctlr->ms_work, send_mode_select);
+ INIT_LIST_HEAD(&ctlr->ms_head);
list_add(&ctlr->node, &ctlr_list);
done:
spin_unlock(&list_lock);
@@ -445,8 +464,7 @@ static int set_mode_select(struct scsi_d
return err;
}
-static int mode_select_handle_sense(struct scsi_device *sdev,
- unsigned char *sensebuf)
+static int mode_select_handle_sense(unsigned char *sensebuf)
{
struct scsi_sense_hdr sense_hdr;
int err = SCSI_DH_IO, ret;
@@ -478,7 +496,7 @@ static int mode_select_handle_sense(stru
err = SCSI_DH_RETRY;
break;
default:
- sdev_printk(KERN_INFO, sdev,
+ printk(KERN_INFO
"MODE_SELECT failed with sense %02x/%02x/%02x.\n",
sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq);
}
@@ -487,11 +505,29 @@ done:
return err;
}
-static int send_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h)
+static void send_mode_select(struct work_struct *work)
{
+ struct rdac_controller *ctlr =
+ container_of(work, struct rdac_controller, ms_work);
struct request *rq;
+ struct scsi_device *sdev = ctlr->ms_sdev;
+ struct rdac_dh_data *h = get_rdac_data(sdev);
struct request_queue *q = sdev->request_queue;
int err, retry_cnt = RDAC_RETRY_COUNT;
+ struct rdac_queue_data *tmp, *qdata;
+ LIST_HEAD(list);
+ u8 *lun_table;
+
+ spin_lock(&ctlr->ms_lock);
+ list_splice_init(&ctlr->ms_head, &list);
+ ctlr->ms_queued = 0;
+ ctlr->ms_sdev = NULL;
+ spin_unlock(&ctlr->ms_lock);
+
+ if (ctlr->use_ms10)
+ lun_table = ctlr->mode_select.expanded.lun_table;
+ else
+ lun_table = ctlr->mode_select.legacy.lun_table;
retry:
err = SCSI_DH_RES_TEMP_UNAVAIL;
@@ -499,13 +535,17 @@ retry:
if (!rq)
goto done;
- sdev_printk(KERN_INFO, sdev, "%s MODE_SELECT command.\n",
+ list_for_each_entry(qdata, &list, entry) {
+ lun_table[qdata->h->lun] = 0x81;
+ }
+
+ printk(KERN_INFO "%s MODE_SELECT command.\n",
(retry_cnt == RDAC_RETRY_COUNT) ? "queueing" : "retrying");
err = blk_execute_rq(q, NULL, rq, 1);
blk_put_request(rq);
if (err != SCSI_DH_OK) {
- err = mode_select_handle_sense(sdev, h->sense);
+ err = mode_select_handle_sense(h->sense);
if (err == SCSI_DH_RETRY && retry_cnt--)
goto retry;
}
@@ -513,10 +553,45 @@ retry:
h->state = RDAC_STATE_ACTIVE;
done:
- return err;
+ list_for_each_entry_safe(qdata, tmp, &list, entry) {
+ list_del(&qdata->entry);
+ if (err == SCSI_DH_OK)
+ qdata->h->state = RDAC_STATE_ACTIVE;
+ if (qdata->callback_fn)
+ qdata->callback_fn(qdata->callback_data, err);
+ kfree(qdata);
+ }
+ return;
}
-static int rdac_activate(struct scsi_device *sdev, activate_complete fn, void *data)
+static int queue_mode_select(struct scsi_device *sdev,
+ activate_complete fn, void *data)
+{
+ struct rdac_queue_data *qdata;
+ struct rdac_controller *ctlr;
+
+ qdata = kzalloc(sizeof(*qdata), GFP_KERNEL);
+ if (!qdata)
+ return SCSI_DH_RETRY;
+
+ qdata->h = get_rdac_data(sdev);
+ qdata->callback_fn = fn;
+ qdata->callback_data = data;
+
+ ctlr = qdata->h->ctlr;
+ spin_lock(&ctlr->ms_lock);
+ list_add_tail(&qdata->entry, &ctlr->ms_head);
+ if (!ctlr->ms_queued) {
+ ctlr->ms_queued = 1;
+ ctlr->ms_sdev = sdev;
+ queue_work(kmpath_rdacd, &ctlr->ms_work);
+ }
+ spin_unlock(&ctlr->ms_lock);
+ return SCSI_DH_OK;
+}
+
+static int rdac_activate(struct scsi_device *sdev,
+ activate_complete fn, void *data)
{
struct rdac_dh_data *h = get_rdac_data(sdev);
int err = SCSI_DH_OK;
@@ -536,8 +611,11 @@ static int rdac_activate(struct scsi_dev
if (err != SCSI_DH_OK)
goto done;
}
- if (h->lun_state == RDAC_LUN_UNOWNED)
- err = send_mode_select(sdev, h);
+ if (h->lun_state == RDAC_LUN_UNOWNED) {
+ err = queue_mode_select(sdev, fn, data);
+ if (err == SCSI_DH_OK)
+ return 0;
+ }
done:
if (fn)
fn(data, err);
@@ -726,13 +804,26 @@ static int __init rdac_init(void)
int r;
r = scsi_register_device_handler(&rdac_dh);
- if (r != 0)
+ if (r != 0) {
printk(KERN_ERR "Failed to register scsi device handler.");
+ goto done;
+ }
+
+ /*
+ * Create workqueue to handle mode selects for rdac
+ */
+ kmpath_rdacd = create_singlethread_workqueue("kmpath_rdacd");
+ if (!kmpath_rdacd) {
+ scsi_unregister_device_handler(&rdac_dh);
+ printk(KERN_ERR "kmpath_rdacd creation failed.\n");
+ }
+done:
return r;
}
static void __exit rdac_exit(void)
{
+ destroy_workqueue(kmpath_rdacd);
scsi_unregister_device_handler(&rdac_dh);
}
next prev parent reply other threads:[~2009-09-30 2:08 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-09-30 2:08 [PATCH 0/4] scsi_dh: Make scsi_dh_activate asynchronous Chandra Seetharaman
2009-09-30 2:08 ` [PATCH 1/4] scsi_dh: Change the scsidh_activate interface to be asynchronous Chandra Seetharaman
2009-10-02 22:04 ` Moger, Babu
2009-10-02 22:36 ` Chandra Seetharaman
2009-10-02 23:02 ` Moger, Babu
2009-09-30 2:08 ` Chandra Seetharaman [this message]
2009-10-02 0:03 ` [PATCH 2/4] scsi_dh: rdac handler: Make rdac hardware handler async Moger, Babu
2009-10-02 0:29 ` Chandra Seetharaman
2009-09-30 2:08 ` [PATCH 3/4] scsi_dh: rdac handler: Make hp " Chandra Seetharaman
2009-09-30 2:08 ` [PATCH 4/4] scsi_dh: rdac handler: Make alua " Chandra Seetharaman
2009-10-01 4:19 ` [PATCH 0/4] scsi_dh: Make scsi_dh_activate asynchronous Moger, Babu
2009-10-01 20:54 ` Chandra Seetharaman
2009-10-05 13:01 ` Hannes Reinecke
2009-10-05 14:35 ` Hannes Reinecke
2009-10-05 23:25 ` Chandra Seetharaman
2009-10-06 8:08 ` Hannes Reinecke
2009-10-06 19:46 ` Moger, Babu
2009-10-07 23:08 ` Moger, Babu
2009-10-09 9:44 ` Hannes Reinecke
2009-10-09 14:06 ` Moger, Babu
2009-10-09 14:55 ` Hannes Reinecke
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090930020823.11455.23935.sendpatchset@chandra-ubuntu \
--to=sekharan@us.ibm.com \
--cc=Benoit_Arthur@emc.com \
--cc=Eddie.Williams@steeleye.com \
--cc=babu.moger@lsi.com \
--cc=berthiaume_wayne@emc.com \
--cc=dm-devel@redhat.com \
--cc=linux-scsi@vger.kernel.org \
--cc=michaelc@cs.wisc.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.