* [PATCH 00/10] Integrate scsi_dh better into the scsi core V4
@ 2015-08-27 12:16 Hannes Reinecke
2015-08-27 12:16 ` [PATCH 01/10] dm-mpath, scsi_dh: don't let dm detach device handlers Hannes Reinecke
` (9 more replies)
0 siblings, 10 replies; 15+ messages in thread
From: Hannes Reinecke @ 2015-08-27 12:16 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, Martin K. Petersen, Mike Snitzer, linux-scsi,
Hannes Reinecke
This series ties scsi_dh deeper into the scsi core, and fixes all kinds
of issues in it, most importantly the race between using and detaching
device handlers.
Changes since V1:
- updated comments / strings based on review feedback
- moved scsi_dh.c to drivers/scsi to fix the srcdir = objdir build
- changed the old patch 2 to have saner handling of mismatching device
handlers in dm.
- dropped patch 1: not having a hw handler is fine if we don't plan to
change it anyway
- dropped patch 3: not necessary anymore.
Changes since V2:
- Fixup issues during attaching device_handler from dm-multipath
- Add patch to clarify scsi_dh_activate() error codes
Changes since V3:
- Fixup minor bugs discovered during testing
- Fixup patch description
Christoph Hellwig (8):
dm-mpath, scsi_dh: don't let dm detach device handlers
dm-mpath, scsi_dh: request scsi_dh modules in scsi_dh, not dm-mpath
scsi_dh: move to drivers/scsi
scsi_dh: integrate into the core SCSI code
scsi_dh: move device matching to the core code
scsi_dh: kill struct scsi_dh_data
scsi_dh: add a common helper to get a scsi_device from a request_queue
scsi_dh: don't allow to detach device handlers at runtime
Hannes Reinecke (2):
scsi_dh: return SCSI_DH_NOTCONN in scsi_dh_activate()
scsi_dh: move 'dh_state' sysfs attribute to generic code
drivers/md/dm-mpath.c | 27 +-
drivers/scsi/Makefile | 1 +
drivers/scsi/device_handler/Kconfig | 2 +-
drivers/scsi/device_handler/Makefile | 1 -
drivers/scsi/device_handler/scsi_dh.c | 621 ----------------------------
drivers/scsi/device_handler/scsi_dh_alua.c | 31 +-
drivers/scsi/device_handler/scsi_dh_emc.c | 58 +--
drivers/scsi/device_handler/scsi_dh_hp_sw.c | 55 +--
drivers/scsi/device_handler/scsi_dh_rdac.c | 80 +---
drivers/scsi/scsi_dh.c | 371 +++++++++++++++++
drivers/scsi/scsi_error.c | 6 +-
drivers/scsi/scsi_lib.c | 6 +-
drivers/scsi/scsi_priv.h | 9 +
drivers/scsi/scsi_sysfs.c | 68 +++
include/scsi/scsi_device.h | 27 +-
include/scsi/scsi_dh.h | 29 +-
16 files changed, 527 insertions(+), 865 deletions(-)
delete mode 100644 drivers/scsi/device_handler/scsi_dh.c
create mode 100644 drivers/scsi/scsi_dh.c
--
1.8.5.6
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 01/10] dm-mpath, scsi_dh: don't let dm detach device handlers
2015-08-27 12:16 [PATCH 00/10] Integrate scsi_dh better into the scsi core V4 Hannes Reinecke
@ 2015-08-27 12:16 ` Hannes Reinecke
2015-08-27 12:16 ` [PATCH 02/10] dm-mpath, scsi_dh: request scsi_dh modules in scsi_dh, not dm-mpath Hannes Reinecke
` (8 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Hannes Reinecke @ 2015-08-27 12:16 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, Martin K. Petersen, Mike Snitzer, linux-scsi
From: Christoph Hellwig <hch@lst.de>
While allowing dm-mpath to attach device handlers is a functionality we need
for backwards compatibility reason there is no reason to reference count
them and detach them if dm-mpath stops using the device for some reason.
If the device handler works for the given device it can just stay attached,
and we can take the retain_hw_handler codepath.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Acked-by: Mike Snitzer <snitzer@redhat.com>
Acked-by: Hannes Reinecke <hare@Suse.de>
---
drivers/md/dm-mpath.c | 21 +++-----
drivers/scsi/device_handler/scsi_dh.c | 96 ++++++++---------------------------
include/scsi/scsi_device.h | 1 -
include/scsi/scsi_dh.h | 5 --
4 files changed, 28 insertions(+), 95 deletions(-)
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index eff7bdd..a9f58fd 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -159,12 +159,9 @@ static struct priority_group *alloc_priority_group(void)
static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
{
struct pgpath *pgpath, *tmp;
- struct multipath *m = ti->private;
list_for_each_entry_safe(pgpath, tmp, pgpaths, list) {
list_del(&pgpath->list);
- if (m->hw_handler_name)
- scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev));
dm_put_device(ti, pgpath->path.dev);
free_pgpath(pgpath);
}
@@ -580,6 +577,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
q = bdev_get_queue(p->path.dev->bdev);
if (m->retain_attached_hw_handler) {
+retain:
attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL);
if (attached_handler_name) {
/*
@@ -599,20 +597,14 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
}
if (m->hw_handler_name) {
- /*
- * Increments scsi_dh reference, even when using an
- * already-attached handler.
- */
r = scsi_dh_attach(q, m->hw_handler_name);
if (r == -EBUSY) {
- /*
- * Already attached to different hw_handler:
- * try to reattach with correct one.
- */
- scsi_dh_detach(q);
- r = scsi_dh_attach(q, m->hw_handler_name);
- }
+ char b[BDEVNAME_SIZE];
+ printk(KERN_INFO "dm-mpath: retaining handler on device %s\n",
+ bdevname(p->path.dev->bdev, b));
+ goto retain;
+ }
if (r < 0) {
ti->error = "error attaching hardware handler";
dm_put_device(ti, p->path.dev);
@@ -624,7 +616,6 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
if (r < 0) {
ti->error = "unable to set hardware "
"handler parameters";
- scsi_dh_detach(q);
dm_put_device(ti, p->path.dev);
goto bad;
}
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
index 1efebc9..869b5bd 100644
--- a/drivers/scsi/device_handler/scsi_dh.c
+++ b/drivers/scsi/device_handler/scsi_dh.c
@@ -100,14 +100,6 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev,
{
struct scsi_dh_data *d;
- if (sdev->scsi_dh_data) {
- if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
- return -EBUSY;
-
- kref_get(&sdev->scsi_dh_data->kref);
- return 0;
- }
-
if (!try_module_get(scsi_dh->module))
return -EINVAL;
@@ -120,7 +112,6 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev,
}
d->scsi_dh = scsi_dh;
- kref_init(&d->kref);
d->sdev = sdev;
spin_lock_irq(sdev->request_queue->queue_lock);
@@ -129,12 +120,14 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev,
return 0;
}
-static void __detach_handler (struct kref *kref)
+/*
+ * scsi_dh_handler_detach - Detach a device handler from a device
+ * @sdev - SCSI device the device handler should be detached from
+ */
+static void scsi_dh_handler_detach(struct scsi_device *sdev)
{
- struct scsi_dh_data *scsi_dh_data =
- container_of(kref, struct scsi_dh_data, kref);
+ struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
struct scsi_device_handler *scsi_dh = scsi_dh_data->scsi_dh;
- struct scsi_device *sdev = scsi_dh_data->sdev;
scsi_dh->detach(sdev);
@@ -147,30 +140,6 @@ static void __detach_handler (struct kref *kref)
}
/*
- * scsi_dh_handler_detach - Detach a device handler from a device
- * @sdev - SCSI device the device handler should be detached from
- * @scsi_dh - Device handler to be detached
- *
- * Detach from a device handler. If a device handler is specified,
- * only detach if the currently attached handler matches @scsi_dh.
- */
-static void scsi_dh_handler_detach(struct scsi_device *sdev,
- struct scsi_device_handler *scsi_dh)
-{
- if (!sdev->scsi_dh_data)
- return;
-
- if (scsi_dh && scsi_dh != sdev->scsi_dh_data->scsi_dh)
- return;
-
- if (!scsi_dh)
- scsi_dh = sdev->scsi_dh_data->scsi_dh;
-
- if (scsi_dh)
- kref_put(&sdev->scsi_dh_data->kref, __detach_handler);
-}
-
-/*
* Functions for sysfs attribute 'dh_state'
*/
static ssize_t
@@ -198,7 +167,7 @@ store_dh_state(struct device *dev, struct device_attribute *attr,
/*
* Detach from a device handler
*/
- scsi_dh_handler_detach(sdev, scsi_dh);
+ scsi_dh_handler_detach(sdev);
err = 0;
} else if (!strncmp(buf, "activate", 8)) {
/*
@@ -290,7 +259,8 @@ static int scsi_dh_notifier(struct notifier_block *nb,
err = scsi_dh_handler_attach(sdev, devinfo);
} else if (action == BUS_NOTIFY_DEL_DEVICE) {
device_remove_file(dev, &scsi_dh_state_attr);
- scsi_dh_handler_detach(sdev, NULL);
+ if (sdev->scsi_dh_data)
+ scsi_dh_handler_detach(sdev);
}
return err;
}
@@ -335,7 +305,8 @@ static int scsi_dh_notifier_remove(struct device *dev, void *data)
sdev = to_scsi_device(dev);
- scsi_dh_handler_detach(sdev, scsi_dh);
+ if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh == scsi_dh)
+ scsi_dh_handler_detach(sdev);
put_device(dev);
@@ -517,45 +488,22 @@ int scsi_dh_attach(struct request_queue *q, const char *name)
err = -ENODEV;
spin_unlock_irqrestore(q->queue_lock, flags);
- if (!err) {
- err = scsi_dh_handler_attach(sdev, scsi_dh);
- put_device(&sdev->sdev_gendev);
- }
- return err;
-}
-EXPORT_SYMBOL_GPL(scsi_dh_attach);
-
-/*
- * scsi_dh_detach - Detach device handler
- * @q - Request queue that is associated with the scsi_device
- * the handler should be detached from
- *
- * This function will detach the device handler only
- * if the sdev is not part of the internal list, ie
- * if it has been attached manually.
- */
-void scsi_dh_detach(struct request_queue *q)
-{
- unsigned long flags;
- struct scsi_device *sdev;
- struct scsi_device_handler *scsi_dh = NULL;
-
- spin_lock_irqsave(q->queue_lock, flags);
- sdev = q->queuedata;
- if (!sdev || !get_device(&sdev->sdev_gendev))
- sdev = NULL;
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- if (!sdev)
- return;
+ if (err)
+ return err;
if (sdev->scsi_dh_data) {
- scsi_dh = sdev->scsi_dh_data->scsi_dh;
- scsi_dh_handler_detach(sdev, scsi_dh);
+ if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
+ err = -EBUSY;
+ goto out_put_device;
}
+
+ err = scsi_dh_handler_attach(sdev, scsi_dh);
+
+out_put_device:
put_device(&sdev->sdev_gendev);
+ return err;
}
-EXPORT_SYMBOL_GPL(scsi_dh_detach);
+EXPORT_SYMBOL_GPL(scsi_dh_attach);
/*
* scsi_dh_attached_handler_name - Get attached device handler's name
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index ae84b22..f4461cd 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -220,7 +220,6 @@ struct scsi_device_handler {
struct scsi_dh_data {
struct scsi_device_handler *scsi_dh;
struct scsi_device *sdev;
- struct kref kref;
};
#define to_scsi_device(d) \
diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h
index 620c723..99c9196 100644
--- a/include/scsi/scsi_dh.h
+++ b/include/scsi/scsi_dh.h
@@ -59,7 +59,6 @@ enum {
extern int scsi_dh_activate(struct request_queue *, activate_complete, void *);
extern int scsi_dh_handler_exist(const char *);
extern int scsi_dh_attach(struct request_queue *, const char *);
-extern void scsi_dh_detach(struct request_queue *);
extern const char *scsi_dh_attached_handler_name(struct request_queue *, gfp_t);
extern int scsi_dh_set_params(struct request_queue *, const char *);
#else
@@ -77,10 +76,6 @@ static inline int scsi_dh_attach(struct request_queue *req, const char *name)
{
return SCSI_DH_NOSYS;
}
-static inline void scsi_dh_detach(struct request_queue *q)
-{
- return;
-}
static inline const char *scsi_dh_attached_handler_name(struct request_queue *q,
gfp_t gfp)
{
--
1.8.5.6
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 02/10] dm-mpath, scsi_dh: request scsi_dh modules in scsi_dh, not dm-mpath
2015-08-27 12:16 [PATCH 00/10] Integrate scsi_dh better into the scsi core V4 Hannes Reinecke
2015-08-27 12:16 ` [PATCH 01/10] dm-mpath, scsi_dh: don't let dm detach device handlers Hannes Reinecke
@ 2015-08-27 12:16 ` Hannes Reinecke
2015-08-28 19:53 ` James Bottomley
2015-08-27 12:16 ` [PATCH 03/10] scsi_dh: move to drivers/scsi Hannes Reinecke
` (7 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Hannes Reinecke @ 2015-08-27 12:16 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, Martin K. Petersen, Mike Snitzer, linux-scsi
From: Christoph Hellwig <hch@lst.de>
This way we can reused the same code any attachment method, not just those
requested from dm-mpath.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Acked-by: Mike Snitzer <snitzer@redhat.com>
---
drivers/md/dm-mpath.c | 6 ------
drivers/scsi/device_handler/scsi_dh.c | 35 ++++++++++++++++++-----------------
include/scsi/scsi_dh.h | 5 -----
3 files changed, 18 insertions(+), 28 deletions(-)
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index a9f58fd..5a67671 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -725,12 +725,6 @@ static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m)
return 0;
m->hw_handler_name = kstrdup(dm_shift_arg(as), GFP_KERNEL);
- if (!try_then_request_module(scsi_dh_handler_exist(m->hw_handler_name),
- "scsi_dh_%s", m->hw_handler_name)) {
- ti->error = "unknown hardware handler type";
- ret = -EINVAL;
- goto fail;
- }
if (hw_argc > 1) {
char *p;
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
index 869b5bd..5bd0af6 100644
--- a/drivers/scsi/device_handler/scsi_dh.c
+++ b/drivers/scsi/device_handler/scsi_dh.c
@@ -29,7 +29,7 @@
static DEFINE_SPINLOCK(list_lock);
static LIST_HEAD(scsi_dh_list);
-static struct scsi_device_handler *get_device_handler(const char *name)
+static struct scsi_device_handler *__scsi_dh_lookup(const char *name)
{
struct scsi_device_handler *tmp, *found = NULL;
@@ -44,6 +44,19 @@ static struct scsi_device_handler *get_device_handler(const char *name)
return found;
}
+static struct scsi_device_handler *scsi_dh_lookup(const char *name)
+{
+ struct scsi_device_handler *dh;
+
+ dh = __scsi_dh_lookup(name);
+ if (!dh) {
+ request_module(name);
+ dh = __scsi_dh_lookup(name);
+ }
+
+ return dh;
+}
+
/*
* device_handler_match_function - Match a device handler to a device
* @sdev - SCSI device to be tested
@@ -158,7 +171,7 @@ store_dh_state(struct device *dev, struct device_attribute *attr,
/*
* Attach to a device handler
*/
- if (!(scsi_dh = get_device_handler(buf)))
+ if (!(scsi_dh = scsi_dh_lookup(buf)))
return err;
err = scsi_dh_handler_attach(sdev, scsi_dh);
} else {
@@ -322,8 +335,7 @@ static int scsi_dh_notifier_remove(struct device *dev, void *data)
*/
int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
{
-
- if (get_device_handler(scsi_dh->name))
+ if (__scsi_dh_lookup(scsi_dh->name))
return -EBUSY;
if (!scsi_dh->attach || !scsi_dh->detach)
@@ -350,7 +362,7 @@ EXPORT_SYMBOL_GPL(scsi_register_device_handler);
int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
{
- if (!get_device_handler(scsi_dh->name))
+ if (!__scsi_dh_lookup(scsi_dh->name))
return -ENODEV;
bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
@@ -455,17 +467,6 @@ int scsi_dh_set_params(struct request_queue *q, const char *params)
EXPORT_SYMBOL_GPL(scsi_dh_set_params);
/*
- * scsi_dh_handler_exist - Return TRUE(1) if a device handler exists for
- * the given name. FALSE(0) otherwise.
- * @name - name of the device handler.
- */
-int scsi_dh_handler_exist(const char *name)
-{
- return (get_device_handler(name) != NULL);
-}
-EXPORT_SYMBOL_GPL(scsi_dh_handler_exist);
-
-/*
* scsi_dh_attach - Attach device handler
* @q - Request queue that is associated with the scsi_device
* the handler should be attached to
@@ -478,7 +479,7 @@ int scsi_dh_attach(struct request_queue *q, const char *name)
struct scsi_device_handler *scsi_dh;
int err = 0;
- scsi_dh = get_device_handler(name);
+ scsi_dh = scsi_dh_lookup(name);
if (!scsi_dh)
return -EINVAL;
diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h
index 99c9196..966b921 100644
--- a/include/scsi/scsi_dh.h
+++ b/include/scsi/scsi_dh.h
@@ -57,7 +57,6 @@ enum {
};
#if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE)
extern int scsi_dh_activate(struct request_queue *, activate_complete, void *);
-extern int scsi_dh_handler_exist(const char *);
extern int scsi_dh_attach(struct request_queue *, const char *);
extern const char *scsi_dh_attached_handler_name(struct request_queue *, gfp_t);
extern int scsi_dh_set_params(struct request_queue *, const char *);
@@ -68,10 +67,6 @@ static inline int scsi_dh_activate(struct request_queue *req,
fn(data, 0);
return 0;
}
-static inline int scsi_dh_handler_exist(const char *name)
-{
- return 0;
-}
static inline int scsi_dh_attach(struct request_queue *req, const char *name)
{
return SCSI_DH_NOSYS;
--
1.8.5.6
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 03/10] scsi_dh: move to drivers/scsi
2015-08-27 12:16 [PATCH 00/10] Integrate scsi_dh better into the scsi core V4 Hannes Reinecke
2015-08-27 12:16 ` [PATCH 01/10] dm-mpath, scsi_dh: don't let dm detach device handlers Hannes Reinecke
2015-08-27 12:16 ` [PATCH 02/10] dm-mpath, scsi_dh: request scsi_dh modules in scsi_dh, not dm-mpath Hannes Reinecke
@ 2015-08-27 12:16 ` Hannes Reinecke
2015-08-27 12:16 ` [PATCH 04/10] scsi_dh: integrate into the core SCSI code Hannes Reinecke
` (6 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Hannes Reinecke @ 2015-08-27 12:16 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, Martin K. Petersen, Mike Snitzer, linux-scsi,
Hannes Reinecke
From: Christoph Hellwig <hch@lst.de>
Prepare for building scsi_dh.c into the core SCSI module by moving it to
drivers/scsi.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/Makefile | 1 +
drivers/scsi/device_handler/Makefile | 1 -
drivers/scsi/device_handler/scsi_dh.c | 570 ----------------------------------
drivers/scsi/scsi_dh.c | 570 ++++++++++++++++++++++++++++++++++
4 files changed, 571 insertions(+), 571 deletions(-)
delete mode 100644 drivers/scsi/device_handler/scsi_dh.c
create mode 100644 drivers/scsi/scsi_dh.c
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 91209e3..22f54b0 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -171,6 +171,7 @@ scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o
scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
scsi_mod-y += scsi_trace.o scsi_logging.o
scsi_mod-$(CONFIG_PM) += scsi_pm.o
+obj-$(CONFIG_SCSI_DH) += scsi_dh.o
hv_storvsc-y := storvsc_drv.o
diff --git a/drivers/scsi/device_handler/Makefile b/drivers/scsi/device_handler/Makefile
index e1d2ea0..09866c5 100644
--- a/drivers/scsi/device_handler/Makefile
+++ b/drivers/scsi/device_handler/Makefile
@@ -1,7 +1,6 @@
#
# SCSI Device Handler
#
-obj-$(CONFIG_SCSI_DH) += scsi_dh.o
obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o
obj-$(CONFIG_SCSI_DH_HP_SW) += scsi_dh_hp_sw.o
obj-$(CONFIG_SCSI_DH_EMC) += scsi_dh_emc.o
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
deleted file mode 100644
index 5bd0af6..0000000
--- a/drivers/scsi/device_handler/scsi_dh.c
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * SCSI device handler infrastruture.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright IBM Corporation, 2007
- * Authors:
- * Chandra Seetharaman <sekharan@us.ibm.com>
- * Mike Anderson <andmike@linux.vnet.ibm.com>
- */
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <scsi/scsi_dh.h>
-#include "../scsi_priv.h"
-
-static DEFINE_SPINLOCK(list_lock);
-static LIST_HEAD(scsi_dh_list);
-
-static struct scsi_device_handler *__scsi_dh_lookup(const char *name)
-{
- struct scsi_device_handler *tmp, *found = NULL;
-
- spin_lock(&list_lock);
- list_for_each_entry(tmp, &scsi_dh_list, list) {
- if (!strncmp(tmp->name, name, strlen(tmp->name))) {
- found = tmp;
- break;
- }
- }
- spin_unlock(&list_lock);
- return found;
-}
-
-static struct scsi_device_handler *scsi_dh_lookup(const char *name)
-{
- struct scsi_device_handler *dh;
-
- dh = __scsi_dh_lookup(name);
- if (!dh) {
- request_module(name);
- dh = __scsi_dh_lookup(name);
- }
-
- return dh;
-}
-
-/*
- * device_handler_match_function - Match a device handler to a device
- * @sdev - SCSI device to be tested
- *
- * Tests @sdev against the match function of all registered device_handler.
- * Returns the found device handler or NULL if not found.
- */
-static struct scsi_device_handler *
-device_handler_match_function(struct scsi_device *sdev)
-{
- struct scsi_device_handler *tmp_dh, *found_dh = NULL;
-
- spin_lock(&list_lock);
- list_for_each_entry(tmp_dh, &scsi_dh_list, list) {
- if (tmp_dh->match && tmp_dh->match(sdev)) {
- found_dh = tmp_dh;
- break;
- }
- }
- spin_unlock(&list_lock);
- return found_dh;
-}
-
-/*
- * device_handler_match - Attach a device handler to a device
- * @scsi_dh - The device handler to match against or NULL
- * @sdev - SCSI device to be tested against @scsi_dh
- *
- * Tests @sdev against the device handler @scsi_dh or against
- * all registered device_handler if @scsi_dh == NULL.
- * Returns the found device handler or NULL if not found.
- */
-static struct scsi_device_handler *
-device_handler_match(struct scsi_device_handler *scsi_dh,
- struct scsi_device *sdev)
-{
- struct scsi_device_handler *found_dh;
-
- found_dh = device_handler_match_function(sdev);
-
- if (scsi_dh && found_dh != scsi_dh)
- found_dh = NULL;
-
- return found_dh;
-}
-
-/*
- * scsi_dh_handler_attach - Attach a device handler to a device
- * @sdev - SCSI device the device handler should attach to
- * @scsi_dh - The device handler to attach
- */
-static int scsi_dh_handler_attach(struct scsi_device *sdev,
- struct scsi_device_handler *scsi_dh)
-{
- struct scsi_dh_data *d;
-
- if (!try_module_get(scsi_dh->module))
- return -EINVAL;
-
- d = scsi_dh->attach(sdev);
- if (IS_ERR(d)) {
- sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%ld)\n",
- scsi_dh->name, PTR_ERR(d));
- module_put(scsi_dh->module);
- return PTR_ERR(d);
- }
-
- d->scsi_dh = scsi_dh;
- d->sdev = sdev;
-
- spin_lock_irq(sdev->request_queue->queue_lock);
- sdev->scsi_dh_data = d;
- spin_unlock_irq(sdev->request_queue->queue_lock);
- return 0;
-}
-
-/*
- * scsi_dh_handler_detach - Detach a device handler from a device
- * @sdev - SCSI device the device handler should be detached from
- */
-static void scsi_dh_handler_detach(struct scsi_device *sdev)
-{
- struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
- struct scsi_device_handler *scsi_dh = scsi_dh_data->scsi_dh;
-
- scsi_dh->detach(sdev);
-
- spin_lock_irq(sdev->request_queue->queue_lock);
- sdev->scsi_dh_data = NULL;
- spin_unlock_irq(sdev->request_queue->queue_lock);
-
- sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", scsi_dh->name);
- module_put(scsi_dh->module);
-}
-
-/*
- * Functions for sysfs attribute 'dh_state'
- */
-static ssize_t
-store_dh_state(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct scsi_device_handler *scsi_dh;
- int err = -EINVAL;
-
- if (sdev->sdev_state == SDEV_CANCEL ||
- sdev->sdev_state == SDEV_DEL)
- return -ENODEV;
-
- if (!sdev->scsi_dh_data) {
- /*
- * Attach to a device handler
- */
- if (!(scsi_dh = scsi_dh_lookup(buf)))
- return err;
- err = scsi_dh_handler_attach(sdev, scsi_dh);
- } else {
- scsi_dh = sdev->scsi_dh_data->scsi_dh;
- if (!strncmp(buf, "detach", 6)) {
- /*
- * Detach from a device handler
- */
- scsi_dh_handler_detach(sdev);
- err = 0;
- } else if (!strncmp(buf, "activate", 8)) {
- /*
- * Activate a device handler
- */
- if (scsi_dh->activate)
- err = scsi_dh->activate(sdev, NULL, NULL);
- else
- err = 0;
- }
- }
-
- return err<0?err:count;
-}
-
-static ssize_t
-show_dh_state(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
-
- if (!sdev->scsi_dh_data)
- return snprintf(buf, 20, "detached\n");
-
- return snprintf(buf, 20, "%s\n", sdev->scsi_dh_data->scsi_dh->name);
-}
-
-static struct device_attribute scsi_dh_state_attr =
- __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state,
- store_dh_state);
-
-/*
- * scsi_dh_sysfs_attr_add - Callback for scsi_init_dh
- */
-static int scsi_dh_sysfs_attr_add(struct device *dev, void *data)
-{
- struct scsi_device *sdev;
- int err;
-
- if (!scsi_is_sdev_device(dev))
- return 0;
-
- sdev = to_scsi_device(dev);
-
- err = device_create_file(&sdev->sdev_gendev,
- &scsi_dh_state_attr);
-
- return 0;
-}
-
-/*
- * scsi_dh_sysfs_attr_remove - Callback for scsi_exit_dh
- */
-static int scsi_dh_sysfs_attr_remove(struct device *dev, void *data)
-{
- struct scsi_device *sdev;
-
- if (!scsi_is_sdev_device(dev))
- return 0;
-
- sdev = to_scsi_device(dev);
-
- device_remove_file(&sdev->sdev_gendev,
- &scsi_dh_state_attr);
-
- return 0;
-}
-
-/*
- * scsi_dh_notifier - notifier chain callback
- */
-static int scsi_dh_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct device *dev = data;
- struct scsi_device *sdev;
- int err = 0;
- struct scsi_device_handler *devinfo = NULL;
-
- if (!scsi_is_sdev_device(dev))
- return 0;
-
- sdev = to_scsi_device(dev);
-
- if (action == BUS_NOTIFY_ADD_DEVICE) {
- err = device_create_file(dev, &scsi_dh_state_attr);
- /* don't care about err */
- devinfo = device_handler_match(NULL, sdev);
- if (devinfo)
- err = scsi_dh_handler_attach(sdev, devinfo);
- } else if (action == BUS_NOTIFY_DEL_DEVICE) {
- device_remove_file(dev, &scsi_dh_state_attr);
- if (sdev->scsi_dh_data)
- scsi_dh_handler_detach(sdev);
- }
- return err;
-}
-
-/*
- * scsi_dh_notifier_add - Callback for scsi_register_device_handler
- */
-static int scsi_dh_notifier_add(struct device *dev, void *data)
-{
- struct scsi_device_handler *scsi_dh = data;
- struct scsi_device *sdev;
-
- if (!scsi_is_sdev_device(dev))
- return 0;
-
- if (!get_device(dev))
- return 0;
-
- sdev = to_scsi_device(dev);
-
- if (device_handler_match(scsi_dh, sdev))
- scsi_dh_handler_attach(sdev, scsi_dh);
-
- put_device(dev);
-
- return 0;
-}
-
-/*
- * scsi_dh_notifier_remove - Callback for scsi_unregister_device_handler
- */
-static int scsi_dh_notifier_remove(struct device *dev, void *data)
-{
- struct scsi_device_handler *scsi_dh = data;
- struct scsi_device *sdev;
-
- if (!scsi_is_sdev_device(dev))
- return 0;
-
- if (!get_device(dev))
- return 0;
-
- sdev = to_scsi_device(dev);
-
- if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh == scsi_dh)
- scsi_dh_handler_detach(sdev);
-
- put_device(dev);
-
- return 0;
-}
-
-/*
- * scsi_register_device_handler - register a device handler personality
- * module.
- * @scsi_dh - device handler to be registered.
- *
- * Returns 0 on success, -EBUSY if handler already registered.
- */
-int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
-{
- if (__scsi_dh_lookup(scsi_dh->name))
- return -EBUSY;
-
- if (!scsi_dh->attach || !scsi_dh->detach)
- return -EINVAL;
-
- spin_lock(&list_lock);
- list_add(&scsi_dh->list, &scsi_dh_list);
- spin_unlock(&list_lock);
-
- bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
- printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name);
-
- return SCSI_DH_OK;
-}
-EXPORT_SYMBOL_GPL(scsi_register_device_handler);
-
-/*
- * scsi_unregister_device_handler - register a device handler personality
- * module.
- * @scsi_dh - device handler to be unregistered.
- *
- * Returns 0 on success, -ENODEV if handler not registered.
- */
-int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
-{
-
- if (!__scsi_dh_lookup(scsi_dh->name))
- return -ENODEV;
-
- bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
- scsi_dh_notifier_remove);
-
- spin_lock(&list_lock);
- list_del(&scsi_dh->list);
- spin_unlock(&list_lock);
- printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name);
-
- return SCSI_DH_OK;
-}
-EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
-
-/*
- * scsi_dh_activate - activate the path associated with the scsi_device
- * corresponding to the given request queue.
- * Returns immediately without waiting for activation to be completed.
- * @q - Request queue that is associated with the scsi_device to be
- * activated.
- * @fn - Function to be called upon completion of the activation.
- * Function fn is called with data (below) and the error code.
- * Function fn may be called from the same calling context. So,
- * do not hold the lock in the caller which may be needed in fn.
- * @data - data passed to the function fn upon completion.
- *
- */
-int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
-{
- int err = 0;
- unsigned long flags;
- struct scsi_device *sdev;
- struct scsi_device_handler *scsi_dh = NULL;
- struct device *dev = NULL;
-
- spin_lock_irqsave(q->queue_lock, flags);
- sdev = q->queuedata;
- if (!sdev) {
- spin_unlock_irqrestore(q->queue_lock, flags);
- err = SCSI_DH_NOSYS;
- if (fn)
- fn(data, err);
- return err;
- }
-
- if (sdev->scsi_dh_data)
- scsi_dh = sdev->scsi_dh_data->scsi_dh;
- dev = get_device(&sdev->sdev_gendev);
- if (!scsi_dh || !dev ||
- sdev->sdev_state == SDEV_CANCEL ||
- sdev->sdev_state == SDEV_DEL)
- err = SCSI_DH_NOSYS;
- if (sdev->sdev_state == SDEV_OFFLINE)
- err = SCSI_DH_DEV_OFFLINED;
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- if (err) {
- if (fn)
- fn(data, err);
- goto out;
- }
-
- if (scsi_dh->activate)
- err = scsi_dh->activate(sdev, fn, data);
-out:
- put_device(dev);
- return err;
-}
-EXPORT_SYMBOL_GPL(scsi_dh_activate);
-
-/*
- * scsi_dh_set_params - set the parameters for the device as per the
- * string specified in params.
- * @q - Request queue that is associated with the scsi_device for
- * which the parameters to be set.
- * @params - parameters in the following format
- * "no_of_params\0param1\0param2\0param3\0...\0"
- * for example, string for 2 parameters with value 10 and 21
- * is specified as "2\010\021\0".
- */
-int scsi_dh_set_params(struct request_queue *q, const char *params)
-{
- int err = -SCSI_DH_NOSYS;
- unsigned long flags;
- struct scsi_device *sdev;
- struct scsi_device_handler *scsi_dh = NULL;
-
- spin_lock_irqsave(q->queue_lock, flags);
- sdev = q->queuedata;
- if (sdev && sdev->scsi_dh_data)
- scsi_dh = sdev->scsi_dh_data->scsi_dh;
- if (scsi_dh && scsi_dh->set_params && get_device(&sdev->sdev_gendev))
- err = 0;
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- if (err)
- return err;
- err = scsi_dh->set_params(sdev, params);
- put_device(&sdev->sdev_gendev);
- return err;
-}
-EXPORT_SYMBOL_GPL(scsi_dh_set_params);
-
-/*
- * scsi_dh_attach - Attach device handler
- * @q - Request queue that is associated with the scsi_device
- * the handler should be attached to
- * @name - name of the handler to attach
- */
-int scsi_dh_attach(struct request_queue *q, const char *name)
-{
- unsigned long flags;
- struct scsi_device *sdev;
- struct scsi_device_handler *scsi_dh;
- int err = 0;
-
- scsi_dh = scsi_dh_lookup(name);
- if (!scsi_dh)
- return -EINVAL;
-
- spin_lock_irqsave(q->queue_lock, flags);
- sdev = q->queuedata;
- if (!sdev || !get_device(&sdev->sdev_gendev))
- err = -ENODEV;
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- if (err)
- return err;
-
- if (sdev->scsi_dh_data) {
- if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
- err = -EBUSY;
- goto out_put_device;
- }
-
- err = scsi_dh_handler_attach(sdev, scsi_dh);
-
-out_put_device:
- put_device(&sdev->sdev_gendev);
- return err;
-}
-EXPORT_SYMBOL_GPL(scsi_dh_attach);
-
-/*
- * scsi_dh_attached_handler_name - Get attached device handler's name
- * @q - Request queue that is associated with the scsi_device
- * that may have a device handler attached
- * @gfp - the GFP mask used in the kmalloc() call when allocating memory
- *
- * Returns name of attached handler, NULL if no handler is attached.
- * Caller must take care to free the returned string.
- */
-const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
-{
- unsigned long flags;
- struct scsi_device *sdev;
- const char *handler_name = NULL;
-
- spin_lock_irqsave(q->queue_lock, flags);
- sdev = q->queuedata;
- if (!sdev || !get_device(&sdev->sdev_gendev))
- sdev = NULL;
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- if (!sdev)
- return NULL;
-
- if (sdev->scsi_dh_data)
- handler_name = kstrdup(sdev->scsi_dh_data->scsi_dh->name, gfp);
-
- put_device(&sdev->sdev_gendev);
- return handler_name;
-}
-EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name);
-
-static struct notifier_block scsi_dh_nb = {
- .notifier_call = scsi_dh_notifier
-};
-
-static int __init scsi_dh_init(void)
-{
- int r;
-
- r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb);
-
- if (!r)
- bus_for_each_dev(&scsi_bus_type, NULL, NULL,
- scsi_dh_sysfs_attr_add);
-
- return r;
-}
-
-static void __exit scsi_dh_exit(void)
-{
- bus_for_each_dev(&scsi_bus_type, NULL, NULL,
- scsi_dh_sysfs_attr_remove);
- bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb);
-}
-
-module_init(scsi_dh_init);
-module_exit(scsi_dh_exit);
-
-MODULE_DESCRIPTION("SCSI device handler");
-MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c
new file mode 100644
index 0000000..3c06c72
--- /dev/null
+++ b/drivers/scsi/scsi_dh.c
@@ -0,0 +1,570 @@
+/*
+ * SCSI device handler infrastruture.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright IBM Corporation, 2007
+ * Authors:
+ * Chandra Seetharaman <sekharan@us.ibm.com>
+ * Mike Anderson <andmike@linux.vnet.ibm.com>
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <scsi/scsi_dh.h>
+#include "scsi_priv.h"
+
+static DEFINE_SPINLOCK(list_lock);
+static LIST_HEAD(scsi_dh_list);
+
+static struct scsi_device_handler *__scsi_dh_lookup(const char *name)
+{
+ struct scsi_device_handler *tmp, *found = NULL;
+
+ spin_lock(&list_lock);
+ list_for_each_entry(tmp, &scsi_dh_list, list) {
+ if (!strncmp(tmp->name, name, strlen(tmp->name))) {
+ found = tmp;
+ break;
+ }
+ }
+ spin_unlock(&list_lock);
+ return found;
+}
+
+static struct scsi_device_handler *scsi_dh_lookup(const char *name)
+{
+ struct scsi_device_handler *dh;
+
+ dh = __scsi_dh_lookup(name);
+ if (!dh) {
+ request_module(name);
+ dh = __scsi_dh_lookup(name);
+ }
+
+ return dh;
+}
+
+/*
+ * device_handler_match_function - Match a device handler to a device
+ * @sdev - SCSI device to be tested
+ *
+ * Tests @sdev against the match function of all registered device_handler.
+ * Returns the found device handler or NULL if not found.
+ */
+static struct scsi_device_handler *
+device_handler_match_function(struct scsi_device *sdev)
+{
+ struct scsi_device_handler *tmp_dh, *found_dh = NULL;
+
+ spin_lock(&list_lock);
+ list_for_each_entry(tmp_dh, &scsi_dh_list, list) {
+ if (tmp_dh->match && tmp_dh->match(sdev)) {
+ found_dh = tmp_dh;
+ break;
+ }
+ }
+ spin_unlock(&list_lock);
+ return found_dh;
+}
+
+/*
+ * device_handler_match - Attach a device handler to a device
+ * @scsi_dh - The device handler to match against or NULL
+ * @sdev - SCSI device to be tested against @scsi_dh
+ *
+ * Tests @sdev against the device handler @scsi_dh or against
+ * all registered device_handler if @scsi_dh == NULL.
+ * Returns the found device handler or NULL if not found.
+ */
+static struct scsi_device_handler *
+device_handler_match(struct scsi_device_handler *scsi_dh,
+ struct scsi_device *sdev)
+{
+ struct scsi_device_handler *found_dh;
+
+ found_dh = device_handler_match_function(sdev);
+
+ if (scsi_dh && found_dh != scsi_dh)
+ found_dh = NULL;
+
+ return found_dh;
+}
+
+/*
+ * scsi_dh_handler_attach - Attach a device handler to a device
+ * @sdev - SCSI device the device handler should attach to
+ * @scsi_dh - The device handler to attach
+ */
+static int scsi_dh_handler_attach(struct scsi_device *sdev,
+ struct scsi_device_handler *scsi_dh)
+{
+ struct scsi_dh_data *d;
+
+ if (!try_module_get(scsi_dh->module))
+ return -EINVAL;
+
+ d = scsi_dh->attach(sdev);
+ if (IS_ERR(d)) {
+ sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%ld)\n",
+ scsi_dh->name, PTR_ERR(d));
+ module_put(scsi_dh->module);
+ return PTR_ERR(d);
+ }
+
+ d->scsi_dh = scsi_dh;
+ d->sdev = sdev;
+
+ spin_lock_irq(sdev->request_queue->queue_lock);
+ sdev->scsi_dh_data = d;
+ spin_unlock_irq(sdev->request_queue->queue_lock);
+ return 0;
+}
+
+/*
+ * scsi_dh_handler_detach - Detach a device handler from a device
+ * @sdev - SCSI device the device handler should be detached from
+ */
+static void scsi_dh_handler_detach(struct scsi_device *sdev)
+{
+ struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
+ struct scsi_device_handler *scsi_dh = scsi_dh_data->scsi_dh;
+
+ scsi_dh->detach(sdev);
+
+ spin_lock_irq(sdev->request_queue->queue_lock);
+ sdev->scsi_dh_data = NULL;
+ spin_unlock_irq(sdev->request_queue->queue_lock);
+
+ sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", scsi_dh->name);
+ module_put(scsi_dh->module);
+}
+
+/*
+ * Functions for sysfs attribute 'dh_state'
+ */
+static ssize_t
+store_dh_state(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct scsi_device_handler *scsi_dh;
+ int err = -EINVAL;
+
+ if (sdev->sdev_state == SDEV_CANCEL ||
+ sdev->sdev_state == SDEV_DEL)
+ return -ENODEV;
+
+ if (!sdev->scsi_dh_data) {
+ /*
+ * Attach to a device handler
+ */
+ if (!(scsi_dh = scsi_dh_lookup(buf)))
+ return err;
+ err = scsi_dh_handler_attach(sdev, scsi_dh);
+ } else {
+ scsi_dh = sdev->scsi_dh_data->scsi_dh;
+ if (!strncmp(buf, "detach", 6)) {
+ /*
+ * Detach from a device handler
+ */
+ scsi_dh_handler_detach(sdev);
+ err = 0;
+ } else if (!strncmp(buf, "activate", 8)) {
+ /*
+ * Activate a device handler
+ */
+ if (scsi_dh->activate)
+ err = scsi_dh->activate(sdev, NULL, NULL);
+ else
+ err = 0;
+ }
+ }
+
+ return err<0?err:count;
+}
+
+static ssize_t
+show_dh_state(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ if (!sdev->scsi_dh_data)
+ return snprintf(buf, 20, "detached\n");
+
+ return snprintf(buf, 20, "%s\n", sdev->scsi_dh_data->scsi_dh->name);
+}
+
+static struct device_attribute scsi_dh_state_attr =
+ __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state,
+ store_dh_state);
+
+/*
+ * scsi_dh_sysfs_attr_add - Callback for scsi_init_dh
+ */
+static int scsi_dh_sysfs_attr_add(struct device *dev, void *data)
+{
+ struct scsi_device *sdev;
+ int err;
+
+ if (!scsi_is_sdev_device(dev))
+ return 0;
+
+ sdev = to_scsi_device(dev);
+
+ err = device_create_file(&sdev->sdev_gendev,
+ &scsi_dh_state_attr);
+
+ return 0;
+}
+
+/*
+ * scsi_dh_sysfs_attr_remove - Callback for scsi_exit_dh
+ */
+static int scsi_dh_sysfs_attr_remove(struct device *dev, void *data)
+{
+ struct scsi_device *sdev;
+
+ if (!scsi_is_sdev_device(dev))
+ return 0;
+
+ sdev = to_scsi_device(dev);
+
+ device_remove_file(&sdev->sdev_gendev,
+ &scsi_dh_state_attr);
+
+ return 0;
+}
+
+/*
+ * scsi_dh_notifier - notifier chain callback
+ */
+static int scsi_dh_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct device *dev = data;
+ struct scsi_device *sdev;
+ int err = 0;
+ struct scsi_device_handler *devinfo = NULL;
+
+ if (!scsi_is_sdev_device(dev))
+ return 0;
+
+ sdev = to_scsi_device(dev);
+
+ if (action == BUS_NOTIFY_ADD_DEVICE) {
+ err = device_create_file(dev, &scsi_dh_state_attr);
+ /* don't care about err */
+ devinfo = device_handler_match(NULL, sdev);
+ if (devinfo)
+ err = scsi_dh_handler_attach(sdev, devinfo);
+ } else if (action == BUS_NOTIFY_DEL_DEVICE) {
+ device_remove_file(dev, &scsi_dh_state_attr);
+ if (sdev->scsi_dh_data)
+ scsi_dh_handler_detach(sdev);
+ }
+ return err;
+}
+
+/*
+ * scsi_dh_notifier_add - Callback for scsi_register_device_handler
+ */
+static int scsi_dh_notifier_add(struct device *dev, void *data)
+{
+ struct scsi_device_handler *scsi_dh = data;
+ struct scsi_device *sdev;
+
+ if (!scsi_is_sdev_device(dev))
+ return 0;
+
+ if (!get_device(dev))
+ return 0;
+
+ sdev = to_scsi_device(dev);
+
+ if (device_handler_match(scsi_dh, sdev))
+ scsi_dh_handler_attach(sdev, scsi_dh);
+
+ put_device(dev);
+
+ return 0;
+}
+
+/*
+ * scsi_dh_notifier_remove - Callback for scsi_unregister_device_handler
+ */
+static int scsi_dh_notifier_remove(struct device *dev, void *data)
+{
+ struct scsi_device_handler *scsi_dh = data;
+ struct scsi_device *sdev;
+
+ if (!scsi_is_sdev_device(dev))
+ return 0;
+
+ if (!get_device(dev))
+ return 0;
+
+ sdev = to_scsi_device(dev);
+
+ if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh == scsi_dh)
+ scsi_dh_handler_detach(sdev);
+
+ put_device(dev);
+
+ return 0;
+}
+
+/*
+ * scsi_register_device_handler - register a device handler personality
+ * module.
+ * @scsi_dh - device handler to be registered.
+ *
+ * Returns 0 on success, -EBUSY if handler already registered.
+ */
+int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
+{
+ if (__scsi_dh_lookup(scsi_dh->name))
+ return -EBUSY;
+
+ if (!scsi_dh->attach || !scsi_dh->detach)
+ return -EINVAL;
+
+ spin_lock(&list_lock);
+ list_add(&scsi_dh->list, &scsi_dh_list);
+ spin_unlock(&list_lock);
+
+ bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
+ printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name);
+
+ return SCSI_DH_OK;
+}
+EXPORT_SYMBOL_GPL(scsi_register_device_handler);
+
+/*
+ * scsi_unregister_device_handler - register a device handler personality
+ * module.
+ * @scsi_dh - device handler to be unregistered.
+ *
+ * Returns 0 on success, -ENODEV if handler not registered.
+ */
+int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
+{
+
+ if (!__scsi_dh_lookup(scsi_dh->name))
+ return -ENODEV;
+
+ bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
+ scsi_dh_notifier_remove);
+
+ spin_lock(&list_lock);
+ list_del(&scsi_dh->list);
+ spin_unlock(&list_lock);
+ printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name);
+
+ return SCSI_DH_OK;
+}
+EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
+
+/*
+ * scsi_dh_activate - activate the path associated with the scsi_device
+ * corresponding to the given request queue.
+ * Returns immediately without waiting for activation to be completed.
+ * @q - Request queue that is associated with the scsi_device to be
+ * activated.
+ * @fn - Function to be called upon completion of the activation.
+ * Function fn is called with data (below) and the error code.
+ * Function fn may be called from the same calling context. So,
+ * do not hold the lock in the caller which may be needed in fn.
+ * @data - data passed to the function fn upon completion.
+ *
+ */
+int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
+{
+ int err = 0;
+ unsigned long flags;
+ struct scsi_device *sdev;
+ struct scsi_device_handler *scsi_dh = NULL;
+ struct device *dev = NULL;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ sdev = q->queuedata;
+ if (!sdev) {
+ spin_unlock_irqrestore(q->queue_lock, flags);
+ err = SCSI_DH_NOSYS;
+ if (fn)
+ fn(data, err);
+ return err;
+ }
+
+ if (sdev->scsi_dh_data)
+ scsi_dh = sdev->scsi_dh_data->scsi_dh;
+ dev = get_device(&sdev->sdev_gendev);
+ if (!scsi_dh || !dev ||
+ sdev->sdev_state == SDEV_CANCEL ||
+ sdev->sdev_state == SDEV_DEL)
+ err = SCSI_DH_NOSYS;
+ if (sdev->sdev_state == SDEV_OFFLINE)
+ err = SCSI_DH_DEV_OFFLINED;
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ if (err) {
+ if (fn)
+ fn(data, err);
+ goto out;
+ }
+
+ if (scsi_dh->activate)
+ err = scsi_dh->activate(sdev, fn, data);
+out:
+ put_device(dev);
+ return err;
+}
+EXPORT_SYMBOL_GPL(scsi_dh_activate);
+
+/*
+ * scsi_dh_set_params - set the parameters for the device as per the
+ * string specified in params.
+ * @q - Request queue that is associated with the scsi_device for
+ * which the parameters to be set.
+ * @params - parameters in the following format
+ * "no_of_params\0param1\0param2\0param3\0...\0"
+ * for example, string for 2 parameters with value 10 and 21
+ * is specified as "2\010\021\0".
+ */
+int scsi_dh_set_params(struct request_queue *q, const char *params)
+{
+ int err = -SCSI_DH_NOSYS;
+ unsigned long flags;
+ struct scsi_device *sdev;
+ struct scsi_device_handler *scsi_dh = NULL;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ sdev = q->queuedata;
+ if (sdev && sdev->scsi_dh_data)
+ scsi_dh = sdev->scsi_dh_data->scsi_dh;
+ if (scsi_dh && scsi_dh->set_params && get_device(&sdev->sdev_gendev))
+ err = 0;
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ if (err)
+ return err;
+ err = scsi_dh->set_params(sdev, params);
+ put_device(&sdev->sdev_gendev);
+ return err;
+}
+EXPORT_SYMBOL_GPL(scsi_dh_set_params);
+
+/*
+ * scsi_dh_attach - Attach device handler
+ * @q - Request queue that is associated with the scsi_device
+ * the handler should be attached to
+ * @name - name of the handler to attach
+ */
+int scsi_dh_attach(struct request_queue *q, const char *name)
+{
+ unsigned long flags;
+ struct scsi_device *sdev;
+ struct scsi_device_handler *scsi_dh;
+ int err = 0;
+
+ scsi_dh = scsi_dh_lookup(name);
+ if (!scsi_dh)
+ return -EINVAL;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ sdev = q->queuedata;
+ if (!sdev || !get_device(&sdev->sdev_gendev))
+ err = -ENODEV;
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ if (err)
+ return err;
+
+ if (sdev->scsi_dh_data) {
+ if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
+ err = -EBUSY;
+ goto out_put_device;
+ }
+
+ err = scsi_dh_handler_attach(sdev, scsi_dh);
+
+out_put_device:
+ put_device(&sdev->sdev_gendev);
+ return err;
+}
+EXPORT_SYMBOL_GPL(scsi_dh_attach);
+
+/*
+ * scsi_dh_attached_handler_name - Get attached device handler's name
+ * @q - Request queue that is associated with the scsi_device
+ * that may have a device handler attached
+ * @gfp - the GFP mask used in the kmalloc() call when allocating memory
+ *
+ * Returns name of attached handler, NULL if no handler is attached.
+ * Caller must take care to free the returned string.
+ */
+const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
+{
+ unsigned long flags;
+ struct scsi_device *sdev;
+ const char *handler_name = NULL;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ sdev = q->queuedata;
+ if (!sdev || !get_device(&sdev->sdev_gendev))
+ sdev = NULL;
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ if (!sdev)
+ return NULL;
+
+ if (sdev->scsi_dh_data)
+ handler_name = kstrdup(sdev->scsi_dh_data->scsi_dh->name, gfp);
+
+ put_device(&sdev->sdev_gendev);
+ return handler_name;
+}
+EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name);
+
+static struct notifier_block scsi_dh_nb = {
+ .notifier_call = scsi_dh_notifier
+};
+
+static int __init scsi_dh_init(void)
+{
+ int r;
+
+ r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb);
+
+ if (!r)
+ bus_for_each_dev(&scsi_bus_type, NULL, NULL,
+ scsi_dh_sysfs_attr_add);
+
+ return r;
+}
+
+static void __exit scsi_dh_exit(void)
+{
+ bus_for_each_dev(&scsi_bus_type, NULL, NULL,
+ scsi_dh_sysfs_attr_remove);
+ bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb);
+}
+
+module_init(scsi_dh_init);
+module_exit(scsi_dh_exit);
+
+MODULE_DESCRIPTION("SCSI device handler");
+MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>");
+MODULE_LICENSE("GPL");
--
1.8.5.6
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 04/10] scsi_dh: integrate into the core SCSI code
2015-08-27 12:16 [PATCH 00/10] Integrate scsi_dh better into the scsi core V4 Hannes Reinecke
` (2 preceding siblings ...)
2015-08-27 12:16 ` [PATCH 03/10] scsi_dh: move to drivers/scsi Hannes Reinecke
@ 2015-08-27 12:16 ` Hannes Reinecke
2015-08-27 12:16 ` [PATCH 05/10] scsi_dh: move device matching to the core code Hannes Reinecke
` (5 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Hannes Reinecke @ 2015-08-27 12:16 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, Martin K. Petersen, Mike Snitzer, linux-scsi
From: Christoph Hellwig <hch@lst.de>
Stop building scsi_dh as a separate module and integrate it fully into the
core SCSI code with explicit callouts at bus scan time. For now the
callouts are placed at the same point as the old bus notifiers were called,
but in the future we will be able to look at ALUA INQUIRY data earlier on.
Note that this also means that the device handler modules need to be loaded
by the time we scan the bus. The next patches will add support for
autoloading device handlers at bus scan time to make sure they are always
loaded if they are enabled in the kernel config.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Acked-by: Mike Snitzer <snitzer@redhat.com>
---
drivers/scsi/Makefile | 2 +-
drivers/scsi/device_handler/Kconfig | 2 +-
drivers/scsi/scsi_dh.c | 183 +++---------------------------------
drivers/scsi/scsi_priv.h | 9 ++
drivers/scsi/scsi_sysfs.c | 10 ++
include/scsi/scsi_dh.h | 2 +-
6 files changed, 34 insertions(+), 174 deletions(-)
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 22f54b0..ef260bb 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -171,7 +171,7 @@ scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o
scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
scsi_mod-y += scsi_trace.o scsi_logging.o
scsi_mod-$(CONFIG_PM) += scsi_pm.o
-obj-$(CONFIG_SCSI_DH) += scsi_dh.o
+scsi_mod-$(CONFIG_SCSI_DH) += scsi_dh.o
hv_storvsc-y := storvsc_drv.o
diff --git a/drivers/scsi/device_handler/Kconfig b/drivers/scsi/device_handler/Kconfig
index 69abd0a..e5647d5 100644
--- a/drivers/scsi/device_handler/Kconfig
+++ b/drivers/scsi/device_handler/Kconfig
@@ -3,7 +3,7 @@
#
menuconfig SCSI_DH
- tristate "SCSI Device Handlers"
+ bool "SCSI Device Handlers"
depends on SCSI
default n
help
diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c
index 3c06c72..2d6a8bd 100644
--- a/drivers/scsi/scsi_dh.c
+++ b/drivers/scsi/scsi_dh.c
@@ -57,15 +57,8 @@ static struct scsi_device_handler *scsi_dh_lookup(const char *name)
return dh;
}
-/*
- * device_handler_match_function - Match a device handler to a device
- * @sdev - SCSI device to be tested
- *
- * Tests @sdev against the match function of all registered device_handler.
- * Returns the found device handler or NULL if not found.
- */
static struct scsi_device_handler *
-device_handler_match_function(struct scsi_device *sdev)
+device_handler_match(struct scsi_device *sdev)
{
struct scsi_device_handler *tmp_dh, *found_dh = NULL;
@@ -81,29 +74,6 @@ device_handler_match_function(struct scsi_device *sdev)
}
/*
- * device_handler_match - Attach a device handler to a device
- * @scsi_dh - The device handler to match against or NULL
- * @sdev - SCSI device to be tested against @scsi_dh
- *
- * Tests @sdev against the device handler @scsi_dh or against
- * all registered device_handler if @scsi_dh == NULL.
- * Returns the found device handler or NULL if not found.
- */
-static struct scsi_device_handler *
-device_handler_match(struct scsi_device_handler *scsi_dh,
- struct scsi_device *sdev)
-{
- struct scsi_device_handler *found_dh;
-
- found_dh = device_handler_match_function(sdev);
-
- if (scsi_dh && found_dh != scsi_dh)
- found_dh = NULL;
-
- return found_dh;
-}
-
-/*
* scsi_dh_handler_attach - Attach a device handler to a device
* @sdev - SCSI device the device handler should attach to
* @scsi_dh - The device handler to attach
@@ -211,119 +181,26 @@ static struct device_attribute scsi_dh_state_attr =
__ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state,
store_dh_state);
-/*
- * scsi_dh_sysfs_attr_add - Callback for scsi_init_dh
- */
-static int scsi_dh_sysfs_attr_add(struct device *dev, void *data)
+int scsi_dh_add_device(struct scsi_device *sdev)
{
- struct scsi_device *sdev;
+ struct scsi_device_handler *devinfo;
int err;
- if (!scsi_is_sdev_device(dev))
- return 0;
-
- sdev = to_scsi_device(dev);
-
- err = device_create_file(&sdev->sdev_gendev,
- &scsi_dh_state_attr);
-
- return 0;
-}
-
-/*
- * scsi_dh_sysfs_attr_remove - Callback for scsi_exit_dh
- */
-static int scsi_dh_sysfs_attr_remove(struct device *dev, void *data)
-{
- struct scsi_device *sdev;
-
- if (!scsi_is_sdev_device(dev))
- return 0;
-
- sdev = to_scsi_device(dev);
-
- device_remove_file(&sdev->sdev_gendev,
- &scsi_dh_state_attr);
-
- return 0;
-}
+ err = device_create_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
+ if (err)
+ return err;
-/*
- * scsi_dh_notifier - notifier chain callback
- */
-static int scsi_dh_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct device *dev = data;
- struct scsi_device *sdev;
- int err = 0;
- struct scsi_device_handler *devinfo = NULL;
-
- if (!scsi_is_sdev_device(dev))
- return 0;
-
- sdev = to_scsi_device(dev);
-
- if (action == BUS_NOTIFY_ADD_DEVICE) {
- err = device_create_file(dev, &scsi_dh_state_attr);
- /* don't care about err */
- devinfo = device_handler_match(NULL, sdev);
- if (devinfo)
- err = scsi_dh_handler_attach(sdev, devinfo);
- } else if (action == BUS_NOTIFY_DEL_DEVICE) {
- device_remove_file(dev, &scsi_dh_state_attr);
- if (sdev->scsi_dh_data)
- scsi_dh_handler_detach(sdev);
- }
+ devinfo = device_handler_match(sdev);
+ if (devinfo)
+ err = scsi_dh_handler_attach(sdev, devinfo);
return err;
}
-/*
- * scsi_dh_notifier_add - Callback for scsi_register_device_handler
- */
-static int scsi_dh_notifier_add(struct device *dev, void *data)
+void scsi_dh_remove_device(struct scsi_device *sdev)
{
- struct scsi_device_handler *scsi_dh = data;
- struct scsi_device *sdev;
-
- if (!scsi_is_sdev_device(dev))
- return 0;
-
- if (!get_device(dev))
- return 0;
-
- sdev = to_scsi_device(dev);
-
- if (device_handler_match(scsi_dh, sdev))
- scsi_dh_handler_attach(sdev, scsi_dh);
-
- put_device(dev);
-
- return 0;
-}
-
-/*
- * scsi_dh_notifier_remove - Callback for scsi_unregister_device_handler
- */
-static int scsi_dh_notifier_remove(struct device *dev, void *data)
-{
- struct scsi_device_handler *scsi_dh = data;
- struct scsi_device *sdev;
-
- if (!scsi_is_sdev_device(dev))
- return 0;
-
- if (!get_device(dev))
- return 0;
-
- sdev = to_scsi_device(dev);
-
- if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh == scsi_dh)
+ if (sdev->scsi_dh_data)
scsi_dh_handler_detach(sdev);
-
- put_device(dev);
-
- return 0;
+ device_remove_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
}
/*
@@ -345,7 +222,6 @@ int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
list_add(&scsi_dh->list, &scsi_dh_list);
spin_unlock(&list_lock);
- bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name);
return SCSI_DH_OK;
@@ -361,13 +237,9 @@ EXPORT_SYMBOL_GPL(scsi_register_device_handler);
*/
int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
{
-
if (!__scsi_dh_lookup(scsi_dh->name))
return -ENODEV;
- bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
- scsi_dh_notifier_remove);
-
spin_lock(&list_lock);
list_del(&scsi_dh->list);
spin_unlock(&list_lock);
@@ -537,34 +409,3 @@ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
return handler_name;
}
EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name);
-
-static struct notifier_block scsi_dh_nb = {
- .notifier_call = scsi_dh_notifier
-};
-
-static int __init scsi_dh_init(void)
-{
- int r;
-
- r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb);
-
- if (!r)
- bus_for_each_dev(&scsi_bus_type, NULL, NULL,
- scsi_dh_sysfs_attr_add);
-
- return r;
-}
-
-static void __exit scsi_dh_exit(void)
-{
- bus_for_each_dev(&scsi_bus_type, NULL, NULL,
- scsi_dh_sysfs_attr_remove);
- bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb);
-}
-
-module_init(scsi_dh_init);
-module_exit(scsi_dh_exit);
-
-MODULE_DESCRIPTION("SCSI device handler");
-MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index e3902fc..644bb73 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -170,6 +170,15 @@ static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
extern struct async_domain scsi_sd_pm_domain;
extern struct async_domain scsi_sd_probe_domain;
+/* scsi_dh.c */
+#ifdef CONFIG_SCSI_DH
+int scsi_dh_add_device(struct scsi_device *sdev);
+void scsi_dh_remove_device(struct scsi_device *sdev);
+#else
+static inline int scsi_dh_add_device(struct scsi_device *sdev) { return 0; }
+static inline void scsi_dh_remove_device(struct scsi_device *sdev) { }
+#endif
+
/*
* internal scsi timeout functions: for use by mid-layer and transport
* classes.
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 9ad4116..b333389 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1030,11 +1030,20 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
"failed to add device: %d\n", error);
return error;
}
+
+ error = scsi_dh_add_device(sdev);
+ if (error) {
+ sdev_printk(KERN_INFO, sdev,
+ "failed to add device handler: %d\n", error);
+ return error;
+ }
+
device_enable_async_suspend(&sdev->sdev_dev);
error = device_add(&sdev->sdev_dev);
if (error) {
sdev_printk(KERN_INFO, sdev,
"failed to add class device: %d\n", error);
+ scsi_dh_remove_device(sdev);
device_del(&sdev->sdev_gendev);
return error;
}
@@ -1074,6 +1083,7 @@ void __scsi_remove_device(struct scsi_device *sdev)
bsg_unregister_queue(sdev->request_queue);
device_unregister(&sdev->sdev_dev);
transport_remove_device(dev);
+ scsi_dh_remove_device(sdev);
device_del(dev);
} else
put_device(&sdev->sdev_dev);
diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h
index 966b921..3a37b4c45 100644
--- a/include/scsi/scsi_dh.h
+++ b/include/scsi/scsi_dh.h
@@ -55,7 +55,7 @@ enum {
SCSI_DH_NOSYS,
SCSI_DH_DRIVER_MAX,
};
-#if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE)
+#ifdef CONFIG_SCSI_DH
extern int scsi_dh_activate(struct request_queue *, activate_complete, void *);
extern int scsi_dh_attach(struct request_queue *, const char *);
extern const char *scsi_dh_attached_handler_name(struct request_queue *, gfp_t);
--
1.8.5.6
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 05/10] scsi_dh: move device matching to the core code
2015-08-27 12:16 [PATCH 00/10] Integrate scsi_dh better into the scsi core V4 Hannes Reinecke
` (3 preceding siblings ...)
2015-08-27 12:16 ` [PATCH 04/10] scsi_dh: integrate into the core SCSI code Hannes Reinecke
@ 2015-08-27 12:16 ` Hannes Reinecke
2015-08-27 12:16 ` [PATCH 06/10] scsi_dh: kill struct scsi_dh_data Hannes Reinecke
` (4 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Hannes Reinecke @ 2015-08-27 12:16 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, Martin K. Petersen, Mike Snitzer, linux-scsi
From: Christoph Hellwig <hch@lst.de>
Add a single list of devices that need non-ALUA device handlers to the core
scsi_dh code so that we can autoload the modules for them at probe time.
While this is a little ugly in terms of architecture it actually
significantly simplifies the code in addition to the new autoloading
functionality.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Acked-by: Mike Snitzer <snitzer@redhat.com>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 6 ---
drivers/scsi/device_handler/scsi_dh_emc.c | 29 ----------
drivers/scsi/device_handler/scsi_dh_hp_sw.c | 30 -----------
drivers/scsi/device_handler/scsi_dh_rdac.c | 50 -----------------
drivers/scsi/scsi_dh.c | 84 ++++++++++++++++++++++-------
include/scsi/scsi_device.h | 1 -
6 files changed, 66 insertions(+), 134 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 854b568..ace2457 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -819,11 +819,6 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
}
-static bool alua_match(struct scsi_device *sdev)
-{
- return (scsi_device_tpgs(sdev) != 0);
-}
-
/*
* alua_bus_attach - Attach device handler
* @sdev: device to be attached to
@@ -877,7 +872,6 @@ static struct scsi_device_handler alua_dh = {
.check_sense = alua_check_sense,
.activate = alua_activate,
.set_params = alua_set_params,
- .match = alua_match,
};
static int __init alua_init(void)
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index 6ed1caa..fd31e67 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -622,34 +622,6 @@ done:
return result;
}
-static const struct {
- char *vendor;
- char *model;
-} clariion_dev_list[] = {
- {"DGC", "RAID"},
- {"DGC", "DISK"},
- {"DGC", "VRAID"},
- {NULL, NULL},
-};
-
-static bool clariion_match(struct scsi_device *sdev)
-{
- int i;
-
- if (scsi_device_tpgs(sdev))
- return false;
-
- for (i = 0; clariion_dev_list[i].vendor; i++) {
- if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor,
- strlen(clariion_dev_list[i].vendor)) &&
- !strncmp(sdev->model, clariion_dev_list[i].model,
- strlen(clariion_dev_list[i].model))) {
- return true;
- }
- }
- return false;
-}
-
static struct scsi_dh_data *clariion_bus_attach(struct scsi_device *sdev)
{
struct clariion_dh_data *h;
@@ -698,7 +670,6 @@ static struct scsi_device_handler clariion_dh = {
.activate = clariion_activate,
.prep_fn = clariion_prep_fn,
.set_params = clariion_set_params,
- .match = clariion_match,
};
static int __init clariion_init(void)
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index 485d995..1bf10d3 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -311,35 +311,6 @@ static int hp_sw_activate(struct scsi_device *sdev,
return 0;
}
-static const struct {
- char *vendor;
- char *model;
-} hp_sw_dh_data_list[] = {
- {"COMPAQ", "MSA1000 VOLUME"},
- {"COMPAQ", "HSV110"},
- {"HP", "HSV100"},
- {"DEC", "HSG80"},
- {NULL, NULL},
-};
-
-static bool hp_sw_match(struct scsi_device *sdev)
-{
- int i;
-
- if (scsi_device_tpgs(sdev))
- return false;
-
- for (i = 0; hp_sw_dh_data_list[i].vendor; i++) {
- if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor,
- strlen(hp_sw_dh_data_list[i].vendor)) &&
- !strncmp(sdev->model, hp_sw_dh_data_list[i].model,
- strlen(hp_sw_dh_data_list[i].model))) {
- return true;
- }
- }
- return false;
-}
-
static struct scsi_dh_data *hp_sw_bus_attach(struct scsi_device *sdev)
{
struct hp_sw_dh_data *h;
@@ -379,7 +350,6 @@ static struct scsi_device_handler hp_sw_dh = {
.detach = hp_sw_bus_detach,
.activate = hp_sw_activate,
.prep_fn = hp_sw_prep_fn,
- .match = hp_sw_match,
};
static int __init hp_sw_init(void)
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index b46ace3..d89616f 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -778,55 +778,6 @@ static int rdac_check_sense(struct scsi_device *sdev,
return SCSI_RETURN_NOT_HANDLED;
}
-static const struct {
- char *vendor;
- char *model;
-} rdac_dev_list[] = {
- {"IBM", "1722"},
- {"IBM", "1724"},
- {"IBM", "1726"},
- {"IBM", "1742"},
- {"IBM", "1745"},
- {"IBM", "1746"},
- {"IBM", "1813"},
- {"IBM", "1814"},
- {"IBM", "1815"},
- {"IBM", "1818"},
- {"IBM", "3526"},
- {"SGI", "TP9"},
- {"SGI", "IS"},
- {"STK", "OPENstorage D280"},
- {"STK", "FLEXLINE 380"},
- {"SUN", "CSM"},
- {"SUN", "LCSM100"},
- {"SUN", "STK6580_6780"},
- {"SUN", "SUN_6180"},
- {"SUN", "ArrayStorage"},
- {"DELL", "MD3"},
- {"NETAPP", "INF-01-00"},
- {"LSI", "INF-01-00"},
- {"ENGENIO", "INF-01-00"},
- {NULL, NULL},
-};
-
-static bool rdac_match(struct scsi_device *sdev)
-{
- int i;
-
- if (scsi_device_tpgs(sdev))
- return false;
-
- for (i = 0; rdac_dev_list[i].vendor; i++) {
- if (!strncmp(sdev->vendor, rdac_dev_list[i].vendor,
- strlen(rdac_dev_list[i].vendor)) &&
- !strncmp(sdev->model, rdac_dev_list[i].model,
- strlen(rdac_dev_list[i].model))) {
- return true;
- }
- }
- return false;
-}
-
static struct scsi_dh_data *rdac_bus_attach(struct scsi_device *sdev)
{
struct rdac_dh_data *h;
@@ -895,7 +846,6 @@ static struct scsi_device_handler rdac_dh = {
.attach = rdac_bus_attach,
.detach = rdac_bus_detach,
.activate = rdac_activate,
- .match = rdac_match,
};
static int __init rdac_init(void)
diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c
index 2d6a8bd..8f0a6dc 100644
--- a/drivers/scsi/scsi_dh.c
+++ b/drivers/scsi/scsi_dh.c
@@ -29,6 +29,67 @@
static DEFINE_SPINLOCK(list_lock);
static LIST_HEAD(scsi_dh_list);
+struct scsi_dh_blist {
+ const char *vendor;
+ const char *model;
+ const char *driver;
+};
+
+static const struct scsi_dh_blist scsi_dh_blist[] = {
+ {"DGC", "RAID", "clariion" },
+ {"DGC", "DISK", "clariion" },
+ {"DGC", "VRAID", "clariion" },
+
+ {"COMPAQ", "MSA1000 VOLUME", "hp_sw" },
+ {"COMPAQ", "HSV110", "hp_sw" },
+ {"HP", "HSV100", "hp_sw"},
+ {"DEC", "HSG80", "hp_sw"},
+
+ {"IBM", "1722", "rdac", },
+ {"IBM", "1724", "rdac", },
+ {"IBM", "1726", "rdac", },
+ {"IBM", "1742", "rdac", },
+ {"IBM", "1745", "rdac", },
+ {"IBM", "1746", "rdac", },
+ {"IBM", "1813", "rdac", },
+ {"IBM", "1814", "rdac", },
+ {"IBM", "1815", "rdac", },
+ {"IBM", "1818", "rdac", },
+ {"IBM", "3526", "rdac", },
+ {"SGI", "TP9", "rdac", },
+ {"SGI", "IS", "rdac", },
+ {"STK", "OPENstorage D280", "rdac", },
+ {"STK", "FLEXLINE 380", "rdac", },
+ {"SUN", "CSM", "rdac", },
+ {"SUN", "LCSM100", "rdac", },
+ {"SUN", "STK6580_6780", "rdac", },
+ {"SUN", "SUN_6180", "rdac", },
+ {"SUN", "ArrayStorage", "rdac", },
+ {"DELL", "MD3", "rdac", },
+ {"NETAPP", "INF-01-00", "rdac", },
+ {"LSI", "INF-01-00", "rdac", },
+ {"ENGENIO", "INF-01-00", "rdac", },
+ {NULL, NULL, NULL },
+};
+
+static const char *
+scsi_dh_find_driver(struct scsi_device *sdev)
+{
+ const struct scsi_dh_blist *b;
+
+ if (scsi_device_tpgs(sdev))
+ return "alua";
+
+ for (b = scsi_dh_blist; b->vendor; b++) {
+ if (!strncmp(sdev->vendor, b->vendor, strlen(b->vendor)) &&
+ !strncmp(sdev->model, b->model, strlen(b->model))) {
+ return b->driver;
+ }
+ }
+ return NULL;
+}
+
+
static struct scsi_device_handler *__scsi_dh_lookup(const char *name)
{
struct scsi_device_handler *tmp, *found = NULL;
@@ -57,22 +118,6 @@ static struct scsi_device_handler *scsi_dh_lookup(const char *name)
return dh;
}
-static struct scsi_device_handler *
-device_handler_match(struct scsi_device *sdev)
-{
- struct scsi_device_handler *tmp_dh, *found_dh = NULL;
-
- spin_lock(&list_lock);
- list_for_each_entry(tmp_dh, &scsi_dh_list, list) {
- if (tmp_dh->match && tmp_dh->match(sdev)) {
- found_dh = tmp_dh;
- break;
- }
- }
- spin_unlock(&list_lock);
- return found_dh;
-}
-
/*
* scsi_dh_handler_attach - Attach a device handler to a device
* @sdev - SCSI device the device handler should attach to
@@ -183,14 +228,17 @@ static struct device_attribute scsi_dh_state_attr =
int scsi_dh_add_device(struct scsi_device *sdev)
{
- struct scsi_device_handler *devinfo;
+ struct scsi_device_handler *devinfo = NULL;
+ const char *drv;
int err;
err = device_create_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
if (err)
return err;
- devinfo = device_handler_match(sdev);
+ drv = scsi_dh_find_driver(sdev);
+ if (drv)
+ devinfo = scsi_dh_lookup(drv);
if (devinfo)
err = scsi_dh_handler_attach(sdev, devinfo);
return err;
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index f4461cd..409e15b 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -214,7 +214,6 @@ struct scsi_device_handler {
int (*activate)(struct scsi_device *, activate_complete, void *);
int (*prep_fn)(struct scsi_device *, struct request *);
int (*set_params)(struct scsi_device *, const char *);
- bool (*match)(struct scsi_device *);
};
struct scsi_dh_data {
--
1.8.5.6
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 06/10] scsi_dh: kill struct scsi_dh_data
2015-08-27 12:16 [PATCH 00/10] Integrate scsi_dh better into the scsi core V4 Hannes Reinecke
` (4 preceding siblings ...)
2015-08-27 12:16 ` [PATCH 05/10] scsi_dh: move device matching to the core code Hannes Reinecke
@ 2015-08-27 12:16 ` Hannes Reinecke
2015-08-27 12:17 ` [PATCH 07/10] scsi_dh: add a common helper to get a scsi_device from a request_queue Hannes Reinecke
` (3 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Hannes Reinecke @ 2015-08-27 12:16 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, Martin K. Petersen, Mike Snitzer, linux-scsi
From: Christoph Hellwig <hch@lst.de>
Add a ->handler and a ->handler_data field to struct scsi_device and kill
this indirection. Also move struct scsi_device_handler to scsi_dh.h so that
changes to it don't require rebuilding every SCSI LLDD.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/device_handler/scsi_dh_alua.c | 25 ++++------
drivers/scsi/device_handler/scsi_dh_emc.c | 29 +++++------
drivers/scsi/device_handler/scsi_dh_hp_sw.c | 25 ++++------
drivers/scsi/device_handler/scsi_dh_rdac.c | 30 +++++-------
drivers/scsi/scsi_dh.c | 75 +++++++++++------------------
drivers/scsi/scsi_error.c | 6 +--
drivers/scsi/scsi_lib.c | 6 +--
include/scsi/scsi_device.h | 25 ++--------
include/scsi/scsi_dh.h | 17 +++++++
9 files changed, 98 insertions(+), 140 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index ace2457..cc2773b 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -62,7 +62,6 @@
#define ALUA_OPTIMIZE_STPG 1
struct alua_dh_data {
- struct scsi_dh_data dh_data;
int group_id;
int rel_port;
int tpgs;
@@ -86,11 +85,6 @@ struct alua_dh_data {
static char print_alua_state(int);
static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *);
-static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev)
-{
- return container_of(sdev->scsi_dh_data, struct alua_dh_data, dh_data);
-}
-
static int realloc_buffer(struct alua_dh_data *h, unsigned len)
{
if (h->buff && h->buff != h->inq)
@@ -708,7 +702,7 @@ out:
*/
static int alua_set_params(struct scsi_device *sdev, const char *params)
{
- struct alua_dh_data *h = get_alua_data(sdev);
+ struct alua_dh_data *h = sdev->handler_data;
unsigned int optimize = 0, argc;
const char *p = params;
int result = SCSI_DH_OK;
@@ -746,7 +740,7 @@ MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than
static int alua_activate(struct scsi_device *sdev,
activate_complete fn, void *data)
{
- struct alua_dh_data *h = get_alua_data(sdev);
+ struct alua_dh_data *h = sdev->handler_data;
int err = SCSI_DH_OK;
int stpg = 0;
@@ -804,7 +798,7 @@ out:
*/
static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
{
- struct alua_dh_data *h = get_alua_data(sdev);
+ struct alua_dh_data *h = sdev->handler_data;
int ret = BLKPREP_OK;
if (h->state == TPGS_STATE_TRANSITIONING)
@@ -823,14 +817,14 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
* alua_bus_attach - Attach device handler
* @sdev: device to be attached to
*/
-static struct scsi_dh_data *alua_bus_attach(struct scsi_device *sdev)
+static int alua_bus_attach(struct scsi_device *sdev)
{
struct alua_dh_data *h;
int err;
h = kzalloc(sizeof(*h) , GFP_KERNEL);
if (!h)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
h->tpgs = TPGS_MODE_UNINITIALIZED;
h->state = TPGS_STATE_OPTIMIZED;
h->group_id = -1;
@@ -843,11 +837,11 @@ static struct scsi_dh_data *alua_bus_attach(struct scsi_device *sdev)
if (err != SCSI_DH_OK && err != SCSI_DH_DEV_OFFLINED)
goto failed;
- sdev_printk(KERN_NOTICE, sdev, "%s: Attached\n", ALUA_DH_NAME);
- return &h->dh_data;
+ sdev->handler_data = h;
+ return 0;
failed:
kfree(h);
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
/*
@@ -856,10 +850,11 @@ failed:
*/
static void alua_bus_detach(struct scsi_device *sdev)
{
- struct alua_dh_data *h = get_alua_data(sdev);
+ struct alua_dh_data *h = sdev->handler_data;
if (h->buff && h->inq != h->buff)
kfree(h->buff);
+ sdev->handler_data = NULL;
kfree(h);
}
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index fd31e67..e6fb97c 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -72,7 +72,6 @@ static const char * lun_state[] =
};
struct clariion_dh_data {
- struct scsi_dh_data dh_data;
/*
* Flags:
* CLARIION_SHORT_TRESPASS
@@ -114,13 +113,6 @@ struct clariion_dh_data {
int current_sp;
};
-static inline struct clariion_dh_data
- *get_clariion_data(struct scsi_device *sdev)
-{
- return container_of(sdev->scsi_dh_data, struct clariion_dh_data,
- dh_data);
-}
-
/*
* Parse MODE_SELECT cmd reply.
*/
@@ -450,7 +442,7 @@ static int clariion_check_sense(struct scsi_device *sdev,
static int clariion_prep_fn(struct scsi_device *sdev, struct request *req)
{
- struct clariion_dh_data *h = get_clariion_data(sdev);
+ struct clariion_dh_data *h = sdev->handler_data;
int ret = BLKPREP_OK;
if (h->lun_state != CLARIION_LUN_OWNED) {
@@ -533,7 +525,7 @@ retry:
static int clariion_activate(struct scsi_device *sdev,
activate_complete fn, void *data)
{
- struct clariion_dh_data *csdev = get_clariion_data(sdev);
+ struct clariion_dh_data *csdev = sdev->handler_data;
int result;
result = clariion_send_inquiry(sdev, csdev);
@@ -574,7 +566,7 @@ done:
*/
static int clariion_set_params(struct scsi_device *sdev, const char *params)
{
- struct clariion_dh_data *csdev = get_clariion_data(sdev);
+ struct clariion_dh_data *csdev = sdev->handler_data;
unsigned int hr = 0, st = 0, argc;
const char *p = params;
int result = SCSI_DH_OK;
@@ -622,14 +614,14 @@ done:
return result;
}
-static struct scsi_dh_data *clariion_bus_attach(struct scsi_device *sdev)
+static int clariion_bus_attach(struct scsi_device *sdev)
{
struct clariion_dh_data *h;
int err;
h = kzalloc(sizeof(*h) , GFP_KERNEL);
if (!h)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
h->lun_state = CLARIION_LUN_UNINITIALIZED;
h->default_sp = CLARIION_UNBOUND_LU;
h->current_sp = CLARIION_UNBOUND_LU;
@@ -647,18 +639,19 @@ static struct scsi_dh_data *clariion_bus_attach(struct scsi_device *sdev)
CLARIION_NAME, h->current_sp + 'A',
h->port, lun_state[h->lun_state],
h->default_sp + 'A');
- return &h->dh_data;
+
+ sdev->handler_data = h;
+ return 0;
failed:
kfree(h);
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
static void clariion_bus_detach(struct scsi_device *sdev)
{
- struct clariion_dh_data *h = get_clariion_data(sdev);
-
- kfree(h);
+ kfree(sdev->handler_data);
+ sdev->handler_data = NULL;
}
static struct scsi_device_handler clariion_dh = {
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index 1bf10d3..9406d5f 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -38,7 +38,6 @@
#define HP_SW_PATH_PASSIVE 1
struct hp_sw_dh_data {
- struct scsi_dh_data dh_data;
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
int path_state;
int retries;
@@ -50,11 +49,6 @@ struct hp_sw_dh_data {
static int hp_sw_start_stop(struct hp_sw_dh_data *);
-static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev)
-{
- return container_of(sdev->scsi_dh_data, struct hp_sw_dh_data, dh_data);
-}
-
/*
* tur_done - Handle TEST UNIT READY return status
* @sdev: sdev the command has been sent to
@@ -267,7 +261,7 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *h)
static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
{
- struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
+ struct hp_sw_dh_data *h = sdev->handler_data;
int ret = BLKPREP_OK;
if (h->path_state != HP_SW_PATH_ACTIVE) {
@@ -292,7 +286,7 @@ static int hp_sw_activate(struct scsi_device *sdev,
activate_complete fn, void *data)
{
int ret = SCSI_DH_OK;
- struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
+ struct hp_sw_dh_data *h = sdev->handler_data;
ret = hp_sw_tur(sdev, h);
@@ -311,14 +305,14 @@ static int hp_sw_activate(struct scsi_device *sdev,
return 0;
}
-static struct scsi_dh_data *hp_sw_bus_attach(struct scsi_device *sdev)
+static int hp_sw_bus_attach(struct scsi_device *sdev)
{
struct hp_sw_dh_data *h;
int ret;
h = kzalloc(sizeof(*h), GFP_KERNEL);
if (!h)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
h->path_state = HP_SW_PATH_UNINITIALIZED;
h->retries = HP_SW_RETRIES;
h->sdev = sdev;
@@ -330,17 +324,18 @@ static struct scsi_dh_data *hp_sw_bus_attach(struct scsi_device *sdev)
sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n",
HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE?
"active":"passive");
- return &h->dh_data;
+
+ sdev->handler_data = h;
+ return 0;
failed:
kfree(h);
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
static void hp_sw_bus_detach( struct scsi_device *sdev )
{
- struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
-
- kfree(h);
+ kfree(sdev->handler_data);
+ sdev->handler_data = NULL;
}
static struct scsi_device_handler hp_sw_dh = {
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index d89616f..3613581 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -181,7 +181,6 @@ struct c2_inquiry {
};
struct rdac_dh_data {
- struct scsi_dh_data dh_data;
struct rdac_controller *ctlr;
#define UNINITIALIZED_LUN (1 << 8)
unsigned lun;
@@ -260,11 +259,6 @@ do { \
sdev_printk(KERN_INFO, sdev, RDAC_NAME ": " f "\n", ## arg); \
} while (0);
-static inline struct rdac_dh_data *get_rdac_data(struct scsi_device *sdev)
-{
- return container_of(sdev->scsi_dh_data, struct rdac_dh_data, dh_data);
-}
-
static struct request *get_rdac_req(struct scsi_device *sdev,
void *buffer, unsigned buflen, int rw)
{
@@ -544,7 +538,7 @@ static int mode_select_handle_sense(struct scsi_device *sdev,
{
struct scsi_sense_hdr sense_hdr;
int err = SCSI_DH_IO, ret;
- struct rdac_dh_data *h = get_rdac_data(sdev);
+ struct rdac_dh_data *h = sdev->handler_data;
ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr);
if (!ret)
@@ -589,7 +583,7 @@ static void send_mode_select(struct work_struct *work)
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 rdac_dh_data *h = sdev->handler_data;
struct request_queue *q = sdev->request_queue;
int err, retry_cnt = RDAC_RETRY_COUNT;
struct rdac_queue_data *tmp, *qdata;
@@ -648,7 +642,7 @@ static int queue_mode_select(struct scsi_device *sdev,
if (!qdata)
return SCSI_DH_RETRY;
- qdata->h = get_rdac_data(sdev);
+ qdata->h = sdev->handler_data;
qdata->callback_fn = fn;
qdata->callback_data = data;
@@ -667,7 +661,7 @@ static int queue_mode_select(struct scsi_device *sdev,
static int rdac_activate(struct scsi_device *sdev,
activate_complete fn, void *data)
{
- struct rdac_dh_data *h = get_rdac_data(sdev);
+ struct rdac_dh_data *h = sdev->handler_data;
int err = SCSI_DH_OK;
int act = 0;
@@ -702,7 +696,7 @@ done:
static int rdac_prep_fn(struct scsi_device *sdev, struct request *req)
{
- struct rdac_dh_data *h = get_rdac_data(sdev);
+ struct rdac_dh_data *h = sdev->handler_data;
int ret = BLKPREP_OK;
if (h->state != RDAC_STATE_ACTIVE) {
@@ -716,7 +710,7 @@ static int rdac_prep_fn(struct scsi_device *sdev, struct request *req)
static int rdac_check_sense(struct scsi_device *sdev,
struct scsi_sense_hdr *sense_hdr)
{
- struct rdac_dh_data *h = get_rdac_data(sdev);
+ struct rdac_dh_data *h = sdev->handler_data;
RDAC_LOG(RDAC_LOG_SENSE, sdev, "array %s, ctlr %d, "
"I/O returned with sense %02x/%02x/%02x",
@@ -778,7 +772,7 @@ static int rdac_check_sense(struct scsi_device *sdev,
return SCSI_RETURN_NOT_HANDLED;
}
-static struct scsi_dh_data *rdac_bus_attach(struct scsi_device *sdev)
+static int rdac_bus_attach(struct scsi_device *sdev)
{
struct rdac_dh_data *h;
int err;
@@ -787,7 +781,7 @@ static struct scsi_dh_data *rdac_bus_attach(struct scsi_device *sdev)
h = kzalloc(sizeof(*h) , GFP_KERNEL);
if (!h)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
h->lun = UNINITIALIZED_LUN;
h->state = RDAC_STATE_ACTIVE;
@@ -812,7 +806,8 @@ static struct scsi_dh_data *rdac_bus_attach(struct scsi_device *sdev)
RDAC_NAME, h->lun, mode[(int)h->mode],
lun_state[(int)h->lun_state]);
- return &h->dh_data;
+ sdev->handler_data = h;
+ return 0;
clean_ctlr:
spin_lock(&list_lock);
@@ -821,12 +816,12 @@ clean_ctlr:
failed:
kfree(h);
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
static void rdac_bus_detach( struct scsi_device *sdev )
{
- struct rdac_dh_data *h = get_rdac_data(sdev);
+ struct rdac_dh_data *h = sdev->handler_data;
if (h->ctlr && h->ctlr->ms_queued)
flush_workqueue(kmpath_rdacd);
@@ -835,6 +830,7 @@ static void rdac_bus_detach( struct scsi_device *sdev )
if (h->ctlr)
kref_put(&h->ctlr->kref, release_controller);
spin_unlock(&list_lock);
+ sdev->handler_data = NULL;
kfree(h);
}
diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c
index 8f0a6dc..f752a45 100644
--- a/drivers/scsi/scsi_dh.c
+++ b/drivers/scsi/scsi_dh.c
@@ -126,26 +126,20 @@ static struct scsi_device_handler *scsi_dh_lookup(const char *name)
static int scsi_dh_handler_attach(struct scsi_device *sdev,
struct scsi_device_handler *scsi_dh)
{
- struct scsi_dh_data *d;
+ int error;
if (!try_module_get(scsi_dh->module))
return -EINVAL;
- d = scsi_dh->attach(sdev);
- if (IS_ERR(d)) {
- sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%ld)\n",
- scsi_dh->name, PTR_ERR(d));
+ error = scsi_dh->attach(sdev);
+ if (error) {
+ sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%d)\n",
+ scsi_dh->name, error);
module_put(scsi_dh->module);
- return PTR_ERR(d);
- }
-
- d->scsi_dh = scsi_dh;
- d->sdev = sdev;
+ } else
+ sdev->handler = scsi_dh;
- spin_lock_irq(sdev->request_queue->queue_lock);
- sdev->scsi_dh_data = d;
- spin_unlock_irq(sdev->request_queue->queue_lock);
- return 0;
+ return error;
}
/*
@@ -154,17 +148,9 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev,
*/
static void scsi_dh_handler_detach(struct scsi_device *sdev)
{
- struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
- struct scsi_device_handler *scsi_dh = scsi_dh_data->scsi_dh;
-
- scsi_dh->detach(sdev);
-
- spin_lock_irq(sdev->request_queue->queue_lock);
- sdev->scsi_dh_data = NULL;
- spin_unlock_irq(sdev->request_queue->queue_lock);
-
- sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", scsi_dh->name);
- module_put(scsi_dh->module);
+ sdev->handler->detach(sdev);
+ sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", sdev->handler->name);
+ module_put(sdev->handler->module);
}
/*
@@ -182,7 +168,7 @@ store_dh_state(struct device *dev, struct device_attribute *attr,
sdev->sdev_state == SDEV_DEL)
return -ENODEV;
- if (!sdev->scsi_dh_data) {
+ if (!sdev->handler) {
/*
* Attach to a device handler
*/
@@ -190,7 +176,6 @@ store_dh_state(struct device *dev, struct device_attribute *attr,
return err;
err = scsi_dh_handler_attach(sdev, scsi_dh);
} else {
- scsi_dh = sdev->scsi_dh_data->scsi_dh;
if (!strncmp(buf, "detach", 6)) {
/*
* Detach from a device handler
@@ -201,8 +186,8 @@ store_dh_state(struct device *dev, struct device_attribute *attr,
/*
* Activate a device handler
*/
- if (scsi_dh->activate)
- err = scsi_dh->activate(sdev, NULL, NULL);
+ if (sdev->handler->activate)
+ err = sdev->handler->activate(sdev, NULL, NULL);
else
err = 0;
}
@@ -216,10 +201,10 @@ show_dh_state(struct device *dev, struct device_attribute *attr, char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);
- if (!sdev->scsi_dh_data)
+ if (!sdev->handler)
return snprintf(buf, 20, "detached\n");
- return snprintf(buf, 20, "%s\n", sdev->scsi_dh_data->scsi_dh->name);
+ return snprintf(buf, 20, "%s\n", sdev->handler->name);
}
static struct device_attribute scsi_dh_state_attr =
@@ -246,7 +231,7 @@ int scsi_dh_add_device(struct scsi_device *sdev)
void scsi_dh_remove_device(struct scsi_device *sdev)
{
- if (sdev->scsi_dh_data)
+ if (sdev->handler)
scsi_dh_handler_detach(sdev);
device_remove_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
}
@@ -315,7 +300,6 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
int err = 0;
unsigned long flags;
struct scsi_device *sdev;
- struct scsi_device_handler *scsi_dh = NULL;
struct device *dev = NULL;
spin_lock_irqsave(q->queue_lock, flags);
@@ -328,10 +312,8 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
return err;
}
- if (sdev->scsi_dh_data)
- scsi_dh = sdev->scsi_dh_data->scsi_dh;
dev = get_device(&sdev->sdev_gendev);
- if (!scsi_dh || !dev ||
+ if (!sdev->handler || !dev ||
sdev->sdev_state == SDEV_CANCEL ||
sdev->sdev_state == SDEV_DEL)
err = SCSI_DH_NOSYS;
@@ -345,8 +327,8 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
goto out;
}
- if (scsi_dh->activate)
- err = scsi_dh->activate(sdev, fn, data);
+ if (sdev->handler->activate)
+ err = sdev->handler->activate(sdev, fn, data);
out:
put_device(dev);
return err;
@@ -368,19 +350,18 @@ int scsi_dh_set_params(struct request_queue *q, const char *params)
int err = -SCSI_DH_NOSYS;
unsigned long flags;
struct scsi_device *sdev;
- struct scsi_device_handler *scsi_dh = NULL;
spin_lock_irqsave(q->queue_lock, flags);
sdev = q->queuedata;
- if (sdev && sdev->scsi_dh_data)
- scsi_dh = sdev->scsi_dh_data->scsi_dh;
- if (scsi_dh && scsi_dh->set_params && get_device(&sdev->sdev_gendev))
+ if (sdev->handler &&
+ sdev->handler->set_params &&
+ get_device(&sdev->sdev_gendev))
err = 0;
spin_unlock_irqrestore(q->queue_lock, flags);
if (err)
return err;
- err = scsi_dh->set_params(sdev, params);
+ err = sdev->handler->set_params(sdev, params);
put_device(&sdev->sdev_gendev);
return err;
}
@@ -412,8 +393,8 @@ int scsi_dh_attach(struct request_queue *q, const char *name)
if (err)
return err;
- if (sdev->scsi_dh_data) {
- if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
+ if (sdev->handler) {
+ if (sdev->handler != scsi_dh)
err = -EBUSY;
goto out_put_device;
}
@@ -450,8 +431,8 @@ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
if (!sdev)
return NULL;
- if (sdev->scsi_dh_data)
- handler_name = kstrdup(sdev->scsi_dh_data->scsi_dh->name, gfp);
+ if (sdev->handler)
+ handler_name = kstrdup(sdev->handler->name, gfp);
put_device(&sdev->sdev_gendev);
return handler_name;
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 6457a8a..4b8c0dc 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -36,6 +36,7 @@
#include <scsi/scsi_transport.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h>
+#include <scsi/scsi_dh.h>
#include <scsi/sg.h>
#include "scsi_priv.h"
@@ -459,11 +460,10 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
if (scsi_sense_is_deferred(&sshdr))
return NEEDS_RETRY;
- if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh &&
- sdev->scsi_dh_data->scsi_dh->check_sense) {
+ if (sdev->handler && sdev->handler->check_sense) {
int rc;
- rc = sdev->scsi_dh_data->scsi_dh->check_sense(sdev, &sshdr);
+ rc = sdev->handler->check_sense(sdev, &sshdr);
if (rc != SCSI_RETURN_NOT_HANDLED)
return rc;
/* handler does not care. Drop down to default handling */
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 448ebda..2a864b8 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -31,6 +31,7 @@
#include <scsi/scsi_driver.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_dh.h>
#include <trace/events/scsi.h>
@@ -1248,9 +1249,8 @@ static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
{
struct scsi_cmnd *cmd = req->special;
- if (unlikely(sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh
- && sdev->scsi_dh_data->scsi_dh->prep_fn)) {
- int ret = sdev->scsi_dh_data->scsi_dh->prep_fn(sdev, req);
+ if (unlikely(sdev->handler && sdev->handler->prep_fn)) {
+ int ret = sdev->handler->prep_fn(sdev, req);
if (ret != BLKPREP_OK)
return ret;
}
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 409e15b..b6b1dc4 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -195,32 +195,13 @@ struct scsi_device {
struct execute_work ew; /* used to get process context on put */
struct work_struct requeue_work;
- struct scsi_dh_data *scsi_dh_data;
+ struct scsi_device_handler *handler;
+ void *handler_data;
+
enum scsi_device_state sdev_state;
unsigned long sdev_data[0];
} __attribute__((aligned(sizeof(unsigned long))));
-typedef void (*activate_complete)(void *, int);
-struct scsi_device_handler {
- /* Used by the infrastructure */
- struct list_head list; /* list of scsi_device_handlers */
-
- /* Filled by the hardware handler */
- struct module *module;
- const char *name;
- int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
- struct scsi_dh_data *(*attach)(struct scsi_device *);
- void (*detach)(struct scsi_device *);
- int (*activate)(struct scsi_device *, activate_complete, void *);
- int (*prep_fn)(struct scsi_device *, struct request *);
- int (*set_params)(struct scsi_device *, const char *);
-};
-
-struct scsi_dh_data {
- struct scsi_device_handler *scsi_dh;
- struct scsi_device *sdev;
-};
-
#define to_scsi_device(d) \
container_of(d, struct scsi_device, sdev_gendev)
#define class_to_sdev(d) \
diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h
index 3a37b4c45..85d7317 100644
--- a/include/scsi/scsi_dh.h
+++ b/include/scsi/scsi_dh.h
@@ -55,6 +55,23 @@ enum {
SCSI_DH_NOSYS,
SCSI_DH_DRIVER_MAX,
};
+
+typedef void (*activate_complete)(void *, int);
+struct scsi_device_handler {
+ /* Used by the infrastructure */
+ struct list_head list; /* list of scsi_device_handlers */
+
+ /* Filled by the hardware handler */
+ struct module *module;
+ const char *name;
+ int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
+ int (*attach)(struct scsi_device *);
+ void (*detach)(struct scsi_device *);
+ int (*activate)(struct scsi_device *, activate_complete, void *);
+ int (*prep_fn)(struct scsi_device *, struct request *);
+ int (*set_params)(struct scsi_device *, const char *);
+};
+
#ifdef CONFIG_SCSI_DH
extern int scsi_dh_activate(struct request_queue *, activate_complete, void *);
extern int scsi_dh_attach(struct request_queue *, const char *);
--
1.8.5.6
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 07/10] scsi_dh: add a common helper to get a scsi_device from a request_queue
2015-08-27 12:16 [PATCH 00/10] Integrate scsi_dh better into the scsi core V4 Hannes Reinecke
` (5 preceding siblings ...)
2015-08-27 12:16 ` [PATCH 06/10] scsi_dh: kill struct scsi_dh_data Hannes Reinecke
@ 2015-08-27 12:17 ` Hannes Reinecke
2015-08-27 12:17 ` [PATCH 08/10] scsi_dh: don't allow to detach device handlers at runtime Hannes Reinecke
` (2 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Hannes Reinecke @ 2015-08-27 12:17 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, Martin K. Petersen, Mike Snitzer, linux-scsi
From: Christoph Hellwig <hch@lst.de>
And cleanup the various messy opencoded versions of this. Note that this
moves the sdev_state checks outside the queue_lock coverage, but as
we don't hold the lock over the activation they are only advisory anyway.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/scsi_dh.c | 99 +++++++++++++++++++++++---------------------------
1 file changed, 46 insertions(+), 53 deletions(-)
diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c
index f752a45..489083c 100644
--- a/drivers/scsi/scsi_dh.c
+++ b/drivers/scsi/scsi_dh.c
@@ -282,6 +282,20 @@ int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
}
EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
+static struct scsi_device *get_sdev_from_queue(struct request_queue *q)
+{
+ struct scsi_device *sdev;
+ unsigned long flags;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ sdev = q->queuedata;
+ if (!sdev || !get_device(&sdev->sdev_gendev))
+ sdev = NULL;
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ return sdev;
+}
+
/*
* scsi_dh_activate - activate the path associated with the scsi_device
* corresponding to the given request queue.
@@ -297,41 +311,37 @@ EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
*/
int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
{
- int err = 0;
- unsigned long flags;
struct scsi_device *sdev;
- struct device *dev = NULL;
+ int err = SCSI_DH_NOSYS;
- spin_lock_irqsave(q->queue_lock, flags);
- sdev = q->queuedata;
+ sdev = get_sdev_from_queue(q);
if (!sdev) {
- spin_unlock_irqrestore(q->queue_lock, flags);
- err = SCSI_DH_NOSYS;
if (fn)
fn(data, err);
return err;
}
- dev = get_device(&sdev->sdev_gendev);
- if (!sdev->handler || !dev ||
- sdev->sdev_state == SDEV_CANCEL ||
+ if (!sdev->handler)
+ goto out_fn;
+ if (sdev->sdev_state == SDEV_CANCEL ||
sdev->sdev_state == SDEV_DEL)
- err = SCSI_DH_NOSYS;
- if (sdev->sdev_state == SDEV_OFFLINE)
- err = SCSI_DH_DEV_OFFLINED;
- spin_unlock_irqrestore(q->queue_lock, flags);
+ goto out_fn;
- if (err) {
- if (fn)
- fn(data, err);
- goto out;
- }
+ err = SCSI_DH_DEV_OFFLINED;
+ if (sdev->sdev_state == SDEV_OFFLINE)
+ goto out_fn;
if (sdev->handler->activate)
err = sdev->handler->activate(sdev, fn, data);
-out:
- put_device(dev);
+
+out_put_device:
+ put_device(&sdev->sdev_gendev);
return err;
+
+out_fn:
+ if (fn)
+ fn(data, err);
+ goto out_put_device;
}
EXPORT_SYMBOL_GPL(scsi_dh_activate);
@@ -347,21 +357,15 @@ EXPORT_SYMBOL_GPL(scsi_dh_activate);
*/
int scsi_dh_set_params(struct request_queue *q, const char *params)
{
- int err = -SCSI_DH_NOSYS;
- unsigned long flags;
struct scsi_device *sdev;
+ int err = -SCSI_DH_NOSYS;
- spin_lock_irqsave(q->queue_lock, flags);
- sdev = q->queuedata;
- if (sdev->handler &&
- sdev->handler->set_params &&
- get_device(&sdev->sdev_gendev))
- err = 0;
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- if (err)
+ sdev = get_sdev_from_queue(q);
+ if (!sdev)
return err;
- err = sdev->handler->set_params(sdev, params);
+
+ if (sdev->handler && sdev->handler->set_params)
+ err = sdev->handler->set_params(sdev, params);
put_device(&sdev->sdev_gendev);
return err;
}
@@ -375,23 +379,19 @@ EXPORT_SYMBOL_GPL(scsi_dh_set_params);
*/
int scsi_dh_attach(struct request_queue *q, const char *name)
{
- unsigned long flags;
struct scsi_device *sdev;
struct scsi_device_handler *scsi_dh;
int err = 0;
- scsi_dh = scsi_dh_lookup(name);
- if (!scsi_dh)
- return -EINVAL;
-
- spin_lock_irqsave(q->queue_lock, flags);
- sdev = q->queuedata;
- if (!sdev || !get_device(&sdev->sdev_gendev))
- err = -ENODEV;
- spin_unlock_irqrestore(q->queue_lock, flags);
+ sdev = get_sdev_from_queue(q);
+ if (!sdev)
+ return -ENODEV;
- if (err)
- return err;
+ scsi_dh = scsi_dh_lookup(name);
+ if (!scsi_dh) {
+ err = -EINVAL;
+ goto out_put_device;
+ }
if (sdev->handler) {
if (sdev->handler != scsi_dh)
@@ -418,22 +418,15 @@ EXPORT_SYMBOL_GPL(scsi_dh_attach);
*/
const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
{
- unsigned long flags;
struct scsi_device *sdev;
const char *handler_name = NULL;
- spin_lock_irqsave(q->queue_lock, flags);
- sdev = q->queuedata;
- if (!sdev || !get_device(&sdev->sdev_gendev))
- sdev = NULL;
- spin_unlock_irqrestore(q->queue_lock, flags);
-
+ sdev = get_sdev_from_queue(q);
if (!sdev)
return NULL;
if (sdev->handler)
handler_name = kstrdup(sdev->handler->name, gfp);
-
put_device(&sdev->sdev_gendev);
return handler_name;
}
--
1.8.5.6
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 08/10] scsi_dh: don't allow to detach device handlers at runtime
2015-08-27 12:16 [PATCH 00/10] Integrate scsi_dh better into the scsi core V4 Hannes Reinecke
` (6 preceding siblings ...)
2015-08-27 12:17 ` [PATCH 07/10] scsi_dh: add a common helper to get a scsi_device from a request_queue Hannes Reinecke
@ 2015-08-27 12:17 ` Hannes Reinecke
2015-08-27 12:17 ` [PATCH 09/10] scsi_dh: return SCSI_DH_NOTCONN in scsi_dh_activate() Hannes Reinecke
2015-08-27 12:17 ` [PATCH 10/10] scsi_dh: move 'dh_state' sysfs attribute to generic code Hannes Reinecke
9 siblings, 0 replies; 15+ messages in thread
From: Hannes Reinecke @ 2015-08-27 12:17 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, Martin K. Petersen, Mike Snitzer, linux-scsi
From: Christoph Hellwig <hch@lst.de>
The I/O submission and completion pathes call into the device handler
without any synchronization agains detachment. So disallow detaching
device handlers at runtime.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/scsi_dh.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c
index 489083c..954ca5e 100644
--- a/drivers/scsi/scsi_dh.c
+++ b/drivers/scsi/scsi_dh.c
@@ -180,8 +180,10 @@ store_dh_state(struct device *dev, struct device_attribute *attr,
/*
* Detach from a device handler
*/
- scsi_dh_handler_detach(sdev);
- err = 0;
+ sdev_printk(KERN_WARNING, sdev,
+ "can't detach handler %s.\n",
+ sdev->handler->name);
+ err = -EINVAL;
} else if (!strncmp(buf, "activate", 8)) {
/*
* Activate a device handler
--
1.8.5.6
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 09/10] scsi_dh: return SCSI_DH_NOTCONN in scsi_dh_activate()
2015-08-27 12:16 [PATCH 00/10] Integrate scsi_dh better into the scsi core V4 Hannes Reinecke
` (7 preceding siblings ...)
2015-08-27 12:17 ` [PATCH 08/10] scsi_dh: don't allow to detach device handlers at runtime Hannes Reinecke
@ 2015-08-27 12:17 ` Hannes Reinecke
2015-08-27 12:17 ` [PATCH 10/10] scsi_dh: move 'dh_state' sysfs attribute to generic code Hannes Reinecke
9 siblings, 0 replies; 15+ messages in thread
From: Hannes Reinecke @ 2015-08-27 12:17 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, Martin K. Petersen, Mike Snitzer, linux-scsi,
Hannes Reinecke
When calling scsi_dh_activate() we should be returning
SCSI_DH_NOTCONN if the device handler couldn't be attached.
Reviewed-by: Bart van Assche <bart.vanassche@sandisk.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/scsi_dh.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c
index 954ca5e..2d93bc9 100644
--- a/drivers/scsi/scsi_dh.c
+++ b/drivers/scsi/scsi_dh.c
@@ -325,6 +325,7 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
if (!sdev->handler)
goto out_fn;
+ err = SCSI_DH_NOTCONN;
if (sdev->sdev_state == SDEV_CANCEL ||
sdev->sdev_state == SDEV_DEL)
goto out_fn;
--
1.8.5.6
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 10/10] scsi_dh: move 'dh_state' sysfs attribute to generic code
2015-08-27 12:16 [PATCH 00/10] Integrate scsi_dh better into the scsi core V4 Hannes Reinecke
` (8 preceding siblings ...)
2015-08-27 12:17 ` [PATCH 09/10] scsi_dh: return SCSI_DH_NOTCONN in scsi_dh_activate() Hannes Reinecke
@ 2015-08-27 12:17 ` Hannes Reinecke
2015-08-28 20:14 ` James Bottomley
2015-09-01 9:35 ` Christoph Hellwig
9 siblings, 2 replies; 15+ messages in thread
From: Hannes Reinecke @ 2015-08-27 12:17 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, Martin K. Petersen, Mike Snitzer, linux-scsi,
Hannes Reinecke
As scsi_dh.c is now always compiled in we should be moving
the 'dh_state' attribute to the generic code.
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/scsi_dh.c | 67 +----------------------------------------------
drivers/scsi/scsi_sysfs.c | 58 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 59 insertions(+), 66 deletions(-)
diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c
index 2d93bc9..1584080 100644
--- a/drivers/scsi/scsi_dh.c
+++ b/drivers/scsi/scsi_dh.c
@@ -153,75 +153,11 @@ static void scsi_dh_handler_detach(struct scsi_device *sdev)
module_put(sdev->handler->module);
}
-/*
- * Functions for sysfs attribute 'dh_state'
- */
-static ssize_t
-store_dh_state(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct scsi_device_handler *scsi_dh;
- int err = -EINVAL;
-
- if (sdev->sdev_state == SDEV_CANCEL ||
- sdev->sdev_state == SDEV_DEL)
- return -ENODEV;
-
- if (!sdev->handler) {
- /*
- * Attach to a device handler
- */
- if (!(scsi_dh = scsi_dh_lookup(buf)))
- return err;
- err = scsi_dh_handler_attach(sdev, scsi_dh);
- } else {
- if (!strncmp(buf, "detach", 6)) {
- /*
- * Detach from a device handler
- */
- sdev_printk(KERN_WARNING, sdev,
- "can't detach handler %s.\n",
- sdev->handler->name);
- err = -EINVAL;
- } else if (!strncmp(buf, "activate", 8)) {
- /*
- * Activate a device handler
- */
- if (sdev->handler->activate)
- err = sdev->handler->activate(sdev, NULL, NULL);
- else
- err = 0;
- }
- }
-
- return err<0?err:count;
-}
-
-static ssize_t
-show_dh_state(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
-
- if (!sdev->handler)
- return snprintf(buf, 20, "detached\n");
-
- return snprintf(buf, 20, "%s\n", sdev->handler->name);
-}
-
-static struct device_attribute scsi_dh_state_attr =
- __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state,
- store_dh_state);
-
int scsi_dh_add_device(struct scsi_device *sdev)
{
struct scsi_device_handler *devinfo = NULL;
const char *drv;
- int err;
-
- err = device_create_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
- if (err)
- return err;
+ int err = 0;
drv = scsi_dh_find_driver(sdev);
if (drv)
@@ -235,7 +171,6 @@ void scsi_dh_remove_device(struct scsi_device *sdev)
{
if (sdev->handler)
scsi_dh_handler_detach(sdev);
- device_remove_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
}
/*
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index b333389..5d64c3f 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -17,6 +17,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_dh.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_driver.h>
@@ -875,6 +876,60 @@ sdev_show_function(queue_depth, "%d\n");
static DEVICE_ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth,
sdev_store_queue_depth);
+#ifdef CONFIG_SCSI_DH
+static ssize_t
+sdev_show_dh_state(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ if (!sdev->handler)
+ return snprintf(buf, 20, "detached\n");
+
+ return snprintf(buf, 20, "%s\n", sdev->handler->name);
+}
+
+static ssize_t
+sdev_store_dh_state(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ int err = -EINVAL;
+
+ if (sdev->sdev_state == SDEV_CANCEL ||
+ sdev->sdev_state == SDEV_DEL)
+ return -ENODEV;
+
+ if (!sdev->handler) {
+ /*
+ * Attach to a device handler
+ */
+ err = scsi_dh_attach(sdev->request_queue, buf);
+ } else if (!strncmp(buf, "activate", 8)) {
+ /*
+ * Activate a device handler
+ */
+ if (sdev->handler->activate)
+ err = sdev->handler->activate(sdev, NULL, NULL);
+ else
+ err = 0;
+ } else if (!strncmp(buf, "detach", 6)) {
+ /*
+ * Detach from a device handler
+ */
+ sdev_printk(KERN_WARNING, sdev,
+ "can't detach handler %s.\n",
+ sdev->handler->name);
+ err = -EINVAL;
+ }
+
+ return err < 0 ? err : count;
+}
+
+static DEVICE_ATTR(dh_state, S_IRUGO | S_IWUSR, sdev_show_dh_state,
+ sdev_store_dh_state);
+#endif
+
static ssize_t
sdev_show_queue_ramp_up_period(struct device *dev,
struct device_attribute *attr,
@@ -944,6 +999,9 @@ static struct attribute *scsi_sdev_attrs[] = {
&dev_attr_modalias.attr,
&dev_attr_queue_depth.attr,
&dev_attr_queue_type.attr,
+#ifdef CONFIG_SCSI_DH
+ &dev_attr_dh_state.attr,
+#endif
&dev_attr_queue_ramp_up_period.attr,
REF_EVT(media_change),
REF_EVT(inquiry_change_reported),
--
1.8.5.6
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 02/10] dm-mpath, scsi_dh: request scsi_dh modules in scsi_dh, not dm-mpath
2015-08-27 12:16 ` [PATCH 02/10] dm-mpath, scsi_dh: request scsi_dh modules in scsi_dh, not dm-mpath Hannes Reinecke
@ 2015-08-28 19:53 ` James Bottomley
2015-08-31 6:39 ` Hannes Reinecke
0 siblings, 1 reply; 15+ messages in thread
From: James Bottomley @ 2015-08-28 19:53 UTC (permalink / raw)
To: Hannes Reinecke
Cc: Christoph Hellwig, Martin K. Petersen, Mike Snitzer, linux-scsi
On Thu, 2015-08-27 at 14:16 +0200, Hannes Reinecke wrote:
> @@ -158,7 +171,7 @@ store_dh_state(struct device *dev, struct device_attribute *attr,
> /*
> * Attach to a device handler
> */
> - if (!(scsi_dh = get_device_handler(buf)))
> + if (!(scsi_dh = scsi_dh_lookup(buf)))
This one's a checkpatch error:
ERROR: do not use assignment in if condition
#71: FILE: drivers/scsi/device_handler/scsi_dh.c:174:
+ if (!(scsi_dh = scsi_dh_lookup(buf)))
For very good reason. The meaning is obvious from the previous code, so
I fixed it up as
scsi_dh = scsi_dh_lookup(buf);
if (!scsi_dh)
But running the series through checkpatch and acting on at least the
errors would have been appreciated.
James
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 10/10] scsi_dh: move 'dh_state' sysfs attribute to generic code
2015-08-27 12:17 ` [PATCH 10/10] scsi_dh: move 'dh_state' sysfs attribute to generic code Hannes Reinecke
@ 2015-08-28 20:14 ` James Bottomley
2015-09-01 9:35 ` Christoph Hellwig
1 sibling, 0 replies; 15+ messages in thread
From: James Bottomley @ 2015-08-28 20:14 UTC (permalink / raw)
To: Hannes Reinecke
Cc: Christoph Hellwig, Martin K. Petersen, Mike Snitzer, linux-scsi
On Thu, 2015-08-27 at 14:17 +0200, Hannes Reinecke wrote:
> As scsi_dh.c is now always compiled in we should be moving
> the 'dh_state' attribute to the generic code.
>
> Signed-off-by: Hannes Reinecke <hare@suse.de>
This looks OK, but needs another reviewer. If you could also fix up the
rejections caused by the if (!(scsi_dh = ...)) as well, that would be
great.
It's independent, so I pulled in the rest.
Thanks,
James
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 02/10] dm-mpath, scsi_dh: request scsi_dh modules in scsi_dh, not dm-mpath
2015-08-28 19:53 ` James Bottomley
@ 2015-08-31 6:39 ` Hannes Reinecke
0 siblings, 0 replies; 15+ messages in thread
From: Hannes Reinecke @ 2015-08-31 6:39 UTC (permalink / raw)
To: James Bottomley
Cc: Christoph Hellwig, Martin K. Petersen, Mike Snitzer, linux-scsi
On 08/28/2015 09:53 PM, James Bottomley wrote:
> On Thu, 2015-08-27 at 14:16 +0200, Hannes Reinecke wrote:
>> @@ -158,7 +171,7 @@ store_dh_state(struct device *dev, struct device_attribute *attr,
>> /*
>> * Attach to a device handler
>> */
>> - if (!(scsi_dh = get_device_handler(buf)))
>> + if (!(scsi_dh = scsi_dh_lookup(buf)))
>
> This one's a checkpatch error:
>
> ERROR: do not use assignment in if condition
> #71: FILE: drivers/scsi/device_handler/scsi_dh.c:174:
> + if (!(scsi_dh = scsi_dh_lookup(buf)))
>
>
> For very good reason. The meaning is obvious from the previous code, so
> I fixed it up as
>
> scsi_dh = scsi_dh_lookup(buf);
> if (!scsi_dh)
>
> But running the series through checkpatch and acting on at least the
> errors would have been appreciated.
>
You're right, sorry. Thanks for fixing it up.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
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] 15+ messages in thread
* Re: [PATCH 10/10] scsi_dh: move 'dh_state' sysfs attribute to generic code
2015-08-27 12:17 ` [PATCH 10/10] scsi_dh: move 'dh_state' sysfs attribute to generic code Hannes Reinecke
2015-08-28 20:14 ` James Bottomley
@ 2015-09-01 9:35 ` Christoph Hellwig
1 sibling, 0 replies; 15+ messages in thread
From: Christoph Hellwig @ 2015-09-01 9:35 UTC (permalink / raw)
To: Hannes Reinecke
Cc: James Bottomley, Christoph Hellwig, Martin K. Petersen,
Mike Snitzer, linux-scsi
On Thu, Aug 27, 2015 at 02:17:03PM +0200, Hannes Reinecke wrote:
> As scsi_dh.c is now always compiled in we should be moving
> the 'dh_state' attribute to the generic code.
>
> Signed-off-by: Hannes Reinecke <hare@suse.de>
Looks good,
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2015-09-01 9:36 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-08-27 12:16 [PATCH 00/10] Integrate scsi_dh better into the scsi core V4 Hannes Reinecke
2015-08-27 12:16 ` [PATCH 01/10] dm-mpath, scsi_dh: don't let dm detach device handlers Hannes Reinecke
2015-08-27 12:16 ` [PATCH 02/10] dm-mpath, scsi_dh: request scsi_dh modules in scsi_dh, not dm-mpath Hannes Reinecke
2015-08-28 19:53 ` James Bottomley
2015-08-31 6:39 ` Hannes Reinecke
2015-08-27 12:16 ` [PATCH 03/10] scsi_dh: move to drivers/scsi Hannes Reinecke
2015-08-27 12:16 ` [PATCH 04/10] scsi_dh: integrate into the core SCSI code Hannes Reinecke
2015-08-27 12:16 ` [PATCH 05/10] scsi_dh: move device matching to the core code Hannes Reinecke
2015-08-27 12:16 ` [PATCH 06/10] scsi_dh: kill struct scsi_dh_data Hannes Reinecke
2015-08-27 12:17 ` [PATCH 07/10] scsi_dh: add a common helper to get a scsi_device from a request_queue Hannes Reinecke
2015-08-27 12:17 ` [PATCH 08/10] scsi_dh: don't allow to detach device handlers at runtime Hannes Reinecke
2015-08-27 12:17 ` [PATCH 09/10] scsi_dh: return SCSI_DH_NOTCONN in scsi_dh_activate() Hannes Reinecke
2015-08-27 12:17 ` [PATCH 10/10] scsi_dh: move 'dh_state' sysfs attribute to generic code Hannes Reinecke
2015-08-28 20:14 ` James Bottomley
2015-09-01 9:35 ` Christoph Hellwig
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).