static struct proc_dir_entry *proc_scsi;
 
-/* Protect sht->present and sht->proc_dir */
+/* Protects scsi_proc_list */
 static DEFINE_MUTEX(global_host_template_mutex);
+static LIST_HEAD(scsi_proc_list);
+
+/**
+ * struct scsi_proc_entry - (host template, SCSI proc dir) association
+ * @entry: entry in scsi_proc_list.
+ * @sht: SCSI host template associated with the procfs directory.
+ * @proc_dir: procfs directory associated with the SCSI host template.
+ * @present: Number of SCSI hosts instantiated for @sht.
+ */
+struct scsi_proc_entry {
+       struct list_head        entry;
+       const struct scsi_host_template *sht;
+       struct proc_dir_entry   *proc_dir;
+       unsigned int            present;
+};
 
 static ssize_t proc_scsi_host_write(struct file *file, const char __user *buf,
                            size_t count, loff_t *ppos)
                                4 * PAGE_SIZE);
 }
 
+static struct scsi_proc_entry *
+__scsi_lookup_proc_entry(const struct scsi_host_template *sht)
+{
+       struct scsi_proc_entry *e;
+
+       lockdep_assert_held(&global_host_template_mutex);
+
+       list_for_each_entry(e, &scsi_proc_list, entry)
+               if (e->sht == sht)
+                       return e;
+
+       return NULL;
+}
+
+static struct scsi_proc_entry *
+scsi_lookup_proc_entry(const struct scsi_host_template *sht)
+{
+       struct scsi_proc_entry *e;
+
+       mutex_lock(&global_host_template_mutex);
+       e = __scsi_lookup_proc_entry(sht);
+       mutex_unlock(&global_host_template_mutex);
+
+       return e;
+}
+
 /**
  * scsi_template_proc_dir() - returns the procfs dir for a SCSI host template
  * @sht: SCSI host template pointer.
 struct proc_dir_entry *
 scsi_template_proc_dir(const struct scsi_host_template *sht)
 {
-       return sht->proc_dir;
+       struct scsi_proc_entry *e = scsi_lookup_proc_entry(sht);
+
+       return e ? e->proc_dir : NULL;
 }
 EXPORT_SYMBOL_GPL(scsi_template_proc_dir);
 
  *
  * Sets sht->proc_dir to the new directory.
  */
-int scsi_proc_hostdir_add(struct scsi_host_template *sht)
+int scsi_proc_hostdir_add(const struct scsi_host_template *sht)
 {
-       int ret = 0;
+       struct scsi_proc_entry *e;
+       int ret;
 
        if (!sht->show_info)
                return 0;
 
        mutex_lock(&global_host_template_mutex);
-       if (!sht->present++) {
-               sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi);
-               if (!sht->proc_dir) {
-                       printk(KERN_ERR "%s: proc_mkdir failed for %s\n",
-                              __func__, sht->proc_name);
+       e = __scsi_lookup_proc_entry(sht);
+       if (!e) {
+               e = kzalloc(sizeof(*e), GFP_KERNEL);
+               if (!e) {
                        ret = -ENOMEM;
+                       goto unlock;
                }
        }
+       if (e->present++)
+               goto success;
+       e->proc_dir = proc_mkdir(sht->proc_name, proc_scsi);
+       if (!e->proc_dir) {
+               printk(KERN_ERR "%s: proc_mkdir failed for %s\n", __func__,
+                      sht->proc_name);
+               ret = -ENOMEM;
+               goto unlock;
+       }
+       e->sht = sht;
+       list_add_tail(&e->entry, &scsi_proc_list);
+success:
+       e = NULL;
+       ret = 0;
+unlock:
        mutex_unlock(&global_host_template_mutex);
 
+       kfree(e);
        return ret;
 }
 
  * scsi_proc_hostdir_rm - remove directory in /proc for a scsi host
  * @sht: owner of directory
  */
-void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
+void scsi_proc_hostdir_rm(const struct scsi_host_template *sht)
 {
+       struct scsi_proc_entry *e;
+
        if (!sht->show_info)
                return;
 
        mutex_lock(&global_host_template_mutex);
-       if (!--sht->present && sht->proc_dir) {
+       e = __scsi_lookup_proc_entry(sht);
+       if (e && !--e->present) {
                remove_proc_entry(sht->proc_name, proc_scsi);
-               sht->proc_dir = NULL;
+               list_del(&e->entry);
+               kfree(e);
        }
        mutex_unlock(&global_host_template_mutex);
 }
  */
 void scsi_proc_host_add(struct Scsi_Host *shost)
 {
-       struct scsi_host_template *sht = shost->hostt;
+       const struct scsi_host_template *sht = shost->hostt;
+       struct scsi_proc_entry *e;
        struct proc_dir_entry *p;
        char name[10];
 
-       if (!sht->proc_dir)
+       if (!sht->show_info)
                return;
 
+       e = scsi_lookup_proc_entry(sht);
+       if (!e)
+               goto err;
+
        sprintf(name,"%d", shost->host_no);
-       p = proc_create_data(name, S_IRUGO | S_IWUSR,
-               sht->proc_dir, &proc_scsi_ops, shost);
+       p = proc_create_data(name, S_IRUGO | S_IWUSR, e->proc_dir,
+                            &proc_scsi_ops, shost);
        if (!p)
-               printk(KERN_ERR "%s: Failed to register host %d in"
-                      "%s\n", __func__, shost->host_no,
-                      sht->proc_name);
+               goto err;
+       return;
+
+err:
+       shost_printk(KERN_ERR, shost,
+                    "%s: Failed to register host (%s failed)\n", __func__,
+                    e ? "proc_create_data()" : "scsi_proc_hostdir_add()");
 }
 
 /**
  */
 void scsi_proc_host_rm(struct Scsi_Host *shost)
 {
+       const struct scsi_host_template *sht = shost->hostt;
+       struct scsi_proc_entry *e;
        char name[10];
 
-       if (!shost->hostt->proc_dir)
+       if (!sht->show_info)
+               return;
+
+       e = scsi_lookup_proc_entry(sht);
+       if (!e)
                return;
 
        sprintf(name,"%d", shost->host_no);
-       remove_proc_entry(name, shost->hostt->proc_dir);
+       remove_proc_entry(name, e->proc_dir);
 }
 /**
  * proc_print_scsidevice - return data about this host