linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Advanced TCA SCSI/FC disk hotswap driver for kernel 2.5.44
@ 2002-10-23 23:27 Steven Dake
  2002-10-24  0:18 ` Greg KH
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Steven Dake @ 2002-10-23 23:27 UTC (permalink / raw)
  To: linux-kernel; +Cc: greg, alan

lkml,

Attached is an update of the Advanced TCA disk hotswap driver to provide 
disk hotswap
support for the Linux Kernel 2.5.43.  Hotswap targets include both SCSI 
and FibreChannel.
Note this support is generic in that it will work in a typical PC system 
with SCSI or
FibreChannel disks.

I've not yet ported or made suggested changes to the ga mapping driver 
yet.  I'll work on
that next.

As always, the latest Advanced TCA hotswap patches are available for 
Linux 2.4 and Linux 2.5
at the sourceforge site: (please note ga mapper hasn't yet been ported 
to 2.5)
http://sourceforge.net/project/showfiles.php?group_id=64580

Changes from kernel 2.4.19 to 2.5.44 release:
* Complete port to linux kernel 2.5.44
* Locking of scsi_host->host_queue structure when traversing scsi device 
list (suggested by Alan Cox)
   - This keeps multiple hotswap commands from corrupting the SCSI 
device list and
     causing system failure
* ioctls deleted and replaced by ramfs scsi_hotswap_fs (suggested by 
Greg KH)
   - removes need for character device node
   - usage information available by read() call to files
   - available over nfs exported directories
* local file-scope functions declared as static instead of global 
(suggested by Greg KH)
* code reformatted to fit on 80 character wide screen and to follow 
linux general kernel
   instead of scsi subsystem format
* KERNEL_SYSCALLS define removed from header (suggested by Greg KH)
* list of include files optimized to only include files as needed
* Removed direct call from scsi.c into scsi_hotswap_init and used 
module_init instead
* Made modular so can be compiled as a module or in the kernel directly
* Fixed bug where scsi_hotswap_insert_by_scsi_id didn't properly add a 
device in some cases


******************************************************


diff -uNr linux-2.5.44-qla/MAINTAINERS 
linux-2.5.44-scsi-hotswap/MAINTAINERS
--- linux-2.5.44-qla/MAINTAINERS    Fri Oct 18 21:01:59 2002
+++ linux-2.5.44-scsi-hotswap/MAINTAINERS    Wed Oct 23 11:44:05 2002
@@ -1418,6 +1418,12 @@
W:    http://www.kernel.dk
S:    Maintained

+SCSI HOTSWAP DRIVER
+P:    Steven Dake
+M:    sdake@mvista.com
+L:    linux-kernel@vger.kernel.org
+S:    Maintained
+
SCSI SG DRIVER
P:    Doug Gilbert
M:    dgilbert@interlog.com
diff -uNr linux-2.5.44-qla/drivers/scsi/Config.help 
linux-2.5.44-scsi-hotswap/drivers/scsi/Config.help
--- linux-2.5.44-qla/drivers/scsi/Config.help    Wed Oct 23 10:26:12 2002
+++ linux-2.5.44-scsi-hotswap/drivers/scsi/Config.help    Wed Oct 23 
11:44:06 2002
@@ -34,6 +34,17 @@
  is located on a SCSI disk. In this case, do not compile the driver
  for your SCSI host adapter (below) as a module either.

+CONFIG_SCSIFCHOTSWAP
+ If you want to support the ability to include the hotswap FibreChannel
+ and SCSI driver, please say yes here.  Hotswap can then be executed
+ through a ramfs interface which provides better error reporting.
+
+ Further, this interface supports insertion and removal by WWN for
+ FibreChannel drivers which support this feature.
+
+ The only FibreChannel driver that supports this feature is Qlogic V6
+ with a specific support patch.
+
CONFIG_SD_EXTRA_DEVS
  This controls the amount of additional space allocated in tables for
  drivers that are loaded as modules after the kernel is booted.  In
diff -uNr linux-2.5.44-qla/drivers/scsi/Config.in 
linux-2.5.44-scsi-hotswap/drivers/scsi/Config.in
--- linux-2.5.44-qla/drivers/scsi/Config.in    Wed Oct 23 10:26:12 2002
+++ linux-2.5.44-scsi-hotswap/drivers/scsi/Config.in    Wed Oct 23 
11:44:06 2002
@@ -1,5 +1,6 @@
comment 'SCSI support type (disk, tape, CD-ROM)'

+dep_tristate '  SCSI hotswap support' CONFIG_SCSIFCHOTSWAP $CONFIG_SCSI
dep_tristate '  SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI

if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then
diff -uNr linux-2.5.44-qla/drivers/scsi/Makefile 
linux-2.5.44-scsi-hotswap/drivers/scsi/Makefile
--- linux-2.5.44-qla/drivers/scsi/Makefile    Wed Oct 23 10:26:12 2002
+++ linux-2.5.44-scsi-hotswap/drivers/scsi/Makefile    Wed Oct 23 
11:44:06 2002
@@ -117,6 +117,7 @@

obj-$(CONFIG_ARCH_ACORN)    += ../acorn/scsi/

+obj-$(CONFIG_SCSIFCHOTSWAP)    += hotswap.o
obj-$(CONFIG_CHR_DEV_ST)    += st.o
obj-$(CONFIG_CHR_DEV_OSST)    += osst.o
obj-$(CONFIG_BLK_DEV_SD)    += sd_mod.o
diff -uNr linux-2.5.44-qla/drivers/scsi/hosts.c 
linux-2.5.44-scsi-hotswap/drivers/scsi/hosts.c
--- linux-2.5.44-qla/drivers/scsi/hosts.c    Fri Oct 18 21:01:09 2002
+++ linux-2.5.44-scsi-hotswap/drivers/scsi/hosts.c    Wed Oct 23 
15:35:30 2002
@@ -371,6 +371,7 @@
    scsi_hosts_registered++;

    spin_lock_init(&shost->default_lock);
+    spin_lock_init(&shost->host_queue_lock);
    scsi_assign_lock(shost, &shost->default_lock);
    atomic_set(&shost->host_active,0);

diff -uNr linux-2.5.44-qla/drivers/scsi/hosts.h 
linux-2.5.44-scsi-hotswap/drivers/scsi/hosts.h
--- linux-2.5.44-qla/drivers/scsi/hosts.h    Fri Oct 18 21:01:21 2002
+++ linux-2.5.44-scsi-hotswap/drivers/scsi/hosts.h    Wed Oct 23 
15:24:39 2002
@@ -264,6 +264,14 @@
     */
    int (* bios_param)(Disk *, struct block_device *, int []);

+#ifdef CONFIG_SCSIFCHOTSWAP
+    /*
+     * Used to determine the id to send the inquiry command to during
+     * hot additions of FibreChannel targets
+     */
+    int (*get_scsi_info_from_wwn)(int mode, unsigned long long wwn, int 
*host, int *channel, int *lun, int *id);
+#endif
+
    /*
     * This determines if we will use a non-interrupt driven
     * or an interrupt driven scheme,  It is set to the maximum number
@@ -374,6 +382,7 @@
     */
    struct list_head      sh_list;
    Scsi_Device           * host_queue;
+    spinlock_t          host_queue_lock;
    struct list_head      all_scsi_hosts;
    struct list_head      my_devices;

diff -uNr linux-2.5.44-qla/drivers/scsi/hotswap.c 
linux-2.5.44-scsi-hotswap/drivers/scsi/hotswap.c
--- linux-2.5.44-qla/drivers/scsi/hotswap.c    Wed Dec 31 17:00:00 1969
+++ linux-2.5.44-scsi-hotswap/drivers/scsi/hotswap.c    Wed Oct 23 
15:28:15 2002
@@ -0,0 +1,1334 @@
+/*
+ * hotswap.c
+ *
+ * SCSI/FibreChannel Hotswap kernel implementaton
+ * + * Author: MontaVista Software, Inc.
+ *         Steven Dake (sdake@mvista.com)
+ *         source@mvista.com
+ *
+ * Copyright (C) 2002 MontaVista Software Inc.
+ *
+ * Derived from linux/scsi/scsi.c hotswap code
+ *
+ *     added FibreChannel hotswap by both WWN/host/channel/lun and WWN 
wildcard
+ *     added ramfs interface
+ *     added locking to scsi host queue structure (list of scsi devices 
on host)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
DAMAGE.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this program; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/types.h>
+#include <linux/dcache.h>
+#include <linux/namei.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/blk.h>
+#include <linux/spinlock.h>
+
+#include <asm/uaccess.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include <linux/scsi_hotswap.h>
+
+#define SCSI_HOTSWAP_MAGIC 0x02834431
+
+#define DRIVER_VERSION "0.9"
+#define DRIVER_AUTHOR "MontaVista Software Inc, Steven Dake 
<sdake@mvista.com>"
+#define DRIVER_DESCRIPTION "SCSI and FibreChannel Hotswap Core"
+
+static struct cmd_fs {
+    struct dentry *insert_by_scsi_id;
+    struct dentry *remove_by_scsi_id;
+    struct dentry *insert_by_fc_wwn;
+    struct dentry *remove_by_fc_wwn;
+    struct dentry *insert_by_fc_wwn_wildcard;
+    struct dentry *remove_by_fc_wwn_wildcard;
+} scsi_hotswap_cmd_fs;
+
+static struct super_operations scsi_hotswap_super_operations;
+static struct file_operations default_file_operations;
+static struct inode_operations scsi_hotswap_dir_inode_operations;
+
+static struct vfsmount *scsi_hotswap_mountpoint;
+
+/*
+ * Default file operations
+ */
+static int scsi_hotswap_statfs (struct super_block *sb, struct statfs 
*buf)
+{
+    buf->f_type = SCSI_HOTSWAP_MAGIC;
+    buf->f_bsize = PAGE_CACHE_SIZE;
+    buf->f_namelen = 255;
+    return (0);
+}
+
+static struct dentry *scsi_hotswap_lookup (struct inode *dir,
+    struct dentry *dentry)
+{
+    d_add (dentry, NULL);
+    return (NULL);
+}
+
+static struct inode *scsi_hotswap_get_inode (struct super_block *sb, 
int mode,
+    int dev)
+{
+    struct inode *inode = new_inode(sb);
+
+    if (inode) {
+        inode->i_mode = mode;
+        inode->i_uid = current->fsuid;
+        inode->i_gid = current->fsgid;
+        inode->i_blksize = PAGE_CACHE_SIZE;
+        inode->i_blocks = 0;
+        inode->i_rdev = NODEV;
+        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+        switch (mode & S_IFMT) {
+        default:
+            init_special_inode (inode, mode, dev);
+            break;
+
+        case S_IFREG:
+            inode->i_fop = &default_file_operations;
+            break;
+        case S_IFDIR:
+            inode->i_op = &scsi_hotswap_dir_inode_operations;
+            inode->i_fop = &simple_dir_operations;
+            inode->i_nlink++;
+            break;
+        }
+    }
+    return (inode);
+}
+
+static int scsi_hotswap_mknod (struct inode *dir, struct dentry *dentry,
+    int mode, int dev)
+{
+    struct inode *inode = scsi_hotswap_get_inode (dir->i_sb, mode, dev);
+    int error = -ENOSPC;
+
+    if (inode) {
+        d_instantiate (dentry, inode);
+        dget (dentry);
+        error = 0;
+    }
+    return (error);
+}
+
+static int scsi_hotswap_mkdir (struct inode *dir, struct dentry *dentry,
+    int mode)
+{
+    return (scsi_hotswap_mknod (dir, dentry, mode | S_IFDIR, 0));
+}
+
+static int scsi_hotswap_create (struct inode *dir, struct dentry *dentry,
+    int mode)
+{
+    return (scsi_hotswap_mknod (dir, dentry, mode | S_IFREG, 0));
+}
+
+static int scsi_hotswap_link (struct dentry *old_dentry, struct inode 
*dir,
+    struct dentry *dentry)
+{
+    struct inode *inode = old_dentry->d_inode;
+
+    if (S_ISDIR(inode->i_mode)) {
+        return (-EPERM);
+    }
+
+    inode->i_nlink++;
+    atomic_inc (&inode->i_count);
+    dget (dentry);
+    d_instantiate (dentry, inode);
+
+    return (0);
+}
+
+static inline int scsi_hotswap_positive (struct dentry *dentry)
+{
+    return (dentry->d_inode && !d_unhashed (dentry));
+}
+
+static int scsi_hotswap_empty (struct dentry *dentry)
+{
+    struct list_head *list;
+
+    spin_lock(&dcache_lock);
+
+    list_for_each (list, &dentry->d_subdirs) {
+        struct dentry *de = list_entry(list, struct dentry, d_child);
+        if (scsi_hotswap_positive (de)) {
+            spin_unlock (&dcache_lock);
+            return 0;
+        }
+        }
+
+    spin_unlock(&dcache_lock);
+    return (1);
+}
+
+static int scsi_hotswap_unlink (struct inode *dir, struct dentry *dentry)
+{
+    int error = -ENOTEMPTY;
+
+    if (scsi_hotswap_empty (dentry)) {
+        struct inode *inode = dentry->d_inode;
+
+        inode->i_nlink--;
+        dput (dentry);
+        error = 0;
+    }
+    return (error);
+}
+
+static int scsi_hotswap_rename (struct inode *old_dir,
+    struct dentry *old_dentry, struct inode *new_dir,
+    struct dentry *new_dentry)
+{
+    int error = -ENOTEMPTY;
+
+    if (scsi_hotswap_empty (new_dentry)) {
+        struct inode *inode = new_dentry->d_inode;
+        if (inode) {
+            inode->i_nlink--;
+            dput (new_dentry);
+        }
+        error = 0;
+    }
+
+    return (error);
+}
+
+#define scsi_hotswap_rmdir scsi_hotswap_unlink
+
+static ssize_t default_read_file (struct file *file, char *buf, size_t 
count,
+    loff_t *ppos)
+{
+    return (0);
+}
+
+static ssize_t default_write_file (struct file *file, const char *buf,
+    size_t count, loff_t *ppos)
+{
+    return (count);
+}
+
+static loff_t default_file_lseek (struct file *file, loff_t offset, int 
orig)
+{
+    loff_t retval = -EINVAL;
+
+    switch(orig) {
+    case 0:
+        if (offset > 0) {
+            file->f_pos = offset;
+            retval = file->f_pos;
+        }
+        break;
+    case 1:
+        if ((offset + file->f_pos) > 0) {
+            file->f_pos += offset;
+            retval = file->f_pos;
+        }
+        break;
+    default:
+        break;
+    }
+
+    return (retval);
+}
+
+static int default_open (struct inode *inode, struct file *filp)
+{
+    if (inode->u.generic_ip) {
+        filp->private_data = inode->u.generic_ip;
+    }
+    return (0);
+}
+
+static int default_sync_file (struct file *file, struct dentry *dentry,
+    int datasync)
+{
+    return (0);
+}
+
+static struct file_operations default_file_operations = {
+    read:        default_read_file,
+    write:         default_write_file,
+    open:        default_open,
+    llseek:        default_file_lseek,
+    fsync:         default_sync_file,
+    mmap:         generic_file_mmap,
+};
+
+static struct inode_operations scsi_hotswap_dir_inode_operations = {
+    create:        scsi_hotswap_create,
+    lookup:        scsi_hotswap_lookup,
+    link:        scsi_hotswap_link,
+    unlink:        scsi_hotswap_unlink,
+    mkdir:        scsi_hotswap_mkdir,
+    rmdir:        scsi_hotswap_rmdir,
+    mknod:        scsi_hotswap_mknod,
+    rename:        scsi_hotswap_rename,
+};
+
+static struct super_operations scsi_hotswap_super_operations = {
+    statfs:        scsi_hotswap_statfs,
+    drop_inode:    generic_delete_inode,
+/* IFDEF LINUX-2.4 +    put_inode:    force_delete,
+*/
+};
+
+/*
+ * scsi_hotswap_insert_by_scsi_id file operations structure
+ */
+static ssize_t scsi_hotswap_insert_by_scsi_id_read_file (struct file 
*file,
+    char *buf, size_t count, loff_t *offset);
+static ssize_t scsi_hotswap_insert_by_scsi_id_write_file (struct file 
*file,
+    const char *buf, size_t count, loff_t *ppos);
+
+static struct file_operations 
scsi_hotswap_insert_by_scsi_id_file_operations = {
+    read:    scsi_hotswap_insert_by_scsi_id_read_file,
+    write:    scsi_hotswap_insert_by_scsi_id_write_file,
+    open:    default_open,
+    llseek:    default_file_lseek,
+    fsync:    default_sync_file,
+    mmap:    generic_file_mmap
+};
+
+/*
+ * scsi_hotswap_remove_by_scsi_id file operations structure
+ */
+static ssize_t scsi_hotswap_remove_by_scsi_id_read_file (struct file 
*file,
+    char *buf, size_t count, loff_t *offset);
+static ssize_t scsi_hotswap_remove_by_scsi_id_write_file (struct file 
*file,
+    const char *buf, size_t count, loff_t *ppos);
+
+static struct file_operations 
scsi_hotswap_remove_by_scsi_id_file_operations = {
+    read:    scsi_hotswap_remove_by_scsi_id_read_file,
+    write:    scsi_hotswap_remove_by_scsi_id_write_file,
+    open:    default_open,
+    llseek:    default_file_lseek,
+    fsync:    default_sync_file,
+    mmap:    generic_file_mmap
+};
+
+/*
+ * scsi_hotswap_insert_by_fc_wwn file operations structure
+ */
+static ssize_t scsi_hotswap_insert_by_fc_wwn_read_file (struct file *file,
+    char *buf, size_t count, loff_t *offset);
+static ssize_t scsi_hotswap_insert_by_fc_wwn_write_file (struct file 
*file,
+    const char *buf, size_t count, loff_t *ppos);
+
+static struct file_operations 
scsi_hotswap_insert_by_fc_wwn_file_operations = {
+    read:    scsi_hotswap_insert_by_fc_wwn_read_file,
+    write:    scsi_hotswap_insert_by_fc_wwn_write_file,
+    open:    default_open,
+    llseek:    default_file_lseek,
+    fsync:    default_sync_file,
+    mmap:    generic_file_mmap
+};
+
+/*
+ * scsi_hotswap_remove_by_fc_wwn file operations structure
+ */
+static ssize_t scsi_hotswap_remove_by_fc_wwn_read_file (struct file *file,
+    char *buf, size_t count, loff_t *offset);
+static ssize_t scsi_hotswap_remove_by_fc_wwn_write_file (struct file 
*file,
+    const char *buf, size_t count, loff_t *ppos);
+
+static struct file_operations 
scsi_hotswap_remove_by_fc_wwn_file_operations = {
+    read:    scsi_hotswap_remove_by_fc_wwn_read_file,
+    write:    scsi_hotswap_remove_by_fc_wwn_write_file,
+    open:    default_open,
+    llseek:    default_file_lseek,
+    fsync:    default_sync_file,
+    mmap:    generic_file_mmap
+};
+/*
+ * scsi_hotswap_insert_by_fc_wwn_wildcard file operations structure
+ */
+static ssize_t scsi_hotswap_insert_by_fc_wwn_wildcard_read_file (struct 
file *file,
+    char *buf, size_t count, loff_t *offset);
+static ssize_t scsi_hotswap_insert_by_fc_wwn_wildcard_write_file 
(struct file *file,
+    const char *buf, size_t count, loff_t *ppos);
+
+static struct file_operations 
scsi_hotswap_insert_by_fc_wwn_wildcard_file_operations = {
+    read:    scsi_hotswap_insert_by_fc_wwn_wildcard_read_file,
+    write:    scsi_hotswap_insert_by_fc_wwn_wildcard_write_file,
+    open:    default_open,
+    llseek:    default_file_lseek,
+    fsync:    default_sync_file,
+    mmap:    generic_file_mmap
+};
+
+/*
+ * scsi_hotswap_remove_by_fc_wwn_wildcard file operations structure
+ */
+static ssize_t scsi_hotswap_remove_by_fc_wwn_wildcard_read_file (struct 
file *file,
+    char *buf, size_t count, loff_t *offset);
+static ssize_t scsi_hotswap_remove_by_fc_wwn_wildcard_write_file 
(struct file *file,
+    const char *buf, size_t count, loff_t *ppos);
+
+static struct file_operations 
scsi_hotswap_remove_by_fc_wwn_wildcard_file_operations = {
+    read:    scsi_hotswap_remove_by_fc_wwn_wildcard_read_file,
+    write:    scsi_hotswap_remove_by_fc_wwn_wildcard_write_file,
+    open:    default_open,
+    llseek:    default_file_lseek,
+    fsync:    default_sync_file,
+    mmap:    generic_file_mmap
+};
+
+//static struct super_block *scsi_hotswap_read_super (struct 
super_block *sb, void *data, int silet) {
+static int scsi_hotswap_fill_super (struct super_block *sb, void *data,
+    int silet)
+{
+    struct inode *inode;
+    struct dentry *root;
+
+    sb->s_blocksize = PAGE_CACHE_SIZE;
+    sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+    sb->s_magic = SCSI_HOTSWAP_MAGIC;
+    sb->s_op = &scsi_hotswap_super_operations;
+    inode = scsi_hotswap_get_inode (sb, S_IFDIR | 0755, 0);
+
+    if (inode == 0) {
+        return (-ENOMEM);
+    }
+
+    root = d_alloc_root (inode);
+    if (root == 0) {
+        iput(inode);
+        return (-ENOMEM);
+    }
+    sb->s_root = root;
+
+    return (0);
+}
+
+static struct super_block *scsi_hotswap_get_sb (struct file_system_type 
*fs_type,
+    int flags, char *dev_name, void *data)
+{
+    return (get_sb_single (fs_type, flags, data, 
scsi_hotswap_fill_super));
+}   
+
+static struct file_system_type scsi_hotswap_fs_type = {
+    owner:        THIS_MODULE,
+    name:        "scsi_hotswap_fs",
+    get_sb:        scsi_hotswap_get_sb,
+    kill_sb:    kill_litter_super,
+};
+
+static int scsi_hotswap_fs_create_by_name (const char *name, mode_t mode,
+    struct dentry *parent, struct dentry **dentry)
+{
+    struct dentry *d = NULL;
+    struct qstr qstr;
+    int error;
+
+    if (parent == 0) {
+        parent = scsi_hotswap_mountpoint->mnt_sb->s_root;
+    }
+
+    if (parent == 0) {
+        return (-EINVAL);
+    }
+
+    *dentry = NULL;
+    qstr.name = name;
+    qstr.len = strlen (name);
+    qstr.hash = full_name_hash (name, qstr.len);
+
+    parent = dget (parent);
+
+    down (&parent->d_inode->i_sem);
+
+    d = lookup_hash (&qstr, parent);
+
+    error = PTR_ERR (d);
+    if (IS_ERR(d) == 0) {
+        switch (mode & S_IFMT) {
+            case 0:
+            case S_IFREG:
+                error = vfs_create (parent->d_inode, d, mode);
+                break;
+            case S_IFDIR:
+                error = vfs_mkdir (parent->d_inode, d, mode);
+                break;
+            default:
+                error = -EINVAL;
+        }
+        *dentry = d;
+    }
+    up (&parent->d_inode->i_sem);
+
+    dput (parent);
+
+    return (error);
+}
+
+static struct dentry *scsi_hotswap_fs_create_file (const char *name,
+    mode_t mode, struct dentry *parent,
+    struct file_operations *file_operations)
+{
+    struct dentry *dentry;
+    int error;
+
+    error = scsi_hotswap_fs_create_by_name (name, mode, parent, &dentry);
+    if (error) {
+        dentry = 0;
+    } else {
+        if (dentry->d_inode) {
+            if (file_operations) {
+                dentry->d_inode->i_fop = file_operations;
+            }
+        }
+    }
+
+    return (dentry);
+}
+
+static void fs_remove_file (struct dentry *dentry) {
+    struct dentry *parent = dentry->d_parent;
+
+    if (!parent || !parent->d_inode) {
+        return;
+    }
+
+    down (&parent->d_inode->i_sem);
+
+    if (scsi_hotswap_positive (dentry)) {
+        if (dentry->d_inode) {
+            if (S_ISDIR (dentry->d_inode->i_mode)) {
+                vfs_rmdir (parent->d_inode,dentry);
+            } else {
+                vfs_unlink (parent->d_inode,dentry);
+            }
+        }
+        dput (dentry);
+    }
+    up (&parent->d_inode->i_sem);
+}
+
+/*
+ * Core file read/write operations interfaces
+ */
+static char scsi_hotswap_insert_by_scsi_id_usage[] = {
+    "Usage: echo \"[host] [channel] [lun] [id]\" > insert_by_scsi_id\n"
+};
+
+static char scsi_hotswap_remove_by_scsi_id_usage[] = {
+    "Usage: echo \"[host] [channel] [lun] [id]\" > remove_by_scsi_id\n"
+};
+
+static char scsi_hotswap_insert_by_fc_wwn_usage[]  = {
+    "Usage: echo \"[host] [channel] [lun] [wwn]\" > insert_by_fc_wwn\n"
+};
+
+static char scsi_hotswap_remove_by_fc_wwn_usage[]  = {
+    "Usage: echo \"[host] [channel] [lun] [wwn]\" > remove_by_fc_wwn\n"
+};
+
+static char scsi_hotswap_insert_by_fc_wwn_wildcard_usage[]  = {
+    "Usage: echo \"[wwn]\" > insert_by_fc_wwn_wildcard\n"
+};
+
+static char scsi_hotswap_remove_by_fc_wwn_wildcard_usage[]  = {
+    "Usage: echo \"[wwn]\" > remove_by_fc_wwn_wildcard\n"
+};
+
+static ssize_t scsi_hotswap_insert_by_scsi_id_read_file (struct file 
*file,
+    char *buf, size_t count, loff_t *offset)
+{
+    int len;
+
+    if (*offset) {
+        return (0);
+    }
+    len = strlen (scsi_hotswap_insert_by_scsi_id_usage);
+    if (copy_to_user (buf, scsi_hotswap_insert_by_scsi_id_usage, len)) {
+        return (-EFAULT);
+    }
+
+    *offset += len;
+    return (len);
+}
+
+static ssize_t scsi_hotswap_insert_by_scsi_id_write_file (struct file 
*file,
+    const char *buf, size_t count, loff_t *ppos)
+{
+    int host, channel, lun, id;
+    char parameters[1024];
+    char *p;
+    int result;
+
+    if (count == 0 || count > 1024) {
+        return (0);
+    }
+
+    if (copy_from_user ((void *)parameters, (void *)buf, count)) {
+        return (-EFAULT);
+    }
+
+    p = parameters;
+    host = simple_strtoul (p, &p, 0);
+    channel = simple_strtoul (p + 1, &p, 0);
+    lun = simple_strtoul (p + 1, &p, 0);
+    id = simple_strtoul (p + 1, &p, 0);
+
+    result = scsi_hotswap_insert_by_scsi_id (host, channel, lun, id);
+
+    if (result) {
+        return (result);
+    }
+    return (count);
+}
+
+static ssize_t scsi_hotswap_remove_by_scsi_id_read_file (struct file 
*file,
+    char *buf, size_t count, loff_t *offset)
+{
+    int len;
+
+    if (*offset) {
+        return (0);
+    }
+    len = strlen (scsi_hotswap_remove_by_scsi_id_usage);
+    if (copy_to_user (buf, scsi_hotswap_remove_by_scsi_id_usage, len)) {
+        return (-EFAULT);
+    }
+
+    *offset += len;
+    return (len);
+}
+
+static ssize_t scsi_hotswap_remove_by_scsi_id_write_file (struct file 
*file,
+    const char *buf, size_t count, loff_t *ppos)
+{
+    int host, channel, lun, id;
+    char parameters[1024];
+    char *p;
+    int result;
+
+    if (count == 0 || count > 1024) {
+        return (0);
+    }
+
+    if (copy_from_user ((void *)parameters, (void *)buf, count)) {
+        return (-EFAULT);
+    }
+
+    p = parameters;
+    host = simple_strtoul (p, &p, 0);
+    channel = simple_strtoul (p + 1, &p, 0);
+    lun = simple_strtoul (p + 1, &p, 0);
+    id = simple_strtoul (p + 1, &p, 0);
+
+    result = scsi_hotswap_remove_by_scsi_id (host, channel, lun, id);
+
+    if (result) {
+        return (result);
+    }
+    return (count);
+    return (-ENOMEM);
+}
+
+static ssize_t scsi_hotswap_insert_by_fc_wwn_read_file (struct file *file,
+    char *buf, size_t count, loff_t *offset)
+{
+    int len;
+
+    if (*offset) {
+        return (0);
+    }
+    len = strlen (scsi_hotswap_insert_by_fc_wwn_usage);
+    if (copy_to_user (buf, scsi_hotswap_insert_by_fc_wwn_usage, len)) {
+        return (-EFAULT);
+    }
+
+    *offset += len;
+    return (len);
+}
+
+static ssize_t scsi_hotswap_insert_by_fc_wwn_write_file (struct file 
*file,
+    const char *buf, size_t count, loff_t *ppos)
+{
+    int host, channel, lun;
+    unsigned long long wwn;
+    char parameters[1024];
+    char *p;
+    int result;
+
+    if (count == 0 || count > 1024) {
+        return (0);
+    }
+
+    if (copy_from_user ((void *)parameters, (void *)buf, count)) {
+        return (-EFAULT);
+    }
+
+    p = parameters;
+    host = simple_strtoul (p, &p, 0);
+    channel = simple_strtoul (p + 1, &p, 0);
+    lun = simple_strtoul (p + 1, &p, 0);
+    wwn = simple_strtoull (p + 1, &p, 0);
+
+    result = scsi_hotswap_insert_by_fc_wwn (host, channel, lun, wwn);
+
+    if (result) {
+        return (result);
+    }
+    return (count);
+}
+
+static ssize_t scsi_hotswap_remove_by_fc_wwn_read_file (struct file *file,
+    char *buf, size_t count, loff_t *offset)
+{
+    int len;
+
+    if (*offset) {
+        return (0);
+    }
+    len = strlen (scsi_hotswap_remove_by_fc_wwn_usage);
+
+    if (copy_to_user (buf, scsi_hotswap_remove_by_fc_wwn_usage, len)) {
+        return (-EFAULT);
+    }
+
+    *offset += len;
+    return (len);
+}
+
+static ssize_t scsi_hotswap_remove_by_fc_wwn_write_file (struct file 
*file,
+    const char *buf, size_t count, loff_t *ppos)
+{
+    int host, channel, lun;
+    unsigned long long wwn;
+    char parameters[1024];
+    char *p;
+    int result;
+
+    if (count == 0 || count > 1024) {
+        return (0);
+    }
+
+    if (copy_from_user ((void *)parameters, (void *)buf, count)) {
+        return (-EFAULT);
+    }
+
+    p = parameters;
+    host = simple_strtoul (p, &p, 0);
+    channel = simple_strtoul (p + 1, &p, 0);
+    lun = simple_strtoul (p + 1, &p, 0);
+    wwn = simple_strtoull (p + 1, &p, 0);
+
+    result = scsi_hotswap_remove_by_fc_wwn (host, channel, lun, wwn);
+
+    if (result) {
+        return (result);
+    }
+    return (count);
+}
+
+static ssize_t scsi_hotswap_insert_by_fc_wwn_wildcard_read_file (struct 
file *file,
+    char *buf, size_t count, loff_t *offset)
+{
+    int len;
+
+    if (*offset) {
+        return (0);
+    }
+    len = strlen (scsi_hotswap_insert_by_fc_wwn_wildcard_usage);
+    if (copy_to_user (buf, scsi_hotswap_insert_by_fc_wwn_wildcard_usage,
+        len)) {
+        return (-EFAULT);
+    }
+
+    *offset += len;
+    return (len);
+}
+
+static ssize_t scsi_hotswap_insert_by_fc_wwn_wildcard_write_file 
(struct file *file,
+    const char *buf, size_t count, loff_t *ppos)
+{
+    unsigned long long wwn;
+    char parameters[1024];
+    char *p;
+    int result;
+
+    if (count == 0 || count > 1024) {
+        return (0);
+    }
+
+    if (copy_from_user ((void *)parameters, (void *)buf, count)) {
+        return (-EFAULT);
+    }
+
+    p = parameters;
+    wwn = simple_strtoull (p, &p, 0);
+
+    result = scsi_hotswap_insert_by_fc_wwn_wildcard (wwn);
+
+    if (result) {
+        return (result);
+    }
+    return (count);
+    return (-ENOMEM);
+}
+
+static ssize_t scsi_hotswap_remove_by_fc_wwn_wildcard_read_file (struct 
file *file,
+    char *buf, size_t count, loff_t *offset)
+{
+    int len;
+
+    if (*offset) {
+        return (0);
+    }
+    len = strlen (scsi_hotswap_remove_by_fc_wwn_wildcard_usage);
+    if (copy_to_user (buf, scsi_hotswap_remove_by_fc_wwn_wildcard_usage,
+        len)) {
+        return (-EFAULT);
+    }
+
+    *offset += len;
+    return (len);
+}
+
+static ssize_t scsi_hotswap_remove_by_fc_wwn_wildcard_write_file 
(struct file *file,
+    const char *buf, size_t count, loff_t *ppos)
+{
+    unsigned long long wwn;
+    char parameters[1024];
+    char *p;
+    int result;
+
+    if (count == 0 || count > 1024) {
+        return (0);
+    }
+
+    if (copy_from_user ((void *)parameters, (void *)buf, count)) {
+        return (-EFAULT);
+    }
+
+    p = parameters;
+    wwn = simple_strtoull (p, &p, 0);
+
+    result = scsi_hotswap_remove_by_fc_wwn_wildcard (wwn);
+
+    if (result) {
+        return (result);
+    }
+    return (count);
+}
+
+/*
+ * Core Interface Implementation
+ * Note these are exported to the global symbol table for
+ * other subsystems to use such as a scsi processor or 1394
+ */
+int scsi_hotswap_insert_by_scsi_id (unsigned int host, unsigned int 
channel,
+    unsigned int lun, unsigned int id)
+{
+    struct Scsi_Host *scsi_host;
+    Scsi_Device *scsi_device;
+
+    for (scsi_host = scsi_host_get_next (NULL); scsi_host;
+        scsi_host = scsi_host_get_next (scsi_host)) {
+        if (scsi_host->host_no == host) {
+            break;
+        }
+    }
+    if (scsi_host == 0) {
+        return (-ENXIO);
+    }
+
+    spin_lock (&scsi_host->host_queue_lock);
+
+    /*
+     * Determine if device already attached
+     */
+    for (scsi_device = scsi_host->host_queue; scsi_device; scsi_device 
= scsi_device->next) {
+        if ((scsi_device->channel == channel
+             && scsi_device->id == id
+             && scsi_device->lun == lun)) {
+            break;
+        }
+    }
+   
+    spin_unlock (&scsi_host->host_queue_lock);
+
+    /*
+     * If scsi_device found in host queue, then device already attached
+     */
+    if (scsi_device) {
+        return (-EEXIST);
+    }
+
+    scan_scsis(scsi_host, 1, channel, id, lun);
+
+    return (0);
+}
+
+int scsi_hotswap_remove_by_scsi_id (unsigned int host, unsigned int 
channel,
+    unsigned int lun, unsigned int id)
+{
+    struct Scsi_Device_Template *scsi_template;
+    struct Scsi_Host *scsi_host;
+    Scsi_Device *scsi_device;
+
+    for (scsi_host = scsi_host_get_next (NULL); scsi_host;
+        scsi_host = scsi_host_get_next (scsi_host)) {
+        if (scsi_host->host_no == host) {
+            break;
+        }
+    }
+    if (scsi_host == 0) {
+        return (-ENODEV);
+    }
+
+    spin_lock (&scsi_host->host_queue_lock);
+
+    for (scsi_device = scsi_host->host_queue; scsi_device;
+        scsi_device = scsi_device->next) {
+        if ((scsi_device->channel == channel
+             && scsi_device->id == id
+             && scsi_device->lun == lun)) {
+            break;
+        }
+    }
+
+    spin_unlock (&scsi_host->host_queue_lock);
+
+    if (scsi_device == NULL) {
+        return (-ENOENT);
+    }
+
+    if (scsi_device->access_count) {
+        return (-EBUSY);
+    }
+
+    for (scsi_template = scsi_devicelist; scsi_template; scsi_template 
= scsi_template->next) {
+        if (scsi_template->detach) {
+            (*scsi_template->detach) (scsi_device);
+        }
+    }
+
+    if (scsi_device->attached == 0) {
+        /*
+         * Nobody is using this device any more.
+         * Free all of the command structures.
+         */
+        if (scsi_host->hostt->revoke)
+            scsi_host->hostt->revoke(scsi_device);
+        devfs_unregister (scsi_device->de);
+        scsi_release_commandblocks(scsi_device);
+
+        /* Now we can remove the device structure */
+        if (scsi_device->next != NULL)
+            scsi_device->next->prev = scsi_device->prev;
+
+        if (scsi_device->prev != NULL)
+            scsi_device->prev->next = scsi_device->next;
+
+        if (scsi_host->host_queue == scsi_device) {
+            scsi_host->host_queue = scsi_device->next;
+        }
+        blk_cleanup_queue(&scsi_device->request_queue);
+        kfree((char *) scsi_device);
+    }
+
+    return (0);
+}
+
+int scsi_hotswap_insert_by_fc_wwn (unsigned int host, unsigned int 
channel,
+    unsigned int lun, unsigned long long wwn)
+{
+    struct Scsi_Host *scsi_host;
+    Scsi_Device *scsi_device;
+    int id;
+    int result;
+
+    for (scsi_host = scsi_host_get_next (NULL); scsi_host;
+        scsi_host = scsi_host_get_next (scsi_host)) {
+        if (scsi_host->host_no == host) {
+            break;
+        }
+    }
+
+    if (scsi_host == 0) {
+        return (-ENXIO);
+    }
+
+    result = scsi_host->hostt->get_scsi_info_from_wwn (0, wwn, &host,
+        &channel, &lun, &id);
+    /*
+     * Nonzero result indicates error
+     */
+    if (result) {
+        return (result);
+    }
+
+    /*
+     * Determine if device already attached
+     */
+    spin_lock (&scsi_host->host_queue_lock);
+
+    for (scsi_device = scsi_host->host_queue; scsi_device;
+        scsi_device = scsi_device->next) {
+        if ((scsi_device->channel == channel
+             && scsi_device->id == id
+             && scsi_device->lun == lun)) {
+            break;
+        }
+    }
+
+    spin_unlock (&scsi_host->host_queue_lock);
+
+    /*
+     * If scsi_device found in host queue, then device already attached
+     */
+    if (scsi_device) {
+        return (-EEXIST);
+    }
+
+    scan_scsis (scsi_host, 1, channel, id, lun);
+    return (0);
+}
+
+int scsi_hotswap_remove_by_fc_wwn (unsigned int host, unsigned int 
channel,
+    unsigned int lun, unsigned long long wwn)
+{
+
+    struct Scsi_Device_Template *scsi_template;
+    Scsi_Device *scsi_device;
+    struct Scsi_Host *scsi_host;
+    int id;
+    int result;
+
+    for (scsi_host = scsi_host_get_next (NULL); scsi_host;
+        scsi_host = scsi_host_get_next (scsi_host)) {
+        if (scsi_host->host_no == host) {
+            break;
+        }
+    }
+    if (scsi_host == 0) {
+        return (-ENODEV);
+    }
+
+    result = scsi_host->hostt->get_scsi_info_from_wwn (1, wwn, &host,
+        &channel, &lun, &id);
+
+    /*
+     * Nonzero indicates error
+     */
+    if (result) {
+        return (result);
+    }
+
+    spin_lock (&scsi_host->host_queue_lock);
+
+    for (scsi_device = scsi_host->host_queue; scsi_device;
+        scsi_device = scsi_device->next) {
+        if ((scsi_device->channel == channel
+             && scsi_device->id == id
+             && scsi_device->lun == lun)) {
+            break;
+        }
+    }
+
+    spin_unlock (&scsi_host->host_queue_lock);
+
+    if (scsi_device == NULL) {
+        return (-ENOENT);
+    }
+
+    if (scsi_device->access_count) {
+        return (-EBUSY);
+    }
+
+    for (scsi_template = scsi_devicelist; scsi_template; scsi_template 
= scsi_template->next) {
+        if (scsi_template->detach) {
+            (*scsi_template->detach) (scsi_device);
+        }
+    }
+
+    if (scsi_device->attached == 0) {
+        /*
+         * Nobody is using this device any more.
+         * Free all of the command structures.
+         */
+        if (scsi_host->hostt->revoke)
+            scsi_host->hostt->revoke(scsi_device);
+        devfs_unregister (scsi_device->de);
+        scsi_release_commandblocks(scsi_device);
+
+        /* Now we can remove the device structure */
+        if (scsi_device->next != NULL)
+            scsi_device->next->prev = scsi_device->prev;
+
+        if (scsi_device->prev != NULL)
+            scsi_device->prev->next = scsi_device->next;
+
+        if (scsi_host->host_queue == scsi_device) {
+            scsi_host->host_queue = scsi_device->next;
+        }
+        blk_cleanup_queue(&scsi_device->request_queue);
+        kfree((char *) scsi_device);
+    }
+    return (0);
+}
+
+int scsi_hotswap_insert_by_fc_wwn_wildcard (unsigned long long wwn)
+{
+    struct Scsi_Host *scsi_host;
+    Scsi_Device *scsi_device;
+    int host, lun, channel, id;
+    int result;
+
+    /*
+     * Search scsi hostlist +     */
+    for (scsi_host = scsi_host_get_next (NULL); scsi_host;
+        scsi_host = scsi_host_get_next (scsi_host)) {
+        /*
+         * Skip unsupported drivers.  This is known because
+         * get_scsi_info_from_wwn would be defined as 0
+         */
+        if (scsi_host->hostt->get_scsi_info_from_wwn == 0) {
+            continue;
+        }
+       
+        result = scsi_host->hostt->get_scsi_info_from_wwn (0, wwn,
+            &host, &channel, &lun, &id);
+        /*
+         * WWN not found, try next adaptor
+         */
+        if (result == -ENOENT) {
+            continue;
+        }
+
+
+        /*
+         * If the currently scanned host doesn't match the WWN's host ID
+         * try again searching with new host id
+         */
+        if (scsi_host->host_no != host) {
+            continue;
+        }
+
+           
+        /*
+         * Verify we are not inserting an existing device
+         */
+        spin_lock (&scsi_host->host_queue_lock);
+
+        for (scsi_device = scsi_host->host_queue; scsi_device;
+            scsi_device = scsi_device->next) {
+            if ((scsi_device->channel == channel
+                 && scsi_device->id == id
+                 && scsi_device->lun == lun)) {
+                break;
+            }
+        }
+
+        spin_unlock (&scsi_host->host_queue_lock);
+
+        /*
+         * Insertion if no device found
+         */
+        if (scsi_device == 0) {
+            scan_scsis(scsi_host, 1, 0, id, lun);
+            scan_scsis(scsi_host, 1, 1, id, lun);
+            break; /* exit scsi_host scan */
+        }
+    } /* scsi_host scan */
+
+    if (scsi_host == 0) {
+        return (-ENOENT);
+    }
+    return (0);
+}
+
+int scsi_hotswap_remove_by_fc_wwn_wildcard (unsigned long long wwn)
+{
+    struct Scsi_Device_Template *scsi_template;
+    Scsi_Device *scsi_device;
+    struct Scsi_Host *scsi_host;
+    int host, lun, channel, id;
+    int result;
+
+    for (scsi_host = scsi_host_get_next (NULL); scsi_host;
+        scsi_host = scsi_host_get_next (scsi_host)) {
+        /*
+         * Skip unsupported drivers
+         */
+        if (scsi_host->hostt->get_scsi_info_from_wwn == 0) {
+            continue;
+        }
+
+        result = scsi_host->hostt->get_scsi_info_from_wwn (1, wwn,
+            &host, &channel, &lun, &id);
+
+        /*
+         * Adaptor not found, try next adaptor +         */
+        if (result) {
+            continue;
+        }
+
+        spin_lock (&scsi_host->host_queue_lock);
+
+        for (scsi_device = scsi_host->host_queue; scsi_device;
+            scsi_device = scsi_device->next) {
+            if ((scsi_device->channel == channel
+                 && scsi_device->id == id
+                 && scsi_device->lun == lun)) {
+                break;
+            }
+        }
+
+        spin_unlock (&scsi_host->host_queue_lock);
+
+        if (scsi_device->access_count) {
+            return (-EBUSY);
+        }
+
+        for (scsi_template = scsi_devicelist; scsi_template;
+            scsi_template = scsi_template->next) {
+            if (scsi_template->detach) {
+                (*scsi_template->detach) (scsi_device);
+            }
+        }
+
+        if (scsi_device->attached == 0) {
+            /*
+             * Nobody is using this device any more.
+             * Free all of the command structures.
+             */
+            if (scsi_host->hostt->revoke)
+                scsi_host->hostt->revoke(scsi_device);
+            devfs_unregister (scsi_device->de);
+            scsi_release_commandblocks(scsi_device);
+
+            /* Now we can remove the device structure */
+            if (scsi_device->next != NULL)
+                scsi_device->next->prev = scsi_device->prev;
+   
+            if (scsi_device->prev != NULL)
+                scsi_device->prev->next = scsi_device->next;
+   
+            if (scsi_host->host_queue == scsi_device) {
+                scsi_host->host_queue = scsi_device->next;
+            }
+            blk_cleanup_queue(&scsi_device->request_queue);
+            kfree((char *) scsi_device);
+        }
+        break; /* Break from scan all hosts since we found match */
+    } /* scan all hosts */
+
+    if (scsi_host == 0) {
+        return (-ENOENT);
+    }
+    return (0);
+}
+
+static int __init scsi_hotswap_init (void) {
+    int result = 0;
+    printk (KERN_INFO "Copyright (C) 2002 MontaVista Software - 
SCSI/FibreChannel hotswap driver\n");
+
+    /*
+     * Register the filesystem
+     */
+    result = register_filesystem (&scsi_hotswap_fs_type);
+
+    /*
+     * Mount the filesystem
+     */
+    scsi_hotswap_mountpoint = kern_mount (&scsi_hotswap_fs_type);
+    if (IS_ERR (scsi_hotswap_mountpoint)) {
+        return (-ENODEV);
+    }
+    mntget (scsi_hotswap_mountpoint);
+
+    /*
+     * Create file command entries in filesystem
+     */
+    scsi_hotswap_cmd_fs.insert_by_scsi_id = scsi_hotswap_fs_create_file 
("insert_by_scsi_id",
+        S_IFREG | S_IRUGO | S_IWUSR,
+        NULL, &scsi_hotswap_insert_by_scsi_id_file_operations);
+
+    scsi_hotswap_cmd_fs.remove_by_scsi_id = scsi_hotswap_fs_create_file 
("remove_by_scsi_id",
+        S_IFREG | S_IRUGO | S_IWUSR,
+        NULL, &scsi_hotswap_remove_by_scsi_id_file_operations);
+
+    scsi_hotswap_cmd_fs.insert_by_fc_wwn = scsi_hotswap_fs_create_file 
("insert_by_fc_wwn",
+        S_IFREG | S_IRUGO | S_IWUSR,
+        NULL, &scsi_hotswap_insert_by_fc_wwn_file_operations);
+
+    scsi_hotswap_cmd_fs.remove_by_fc_wwn = scsi_hotswap_fs_create_file 
("remove_by_fc_wwn",
+        S_IFREG | S_IRUGO | S_IWUSR,
+        NULL, &scsi_hotswap_remove_by_fc_wwn_file_operations);
+
+    scsi_hotswap_cmd_fs.insert_by_fc_wwn_wildcard = 
scsi_hotswap_fs_create_file ("insert_by_fc_wwn_wildcard",
+        S_IFREG | S_IRUGO | S_IWUSR,
+        NULL, &scsi_hotswap_insert_by_fc_wwn_wildcard_file_operations);
+
+    scsi_hotswap_cmd_fs.remove_by_fc_wwn_wildcard = 
scsi_hotswap_fs_create_file ("remove_by_fc_wwn_wildcard",
+        S_IFREG | S_IRUGO | S_IWUSR,
+        NULL, &scsi_hotswap_remove_by_fc_wwn_wildcard_file_operations);
+
+    return (result);
+}
+
+static void __exit scsi_hotswap_exit (void) {
+    /*
+     * Delete all files in filesystem
+     */
+    fs_remove_file (scsi_hotswap_cmd_fs.insert_by_scsi_id);
+    fs_remove_file (scsi_hotswap_cmd_fs.remove_by_scsi_id);
+    fs_remove_file (scsi_hotswap_cmd_fs.insert_by_fc_wwn);
+    fs_remove_file (scsi_hotswap_cmd_fs.remove_by_fc_wwn);
+    fs_remove_file (scsi_hotswap_cmd_fs.insert_by_fc_wwn_wildcard);
+    fs_remove_file (scsi_hotswap_cmd_fs.remove_by_fc_wwn_wildcard);
+
+    /*
+     * Remove mount
+     */
+    mntput (scsi_hotswap_mountpoint);
+
+    /*
+     * Remove filesystem registration
+     */
+    unregister_filesystem (&scsi_hotswap_fs_type);
+}
+
+module_init(scsi_hotswap_init);
+module_exit(scsi_hotswap_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
+MODULE_LICENSE("GPL");
diff -uNr linux-2.5.44-qla/drivers/scsi/qla2xxx/qla2x00.c 
linux-2.5.44-scsi-hotswap/drivers/scsi/qla2xxx/qla2x00.c
--- linux-2.5.44-qla/drivers/scsi/qla2xxx/qla2x00.c    Wed Oct 23 
15:47:43 2002
+++ linux-2.5.44-scsi-hotswap/drivers/scsi/qla2xxx/qla2x00.c    Wed Oct 
23 15:47:03 2002
@@ -244,6 +244,7 @@
STATIC uint8_t  qla2x00_register_with_Linux(scsi_qla_host_t *ha, uint8_t 
maxchannels);
STATIC int   qla2x00_done(scsi_qla_host_t *);
//STATIC void qla2x00_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
+int qla2x00_get_scsi_info_from_wwn (int mode, unsigned long long wwn, 
int *host, int *channel, int *lun, int *id);

STATIC void
qla2x00_timer(scsi_qla_host_t *);
@@ -2037,6 +2038,7 @@
    host->can_queue = max_srbs;  /* default value:-MAX_SRBS(4096)  */
    host->cmd_per_lun = 1;
//    host->select_queue_depths = qla2x00_select_queue_depth;
+    host->hostt->get_scsi_info_from_wwn = qla2x00_get_scsi_info_from_wwn;

    host->n_io_port = 0xFF;

@@ -3989,6 +3991,80 @@
}
#endif

+union wwnmap {
+    unsigned long long wwn;
+    unsigned char wwn_u8[8];
+};
+
+int qla2x00_get_scsi_info_from_wwn (int mode,
+    unsigned long long wwn,
+    int *host,
+    int *channel,
+    int *lun,
+    int *id) {
+
+scsi_qla_host_t *list;
+Scsi_Device *scsi_device;
+union wwnmap wwncompare;
+union wwnmap wwncompare2;
+int i, j, k;
+
+    /*
+     * Retrieve big endian version of world wide name
+     */
+    wwncompare2.wwn = wwn;
+    for (j = 0, k=7; j < 8; j++, k--) {
+        wwncompare.wwn_u8[j] = wwncompare2.wwn_u8[k];
+    }
+
+    /*
+     * query all hosts searching for WWN
+     */
+    for (list = qla2x00_hostlist; list; list = list->next) {
+        for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+            /*
+             * Scan all devices in FibreChannel database
+             * if WWN match found, return SCSI device information
+             */
+            if (memcmp (wwncompare.wwn_u8, list->fc_db[i].wwn, 8) == 0) {
+                /*
+                 * If inserting, avoid scan for channel and lun 
information
+                 */
+                if (mode == 0) {
+                    *channel = 0;
+                    *lun = 0;
+                    *host = list->host->host_no;
+                    *id = i;
+                    return (0);
+                }
+           
+
+                /*
+                 * WWN matches, find channel and lun information from scsi
+                 * device
+                 */
+                for (scsi_device = list->host->host_queue; scsi_device; 
scsi_device = scsi_device->next) {
+                    if (scsi_device->id == i) {
+                        *channel = scsi_device->channel;
+                        *lun = scsi_device->lun;
+                        break;
+                    }
+                }
+                if (scsi_device == 0) {
+                    return (-ENOENT);
+                }
+                /*
+                 * Device found, return all data
+                 */
+                *host = list->host->host_no;
+                *id = i;
+                return (0);
+            } /* memcmp */
+        } /* i < MAXFIBREDEVICES */
+    }
+    return (-ENOENT);
+}
+
/**************************************************************************
*   qla2x00_select_queue_depth
*
diff -uNr linux-2.5.44-qla/drivers/scsi/scsi.c 
linux-2.5.44-scsi-hotswap/drivers/scsi/scsi.c
--- linux-2.5.44-qla/drivers/scsi/scsi.c    Fri Oct 18 21:01:54 2002
+++ linux-2.5.44-scsi-hotswap/drivers/scsi/scsi.c    Wed Oct 23 15:15:07 
2002
@@ -413,6 +413,9 @@
                 * allow us to more easily figure out whether we should
                 * do anything here or not.
                 */
+
+                spin_lock (&host->host_queue_lock);
+
                for (SDpnt = host->host_queue;
                     SDpnt;
                     SDpnt = SDpnt->next) {
@@ -430,6 +433,9 @@
                                                break;
                                        }
                }
+
+                spin_unlock (&host->host_queue_lock);
+
                if (SDpnt) {
                    /*
                     * Some other device in this cluster is busy.
@@ -1694,6 +1700,8 @@
        len += size;
        pos = begin + len;
#endif
+        spin_lock (&HBA_ptr->host_queue_lock);
+
        for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
            proc_print_scsidevice(scd, buffer, &size, len);
            len += size;
@@ -1706,6 +1714,8 @@
            if (pos > offset + length)
                goto stop_output;
        }
+
+        spin_unlock (&HBA_ptr->host_queue_lock);
    }

stop_output:
@@ -1864,6 +1874,8 @@
        if (!HBA_ptr)
            goto out;

+        spin_lock (&HBA_ptr->host_queue_lock);
+
        for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
            if ((scd->channel == channel
                 && scd->id == id
@@ -1872,6 +1884,8 @@
            }
        }

+        spin_unlock (&HBA_ptr->host_queue_lock);
+
        err = -ENOSYS;
        if (scd)
            goto out;    /* We do not yet support unplugging */
@@ -1910,6 +1924,8 @@
        if (!HBA_ptr)
            goto out;

+        spin_lock (&HBA_ptr->host_queue_lock);
+
        for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
            if ((scd->channel == channel
                 && scd->id == id
@@ -1918,6 +1934,8 @@
            }
        }

+        spin_unlock (&HBA_ptr->host_queue_lock);
+
        if (scd == NULL)
            goto out;    /* there is no such device attached */

@@ -1951,9 +1969,14 @@
            if (scd->prev != NULL)
                scd->prev->next = scd->next;

+            spin_lock (&HBA_ptr->host_queue_lock);
+
            if (HBA_ptr->host_queue == scd) {
                HBA_ptr->host_queue = scd->next;
            }
+
+            spin_unlock (&HBA_ptr->host_queue_lock);
+
            blk_cleanup_queue(&scd->request_queue);
            if (scd->inquiry)
                kfree(scd->inquiry);
@@ -1997,11 +2020,15 @@

    for (shpnt = scsi_host_get_next(NULL); shpnt;
         shpnt = scsi_host_get_next(shpnt)) {
+        spin_lock (&shpnt->host_queue_lock);
+
        for (SDpnt = shpnt->host_queue; SDpnt;
             SDpnt = SDpnt->next) {
            if (tpnt->detect)
                SDpnt->attached += (*tpnt->detect) (SDpnt);
        }
+
+        spin_unlock (&shpnt->host_queue_lock);
    }

    /*
@@ -2017,6 +2044,8 @@
     */
    for (shpnt = scsi_host_get_next(NULL); shpnt;
         shpnt = scsi_host_get_next(shpnt)) {
+        spin_lock (&shpnt->host_queue_lock);
+
        for (SDpnt = shpnt->host_queue; SDpnt;
             SDpnt = SDpnt->next) {
            if (tpnt->attach)
@@ -2032,6 +2061,8 @@
                    out_of_space = 1;
            }
        }
+
+        spin_unlock (&shpnt->host_queue_lock);
    }

    /*
@@ -2068,6 +2099,8 @@

    for (shpnt = scsi_host_get_next(NULL); shpnt;
         shpnt = scsi_host_get_next(shpnt)) {
+        spin_lock (&shpnt->host_queue_lock);
+
        for (SDpnt = shpnt->host_queue; SDpnt;
             SDpnt = SDpnt->next) {
            if (tpnt->detach)
@@ -2084,6 +2117,8 @@
                scsi_release_commandblocks(SDpnt);
            }
        }
+
+        spin_unlock (&shpnt->host_queue_lock);
    }
    /*
     * Extract the template from the linked list.
@@ -2154,6 +2189,8 @@
    for (shpnt = scsi_host_get_next(NULL); shpnt;
         shpnt = scsi_host_get_next(shpnt)) {
        printk(KERN_INFO "h:c:t:l (dev sect nsect cnumsec sg) (ret all 
flg) (to/cmd to ito) cmd snse result\n");
+        spin_lock (&shpnt->host_queue_lock);
+
        for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
            for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
                /*  (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all 
flg) (to/cmd to ito) cmd snse result %d %x      */
@@ -2185,6 +2222,8 @@
                       SCpnt->result);
            }
        }
+
+        spin_unlock (&shpnt->host_queue_lock);
    }
#endif    /* CONFIG_SCSI_LOGGING */ /* } */
}
diff -uNr linux-2.5.44-qla/drivers/scsi/scsi_error.c 
linux-2.5.44-scsi-hotswap/drivers/scsi/scsi_error.c
--- linux-2.5.44-qla/drivers/scsi/scsi_error.c    Fri Oct 18 21:01:07 2002
+++ linux-2.5.44-scsi-hotswap/drivers/scsi/scsi_error.c    Wed Oct 23 
11:48:20 2002
@@ -202,6 +202,8 @@
    int devices_failed = 0;


+    spin_lock (&shost->host_queue_lock);
+
    for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
        for (scmd = sc_list; scmd; scmd = scmd->bh_next) {
            if (scmd->device == sdev) {
@@ -227,6 +229,8 @@
        }
    }

+    spin_unlock (&shost->host_queue_lock);
+
    SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d commands on %d"
                      " devices require eh work\n",
                  total_failures, devices_failed));
@@ -247,6 +251,8 @@
    Scsi_Device *sdev;
    Scsi_Cmnd *scmd;

+    spin_lock (&shost->host_queue_lock);
+
    for (found = 0, sdev = shost->host_queue; sdev; sdev = sdev->next) {
        for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
            if (scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR)) {
@@ -283,6 +289,8 @@
        }
    }

+    spin_unlock (&shost->host_queue_lock);
+
    SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(*sc_list, shost));

    if (shost->host_failed != found)
@@ -962,6 +970,8 @@

    SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Trying BDR\n", __FUNCTION__));

+    spin_lock (&shost->host_queue_lock);
+
    for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
        for (scmd = sc_todo; scmd; scmd = scmd->bh_next)
            if ((scmd->device == sdev) &&
@@ -985,6 +995,7 @@
                            scsi_eh_finish_cmd(scmd, shost);
                    }
    }
+    spin_unlock (&shost->host_queue_lock);

    return shost->host_failed;
}
@@ -1016,11 +1027,15 @@
        /*
         * Mark all affected devices to expect a unit attention.
         */
+        spin_lock (&scmd->host->host_queue_lock);
+
        for (sdev = scmd->host->host_queue; sdev; sdev = sdev->next)
            if (scmd->channel == sdev->channel) {
                sdev->was_reset = 1;
                sdev->expecting_cc_ua = 1;
            }
+
+        spin_unlock (&scmd->host->host_queue_lock);
    }
    return rtn;
}
@@ -1052,11 +1067,13 @@
        /*
         * Mark all affected devices to expect a unit attention.
         */
+        spin_lock (&scmd->host->host_queue_lock);
        for (sdev = scmd->host->host_queue; sdev; sdev = sdev->next)
            if (scmd->channel == sdev->channel) {
                sdev->was_reset = 1;
                sdev->expecting_cc_ua = 1;
            }
+        spin_unlock (&scmd->host->host_queue_lock);
    }
    return rtn;
}
@@ -1475,6 +1492,8 @@
     * requests are started.
     */
    spin_lock_irqsave(shost->host_lock, flags);
+    spin_lock (&shost->host_queue_lock);
+
    for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
        request_queue_t *q = &sdev->request_queue;

@@ -1487,6 +1506,8 @@

        q->request_fn(q);
    }
+
+    spin_unlock (&shost->host_queue_lock);
    spin_unlock_irqrestore(shost->host_lock, flags);
}

diff -uNr linux-2.5.44-qla/drivers/scsi/scsi_lib.c 
linux-2.5.44-scsi-hotswap/drivers/scsi/scsi_lib.c
--- linux-2.5.44-qla/drivers/scsi/scsi_lib.c    Fri Oct 18 21:01:53 2002
+++ linux-2.5.44-scsi-hotswap/drivers/scsi/scsi_lib.c    Wed Oct 23 
11:44:06 2002
@@ -261,6 +261,8 @@
    if (SDpnt->single_lun && blk_queue_empty(q) && SDpnt->device_busy ==0) {
        request_queue_t *q;

+        spin_lock (&SHpnt->host_queue_lock);
+
        for (SDpnt = SHpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
            if (((SHpnt->can_queue > 0)
                 && (SHpnt->host_busy >= SHpnt->can_queue))
@@ -273,6 +275,8 @@
            q = &SDpnt->request_queue;
            q->request_fn(q);
        }
+
+        spin_unlock (&SHpnt->host_queue_lock);
    }

    /*
@@ -285,6 +289,7 @@
     */
    all_clear = 1;
    if (SHpnt->some_device_starved) {
+        spin_lock (&SHpnt->host_queue_lock);
        for (SDpnt = SHpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
            request_queue_t *q;
            if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= 
SHpnt->can_queue))
@@ -299,6 +304,7 @@
            q->request_fn(q);
            all_clear = 0;
        }
+        spin_unlock (&SHpnt->host_queue_lock);
        if (SDpnt == NULL && all_clear) {
            SHpnt->some_device_starved = 0;
        }
@@ -1038,8 +1044,13 @@

    SHpnt->host_self_blocked = FALSE;
    /* Now that we are unblocked, try to start the queues. */
+
+    spin_lock (&SHpnt->host_queue_lock);
+
    for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next)
        scsi_queue_next_request(&SDloop->request_queue, NULL);
+
+    spin_unlock (&SHpnt->host_queue_lock);
}

/*
@@ -1066,12 +1077,17 @@
void scsi_report_bus_reset(struct Scsi_Host * SHpnt, int channel)
{
    Scsi_Device *SDloop;
+
+    spin_lock (&SHpnt->host_queue_lock);
+
    for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next) {
        if (channel == SDloop->channel) {
            SDloop->was_reset = 1;
            SDloop->expecting_cc_ua = 1;
        }
    }
+
+    spin_unlock (&SHpnt->host_queue_lock);
}

/*
diff -uNr linux-2.5.44-qla/drivers/scsi/scsi_scan.c 
linux-2.5.44-scsi-hotswap/drivers/scsi/scsi_scan.c
--- linux-2.5.44-qla/drivers/scsi/scsi_scan.c    Fri Oct 18 21:02:28 2002
+++ linux-2.5.44-scsi-hotswap/drivers/scsi/scsi_scan.c    Wed Oct 23 
11:44:06 2002
@@ -530,6 +530,8 @@
        /*
         * Add it to the end of the shost->host_queue list.
         */
+        spin_lock (&shost->host_queue_lock);
+
        if (shost->host_queue != NULL) {
            sdev->prev = shost->host_queue;
            while (sdev->prev->next != NULL)
@@ -538,6 +540,8 @@
        } else
            shost->host_queue = sdev;

+        spin_unlock (&shost->host_queue_lock);
+
    }
    return (sdev);
}
@@ -554,8 +558,12 @@
{
    if (sdev->prev != NULL)
        sdev->prev->next = sdev->next;
-    else
+    else {
+        spin_lock (&sdev->host->host_queue_lock);
        sdev->host->host_queue = sdev->next;
+        spin_unlock (&sdev->host->host_queue_lock);
+    }
+
    if (sdev->next != NULL)
        sdev->next->prev = sdev->prev;

diff -uNr linux-2.5.44-qla/include/linux/scsi_hotswap.h 
linux-2.5.44-scsi-hotswap/include/linux/scsi_hotswap.h
--- linux-2.5.44-qla/include/linux/scsi_hotswap.h    Wed Dec 31 17:00:00 
1969
+++ linux-2.5.44-scsi-hotswap/include/linux/scsi_hotswap.h    Wed Oct 23 
11:44:06 2002
@@ -0,0 +1,84 @@
+/*
+ * scsi_hotswap.h
+ *
+ * SCSI/FibreChannel Hotswap userland interface to kernel features
+ * + * Author: MontaVista Software, Inc.
+ *         Steven Dake (sdake@mvista.com)
+ *         source@mvista.com
+ *
+ * Copyright (C) 2002 MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
DAMAGE.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this program; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SCSI_HOTSWAP_H
+#define __SCSI_HOTSWAP_H
+
+/*
+ * Software Interface
+ */
+
+/*
+ * Find a device by host, channel, lun and scsi id and insert it into 
the system
+ */
+extern int scsi_hotswap_insert_by_scsi_id (unsigned int host,
+    unsigned int channel,
+    unsigned int lun,
+    unsigned int id);
+
+/*
+ * Find a device by host, channel, lun and scsi id and remove it from 
the system
+ */
+extern int scsi_hotswap_remove_by_scsi_id (unsigned int host,
+    unsigned int channel,
+    unsigned int lun,
+    unsigned int id);
+
+/*
+ * Find a device by host, channel, lun and wwn and insert it into the 
system
+ */
+extern int scsi_hotswap_insert_by_fc_wwn (unsigned int host,
+    unsigned int channel,
+    unsigned int lun,
+    unsigned long long wwn);
+
+/*
+ * Find a device by host, channel, lun and wwn and remove it from the 
system
+ */
+extern int scsi_hotswap_remove_by_fc_wwn (unsigned int host,
+    unsigned int channel,
+    unsigned int lun,
+    unsigned long long wwn);
+
+/*
+ * Find a device by WWN, searching all adaptor hosts and channels.
+ * If found, insert it into the system
+ */
+extern int scsi_hotswap_insert_by_fc_wwn_wildcard (unsigned long long 
wwn);
+
+/*
+ * Find a device by WWN, searching all adaptor hosts and channels.
+ * If found, remove it from the system
+ */
+extern int scsi_hotswap_remove_by_fc_wwn_wildcard (unsigned long long 
wwn);
+
+#endif /* __SCSI_HOTSWAP_H */








^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] Advanced TCA SCSI/FC disk hotswap driver for kernel 2.5.44
  2002-10-23 23:27 [PATCH] Advanced TCA SCSI/FC disk hotswap driver for kernel 2.5.44 Steven Dake
@ 2002-10-24  0:18 ` Greg KH
  2002-10-24  0:26   ` Steven Dake
  2002-10-24  0:27 ` Greg KH
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Greg KH @ 2002-10-24  0:18 UTC (permalink / raw)
  To: Steven Dake; +Cc: linux-kernel, alan

