- Update to 3.3-rc2.
[linux-flexiantxendom0-3.2.10.git] / drivers / ata / ata_piix.c
index fdf27b9..f01bc40 100644 (file)
@@ -167,6 +167,7 @@ struct piix_host_priv {
 static int piix_init_one(struct pci_dev *pdev,
                         const struct pci_device_id *ent);
 static void piix_remove_one(struct pci_dev *pdev);
+static unsigned int piix_pata_read_id(struct ata_device *adev, struct ata_taskfile *tf, u16 *id);
 static int piix_pata_prereset(struct ata_link *link, unsigned long deadline);
 static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev);
 static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev);
@@ -351,6 +352,7 @@ static struct ata_port_operations piix_pata_ops = {
        .set_piomode            = piix_set_piomode,
        .set_dmamode            = piix_set_dmamode,
        .prereset               = piix_pata_prereset,
+       .read_id                = piix_pata_read_id,
 };
 
 static struct ata_port_operations piix_vmw_ops = {
@@ -638,6 +640,26 @@ MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
+static int piix_msft_hyperv(void)
+{
+       int hv = 0;
+#if defined(CONFIG_HYPERV_STORAGE) || defined(CONFIG_HYPERV_STORAGE_MODULE)
+       static const struct dmi_system_id hv_dmi_ident[]  = {
+               {
+                       .ident = "Hyper-V",
+                       .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+                               DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+                               DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"),
+                       },
+               },
+               { }     /* terminate list */
+       };
+       hv = !!dmi_check_system(hv_dmi_ident);
+#endif
+       return hv;
+}
+
 struct ich_laptop {
        u16 device;
        u16 subvendor;
@@ -729,6 +751,26 @@ static int piix_pata_prereset(struct ata_link *link, unsigned long deadline)
        return ata_sff_prereset(link, deadline);
 }
 
+static unsigned int piix_pata_read_id(struct ata_device *adev, struct ata_taskfile *tf, u16 *id)
+{
+       unsigned int err_mask = ata_do_dev_read_id(adev, tf, id);
+       /*
+        * Ignore disks in a hyper-v guest.
+        * There is no unplug protocol like it is done with xen_emul_unplug= option.
+        * Emulate the unplug by ignoring disks when the hv_storvsc driver is enabled.
+        * If the disks are not ignored, they will appear twice: once through
+        * piix and once through hv_storvsc.
+        * hv_storvsc can not handle ATAPI devices because they can only be
+        * accessed through the emulated code path (not through the vm_bus
+        * channel), the piix driver is still required.
+        */
+       if (ata_id_is_ata(id) && piix_msft_hyperv()) {
+               ata_dev_printk(adev, KERN_WARNING, "ATA device ignored in Hyper-V guest\n");
+               id[ATA_ID_CONFIG] |= (1 << 15);
+       }
+       return err_mask;
+}
+
 static DEFINE_SPINLOCK(piix_lock);
 
 static void piix_set_timings(struct ata_port *ap, struct ata_device *adev,