aoe: provide ATA identify device content to user on request
authorEd Cashin <ecashin@coraid.com>
Tue, 18 Dec 2012 00:03:42 +0000 (16:03 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 18 Dec 2012 01:15:24 +0000 (17:15 -0800)
Make the aoe driver follow expected behavior when the user uses ioctl to
get the ATA device identify information, allowing access to model, serial
number, etc.

Signed-off-by: Ed Cashin <ecashin@coraid.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/block/aoe/aoe.h
drivers/block/aoe/aoeblk.c
drivers/block/aoe/aoecmd.c

index 536942b46ab68220ab7e3990780016ef5aee6b7a..f6e0c03fe7b2a642f63a52bc436a0c0932771477 100644 (file)
@@ -169,6 +169,7 @@ struct aoedev {
        struct aoetgt *htgt;    /* target needing rexmit assistance */
        ulong ntargets;
        ulong kicked;
+       char ident[512];
 };
 
 /* kthread tracking */
index 56736cd5f3fef359fcd3f8a5b7d731c3e2b13d5a..7ba0fcf7b06b998472ccafaf55fb0b834fcb6307 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/mutex.h>
 #include <linux/export.h>
 #include <linux/moduleparam.h>
+#include <scsi/sg.h>
 #include "aoe.h"
 
 static DEFINE_MUTEX(aoeblk_mutex);
@@ -212,9 +213,38 @@ aoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return 0;
 }
 
+static int
+aoeblk_ioctl(struct block_device *bdev, fmode_t mode, uint cmd, ulong arg)
+{
+       struct aoedev *d;
+
+       if (!arg)
+               return -EINVAL;
+
+       d = bdev->bd_disk->private_data;
+       if ((d->flags & DEVFL_UP) == 0) {
+               pr_err("aoe: disk not up\n");
+               return -ENODEV;
+       }
+
+       if (cmd == HDIO_GET_IDENTITY) {
+               if (!copy_to_user((void __user *) arg, &d->ident,
+                       sizeof(d->ident)))
+                       return 0;
+               return -EFAULT;
+       }
+
+       /* udev calls scsi_id, which uses SG_IO, resulting in noise */
+       if (cmd != SG_IO)
+               pr_info("aoe: unknown ioctl 0x%x\n", cmd);
+
+       return -ENOTTY;
+}
+
 static const struct block_device_operations aoe_bdops = {
        .open = aoeblk_open,
        .release = aoeblk_release,
+       .ioctl = aoeblk_ioctl,
        .getgeo = aoeblk_getgeo,
        .owner = THIS_MODULE,
 };
index 3ce01f6b3a5d1fab5d2262dccf18e9f69eb48559..c4ff70b61e7e67b6509656110a674b46728fc6b7 100644 (file)
@@ -798,6 +798,17 @@ aoecmd_sleepwork(struct work_struct *work)
        }
 }
 
+static void
+ata_ident_fixstring(u16 *id, int ns)
+{
+       u16 s;
+
+       while (ns-- > 0) {
+               s = *id;
+               *id++ = s >> 8 | s << 8;
+       }
+}
+
 static void
 ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id)
 {
@@ -833,6 +844,11 @@ ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id)
                d->geo.sectors = get_unaligned_le16(&id[56 << 1]);
        }
 
+       ata_ident_fixstring((u16 *) &id[10<<1], 10);    /* serial */
+       ata_ident_fixstring((u16 *) &id[23<<1], 4);     /* firmware */
+       ata_ident_fixstring((u16 *) &id[27<<1], 20);    /* model */
+       memcpy(d->ident, id, sizeof(d->ident));
+
        if (d->ssize != ssize)
                printk(KERN_INFO
                        "aoe: %pm e%ld.%d v%04x has %llu sectors\n",