On Wed, Oct 23, 2002 at 04:27:06PM -0700, Steven Dake wrote:
> 
> Changes from kernel 2.4.19 to 2.5.44 release:

First off, your patch is line wrapped, please fix your email client.

Also, please read Documentation/CodingStyle and use tabs.  Unless this
is a side effect of your email client munging the patch.

> * ioctls deleted and replaced by ramfs scsi_hotswap_fs (suggested by
> Greg KH)

Any reason you can't use driverfs for the 2.5 code?


> +/*
> + * Core file read/write operations interfaces
> + */
> +static char scsi_hotswap_insert_by_scsi_id_usage[] = {
> +    "Usage: echo \"[host] [channel] [lun] [id]\" > insert_by_scsi_id\n"
> +};

I really like this, a user friendly kernel interface :)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] Advanced TCA SCSI/FC disk hotswap driver for kernel 2.5.44
  2002-10-24  0:18 ` Greg KH
@ 2002-10-24  0:26   ` Steven Dake
  2002-10-24  0:30     ` Greg KH
  2002-10-24 16:51     ` Patrick Mochel
  0 siblings, 2 replies; 9+ messages in thread
From: Steven Dake @ 2002-10-24  0:26 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, alan

Greg,


Greg KH wrote:

>On Wed, Oct 23, 2002 at 04:27:06PM -0700, Steven Dake wrote:
>  
>
>>Changes from kernel 2.4.19 to 2.5.44 release:
>>    
>>
>
>First off, your patch is line wrapped, please fix your email client.
>
>Also, please read Documentation/CodingStyle and use tabs.  Unless this
>is a side effect of your email client munging the patch.
>  
>
Thanks yes, it is definately this brain dead mozilla mailer.  I did use 
tabs of course.

