Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 314155 Details for
Bug 438761
LTC:5.4:201049:DM-MP SCSI Hardware Handlers
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
Basic infrastructure for SCSI Hardware Handler
01-scsi_dh-scsi-add-device-handler.patch (text/plain), 27.45 KB, created by
IBM Bug Proxy
on 2008-08-13 00:51:11 UTC
(
hide
)
Description:
Basic infrastructure for SCSI Hardware Handler
Filename:
MIME Type:
Creator:
IBM Bug Proxy
Created:
2008-08-13 00:51:11 UTC
Size:
27.45 KB
patch
obsolete
> >Subject: scsi_dh: add infrastructure for SCSI Device Handlers > >From: Chandra Seetharaman <sekharan@us.ibm.com> > >Some of the storage devices (that can be accessed through multiple paths), >do need some special handling for > 1. Activating the passive path of the storage access. > 2. Decode and handle the special sense codes returned by the devices. > 3. Handle the I/Os being sent to the passive path, especially > during the device probe time. >when accessed through multiple paths. > >As of today this special device handling is done at the dm-multipath >layer using dm-handlers. That works well for (1); for (2) to be handled >at dm layer, scsi sense information need to be exported from SCSI to dm-layer, >which is not very attractive; (3) cannot be done at all at the dm layer. > >Device handler has been moved to SCSI mainly to handle (2) and (3) properly. > >-- >This patch provides the infrastructure for moving the feature over to SCSI. > >Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com> >Signed-off-by: Mike Anderson <andmike@linux.vnet.ibm.com> >Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> >--- > > drivers/scsi/Kconfig | 2 2 + 0 - 0 ! > drivers/scsi/Makefile | 1 1 + 0 - 0 ! > drivers/scsi/device_handler/Kconfig | 12 12 + 0 - 0 ! > drivers/scsi/device_handler/Makefile | 4 4 + 0 - 0 ! > drivers/scsi/device_handler/scsi_dh.c | 151 151 + 0 - 0 ! > drivers/scsi/scsi_error.c | 11 11 + 0 - 0 ! > drivers/scsi/scsi_lib.c | 8 8 + 0 - 0 ! > drivers/scsi/scsi_sysfs.c | 1 1 + 0 - 0 ! > include/scsi/scsi.h | 1 1 + 0 - 0 ! > include/scsi/scsi_device.h | 22 22 + 0 - 0 ! > include/scsi/scsi_dh.h | 58 58 + 0 - 0 ! > 11 files changed, 271 insertions(+) > >Index: linux-2.6.18.ppc64/drivers/scsi/Kconfig >=================================================================== >--- linux-2.6.18.ppc64.orig/drivers/scsi/Kconfig >+++ linux-2.6.18.ppc64/drivers/scsi/Kconfig >@@ -1743,4 +1743,6 @@ endmenu > > source "drivers/scsi/pcmcia/Kconfig" > >+source "drivers/scsi/device_handler/Kconfig" >+ > endmenu >Index: linux-2.6.18.ppc64/drivers/scsi/device_handler/Kconfig >=================================================================== >--- /dev/null >+++ linux-2.6.18.ppc64/drivers/scsi/device_handler/Kconfig >@@ -0,0 +1,12 @@ >+# >+# SCSI Device Handler configuration >+# >+ >+menuconfig SCSI_DH >+ tristate "SCSI Device Handlers" >+ depends on SCSI >+ default n >+ help >+ SCSI Device Handlers provide device specific support for >+ devices utilized in multipath configurations. Say Y here to >+ select support for specific hardware. >Index: linux-2.6.18.ppc64/drivers/scsi/device_handler/Makefile >=================================================================== >--- /dev/null >+++ linux-2.6.18.ppc64/drivers/scsi/device_handler/Makefile >@@ -0,0 +1,4 @@ >+# >+# SCSI Device Handler >+# >+obj-$(CONFIG_SCSI_DH) += scsi_dh.o >Index: linux-2.6.18.ppc64/drivers/scsi/scsi_error.c >=================================================================== >--- linux-2.6.18.ppc64.orig/drivers/scsi/scsi_error.c >+++ linux-2.6.18.ppc64/drivers/scsi/scsi_error.c >@@ -33,6 +33,7 @@ > #include <scsi/scsi_transport.h> > #include <scsi/scsi_host.h> > #include <scsi/scsi_ioctl.h> >+#include <scsi/scsi_dh.h> > > #include "scsi_priv.h" > #include "scsi_logging.h" >@@ -298,7 +299,9 @@ static inline void scsi_eh_prt_fail_stat > **/ > static int scsi_check_sense(struct scsi_cmnd *scmd) > { >+ struct scsi_device *sdev = scmd->device; > struct scsi_sense_hdr sshdr; >+ struct scsi_dh_data *scsi_dh_data = retrieve_scsi_dh_data(sdev); > > if (! scsi_command_normalize_sense(scmd, &sshdr)) > return FAILED; /* no valid sense data */ >@@ -306,6 +309,16 @@ static int scsi_check_sense(struct scsi_ > if (scsi_sense_is_deferred(&sshdr)) > return NEEDS_RETRY; > >+ if (scsi_dh_data && scsi_dh_data->scsi_dh && >+ scsi_dh_data->scsi_dh->check_sense) { >+ int rc; >+ >+ rc = scsi_dh_data->scsi_dh->check_sense(sdev, &sshdr); >+ if (rc != SCSI_RETURN_NOT_HANDLED) >+ return rc; >+ /* handler does not care. Drop down to default handling */ >+ } >+ > /* > * Previous logic looked for FILEMARK, EOM or ILI which are > * mainly associated with tapes and returned SUCCESS. >Index: linux-2.6.18.ppc64/include/scsi/scsi_device.h >=================================================================== >--- linux-2.6.18.ppc64.orig/include/scsi/scsi_device.h >+++ linux-2.6.18.ppc64/include/scsi/scsi_device.h >@@ -7,6 +7,7 @@ > #include <linux/workqueue.h> > #include <asm/atomic.h> > >+struct request; > struct request_queue; > struct scsi_cmnd; > struct scsi_lun; >@@ -161,9 +162,36 @@ struct scsi_device { > > struct execute_work ew; /* used to get process context on put */ > >+ struct scsi_dh_data *scsi_dh_data; > enum scsi_device_state sdev_state; > unsigned long sdev_data[0]; > } __attribute__((aligned(sizeof(unsigned long)))); >+ >+struct scsi_dh_devlist { >+ char *vendor; >+ char *model; >+}; >+ >+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; >+ const struct scsi_dh_devlist *devlist; >+ 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 *); >+ int (*prep_fn)(struct scsi_device *, struct request *); >+}; >+ >+struct scsi_dh_data { >+ struct scsi_device_handler *scsi_dh; >+ char buf[0]; >+}; >+ > #define to_scsi_device(d) \ > container_of(d, struct scsi_device, sdev_gendev) > #define class_to_sdev(d) \ >@@ -238,6 +266,9 @@ extern int scsi_add_device(struct Scsi_H > extern void scsi_remove_device(struct scsi_device *); > extern int scsi_device_cancel(struct scsi_device *, int); > >+extern int scsi_register_device_handler(struct scsi_device_handler *scsi_dh); >+extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh); >+ > extern int scsi_device_get(struct scsi_device *); > extern void scsi_device_put(struct scsi_device *); > extern struct scsi_device *scsi_device_lookup(struct Scsi_Host *, >Index: linux-2.6.18.ppc64/drivers/scsi/device_handler/scsi_dh.c >=================================================================== >--- /dev/null >+++ linux-2.6.18.ppc64/drivers/scsi/device_handler/scsi_dh.c >@@ -0,0 +1,554 @@ >+/* >+ * 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 <scsi/scsi_dh.h> >+#include "../scsi_priv.h" >+ >+struct scsi_dh_devinfo_list { >+ struct list_head node; >+ char vendor[9]; >+ char model[17]; >+ struct scsi_device_handler *handler; >+}; >+ >+static DEFINE_SPINLOCK(list_lock); >+static LIST_HEAD(scsi_dh_list); >+static LIST_HEAD(scsi_dh_dev_list); >+ >+static struct scsi_device_handler *get_device_handler(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_cache_lookup(struct scsi_device *sdev) >+{ >+ struct scsi_dh_devinfo_list *tmp; >+ struct scsi_device_handler *found_dh = NULL; >+ >+ spin_lock(&list_lock); >+ list_for_each_entry(tmp, &scsi_dh_dev_list, node) { >+ if (!strncmp(sdev->vendor, tmp->vendor, strlen(tmp->vendor)) && >+ !strncmp(sdev->model, tmp->model, strlen(tmp->model))) { >+ found_dh = tmp->handler; >+ break; >+ } >+ } >+ spin_unlock(&list_lock); >+ >+ return found_dh; >+} >+ >+static int scsi_dh_handler_lookup(struct scsi_device_handler *scsi_dh, >+ struct scsi_device *sdev) >+{ >+ int i, found = 0; >+ >+ for(i = 0; scsi_dh->devlist[i].vendor; i++) { >+ if (!strncmp(sdev->vendor, scsi_dh->devlist[i].vendor, >+ strlen(scsi_dh->devlist[i].vendor)) && >+ !strncmp(sdev->model, scsi_dh->devlist[i].model, >+ strlen(scsi_dh->devlist[i].model))) { >+ found = 1; >+ break; >+ } >+ } >+ return found; >+} >+ >+/* >+ * 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 = NULL; >+ struct scsi_dh_devinfo_list *tmp; >+ >+ found_dh = scsi_dh_cache_lookup(sdev); >+ if (found_dh) >+ return found_dh; >+ >+ if (scsi_dh) { >+ if (scsi_dh_handler_lookup(scsi_dh, sdev)) >+ found_dh = scsi_dh; >+ } else { >+ struct scsi_device_handler *tmp_dh; >+ >+ spin_lock(&list_lock); >+ list_for_each_entry(tmp_dh, &scsi_dh_list, list) { >+ if (scsi_dh_handler_lookup(tmp_dh, sdev)) >+ found_dh = tmp_dh; >+ } >+ spin_unlock(&list_lock); >+ } >+ >+ if (found_dh) { /* If device is found, add it to the cache */ >+ tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); >+ if (tmp) { >+ strncpy(tmp->vendor, sdev->vendor, 8); >+ strncpy(tmp->model, sdev->model, 16); >+ tmp->vendor[8] = '\0'; >+ tmp->model[16] = '\0'; >+ tmp->handler = found_dh; >+ spin_lock(&list_lock); >+ list_add(&tmp->node, &scsi_dh_dev_list); >+ spin_unlock(&list_lock); >+ } else { >+ 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) >+{ >+ int err = 0; >+ struct scsi_dh_data *scsi_dh_data = retrieve_scsi_dh_data(sdev); >+ >+ if (scsi_dh_data) { >+ if (scsi_dh_data->scsi_dh != scsi_dh) >+ err = -EBUSY; >+ } else if (scsi_dh->attach) >+ err = scsi_dh->attach(sdev); >+ >+ return err; >+} >+ >+/* >+ * 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) >+{ >+ struct scsi_dh_data *scsi_dh_data = retrieve_scsi_dh_data(sdev); >+ >+ if (!scsi_dh_data) >+ return; >+ >+ if (scsi_dh && scsi_dh != scsi_dh_data->scsi_dh) >+ return; >+ >+ if (!scsi_dh) >+ scsi_dh = scsi_dh_data->scsi_dh; >+ >+ if (scsi_dh && scsi_dh->detach) >+ scsi_dh->detach(sdev); >+} >+ >+/* >+ * 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_dh_data *scsi_dh_data = retrieve_scsi_dh_data(sdev); >+ struct scsi_device_handler *scsi_dh; >+ int err = -EINVAL; >+ >+ if (!scsi_dh_data) { >+ /* >+ * Attach to a device handler >+ */ >+ if (!(scsi_dh = get_device_handler(buf))) >+ return err; >+ err = scsi_dh_handler_attach(sdev, scsi_dh); >+ } else { >+ scsi_dh = scsi_dh_data->scsi_dh; >+ if (!strncmp(buf, "detach", 6)) { >+ /* >+ * Detach from a device handler >+ */ >+ scsi_dh_handler_detach(sdev, scsi_dh); >+ err = 0; >+ } else if (!strncmp(buf, "activate", 8)) { >+ /* >+ * Activate a device handler >+ */ >+ if (scsi_dh->activate) >+ err = scsi_dh->activate(sdev); >+ 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); >+ struct scsi_dh_data *scsi_dh_data = retrieve_scsi_dh_data(sdev); >+ >+ if (!scsi_dh_data) >+ return snprintf(buf, 20, "detached\n"); >+ >+ return snprintf(buf, 20, "%s\n", 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) { >+ devinfo = device_handler_match(NULL, sdev); >+ if (!devinfo) >+ goto out; >+ >+ err = scsi_dh_handler_attach(sdev, devinfo); >+ if (!err) >+ err = device_create_file(dev, &scsi_dh_state_attr); >+ } else if (action == BUS_NOTIFY_DEL_DEVICE) { >+ device_remove_file(dev, &scsi_dh_state_attr); >+ scsi_dh_handler_detach(sdev, NULL); >+ } >+out: >+ 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); >+ >+ scsi_dh_handler_detach(sdev, scsi_dh); >+ >+ 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 (get_device_handler(scsi_dh->name)) >+ return -EBUSY; >+ >+ 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) >+{ >+ struct scsi_dh_devinfo_list *tmp, *pos; >+ >+ if (!get_device_handler(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); >+ list_for_each_entry_safe(pos, tmp, &scsi_dh_dev_list, node) { >+ if (pos->handler == scsi_dh) { >+ list_del(&pos->node); >+ kfree(pos); >+ } >+ } >+ 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. >+ * @q - Request queue that is associated with the scsi_device to be >+ * activated. >+ */ >+int scsi_dh_activate(struct request_queue *q) >+{ >+ int err = 0; >+ unsigned long flags; >+ struct scsi_device *sdev; >+ struct scsi_device_handler *scsi_dh = NULL; >+ struct scsi_dh_data *data; >+ >+ spin_lock_irqsave(q->queue_lock, flags); >+ sdev = q->queuedata; >+ if (sdev && ((data = retrieve_scsi_dh_data(sdev)) != NULL)) >+ scsi_dh = data->scsi_dh; >+ if (!scsi_dh || !get_device(&sdev->sdev_gendev)) >+ err = SCSI_DH_NOSYS; >+ spin_unlock_irqrestore(q->queue_lock, flags); >+ >+ if (err) >+ return err; >+ >+ if (scsi_dh->activate) >+ err = scsi_dh->activate(sdev); >+ put_device(&sdev->sdev_gendev); >+ return err; >+} >+EXPORT_SYMBOL_GPL(scsi_dh_activate); >+ >+/* >+ * 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_handler_attach - Attach device handler >+ * @sdev - sdev 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 = get_device_handler(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) { >+ err = scsi_dh_handler_attach(sdev, scsi_dh); >+ >+ put_device(&sdev->sdev_gendev); >+ } >+ return err; >+} >+EXPORT_SYMBOL_GPL(scsi_dh_attach); >+ >+/* >+ * scsi_dh_handler_detach - Detach device handler >+ * @sdev - sdev 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; >+ struct scsi_dh_data *scsi_dh_data; >+ >+ 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; >+ >+ scsi_dh_data = retrieve_scsi_dh_data(sdev); >+ if (scsi_dh_data) { >+ /* if sdev is not on internal list, detach */ >+ scsi_dh = scsi_dh_data->scsi_dh; >+ if (!device_handler_match(scsi_dh, sdev)) >+ scsi_dh_handler_detach(sdev, scsi_dh); >+ } >+ put_device(&sdev->sdev_gendev); >+} >+EXPORT_SYMBOL_GPL(scsi_dh_detach); >+ >+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"); >Index: linux-2.6.18.ppc64/include/scsi/scsi_dh.h >=================================================================== >--- /dev/null >+++ linux-2.6.18.ppc64/include/scsi/scsi_dh.h >@@ -0,0 +1,91 @@ >+/* >+ * Header file for SCSI device handler infrastruture. >+ * >+ * Modified version of patches posted by Mike Christie <michaelc@cs.wisc.edu> >+ * >+ * 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/blkdev.h> >+#include <scsi/scsi_device.h> >+ >+enum { >+ SCSI_DH_OK = 0, >+ /* >+ * device errors >+ */ >+ SCSI_DH_DEV_FAILED, /* generic device error */ >+ SCSI_DH_DEV_TEMP_BUSY, >+ SCSI_DH_DEVICE_MAX, /* max device blkerr definition */ >+ >+ /* >+ * transport errors >+ */ >+ SCSI_DH_NOTCONN = SCSI_DH_DEVICE_MAX + 1, >+ SCSI_DH_CONN_FAILURE, >+ SCSI_DH_TRANSPORT_MAX, /* max transport blkerr definition */ >+ >+ /* >+ * driver and generic errors >+ */ >+ SCSI_DH_IO = SCSI_DH_TRANSPORT_MAX + 1, /* generic error */ >+ SCSI_DH_INVALID_IO, >+ SCSI_DH_RETRY, /* retry the req, but not immediately */ >+ SCSI_DH_IMM_RETRY, /* immediately retry the req */ >+ SCSI_DH_TIMED_OUT, >+ SCSI_DH_RES_TEMP_UNAVAIL, >+ SCSI_DH_DEV_OFFLINED, >+ SCSI_DH_NOSYS, >+ SCSI_DH_DRIVER_MAX, >+}; >+ >+#if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE) >+extern int scsi_dh_activate(struct request_queue *); >+extern int scsi_dh_handler_exist(const char *); >+extern void store_scsi_dh_data(struct scsi_device *, struct scsi_dh_data *); >+extern struct scsi_dh_data *retrieve_scsi_dh_data(struct scsi_device *); >+extern int scsi_dh_attach(struct request_queue *, const char *); >+extern void scsi_dh_detach(struct request_queue *); >+#else >+static inline int scsi_dh_activate(struct request_queue *req) >+{ >+ return 0; >+} >+static inline int scsi_dh_handler_exist(const char *name) >+{ >+ return 0; >+} >+static inline void store_scsi_dh_data(struct scsi_device *sdev, >+ struct scsi_dh_data *scsi_dh_data) >+{ >+} >+static inline struct scsi_dh_data *retrieve_scsi_dh_data(struct scsi_device *sdev) >+{ >+ return NULL; >+} >+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; >+} >+#endif >Index: linux-2.6.18.ppc64/include/scsi/scsi.h >=================================================================== >--- linux-2.6.18.ppc64.orig/include/scsi/scsi.h >+++ linux-2.6.18.ppc64/include/scsi/scsi.h >@@ -347,6 +347,7 @@ struct scsi_lun { > #define SOFT_ERROR 0x2005 > #define ADD_TO_MLQUEUE 0x2006 > #define TIMEOUT_ERROR 0x2007 >+#define SCSI_RETURN_NOT_HANDLED 0x2008 > > /* > * Midlevel queue return values. >Index: linux-2.6.18.ppc64/drivers/scsi/scsi_sysfs.c >=================================================================== >--- linux-2.6.18.ppc64.orig/drivers/scsi/scsi_sysfs.c >+++ linux-2.6.18.ppc64/drivers/scsi/scsi_sysfs.c >@@ -313,6 +313,7 @@ struct bus_type scsi_bus_type = { > .suspend = scsi_bus_suspend, > .resume = scsi_bus_resume, > }; >+EXPORT_SYMBOL_GPL(scsi_bus_type); > > int scsi_sysfs_register(void) > { >Index: linux-2.6.18.ppc64/drivers/scsi/scsi_lib.c >=================================================================== >--- linux-2.6.18.ppc64.orig/drivers/scsi/scsi_lib.c >+++ linux-2.6.18.ppc64/drivers/scsi/scsi_lib.c >@@ -25,6 +25,7 @@ > #include <scsi/scsi_driver.h> > #include <scsi/scsi_eh.h> > #include <scsi/scsi_host.h> >+#include <scsi/scsi_dh.h> > > #include "scsi_priv.h" > #include "scsi_logging.h" >@@ -1104,6 +1105,7 @@ static int scsi_prep_fn(struct request_q > struct scsi_device *sdev = q->queuedata; > struct scsi_cmnd *cmd; > int specials_only = 0; >+ struct scsi_dh_data *scsi_dh_data = retrieve_scsi_dh_data(sdev); > > /* > * Just check to see if the device is online. If it isn't, we >@@ -1131,6 +1133,18 @@ static int scsi_prep_fn(struct request_q > } > > /* >+ * If it is a filesystem cmd, call the prep_fn of the >+ * hardware handler. >+ */ >+ if (blk_fs_request(req) && >+ unlikely(scsi_dh_data && scsi_dh_data->scsi_dh >+ && scsi_dh_data->scsi_dh->prep_fn)) { >+ int ret = scsi_dh_data->scsi_dh->prep_fn(sdev, req); >+ if (ret != BLKPREP_OK) >+ return ret; >+ } >+ >+ /* > * Find the actual device driver associated with this command. > * The SPECIAL requests are things like character device or > * ioctls, which did not originate from ll_rw_blk. Note that >Index: linux-2.6.18.ppc64/drivers/scsi/Makefile >=================================================================== >--- linux-2.6.18.ppc64.orig/drivers/scsi/Makefile >+++ linux-2.6.18.ppc64/drivers/scsi/Makefile >@@ -33,6 +33,7 @@ obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_tra > obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o > obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o > obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/ >+obj-y += device_handler/ > > obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o > obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o >@@ -144,7 +145,7 @@ obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o > scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \ > scsicam.o scsi_error.o scsi_lib.o \ > scsi_scan.o scsi_sysfs.o \ >- scsi_devinfo.o >+ scsi_devinfo.o scsi_dh_export.o > scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o > scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o > scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o >Index: linux-2.6.18.ppc64/drivers/scsi/scsi_dh_export.c >=================================================================== >--- /dev/null >+++ linux-2.6.18.ppc64/drivers/scsi/scsi_dh_export.c >@@ -0,0 +1,36 @@ >+/* >+ * SCSI device handler infrastruture - export symbols used by scsi generic >+ * >+ * 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, 2008 >+ * Authors: >+ * Chandra Seetharaman <sekharan@us.ibm.com> >+ */ >+ >+#include <scsi/scsi_dh.h> >+ >+void store_scsi_dh_data(struct scsi_device *sdev, struct scsi_dh_data *data) >+{ >+ sdev->scsi_dh_data = data; >+} >+EXPORT_SYMBOL_GPL(store_scsi_dh_data); >+ >+struct scsi_dh_data *retrieve_scsi_dh_data(struct scsi_device *sdev) >+{ >+ return sdev->scsi_dh_data; >+} >+EXPORT_SYMBOL_GPL(retrieve_scsi_dh_data); >+
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 438761
:
314153
|
314154
| 314155 |
314156
|
314157
|
314158
|
314159
|
314160
|
314161
|
314162
|
314163
|
314339
|
314426
|
314828
|
314829
|
316641