Staging: hv: storvsc: Handle IDE devices using the storvsc driver
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / hv / storvsc_drv.c
index 7effaf32e25f531a0787ca2dfbdb56d6d638f8f5..9464f99bf7a1ed37b0d48adf33a42b74f0d63e58 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/blkdev.h>
-#include <linux/dmi.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_host.h>
@@ -42,16 +41,6 @@ static int storvsc_ringbuffer_size = STORVSC_RING_BUFFER_SIZE;
 module_param(storvsc_ringbuffer_size, int, S_IRUGO);
 MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
 
-static const char *driver_name = "storvsc";
-
-/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
-static const struct hv_guid stor_vsci_device_type = {
-       .data = {
-               0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
-               0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
-       }
-};
-
 struct hv_host_device {
        struct hv_device *dev;
        struct kmem_cache *request_pool;
@@ -70,6 +59,17 @@ struct storvsc_cmd_request {
        struct hv_storvsc_request request;
 };
 
+static void storvsc_get_ide_info(struct hv_device *dev, int *target, int *path)
+{
+       *target =
+               dev->dev_instance.b[5] << 8 | dev->dev_instance.b[4];
+
+       *path =
+               dev->dev_instance.b[3] << 24 |
+               dev->dev_instance.b[2] << 16 |
+               dev->dev_instance.b[1] << 8  | dev->dev_instance.b[0];
+}
+
 
 static int storvsc_device_alloc(struct scsi_device *sdevice)
 {
@@ -355,9 +355,9 @@ static int storvsc_host_reset(struct hv_device *device)
        int ret, t;
 
 
-       stor_device = get_stor_device(device);
+       stor_device = get_out_stor_device(device);
        if (!stor_device)
-               return -1;
+               return -ENODEV;
 
        request = &stor_device->reset_request;
        vstor_packet = &request->vstor_packet;
@@ -389,7 +389,6 @@ static int storvsc_host_reset(struct hv_device *device)
         */
 
 cleanup:
-       put_stor_device(device);
        return ret;
 }
 
@@ -589,7 +588,7 @@ retry_request:
        /* Invokes the vsc to start an IO */
        ret = storvsc_do_io(dev, &cmd_request->request);
 
-       if (ret == -1) {
+       if (ret == -EAGAIN) {
                /* no more space */
 
                if (cmd_request->bounce_sgl_count) {
@@ -646,6 +645,22 @@ static struct scsi_host_template scsi_driver = {
        .dma_boundary =         PAGE_SIZE-1,
 };
 
+/*
+ * The storvsc_probe function assumes that the IDE guid
+ * is the second entry.
+ */
+static const struct hv_vmbus_device_id id_table[] = {
+       /* SCSI guid */
+       { VMBUS_DEVICE(0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
+                      0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f) },
+       /* IDE guid */
+       { VMBUS_DEVICE(0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
+                      0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5) },
+       { },
+};
+
+MODULE_DEVICE_TABLE(vmbus, id_table);
+
 
 /*
  * storvsc_probe - Add a new device for this driver
@@ -657,6 +672,14 @@ static int storvsc_probe(struct hv_device *device)
        struct Scsi_Host *host;
        struct hv_host_device *host_dev;
        struct storvsc_device_info device_info;
+       bool dev_is_ide;
+       int path = 0;
+       int target = 0;
+
+       if (!memcmp(&device->dev_type.b, id_table[1].guid, sizeof(uuid_le)))
+               dev_is_ide = true;
+       else
+               dev_is_ide = false;
 
        host = scsi_host_alloc(&scsi_driver,
                               sizeof(struct hv_host_device));
@@ -689,9 +712,12 @@ static int storvsc_probe(struct hv_device *device)
        if (ret != 0) {
                kmem_cache_destroy(host_dev->request_pool);
                scsi_host_put(host);
-               return -1;
+               return -ENODEV;
        }
 
+       if (dev_is_ide)
+               storvsc_get_ide_info(device, &target, &path);
+
        host_dev->path = device_info.path_id;
        host_dev->target = device_info.target_id;
 
@@ -704,51 +730,38 @@ static int storvsc_probe(struct hv_device *device)
 
        /* Register the HBA and start the scsi bus scan */
        ret = scsi_add_host(host, &device->device);
-       if (ret != 0) {
-
-               storvsc_dev_remove(device);
+       if (ret != 0)
+               goto err_out;
 
-               kmem_cache_destroy(host_dev->request_pool);
-               scsi_host_put(host);
-               return -1;
+       if (!dev_is_ide) {
+               scsi_scan_host(host);
+               return 0;
        }
+       ret = scsi_add_device(host, 0, target, 0);
+       if (ret) {
+               scsi_remove_host(host);
+               goto err_out;
+       }
+       return 0;
 
-       scsi_scan_host(host);
-       return ret;
+err_out:
+       storvsc_dev_remove(device);
+       kmem_cache_destroy(host_dev->request_pool);
+       scsi_host_put(host);
+       return -ENODEV;
 }
 
 /* The one and only one */
 
 static struct hv_driver storvsc_drv = {
+       .name = "storvsc",
+       .id_table = id_table,
        .probe = storvsc_probe,
        .remove = storvsc_remove,
 };
 
-/*
- * We use a DMI table to determine if we should autoload this driver  This is
- * needed by distro tools to determine if the hyperv drivers should be
- * installed and/or configured.  We don't do anything else with the table, but
- * it needs to be present.
- */
-
-static const struct dmi_system_id __initconst
-hv_stor_dmi_table[] __maybe_unused  = {
-       {
-               .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"),
-               },
-       },
-       { },
-};
-MODULE_DEVICE_TABLE(dmi, hv_stor_dmi_table);
-
 static int __init storvsc_drv_init(void)
 {
-       int ret;
-       struct hv_driver *drv = &storvsc_drv;
        u32 max_outstanding_req_per_channel;
 
        /*
@@ -757,32 +770,22 @@ static int __init storvsc_drv_init(void)
         * the ring buffer indices) by the max request size (which is
         * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64)
         */
-
        max_outstanding_req_per_channel =
-       ((storvsc_ringbuffer_size - PAGE_SIZE) /
-       ALIGN(MAX_MULTIPAGE_BUFFER_PACKET +
-       sizeof(struct vstor_packet) + sizeof(u64),
-       sizeof(u64)));
-
-       memcpy(&drv->dev_type, &stor_vsci_device_type,
-              sizeof(struct hv_guid));
+               ((storvsc_ringbuffer_size - PAGE_SIZE) /
+               ALIGN(MAX_MULTIPAGE_BUFFER_PACKET +
+               sizeof(struct vstor_packet) + sizeof(u64),
+               sizeof(u64)));
 
        if (max_outstanding_req_per_channel <
            STORVSC_MAX_IO_REQUESTS)
-               return -1;
-
-       drv->driver.name = driver_name;
-
+               return -EINVAL;
 
-       /* The driver belongs to vmbus */
-       ret = vmbus_child_driver_register(&drv->driver);
-
-       return ret;
+       return vmbus_driver_register(&storvsc_drv);
 }
 
 static void __exit storvsc_drv_exit(void)
 {
-       vmbus_child_driver_unregister(&storvsc_drv.driver);
+       vmbus_driver_unregister(&storvsc_drv);
 }
 
 MODULE_LICENSE("GPL");