>  
>
>>* ioctls deleted and replaced by ramfs scsi_hotswap_fs (suggested by
>>Greg KH)
>>    
>>
>
>Any reason you can't use driverfs for the 2.5 code?
>
>  
>
I'm not sure how driverfs would be used by this particular patch.  Could 
you be more specific in stating how this could be used?

>  
>
>>+/*
>>+ * Core file read/write operations interfaces
>>+ */
>>+static char scsi_hotswap_insert_by_scsi_id_usage[] = {
>>+    "Usage: echo \"[host] [channel] [lun] [id]\" > insert_by_scsi_id\n"
>>+};
>>    
>>
>
>I really like this, a user friendly kernel interface :)
>  
>
Think this looks good for inclusion in 2.5.45?

Thanks
-steve

>thanks,
>
>greg k-h
>
>
>
>  
>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] Advanced TCA SCSI/FC disk hotswap driver for kernel 2.5.44
  2002-10-23 23:27 [PATCH] Advanced TCA SCSI/FC disk hotswap driver for kernel 2.5.44 Steven Dake
  2002-10-24  0:18 ` Greg KH
@ 2002-10-24  0:27 ` Greg KH
  2002-10-24  0:42 ` Christoph Hellwig
       [not found] ` <20021024042838.GA30891@codepoet.org>
  3 siblings, 0 replies; 9+ messages in thread
