Revert to Fedora kernel-2.6.17-1.2187_FC5 patched with vs2.0.2.1; there are too many...
[linux-2.6.git] / drivers / infiniband / hw / ipath / ipath_diag.c
index 147dd89..28ddceb 100644 (file)
@@ -1,5 +1,4 @@
 /*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
 #include <linux/pci.h>
 #include <asm/uaccess.h>
 
+#include "ipath_common.h"
 #include "ipath_kernel.h"
+#include "ips_common.h"
 #include "ipath_layer.h"
-#include "ipath_common.h"
 
 int ipath_diag_inuse;
 static int diag_set_link;
@@ -66,20 +66,18 @@ static struct file_operations diag_file_ops = {
        .release = ipath_diag_release
 };
 
-int ipath_diag_add(struct ipath_devdata *dd)
-{
-       char name[16];
-
-       snprintf(name, sizeof(name), "ipath_diag%d", dd->ipath_unit);
+static struct cdev *diag_cdev;
+static struct class_device *diag_class_dev;
 
-       return ipath_cdev_init(IPATH_DIAG_MINOR_BASE + dd->ipath_unit, name,
-                              &diag_file_ops, &dd->diag_cdev,
-                              &dd->diag_class_dev);
+int ipath_diag_init(void)
+{
+       return ipath_cdev_init(IPATH_DIAG_MINOR, "ipath_diag",
+                              &diag_file_ops, &diag_cdev, &diag_class_dev);
 }
 
-void ipath_diag_remove(struct ipath_devdata *dd)
+void ipath_diag_cleanup(void)
 {
-       ipath_cdev_cleanup(&dd->diag_cdev, &dd->diag_class_dev);
+       ipath_cdev_cleanup(&diag_cdev, &diag_class_dev);
 }
 
 /**
@@ -103,7 +101,8 @@ static int ipath_read_umem64(struct ipath_devdata *dd, void __user *uaddr,
        int ret;
 
        /* not very efficient, but it works for now */
-       if (reg_addr < dd->ipath_kregbase || reg_end > dd->ipath_kregend) {
+       if (reg_addr < dd->ipath_kregbase ||
+           reg_end > dd->ipath_kregend) {
                ret = -EINVAL;
                goto bail;
        }
@@ -114,7 +113,7 @@ static int ipath_read_umem64(struct ipath_devdata *dd, void __user *uaddr,
                        goto bail;
                }
                reg_addr++;
-               uaddr += sizeof(u64);
+               uaddr++;
        }
        ret = 0;
 bail:
@@ -140,7 +139,8 @@ static int ipath_write_umem64(struct ipath_devdata *dd, void __iomem *caddr,
        int ret;
 
        /* not very efficient, but it works for now */
-       if (reg_addr < dd->ipath_kregbase || reg_end > dd->ipath_kregend) {
+       if (reg_addr < dd->ipath_kregbase ||
+           reg_end > dd->ipath_kregend) {
                ret = -EINVAL;
                goto bail;
        }
@@ -153,7 +153,7 @@ static int ipath_write_umem64(struct ipath_devdata *dd, void __iomem *caddr,
                writeq(data, reg_addr);
 
                reg_addr++;
-               uaddr += sizeof(u64);
+               uaddr++;
        }
        ret = 0;
 bail:
@@ -191,8 +191,7 @@ static int ipath_read_umem32(struct ipath_devdata *dd, void __user *uaddr,
                }
 
                reg_addr++;
-               uaddr += sizeof(u32);
-
+               uaddr++;
        }
        ret = 0;
 bail:
@@ -231,7 +230,7 @@ static int ipath_write_umem32(struct ipath_devdata *dd, void __iomem *caddr,
                writel(data, reg_addr);
 
                reg_addr++;
-               uaddr += sizeof(u32);
+               uaddr++;
        }
        ret = 0;
 bail:
@@ -240,45 +239,59 @@ bail:
 
 static int ipath_diag_open(struct inode *in, struct file *fp)
 {
-       int unit = iminor(in) - IPATH_DIAG_MINOR_BASE;
        struct ipath_devdata *dd;
+       int unit = 0; /* XXX this is bogus */
+       unsigned long flags;
        int ret;
 
+       dd = ipath_lookup(unit);
+
        mutex_lock(&ipath_mutex);
+       spin_lock_irqsave(&ipath_devs_lock, flags);
 
        if (ipath_diag_inuse) {
                ret = -EBUSY;
                goto bail;
        }
 
-       dd = ipath_lookup(unit);
-
-       if (dd == NULL || !(dd->ipath_flags & IPATH_PRESENT) ||
-           !dd->ipath_kregbase) {
-               ret = -ENODEV;
+       list_for_each_entry(dd, &ipath_dev_list, ipath_list) {
+               /*
+                * we need at least one infinipath device to be present
+                * (don't use INITTED, because we want to be able to open
+                * even if device is in freeze mode, which cleared INITTED).
+                * There is a small amount of risk to this, which is why we
+                * also verify kregbase is set.
+                */
+
+               if (!(dd->ipath_flags & IPATH_PRESENT) ||
+                   !dd->ipath_kregbase)
+                       continue;
+
+               ipath_diag_inuse = 1;
+               diag_set_link = 0;
+               ret = 0;
                goto bail;
        }
 
-       fp->private_data = dd;
-       ipath_diag_inuse = 1;
-       diag_set_link = 0;
-       ret = 0;
+       ret = -ENODEV;
+
+bail:
+       spin_unlock_irqrestore(&ipath_devs_lock, flags);
 
        /* Only expose a way to reset the device if we
           make it into diag mode. */
-       ipath_expose_reset(&dd->pcidev->dev);
+       if (ret == 0)
+               ipath_expose_reset(&dd->pcidev->dev);
 
-bail:
        mutex_unlock(&ipath_mutex);
 
        return ret;
 }
 
-static int ipath_diag_release(struct inode *in, struct file *fp)
+static int ipath_diag_release(struct inode *i, struct file *f)
 {
        mutex_lock(&ipath_mutex);
        ipath_diag_inuse = 0;
-       fp->private_data = NULL;
        mutex_unlock(&ipath_mutex);
        return 0;
 }
@@ -286,10 +299,17 @@ static int ipath_diag_release(struct inode *in, struct file *fp)
 static ssize_t ipath_diag_read(struct file *fp, char __user *data,
                               size_t count, loff_t *off)
 {
-       struct ipath_devdata *dd = fp->private_data;
+       int unit = 0; /* XXX provide for reads on other units some day */
+       struct ipath_devdata *dd;
        void __iomem *kreg_base;
        ssize_t ret;
 
+       dd = ipath_lookup(unit);
+       if (!dd) {
+               ret = -ENODEV;
+               goto bail;
+       }
+
        kreg_base = dd->ipath_kregbase;
 
        if (count == 0)
@@ -308,16 +328,23 @@ static ssize_t ipath_diag_read(struct file *fp, char __user *data,
                ret = count;
        }
 
+bail:
        return ret;
 }
 
 static ssize_t ipath_diag_write(struct file *fp, const char __user *data,
                                size_t count, loff_t *off)
 {
-       struct ipath_devdata *dd = fp->private_data;
+       int unit = 0; /* XXX this is bogus */
+       struct ipath_devdata *dd;
        void __iomem *kreg_base;
        ssize_t ret;
 
+       dd = ipath_lookup(unit);
+       if (!dd) {
+               ret = -ENODEV;
+               goto bail;
+       }
        kreg_base = dd->ipath_kregbase;
 
        if (count == 0)
@@ -336,5 +363,6 @@ static ssize_t ipath_diag_write(struct file *fp, const char __user *data,
                ret = count;
        }
 
+bail:
        return ret;
 }