From 99874e8cedc6c0aad950a9a4ecf70734567f1028 Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Mon, 27 Aug 2012 13:43:14 -0300
Subject: [RHEL6 qemu-kvm PATCH 4/5] ide: Adds wwn=hex qdev option

RH-Author: Paolo Bonzini <pbonzini@redhat.com>
Message-id: <1346074994-12293-3-git-send-email-pbonzini@redhat.com>
Patchwork-id: 41336
O-Subject: [RHEL 6.4 qemu-kvm PATCH 2/2] ide: Adds wwn=hex qdev option
Bugzilla: 831102
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Alex Williamson <alex.williamson@redhat.com>

From: Floris Bos <bos@je-eigen-domein.nl>

Bugzilla: 831102

Allow the user to specify a disk's World Wide Name.

Linux guests can address disks by their unique World Wide Name number
(e.g. /dev/disk/by-id/wwn-0x5001517959123522). This patch adds support
for assigning a World Wide Name number to a virtual IDE disk.

Cc: kwolf@redhat.com
Signed-off-by: Floris Bos <dev@noc-ps.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 95ebda85e09ed2b7f00deb2adbdafa5ccf5db948)

Conflicts:
	hw/ide/core.c
	hw/ide/internal.h
	hw/ide/qdev.c
---
 hw/ide/core.c     | 29 +++++++++++++++++++++++------
 hw/ide/internal.h |  5 ++++-
 hw/ide/qdev.c     |  3 ++-
 3 file modificati, 29 inserzioni(+), 8 rimozioni(-)

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 hw/ide/core.c     | 29 +++++++++++++++++++++++------
 hw/ide/internal.h |  5 ++++-
 hw/ide/qdev.c     |  3 ++-
 3 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 0eb1da1..74e7831 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -119,8 +119,12 @@ static void ide_identify(IDEState *s)
     put_le16(p + 82, (1 << 14) | 1);
     /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
     put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
-    /* 14=set to 1, 1=SMART self test, 0=SMART error logging */
-    put_le16(p + 84, (1 << 14) | 0);
+    /* 14=set to 1, 8=has WWN, 1=SMART self test, 0=SMART error logging */
+    if (s->wwn) {
+        put_le16(p + 84, (1 << 14) | (1 << 8) | 0);
+    } else {
+        put_le16(p + 84, (1 << 14) | 0);
+    }
     /* 14 = NOP supported, 5=WCACHE enabled, 0=SMART feature set enabled */
     if (bdrv_enable_write_cache(s->bs))
          put_le16(p + 85, (1 << 14) | (1 << 5) | 1);
@@ -128,8 +132,12 @@ static void ide_identify(IDEState *s)
          put_le16(p + 85, (1 << 14) | 1);
     /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
     put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
-    /* 14=set to 1, 1=smart self test, 0=smart error logging */
-    put_le16(p + 87, (1 << 14) | 0);
+    /* 14=set to 1, 8=has WWN, 1=SMART self test, 0=SMART error logging */
+    if (s->wwn) {
+        put_le16(p + 87, (1 << 14) | (1 << 8) | 0);
+    } else {
+        put_le16(p + 87, (1 << 14) | 0);
+    }
     put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
     put_le16(p + 93, 1 | (1 << 14) | 0x2000);
     put_le16(p + 100, s->nb_sectors);
@@ -139,6 +147,13 @@ static void ide_identify(IDEState *s)
     dev = s->unit ? s->bus->slave : s->bus->master;
     if (dev && dev->conf.physical_block_size)
         put_le16(p + 106, 0x6000 | get_physical_block_exp(&dev->conf));
+    if (s->wwn) {
+        /* LE 16-bit words 111-108 contain 64-bit World Wide Name */
+        put_le16(p + 108, s->wwn >> 48);
+        put_le16(p + 109, s->wwn >> 32);
+        put_le16(p + 110, s->wwn >> 16);
+        put_le16(p + 111, s->wwn);
+    }
 
     memcpy(s->identify_data, p, sizeof(s->identify_data));
     s->identify_set = 1;
@@ -1853,7 +1868,8 @@ static const BlockDevOps ide_cd_block_ops = {
     .is_medium_locked = ide_cd_is_medium_locked,
 };
 
-int ide_init_drive(IDEState *s, BlockDriverState *bs, const char *version)
+int ide_init_drive(IDEState *s, BlockDriverState *bs, const char *version,
+                   uint64_t wwn)
 {
     int cylinders, heads, secs;
     uint64_t nb_sectors;
@@ -1877,6 +1893,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, const char *version)
     s->heads = heads;
     s->sectors = secs;
     s->nb_sectors = nb_sectors;
+    s->wwn = wwn;
     /* The SMART values should be preserved across power cycles
        but they aren't.  */
     s->smart_enabled = 1;
@@ -1952,7 +1969,7 @@ void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
         dinfo = i == 0 ? hd0 : hd1;
         ide_init1(bus, i);
         if (dinfo) {
-            if (ide_init_drive(&bus->ifs[i], dinfo->bdrv, NULL) < 0) {
+            if (ide_init_drive(&bus->ifs[i], dinfo->bdrv, NULL, 0) < 0) {
                 error_report("Can't set up IDE drive %s", dinfo->id);
                 exit(1);
             }
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index d0bfc7d..83ae6f0 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -399,6 +399,7 @@ struct IDEState {
     uint8_t identify_data[512];
     int drive_serial;
     char drive_serial_str[21];
+    uint64_t wwn;
     /* ide regs */
     uint8_t feature;
     uint8_t error;
@@ -485,6 +486,7 @@ struct IDEDevice {
     uint32_t unit;
     BlockConf conf;
     char *version;
+    uint64_t wwn;
 };
 
 typedef int (*ide_qdev_initfn)(IDEDevice *dev);
@@ -596,7 +598,8 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr);
 void ide_data_writel(void *opaque, uint32_t addr, uint32_t val);
 uint32_t ide_data_readl(void *opaque, uint32_t addr);
 
-int ide_init_drive(IDEState *s, BlockDriverState *bs, const char *version);
+int ide_init_drive(IDEState *s, BlockDriverState *bs, const char *version,
+                   uint64_t wwn);
 void ide_init2(IDEBus *bus, qemu_irq irq);
 void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
                                     DriveInfo *hd1, qemu_irq irq);
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 703de84..247f879 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -113,7 +113,7 @@ static int ide_drive_initfn(IDEDevice *dev)
 {
     IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
 
-    if (ide_init_drive(bus->ifs + dev->unit, dev->conf.bs, dev->version) < 0) {
+    if (ide_init_drive(bus->ifs + dev->unit, dev->conf.bs, dev->version, dev->wwn) < 0) {
         return -1;
     }
 
@@ -132,6 +132,7 @@ static IDEDeviceInfo ide_drive_info = {
         DEFINE_PROP_UINT32("unit", IDEDrive, dev.unit, -1),
         DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf),
         DEFINE_PROP_STRING("ver",  IDEDrive, dev.version),
+        DEFINE_PROP_HEX64("wwn",  IDEDrive, dev.wwn, 0),
         DEFINE_PROP_END_OF_LIST(),
     }
 };
-- 
1.7.11.4