From: Greg KH @ 2002-10-24  0:27 UTC (permalink / raw)
  To: Steven Dake; +Cc: linux-kernel, alan

On Wed, Oct 23, 2002 at 04:27:06PM -0700, Steven Dake wrote:
> +static ssize_t scsi_hotswap_insert_by_scsi_id_write_file (struct file 
> *file,
> +    const char *buf, size_t count, loff_t *ppos)
> +{
> +    int host, channel, lun, id;
> +    char parameters[1024];

Ouch, don't put 1k on the stack, dynamically allocate it please.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] Advanced TCA SCSI/FC disk hotswap driver for kernel 2.5.44
  2002-10-24  0:26   ` Steven Dake
@ 2002-10-24  0:30     ` Greg KH
  2002-10-24 16:51     ` Patrick Mochel
  1 sibling, 0 replies; 9+ messages in thread
From: Greg KH @ 2002-10-24  0:30 UTC (permalink / raw)
  To: Steven Dake; +Cc: linux-kernel, alan

On Wed, Oct 23, 2002 at 05:26:18PM -0700, Steven Dake wrote:
> I'm not sure how driverfs would be used by this particular patch.  Could 
> you be more specific in stating how this could be used?

Your "driver" needs only 6 or so files to work properly, right?  Why not
just create those files under /sys/bus/scsi/ somewhere?  That way you
don't have to create your own fs, and only have to provide read and
write functions for those files, which would be much smaller.

pcihpfs is moving under driverfs soon, once I get some spare cycles.

> >I really like this, a user friendly kernel interface :)
> >
> Think this looks good for inclusion in 2.5.45?

I'll let the scsi people make that call, I don't know the scsi layer at
all (and don't really want to...)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] Advanced TCA SCSI/FC disk hotswap driver for kernel 2.5.44
  2002-10-23 23:27 [PATCH] Advanced TCA SCSI/FC disk hotswap driver for kernel 2.5.44 Steven Dake
  2002-10-24  0:18 ` Greg KH
  2002-10-24  0:27 ` Greg KH
@ 2002-10-24  0:42 ` Christoph Hellwig
  2002-10-24 20:04   ` Steven Dake
       [not found] ` <20021024042838.GA30891@codepoet.org>
  3 siblings, 1 reply; 9+ messages in thread
From: Christoph Hellwig @ 2002-10-24  0:42 UTC (permalink / raw)
  To: Steven Dake; +Cc: linux-kernel, greg, alan, linux-scsi

On Wed, Oct 23, 2002 at 04:27:06PM -0700, Steven Dake wrote:
> lkml,
> 
> Attached is an update of the Advanced TCA disk hotswap driver to provide 
> disk hotswap
> support for the Linux Kernel 2.5.43.  Hotswap targets include both SCSI 
> and FibreChannel.
> Note this support is generic in that it will work in a typical PC system 
> with SCSI or
> FibreChannel disks.

Thanks a lot for doing the work.  There are still some issues to sort
out, but I guess we'll be able to finish getting it integrated into
the tree.

Btw, please Cc linux-scsi@vger.kernel.org for scsi-related patches.

> linux-2.5.44-scsi-hotswap/drivers/scsi/hosts.c
> --- linux-2.5.44-qla/drivers/scsi/hosts.c    Fri Oct 18 21:01:09 2002
> +++ linux-2.5.44-scsi-hotswap/drivers/scsi/hosts.c    Wed Oct 23 
> 15:35:30 2002
> @@ -371,6 +371,7 @@
>     scsi_hosts_registered++;
> 
>     spin_lock_init(&shost->default_lock);
> +    spin_lock_init(&shost->host_queue_lock);
>     scsi_assign_lock(shost, &shost->default_lock);
>     atomic_set(&shost->host_active,0);

I think your mailer mangles the patch a bit, I'm pretty sure that
code uses one tab indentation.  Please make sure that you use
that indentation in new code (if you editor gets it wrong all
the time just run the source through unexpand(1))

>     int (* bios_param)(Disk *, struct block_device *, int []);
> 
> +#ifdef CONFIG_SCSIFCHOTSWAP
> +    /*
> +     * Used to determine the id to send the inquiry command to during
> +     * hot additions of FibreChannel targets
> +     */
> +    int (*get_scsi_info_from_wwn)(int mode, unsigned long long wwn, int 
> *host, int *channel, int *lun, int *id);
> +#endif

Please make this method unconditional - even if we don't call it without
your option set, the drivers are cluttered up much less this way.

> @@ -0,0 +1,1334 @@
> +/*
> + * hotswap.c
> + *
> + * SCSI/FibreChannel Hotswap kernel implementaton
> + * + * Author: MontaVista Software, Inc.

Is this + * intentional or a cut & paste error? :)

> *buf)
> +{
> +    buf->f_type = SCSI_HOTSWAP_MAGIC;
> +    buf->f_bsize = PAGE_CACHE_SIZE;
> +    buf->f_namelen = 255;
> +    return (0);
> +}

Please take a look at fs/libfs.c.  For most of your filesystem
methods you can just use the simple_* functions there.

> +static int scsi_hotswap_mkdir (struct inode *dir, struct dentry *dentry,
> +    int mode)
> +{
> +    return (scsi_hotswap_mknod (dir, dentry, mode | S_IFDIR, 0));

Small codingstyle issue, this should be:

	return scsi_hotswap_mknod(dir, dentry, mode | S_IFDIR, 0);

Btw, have you read Documentation/CodingStyle in the kernel tree?

> +
> +static ssize_t default_read_file (struct file *file, char *buf, size_t 
> count,
> +    loff_t *ppos)
> +{
> +    return (0);
> +}
> +
> +static ssize_t default_write_file (struct file *file, const char *buf,
> +    size_t count, loff_t *ppos)
> +{
> +    return (count);
> +}

If you don't need read/write just don't set those methods in
the operation vector - the kernel can cope with that.

> +
> +static loff_t default_file_lseek (struct file *file, loff_t offset, int 
> orig)
> +{
> +    loff_t retval = -EINVAL;
> +
> +    switch(orig) {
> +    case 0:
> +        if (offset > 0) {
> +            file->f_pos = offset;
> +            retval = file->f_pos;
> +        }
> +        break;
> +    case 1:
> +        if ((offset + file->f_pos) > 0) {
> +            file->f_pos += offset;
> +            retval = file->f_pos;
> +        }
> +        break;
> +    default:
> +        break;
> +    }
> +
> +    return (retval);
> +}

This isn't different from default_llseek (except of missing locking),
just don't implement ->llseek, the VFS will take care of you.

> +
> +static int default_open (struct inode *inode, struct file *filp)
> +{
> +    if (inode->u.generic_ip) {
> +        filp->private_data = inode->u.generic_ip;
> +    }
> +    return (0);
> +}

You don't seem to actually use file->private_data.  Unless I'm
wrong you don't have to implement ->open at all.

> +
> +static int default_sync_file (struct file *file, struct dentry *dentry,
> +    int datasync)
> +{
> +    return (0);
> +}

Again, no need to implement a noop ->fsync, VFS deals with it not beeing
implemented.

> +static struct file_operations default_file_operations = {
> +    read:        default_read_file,
> +    write:         default_write_file,
> +    open:        default_open,
> +    llseek:        default_file_lseek,
> +    fsync:         default_sync_file,
> +    mmap:         generic_file_mmap,
> +};

Please use C99 struct-initializers, i.e.

static struct file_operations default_file_operations = {
	.mmap = 	generic_file_mmap,
};

> + * scsi_hotswap_insert_by_scsi_id file operations structure
> + */
> +static ssize_t scsi_hotswap_insert_by_scsi_id_read_file (struct file 
> *file,
> +    char *buf, size_t count, loff_t *offset);
> +static ssize_t scsi_hotswap_insert_by_scsi_id_write_file (struct file 
> *file,
> +    const char *buf, size_t count, loff_t *ppos);

Looks like this wants a bit nicer line-wrapping (or shorter function
names :))

