jmicron ATA: reimplement jmicron ATA quirk
[powerpc.git] / block / genhd.c
index db4c60c..050a1f0 100644 (file)
@@ -2,10 +2,10 @@
  *  gendisk handling
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/genhd.h>
+#include <linux/kdev_t.h>
 #include <linux/kernel.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
 #include <linux/buffer_head.h>
 #include <linux/mutex.h>
 
-#define MAX_PROBE_HASH 255     /* random */
-
-static struct subsystem block_subsys;
-
+struct subsystem block_subsys;
 static DEFINE_MUTEX(block_subsys_lock);
 
 /*
@@ -31,108 +28,29 @@ static struct blk_major_name {
        struct blk_major_name *next;
        int major;
        char name[16];
-} *major_names[MAX_PROBE_HASH];
+} *major_names[BLKDEV_MAJOR_HASH_SIZE];
 
 /* index in the above - for now: assume no multimajor ranges */
 static inline int major_to_index(int major)
 {
-       return major % MAX_PROBE_HASH;
-}
-
-struct blkdev_info {
-        int index;
-        struct blk_major_name *bd;
-};
-
-/*
- * iterate over a list of blkdev_info structures.  allows
- * the major_names array to be iterated over from outside this file
- * must be called with the block_subsys_lock held
- */
-void *get_next_blkdev(void *dev)
-{
-        struct blkdev_info *info;
-
-        if (dev == NULL) {
-                info = kmalloc(sizeof(*info), GFP_KERNEL);
-                if (!info)
-                        goto out;
-                info->index=0;
-                info->bd = major_names[info->index];
-                if (info->bd)
-                        goto out;
-        } else {
-                info = dev;
-        }
-
-        while (info->index < ARRAY_SIZE(major_names)) {
-                if (info->bd)
-                        info->bd = info->bd->next;
-                if (info->bd)
-                        goto out;
-                /*
-                 * No devices on this chain, move to the next
-                 */
-                info->index++;
-                info->bd = (info->index < ARRAY_SIZE(major_names)) ?
-                       major_names[info->index] : NULL;
-                if (info->bd)
-                        goto out;
-        }
-
-out:
-        return info;
-}
-
-void *acquire_blkdev_list(void)
-{
-        mutex_lock(&block_subsys_lock);
-        return get_next_blkdev(NULL);
-}
-
-void release_blkdev_list(void *dev)
-{
-        mutex_unlock(&block_subsys_lock);
-        kfree(dev);
+       return major % BLKDEV_MAJOR_HASH_SIZE;
 }
 
+#ifdef CONFIG_PROC_FS
 
-/*
- * Count the number of records in the blkdev_list.
- * must be called with the block_subsys_lock held
- */
-int count_blkdev_list(void)
+void blkdev_show(struct seq_file *f, off_t offset)
 {
-       struct blk_major_name *n;
-       int i, count;
-
-       count = 0;
+       struct blk_major_name *dp;
 
-       for (i = 0; i < ARRAY_SIZE(major_names); i++) {
-               for (n = major_names[i]; n; n = n->next)
-                               count++;
+       if (offset < BLKDEV_MAJOR_HASH_SIZE) {
+               mutex_lock(&block_subsys_lock);
+               for (dp = major_names[offset]; dp; dp = dp->next)
+                       seq_printf(f, "%3d %s\n", dp->major, dp->name);
+               mutex_unlock(&block_subsys_lock);
        }
-
-       return count;
-}
-
-/*
- * extract the major and name values from a blkdev_info struct
- * passed in as a void to *dev.  Must be called with
- * block_subsys_lock held
- */
-int get_blkdev_info(void *dev, int *major, char **name)
-{
-        struct blkdev_info *info = dev;
-
-        if (info->bd == NULL)
-                return 1;
-
-        *major = info->bd->major;
-        *name = info->bd->name;
-        return 0;
 }
 
+#endif /* CONFIG_PROC_FS */
 
 int register_blkdev(unsigned int major, const char *name)
 {
@@ -144,6 +62,8 @@ int register_blkdev(unsigned int major, const char *name)
        /* temporary */
        if (major == 0) {
                for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {
+                       if (is_lanana_major(index))
+                               continue;
                        if (major_names[index] == NULL)
                                break;
                }
@@ -378,10 +298,15 @@ static struct kobject *base_probe(dev_t dev, int *part, void *data)
 
 static int __init genhd_device_init(void)
 {
+       int err;
+
        bdev_map = kobj_map_init(base_probe, &block_subsys_lock);
        blk_dev_init();
-       subsystem_register(&block_subsys);
-       return 0;
+       err = subsystem_register(&block_subsys);
+       if (err < 0)
+               printk(KERN_WARNING "%s: subsystem_register error: %d\n",
+                       __FUNCTION__, err);
+       return err;
 }
 
 subsys_initcall(genhd_device_init);
@@ -495,6 +420,34 @@ static struct disk_attribute disk_attr_stat = {
        .show   = disk_stats_read
 };
 
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+
+static ssize_t disk_fail_store(struct gendisk * disk,
+                              const char *buf, size_t count)
+{
+       int i;
+
+       if (count > 0 && sscanf(buf, "%d", &i) > 0) {
+               if (i == 0)
+                       disk->flags &= ~GENHD_FL_FAIL;
+               else
+                       disk->flags |= GENHD_FL_FAIL;
+       }
+
+       return count;
+}
+static ssize_t disk_fail_read(struct gendisk * disk, char *page)
+{
+       return sprintf(page, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0);
+}
+static struct disk_attribute disk_attr_fail = {
+       .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR },
+       .store  = disk_fail_store,
+       .show   = disk_fail_read
+};
+
+#endif
+
 static struct attribute * default_attrs[] = {
        &disk_attr_uevent.attr,
        &disk_attr_dev.attr,
@@ -502,6 +455,9 @@ static struct attribute * default_attrs[] = {
        &disk_attr_removable.attr,
        &disk_attr_size.attr,
        &disk_attr_stat.attr,
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+       &disk_attr_fail.attr,
+#endif
        NULL,
 };
 
@@ -592,9 +548,7 @@ static struct kset_uevent_ops block_uevent_ops = {
        .uevent         = block_uevent,
 };
 
-/* declare block_subsys. */
-static decl_subsys(block, &ktype_block, &block_uevent_ops);
-
+decl_subsys(block, &ktype_block, &block_uevent_ops);
 
 /*
  * aggregate disk stat collector.  Uses the same stats that the sysfs