<lots of file_operations snipped)

Mayb you can put a switch into ->read/->write instead of having
many different file operations?

> +/*
> + * Core file read/write operations interfaces
> + */
> +static char scsi_hotswap_insert_by_scsi_id_usage[] = {
> +    "Usage: echo \"[host] [channel] [lun] [id]\" > insert_by_scsi_id\n"
> +};

I don't think the kernel should supply usage information.

> +/*
> + * Core Interface Implementation
> + * Note these are exported to the global symbol table for
> + * other subsystems to use such as a scsi processor or 1394
> + */
> +int scsi_hotswap_insert_by_scsi_id (unsigned int host, unsigned int 
> channel,
> +    unsigned int lun, unsigned int id)
> +{
> +    struct Scsi_Host *scsi_host;
> +    Scsi_Device *scsi_device;
> +
> +    for (scsi_host = scsi_host_get_next (NULL); scsi_host;
> +        scsi_host = scsi_host_get_next (scsi_host)) {
> +        if (scsi_host->host_no == host) {
> +            break;
> +        }
> +    }
> +    if (scsi_host == 0) {
> +        return (-ENXIO);
> +    }
> +
> +    spin_lock (&scsi_host->host_queue_lock);
> +
> +    /*
> +     * Determine if device already attached
> +     */
> +    for (scsi_device = scsi_host->host_queue; scsi_device; scsi_device 
> = scsi_device->next) {
> +        if ((scsi_device->channel == channel
> +             && scsi_device->id == id
> +             && scsi_device->lun == lun)) {
> +            break;
> +        }
> +    }
> +   
> +    spin_unlock (&scsi_host->host_queue_lock);
> +
> +    /*
> +     * If scsi_device found in host queue, then device already attached
> +     */
> +    if (scsi_device) {
> +        return (-EEXIST);
> +    }
> +
> +    scan_scsis(scsi_host, 1, channel, id, lun);
> +
> +    return (0);
> +}

This seems to be largely copied from proc_scsi_gen_write().  What about
factoring out a common support function? (dito for many of the functions
below)

> diff -uNr linux-2.5.44-qla/drivers/scsi/qla2xxx/qla2x00.c 
> linux-2.5.44-scsi-hotswap/drivers/scsi/qla2xxx/qla2x00.c
> --- linux-2.5.44-qla/drivers/scsi/qla2xxx/qla2x00.c    Wed Oct 23 

Doesn't seem to exist in my tree..

> diff -uNr linux-2.5.44-qla/include/linux/scsi_hotswap.h 
> linux-2.5.44-scsi-hotswap/include/linux/scsi_hotswap.h
> --- linux-2.5.44-qla/include/linux/scsi_hotswap.h    Wed Dec 31 17:00:00 
> 1969
> +++ linux-2.5.44-scsi-hotswap/include/linux/scsi_hotswap.h    Wed Oct 23 

I think this one should go to include/scsi/ instead, that's where
the other scsi headers live.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] Advanced TCA SCSI/FC disk hotswap driver for kernel 2.5.44
  2002-10-24  0:26   ` Steven Dake
  2002-10-24  0:30     ` Greg KH
@ 2002-10-24 16:51     ` Patrick Mochel
  1 sibling, 0 replies; 9+ messages in thread
From: Patrick Mochel @ 2002-10-24 16:51 UTC (permalink / raw)
  To: Steven Dake; +Cc: Greg KH, linux-kernel, alan


> >Any reason you can't use driverfs for the 2.5 code?
> >
> >  
> >
> I'm not sure how driverfs would be used by this particular patch.  Could 
> you be more specific in stating how this could be used?

I haven't looked extensively at the code, but I'll give you these hints: 
Each scsi device gets a directory in the driverfes hierarchy. If you can 
obtain a pointer to that device during initialization, you can create 
attribute files to handle read/write in that directory. 

You need to declare a struct device attribute, which looks like: 

(from include/linux/device.h)

struct device_attribute {
        struct attribute        attr;
        ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off);
        ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off);
};

for each file you want to export.


There is a macro to help, which will fill in the embedded attr structure 
for you: 

DEVICE_ATTR(name,mode,show,store);

which is equivalent to declaring. 

struct device_attribute dev_attr_<name> = { ... };

(You can do it manually, too, if you feel really manly). 


I assume that the ability to hotswap drives in a feature supported by a 
subset of SCSI drives. I don't know how you handle checking each device, 
and it's not really relevant. Whenever you find a device that supports 
hotswap, then do something like:

{
	Scsi_Device * scsi_dev;
	...
	device_create_file(&scsi_dev->sdev_driverfs_dev,&hotswap_attr); 
	...
}

The attribute descriptor will be reused for each device that exports it. 
On read() and write(), your show() and store() callbacks will be called, 
with a pointer to the device for which it was called as the first 
argument. 

I hope this all makes sense... If you have any questions, please feel free
to ask.


	-pat


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] Advanced TCA SCSI/FC disk hotswap driver for kernel 2.5.44
       [not found] ` <20021024042838.GA30891@codepoet.org>
@ 2002-10-24 18:12   ` Steven Dake
  0 siblings, 0 replies; 9+ messages in thread
From: Steven Dake @ 2002-10-24 18:12 UTC (permalink / raw)
  To: andersen; +Cc: greg, linux-kernel

Erik,


Erik Andersen wrote:

>On Wed Oct 23, 2002 at 04:27:06PM -0700, Steven Dake wrote:
>  
>
>>lkml,
>>
>>Attached is an update of the Advanced TCA disk hotswap driver to provide 
>>disk hotswap
>>support for the Linux Kernel 2.5.43.  Hotswap targets include both SCSI 
>>and FibreChannel.
>>    
>>
>
>This looks (in parts) similar to the patch I made to make 1394
>hotswapping work correctly.
>    http://codepoet.org/scsi_add_remove_single.patch
>The patch is vs 2.4, but you get the idea.  Anyway, I think it 
>would make more sense for you to fixup proc_scsi_gen_write() to
>make the old hotswap interface (you know the 
>    echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
>    echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
>  
>
I wanted to seperate the hotswap functionality from the main scsi code. 
 I also feel
that hotswap shouldn't be a function of proc.  Also, the patch I 
supplied supports
fibrechannel hotswap as well.  Your patch looks pretty good and I plan 
to change
the proc_scsi_gen_write() to use the scsi hotswap commands in hotswap.c. 
 The
advantage of this technique is that the HBA_ptr doesn't have to be known 
(and
this generic code can go in the actual routine instead of the proc 
parsing routine).
The final advantage of having seperate comands is less time is spent 
passing and
parsing text data.  Plus my patch provides usage information for those 
that don't
or can't read the source code to understand the interface :)

As far as I'm concerned, I'd be happy to entirely remove the 
proc_scsi_gen_write
code, but I think that might confuse some people.

As for the interfaces stomping each other, I've added correct locking to 
proc_scsi_gen_write()
to ensure that the host_queue is locked during access so changes to it 
cannot occur
during hotswap operations.  This keeps a scsi_device entry from being 
deleted while
the list is being parsed, resulting in bad magic.

>one) and make it use your new hotswap code.  Otherwise the two
>interfaces could easily stomp on each other and hose up the
>kernel when mucking about with scsi host internals.
>
> -Erik
>
>--
>Erik B. Andersen             http://codepoet-consulting.com/
>--This message was written using 73% post-consumer electrons--
>
>
>
>  
>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] Advanced TCA SCSI/FC disk hotswap driver for kernel 2.5.44
  2002-10-24  0:42 ` Christoph Hellwig
@ 2002-10-24 20:04   ` Steven Dake
  0 siblings, 0 replies; 9+ messages in thread
From: Steven Dake @ 2002-10-24 20:04 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-kernel, linux-scsi

Christoph

Thanks for the comments some responses below.

Christoph Hellwig wrote:

>On Wed, Oct 23, 2002 at 04:27:06PM -0700, Steven Dake wrote:
>  
>
>>lkml,
>>
>>Attached is an update of the Advanced TCA disk hotswap driver to provide 
>>disk hotswap
>>support for the Linux Kernel 2.5.43.  Hotswap targets include both SCSI 
>>and FibreChannel.
>>Note this support is generic in that it will work in a typical PC system 
>>with SCSI or
>>FibreChannel disks.
>>    
>>
>
>Thanks a lot for doing the work.  There are still some issues to sort
>out, but I guess we'll be able to finish getting it integrated into
>the tree.
>
>Btw, please Cc linux-scsi@vger.kernel.org for scsi-related patches.
>
>  
>
>>linux-2.5.44-scsi-hotswap/drivers/scsi/hosts.c
>>--- linux-2.5.44-qla/drivers/scsi/hosts.c    Fri Oct 18 21:01:09 2002
>>+++ linux-2.5.44-scsi-hotswap/drivers/scsi/hosts.c    Wed Oct 23 
>>15:35:30 2002
>>@@ -371,6 +371,7 @@
>>    scsi_hosts_registered++;
>>
>>    spin_lock_init(&shost->default_lock);
>>+    spin_lock_init(&shost->host_queue_lock);
>>    scsi_assign_lock(shost, &shost->default_lock);
>>    atomic_set(&shost->host_active,0);
>>    
>>
>
>I think your mailer mangles the patch a bit, I'm pretty sure that
>code uses one tab indentation.  Please make sure that you use
>that indentation in new code (if you editor gets it wrong all
>the time just run the source through unexpand(1))
>  
>
I used tabs.  My mozilla mailer won't let me include patches inline so I 
guess I can just
attach them in the future.

>  
>
>>    int (* bios_param)(Disk *, struct block_device *, int []);
>>
>>+#ifdef CONFIG_SCSIFCHOTSWAP
>>+    /*
>>+     * Used to determine the id to send the inquiry command to during
>>+     * hot additions of FibreChannel targets
>>+     */
>>+    int (*get_scsi_info_from_wwn)(int mode, unsigned long long wwn, int 
>>*host, int *channel, int *lun, int *id);
>>+#endif
>>    
>>
>
>Please make this method unconditional - even if we don't call it without
>your option set, the drivers are cluttered up much less this way.
>  
>
I see your point.  Will do.

>  
>
>>@@ -0,0 +1,1334 @@
>>+/*
>>+ * hotswap.c
>>+ *
>>+ * SCSI/FibreChannel Hotswap kernel implementaton
>>+ * + * Author: MontaVista Software, Inc.
>>    
>>
>
>Is this + * intentional or a cut & paste error? :)
>  
>
must be a cut and paste error

>  
>
>>*buf)
>>+{
>>+    buf->f_type = SCSI_HOTSWAP_MAGIC;
>>+    buf->f_bsize = PAGE_CACHE_SIZE;
>>+    buf->f_namelen = 255;
>>+    return (0);
>>+}
>>    
>>
>
>Please take a look at fs/libfs.c.  For most of your filesystem
>methods you can just use the simple_* functions there.
>  
>
I'm going to move the driver to driverfs for the 2.5 patch so most of 
the comments should fall
out.  Thanks for looking at the code though!

[SNIP]

>  
>
>  
>
>>+static struct file_operations default_file_operations = {
>>+    read:        default_read_file,
>>+    write:         default_write_file,
>>+    open:        default_open,
>>+    llseek:        default_file_lseek,
>>+    fsync:         default_sync_file,
>>+    mmap:         generic_file_mmap,
>>+};
>>    
>>
>
>Please use C99 struct-initializers, i.e.
>
>static struct file_operations default_file_operations = {
>	.mmap = 	generic_file_mmap,
>};
>
>  
>
Thanks will do.

>>+ * scsi_hotswap_insert_by_scsi_id file operations structure
>>+ */
>>+static ssize_t scsi_hotswap_insert_by_scsi_id_read_file (struct file 
>>*file,
>>+    char *buf, size_t count, loff_t *offset);
>>+static ssize_t scsi_hotswap_insert_by_scsi_id_write_file (struct file 
>>*file,
>>+    const char *buf, size_t count, loff_t *ppos);
>>    
>>
>
>Looks like this wants a bit nicer line-wrapping (or shorter function
>names :))
>
><lots of file_operations snipped)
>
>Mayb you can put a switch into ->read/->write instead of having
>many different file operations?
>  
>
Good idea.

>  
>
>>+/*
>>+ * Core file read/write operations interfaces
>>+ */
>>+static char scsi_hotswap_insert_by_scsi_id_usage[] = {
>>+    "Usage: echo \"[host] [channel] [lun] [id]\" > insert_by_scsi_id\n"
>>+};
>>    
>>
>
>I don't think the kernel should supply usage information.
>  
>
I've gotten mixed feedback on this one.  One thing that annoys me about 
some of the proc read/write routines
to control the kernel is without looking at the code, there is no way to 
understand how to use them.

The user should be able to read the file and see "how to use" the method 
exported by the filesystem
without looking at the code (imho).  This is a big advantage of having a 
read() method.

>  
>
>>+/*
>>+ * Core Interface Implementation
>>+ * Note these are exported to the global symbol table for
>>+ * other subsystems to use such as a scsi processor or 1394
>>+ */
>>+int scsi_hotswap_insert_by_scsi_id (unsigned int host, unsigned int 
>>channel,
>>+    unsigned int lun, unsigned int id)
>>+{
>>+    struct Scsi_Host *scsi_host;
>>+    Scsi_Device *scsi_device;
>>+
>>+    for (scsi_host = scsi_host_get_next (NULL); scsi_host;
>>+        scsi_host = scsi_host_get_next (scsi_host)) {
>>+        if (scsi_host->host_no == host) {
>>+            break;
>>+        }
>>+    }
>>+    if (scsi_host == 0) {
>>+        return (-ENXIO);
>>+    }
>>+
>>+    spin_lock (&scsi_host->host_queue_lock);
>>+
>>+    /*
>>+     * Determine if device already attached
>>+     */
>>+    for (scsi_device = scsi_host->host_queue; scsi_device; scsi_device 
>>= scsi_device->next) {
>>+        if ((scsi_device->channel == channel
>>+             && scsi_device->id == id
>>+             && scsi_device->lun == lun)) {
>>+            break;
>>+        }
>>+    }
>>+   
>>+    spin_unlock (&scsi_host->host_queue_lock);
>>+
>>+    /*
>>+     * If scsi_device found in host queue, then device already attached
>>+     */
>>+    if (scsi_device) {
>>+        return (-EEXIST);
>>+    }
>>+
>>+    scan_scsis(scsi_host, 1, channel, id, lun);
>>+
>>+    return (0);
>>+}
>>    
>>
>
>This seems to be largely copied from proc_scsi_gen_write().  What about
>factoring out a common support function? (dito for many of the functions
>below)
>  
>
I'll replace proc_scsi_gen_writes() routine with this routine instead. 
 The point of this
routine is to be a generic call for other kernel functions to call like 
proc_scsi_gen_write.

I do think hotswap functionality should be removed from 
proc_scsi_gen_write but that might
confuse some folks that rely on that functionality.

>  
>
>>diff -uNr linux-2.5.44-qla/drivers/scsi/qla2xxx/qla2x00.c 
>>linux-2.5.44-scsi-hotswap/drivers/scsi/qla2xxx/qla2x00.c
>>--- linux-2.5.44-qla/drivers/scsi/qla2xxx/qla2x00.c    Wed Oct 23 
>>    
>>
>
>Doesn't seem to exist in my tree..
>  
>
This is in my private tree only and is the QLogic 6.1 driver integrated 
into 2.5.44.  This is
needed to support FibreChannel hotswap only.  The generic kernel can 
live without this patch
until the QLogic driver is integrated...

>  
>
>>diff -uNr linux-2.5.44-qla/include/linux/scsi_hotswap.h 
>>linux-2.5.44-scsi-hotswap/include/linux/scsi_hotswap.h
>>--- linux-2.5.44-qla/include/linux/scsi_hotswap.h    Wed Dec 31 17:00:00 
>>1969
>>+++ linux-2.5.44-scsi-hotswap/include/linux/scsi_hotswap.h    Wed Oct 23 
>>    
>>
>
>I think this one should go to include/scsi/ instead, that's where
>the other scsi headers live.
>
>  
>
This is in include/linux so that other kernel functions may call the 
hotswap operations and
have the function prototypes defined.  An example here is 1394.  We 
don't want 1394 having
to include "../../drivers/scsi/scsi_hotswap.h" I don't think :)

I'll make some of the changes you have suggested and post a new patch.

Thanks for the comments!
-steve


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2002-10-24 19:55 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-10-23 23:27 [PATCH] Advanced TCA SCSI/FC disk hotswap driver for kernel 2.5.44 Steven Dake
2002-10-24  0:18 ` Greg KH
2002-10-24  0:26   ` Steven Dake
2002-10-24  0:30     ` Greg KH
2002-10-24 16:51     ` Patrick Mochel
2002-10-24  0:27 ` Greg KH
2002-10-24  0:42 ` Christoph Hellwig
2002-10-24 20:04   ` Steven Dake
     [not found] ` <20021024042838.GA30891@codepoet.org>
2002-10-24 18:12   ` Steven Dake

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).