Staging: hv: storvsc_drv: Get rid of some unnecessary DPRINTs
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / hv / storvsc_drv.c
index 2060206024bd552a55d8debe486e431f825ece94..07db877ff18125f4552e1f858dd313e1c4da82e6 100644 (file)
@@ -17,6 +17,7 @@
  * Authors:
  *   Haiyang Zhang <haiyangz@microsoft.com>
  *   Hank Janssen  <hjanssen@microsoft.com>
+ *   K. Y. Srinivasan <kys@microsoft.com>
  */
 #include <linux/init.h>
 #include <linux/slab.h>
 #include "vstorage.h"
 #include "channel.h"
 
+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 *g_driver_name = "storvsc";
+static const char *driver_name = "storvsc";
 
 /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
 static const struct hv_guid gStorVscDeviceType = {
@@ -50,11 +55,8 @@ static const struct hv_guid gStorVscDeviceType = {
        }
 };
 
-struct host_device_context {
-       /* must be 1st field
-        * FIXME this is a bug */
-       /* point back to our device context */
-       struct hv_device *device_ctx;
+struct hv_host_device {
+       struct hv_device *dev;
        struct kmem_cache *request_pool;
        unsigned int port;
        unsigned char path;
@@ -73,25 +75,18 @@ struct storvsc_cmd_request {
 
 
 /*
- * stor_vsc_initialize - Main entry point
+ * storvsc_initialize - Main entry point
  */
-static int stor_vsc_initialize(struct hv_driver *driver)
+static int storvsc_initialize(struct hv_driver *driver)
 {
-       struct storvsc_driver_object *stor_driver;
+       struct storvsc_driver *stor_driver;
 
        stor_driver = hvdr_to_stordr(driver);
 
-       DPRINT_DBG(STORVSC,
-                  "sizeof(struct hv_storvsc_request)=%zd "
-                  "sizeof(struct vstor_packet)=%zd, "
-                  "sizeof(struct vmscsi_request)=%zd",
-                  sizeof(struct hv_storvsc_request),
-                  sizeof(struct vstor_packet),
-                  sizeof(struct vmscsi_request));
 
        /* Make sure we are at least 2 pages since 1 page is used for control */
 
-       driver->name = g_driver_name;
+       driver->name = driver_name;
        memcpy(&driver->dev_type, &gStorVscDeviceType,
               sizeof(struct hv_guid));
 
@@ -108,379 +103,58 @@ static int stor_vsc_initialize(struct hv_driver *driver)
                           sizeof(struct vstor_packet) + sizeof(u64),
                           sizeof(u64)));
 
-       DPRINT_INFO(STORVSC, "max io %u, currently %u\n",
-                   stor_driver->max_outstanding_req_per_channel,
-                   STORVSC_MAX_IO_REQUESTS);
-
-       /* Setup the dispatch table */
-       stor_driver->base.dev_add       = stor_vsc_on_device_add;
-       stor_driver->base.dev_rm        = stor_vsc_on_device_remove;
-       stor_driver->base.cleanup       = stor_vsc_on_cleanup;
-
-       stor_driver->on_io_request      = stor_vsc_on_io_request;
 
        return 0;
 }
 
-/* Static decl */
-static int storvsc_probe(struct hv_device *dev);
-static int storvsc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd);
-static int storvsc_device_alloc(struct scsi_device *);
-static int storvsc_device_configure(struct scsi_device *);
-static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd);
-static int storvsc_remove(struct device *dev);
-
-static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl,
-                                               unsigned int sg_count,
-                                               unsigned int len);
-static void destroy_bounce_buffer(struct scatterlist *sgl,
-                                 unsigned int sg_count);
-static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count);
-static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
-                                           struct scatterlist *bounce_sgl,
-                                           unsigned int orig_sgl_count);
-static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
-                                         struct scatterlist *bounce_sgl,
-                                         unsigned int orig_sgl_count);
-
-static int storvsc_get_chs(struct scsi_device *sdev, struct block_device *bdev,
-                          sector_t capacity, int *info);
-
-
-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)");
-
-/* The one and only one */
-static struct storvsc_driver_object g_storvsc_drv;
-
-/* Scsi driver */
-static struct scsi_host_template scsi_driver = {
-       .module =               THIS_MODULE,
-       .name =                 "storvsc_host_t",
-       .bios_param =           storvsc_get_chs,
-       .queuecommand =         storvsc_queuecommand,
-       .eh_host_reset_handler =        storvsc_host_reset_handler,
-       .slave_alloc =          storvsc_device_alloc,
-       .slave_configure =      storvsc_device_configure,
-       .cmd_per_lun =          1,
-       /* 64 max_queue * 1 target */
-       .can_queue =            STORVSC_MAX_IO_REQUESTS*STORVSC_MAX_TARGETS,
-       .this_id =              -1,
-       /* no use setting to 0 since ll_blk_rw reset it to 1 */
-       /* currently 32 */
-       .sg_tablesize =         MAX_MULTIPAGE_BUFFER_COUNT,
-       /*
-        * ENABLE_CLUSTERING allows mutiple physically contig bio_vecs to merge
-        * into 1 sg element. If set, we must limit the max_segment_size to
-        * PAGE_SIZE, otherwise we may get 1 sg element that represents
-        * multiple
-        */
-       /* physically contig pfns (ie sg[x].length > PAGE_SIZE). */
-       .use_clustering =       ENABLE_CLUSTERING,
-       /* Make sure we dont get a sg segment crosses a page boundary */
-       .dma_boundary =         PAGE_SIZE-1,
-};
-
-
-/*
- * storvsc_drv_init - StorVsc driver initialization.
- */
-static int storvsc_drv_init(void)
-{
-       int ret;
-       struct storvsc_driver_object *storvsc_drv_obj = &g_storvsc_drv;
-       struct hv_driver *drv = &g_storvsc_drv.base;
-
-       storvsc_drv_obj->ring_buffer_size = storvsc_ringbuffer_size;
-
-       /* Callback to client driver to complete the initialization */
-       stor_vsc_initialize(&storvsc_drv_obj->base);
-
-       DPRINT_INFO(STORVSC_DRV,
-                   "max outstanding reqs %u",
-                   storvsc_drv_obj->max_outstanding_req_per_channel);
-
-       if (storvsc_drv_obj->max_outstanding_req_per_channel <
-           STORVSC_MAX_IO_REQUESTS) {
-               DPRINT_ERR(STORVSC_DRV,
-                          "The number of outstanding io requests (%d) "
-                          "is larger than that supported (%d) internally.",
-                          STORVSC_MAX_IO_REQUESTS,
-                          storvsc_drv_obj->max_outstanding_req_per_channel);
-               return -1;
-       }
-
-       drv->driver.name = storvsc_drv_obj->base.name;
-
-       drv->probe = storvsc_probe;
-       drv->driver.remove = storvsc_remove;
-
-       /* The driver belongs to vmbus */
-       ret = vmbus_child_driver_register(&drv->driver);
-
-       return ret;
-}
-
-
-static int stor_vsc_on_host_reset(struct hv_device *device)
+static int storvsc_device_alloc(struct scsi_device *sdevice)
 {
-       struct storvsc_device *stor_device;
-       struct hv_storvsc_request *request;
-       struct vstor_packet *vstor_packet;
-       int ret, t;
-
-       DPRINT_INFO(STORVSC, "resetting host adapter...");
-
-       stor_device = get_stor_device(device);
-       if (!stor_device) {
-               DPRINT_ERR(STORVSC, "unable to get stor device..."
-                          "device being destroyed?");
-               return -1;
-       }
-
-       request = &stor_device->reset_request;
-       vstor_packet = &request->vstor_packet;
-
-       init_completion(&request->wait_event);
-
-       vstor_packet->operation = VSTOR_OPERATION_RESET_BUS;
-       vstor_packet->flags = REQUEST_COMPLETION_FLAG;
-       vstor_packet->vm_srb.path_id = stor_device->path_id;
-
-       ret = vmbus_sendpacket(device->channel, vstor_packet,
-                              sizeof(struct vstor_packet),
-                              (unsigned long)&stor_device->reset_request,
-                              VM_PKT_DATA_INBAND,
-                              VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-       if (ret != 0) {
-               DPRINT_ERR(STORVSC, "Unable to send reset packet %p ret %d",
-                          vstor_packet, ret);
-               goto cleanup;
-       }
-
-       t = wait_for_completion_timeout(&request->wait_event, HZ);
-       if (t == 0) {
-               ret = -ETIMEDOUT;
-               goto cleanup;
-       }
-
-       DPRINT_INFO(STORVSC, "host adapter reset completed");
-
        /*
-        * At this point, all outstanding requests in the adapter
-        * should have been flushed out and return to us
+        * This enables luns to be located sparsely. Otherwise, we may not
+        * discovered them.
         */
-
-cleanup:
-       put_stor_device(device);
-       return ret;
-}
-
-static int storvsc_drv_exit_cb(struct device *dev, void *data)
-{
-       struct device **curr = (struct device **)data;
-       *curr = dev;
-       return 1; /* stop iterating */
-}
-
-static void storvsc_drv_exit(void)
-{
-       struct storvsc_driver_object *storvsc_drv_obj = &g_storvsc_drv;
-       struct hv_driver *drv = &g_storvsc_drv.base;
-       struct device *current_dev = NULL;
-       int ret;
-
-       while (1) {
-               current_dev = NULL;
-
-               /* Get the device */
-               ret = driver_for_each_device(&drv->driver, NULL,
-                                            (void *) &current_dev,
-                                            storvsc_drv_exit_cb);
-
-               if (ret)
-                       DPRINT_WARN(STORVSC_DRV,
-                                   "driver_for_each_device returned %d", ret);
-
-               if (current_dev == NULL)
-                       break;
-
-               /* Initiate removal from the top-down */
-               device_unregister(current_dev);
-       }
-
-       if (storvsc_drv_obj->base.cleanup)
-               storvsc_drv_obj->base.cleanup(&storvsc_drv_obj->base);
-
-       vmbus_child_driver_unregister(&drv->driver);
-       return;
+       sdevice->sdev_bflags |= BLIST_SPARSELUN | BLIST_LARGELUN;
+       return 0;
 }
 
-/*
- * storvsc_probe - Add a new device for this driver
- */
-static int storvsc_probe(struct hv_device *device)
+static int storvsc_merge_bvec(struct request_queue *q,
+                             struct bvec_merge_data *bmd, struct bio_vec *bvec)
 {
-       int ret;
-       struct storvsc_driver_object *storvsc_drv_obj =
-                drv_to_stordrv(device->device.driver);
-       struct Scsi_Host *host;
-       struct host_device_context *host_device_ctx;
-       struct storvsc_device_info device_info;
-
-       if (!storvsc_drv_obj->base.dev_add)
-               return -1;
-
-       host = scsi_host_alloc(&scsi_driver,
-                              sizeof(struct host_device_context));
-       if (!host) {
-               DPRINT_ERR(STORVSC_DRV, "unable to allocate scsi host object");
-               return -ENOMEM;
-       }
-
-       dev_set_drvdata(&device->device, host);
-
-       host_device_ctx = (struct host_device_context *)host->hostdata;
-       memset(host_device_ctx, 0, sizeof(struct host_device_context));
-
-       host_device_ctx->port = host->host_no;
-       host_device_ctx->device_ctx = device;
-
-       host_device_ctx->request_pool =
-                               kmem_cache_create(dev_name(&device->device),
-                                       sizeof(struct storvsc_cmd_request), 0,
-                                       SLAB_HWCACHE_ALIGN, NULL);
-
-       if (!host_device_ctx->request_pool) {
-               scsi_host_put(host);
-               return -ENOMEM;
-       }
-
-       device_info.port_number = host->host_no;
-       /* Call to the vsc driver to add the device */
-       ret = storvsc_drv_obj->base.dev_add(device, (void *)&device_info);
-
-       if (ret != 0) {
-               DPRINT_ERR(STORVSC_DRV, "unable to add scsi vsc device");
-               kmem_cache_destroy(host_device_ctx->request_pool);
-               scsi_host_put(host);
-               return -1;
-       }
-
-       /* host_device_ctx->port = device_info.PortNumber; */
-       host_device_ctx->path = device_info.path_id;
-       host_device_ctx->target = device_info.target_id;
-
-       /* max # of devices per target */
-       host->max_lun = STORVSC_MAX_LUNS_PER_TARGET;
-       /* max # of targets per channel */
-       host->max_id = STORVSC_MAX_TARGETS;
-       /* max # of channels */
-       host->max_channel = STORVSC_MAX_CHANNELS - 1;
-
-       /* Register the HBA and start the scsi bus scan */
-       ret = scsi_add_host(host, &device->device);
-       if (ret != 0) {
-               DPRINT_ERR(STORVSC_DRV, "unable to add scsi host device");
-
-               storvsc_drv_obj->base.dev_rm(device);
-
-               kmem_cache_destroy(host_device_ctx->request_pool);
-               scsi_host_put(host);
-               return -1;
-       }
-
-       scsi_scan_host(host);
-       return ret;
+       /* checking done by caller. */
+       return bvec->bv_len;
 }
 
-/*
- * storvsc_remove - Callback when our device is removed
- */
-static int storvsc_remove(struct device *device)
+static int storvsc_device_configure(struct scsi_device *sdevice)
 {
-       struct storvsc_driver_object *storvsc_drv_obj =
-                        drv_to_stordrv(device->driver);
-       struct hv_device *device_obj = device_to_hv_device(device);
-       struct Scsi_Host *host = dev_get_drvdata(device);
-       struct host_device_context *host_device_ctx =
-                       (struct host_device_context *)host->hostdata;
+       scsi_adjust_queue_depth(sdevice, MSG_SIMPLE_TAG,
+                               STORVSC_MAX_IO_REQUESTS);
 
-       /*
-        * Call to the vsc driver to let it know that the device is being
-        * removed
-        */
-       storvsc_drv_obj->base.dev_rm(device_obj);
+       DPRINT_INFO(STORVSC_DRV, "sdev (%p) - setting max segment size to %ld",
+                   sdevice, PAGE_SIZE);
+       blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE);
 
-       if (host_device_ctx->request_pool) {
-               kmem_cache_destroy(host_device_ctx->request_pool);
-               host_device_ctx->request_pool = NULL;
-       }
+       DPRINT_INFO(STORVSC_DRV, "sdev (%p) - adding merge bio vec routine",
+                   sdevice);
+       blk_queue_merge_bvec(sdevice->request_queue, storvsc_merge_bvec);
 
-       DPRINT_INFO(STORVSC, "removing host adapter (%p)...", host);
-       scsi_remove_host(host);
+       blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY);
 
-       DPRINT_INFO(STORVSC, "releasing host adapter (%p)...", host);
-       scsi_host_put(host);
        return 0;
 }
 
-/*
- * storvsc_commmand_completion - Command completion processing
- */
-static void storvsc_commmand_completion(struct hv_storvsc_request *request)
+static void destroy_bounce_buffer(struct scatterlist *sgl,
+                                 unsigned int sg_count)
 {
-       struct storvsc_cmd_request *cmd_request =
-               (struct storvsc_cmd_request *)request->context;
-       struct scsi_cmnd *scmnd = cmd_request->cmd;
-       struct host_device_context *host_device_ctx =
-               (struct host_device_context *)scmnd->device->host->hostdata;
-       void (*scsi_done_fn)(struct scsi_cmnd *);
-       struct scsi_sense_hdr sense_hdr;
-       struct vmscsi_request *vm_srb;
-
-       /* ASSERT(request == &cmd_request->request); */
-       /* ASSERT(scmnd); */
-       /* ASSERT((unsigned long)scmnd->host_scribble == */
-       /*        (unsigned long)cmd_request); */
-       /* ASSERT(scmnd->scsi_done); */
-
-       if (cmd_request->bounce_sgl_count) {
-               /* using bounce buffer */
-               /* printk("copy_from_bounce_buffer\n"); */
-
-               /* FIXME: We can optimize on writes by just skipping this */
-               copy_from_bounce_buffer(scsi_sglist(scmnd),
-                                       cmd_request->bounce_sgl,
-                                       scsi_sg_count(scmnd));
-               destroy_bounce_buffer(cmd_request->bounce_sgl,
-                                     cmd_request->bounce_sgl_count);
-       }
-
-       vm_srb = &request->vstor_packet.vm_srb;
-       scmnd->result = vm_srb->scsi_status;
+       int i;
+       struct page *page_buf;
 
-       if (scmnd->result) {
-               if (scsi_normalize_sense(scmnd->sense_buffer,
-                               SCSI_SENSE_BUFFERSIZE, &sense_hdr))
-                       scsi_print_sense_hdr("storvsc", &sense_hdr);
+       for (i = 0; i < sg_count; i++) {
+               page_buf = sg_page((&sgl[i]));
+               if (page_buf != NULL)
+                       __free_page(page_buf);
        }
 
-       /* ASSERT(request->BytesXfer <= request->data_buffer.Length); */
-       scsi_set_resid(scmnd,
-               request->data_buffer.len -
-               vm_srb->data_transfer_length);
-
-       scsi_done_fn = scmnd->scsi_done;
-
-       scmnd->host_scribble = NULL;
-       scmnd->scsi_done = NULL;
-
-       /* !!DO NOT MODIFY the scmnd after this call */
-       scsi_done_fn(scmnd);
-
-       kmem_cache_free(host_device_ctx->request_pool, cmd_request);
+       kfree(sgl);
 }
 
 static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count)
@@ -539,21 +213,72 @@ cleanup:
        return NULL;
 }
 
-static void destroy_bounce_buffer(struct scatterlist *sgl,
-                                 unsigned int sg_count)
+
+/* Assume the original sgl has enough room */
+static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
+                                           struct scatterlist *bounce_sgl,
+                                           unsigned int orig_sgl_count)
 {
        int i;
-       struct page *page_buf;
+       int j = 0;
+       unsigned long src, dest;
+       unsigned int srclen, destlen, copylen;
+       unsigned int total_copied = 0;
+       unsigned long bounce_addr = 0;
+       unsigned long dest_addr = 0;
+       unsigned long flags;
 
-       for (i = 0; i < sg_count; i++) {
-               page_buf = sg_page((&sgl[i]));
-               if (page_buf != NULL)
-                       __free_page(page_buf);
+       local_irq_save(flags);
+
+       for (i = 0; i < orig_sgl_count; i++) {
+               dest_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])),
+                                       KM_IRQ0) + orig_sgl[i].offset;
+               dest = dest_addr;
+               destlen = orig_sgl[i].length;
+
+               if (bounce_addr == 0)
+                       bounce_addr =
+                       (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])),
+                                                       KM_IRQ0);
+
+               while (destlen) {
+                       src = bounce_addr + bounce_sgl[j].offset;
+                       srclen = bounce_sgl[j].length - bounce_sgl[j].offset;
+
+                       copylen = min(srclen, destlen);
+                       memcpy((void *)dest, (void *)src, copylen);
+
+                       total_copied += copylen;
+                       bounce_sgl[j].offset += copylen;
+                       destlen -= copylen;
+                       dest += copylen;
+
+                       if (bounce_sgl[j].offset == bounce_sgl[j].length) {
+                               /* full */
+                               kunmap_atomic((void *)bounce_addr, KM_IRQ0);
+                               j++;
+
+                               /* if we need to use another bounce buffer */
+                               if (destlen || i != orig_sgl_count - 1)
+                                       bounce_addr =
+                                       (unsigned long)kmap_atomic(
+                                       sg_page((&bounce_sgl[j])), KM_IRQ0);
+                       } else if (destlen == 0 && i == orig_sgl_count - 1) {
+                               /* unmap the last bounce that is < PAGE_SIZE */
+                               kunmap_atomic((void *)bounce_addr, KM_IRQ0);
+                       }
+               }
+
+               kunmap_atomic((void *)(dest_addr - orig_sgl[i].offset),
+                             KM_IRQ0);
        }
 
-       kfree(sgl);
+       local_irq_restore(flags);
+
+       return total_copied;
 }
 
+
 /* Assume the bounce_sgl has enough room ie using the create_bounce_buffer() */
 static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
                                          struct scatterlist *bounce_sgl,
@@ -576,10 +301,10 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
                src = src_addr;
                srclen = orig_sgl[i].length;
 
-               /* ASSERT(orig_sgl[i].offset + orig_sgl[i].length <= PAGE_SIZE); */
-
                if (bounce_addr == 0)
-                       bounce_addr = (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])), KM_IRQ0);
+                       bounce_addr =
+                       (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])),
+                                               KM_IRQ0);
 
                while (srclen) {
                        /* assume bounce offset always == 0 */
@@ -601,7 +326,10 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
 
                                /* if we need to use another bounce buffer */
                                if (srclen || i != orig_sgl_count - 1)
-                                       bounce_addr = (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])), KM_IRQ0);
+                                       bounce_addr =
+                                       (unsigned long)kmap_atomic(
+                                       sg_page((&bounce_sgl[j])), KM_IRQ0);
+
                        } else if (srclen == 0 && i == orig_sgl_count - 1) {
                                /* unmap the last bounce that is < PAGE_SIZE */
                                kunmap_atomic((void *)bounce_addr, KM_IRQ0);
@@ -616,67 +344,185 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
        return total_copied;
 }
 
-/* Assume the original sgl has enough room */
-static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
-                                           struct scatterlist *bounce_sgl,
-                                           unsigned int orig_sgl_count)
+
+/*
+ * storvsc_remove - Callback when our device is removed
+ */
+static int storvsc_remove(struct hv_device *dev)
+{
+       struct Scsi_Host *host = dev_get_drvdata(&dev->device);
+       struct hv_host_device *host_dev =
+                       (struct hv_host_device *)host->hostdata;
+
+       /*
+        * Call to the vsc driver to let it know that the device is being
+        * removed
+        */
+       storvsc_dev_remove(dev);
+
+       if (host_dev->request_pool) {
+               kmem_cache_destroy(host_dev->request_pool);
+               host_dev->request_pool = NULL;
+       }
+
+       DPRINT_INFO(STORVSC, "removing host adapter (%p)...", host);
+       scsi_remove_host(host);
+
+       DPRINT_INFO(STORVSC, "releasing host adapter (%p)...", host);
+       scsi_host_put(host);
+       return 0;
+}
+
+
+static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev,
+                          sector_t capacity, int *info)
+{
+       sector_t nsect = capacity;
+       sector_t cylinders = nsect;
+       int heads, sectors_pt;
+
+       /*
+        * We are making up these values; let us keep it simple.
+        */
+       heads = 0xff;
+       sectors_pt = 0x3f;      /* Sectors per track */
+       sector_div(cylinders, heads * sectors_pt);
+       if ((sector_t)(cylinders + 1) * heads * sectors_pt < nsect)
+               cylinders = 0xffff;
+
+       info[0] = heads;
+       info[1] = sectors_pt;
+       info[2] = (int)cylinders;
+
+       DPRINT_INFO(STORVSC_DRV, "CHS (%d, %d, %d)", (int)cylinders, heads,
+                       sectors_pt);
+
+       return 0;
+}
+
+static int storvsc_host_reset(struct hv_device *device)
+{
+       struct storvsc_device *stor_device;
+       struct hv_storvsc_request *request;
+       struct vstor_packet *vstor_packet;
+       int ret, t;
+
+       DPRINT_INFO(STORVSC, "resetting host adapter...");
+
+       stor_device = get_stor_device(device);
+       if (!stor_device)
+               return -1;
+
+       request = &stor_device->reset_request;
+       vstor_packet = &request->vstor_packet;
+
+       init_completion(&request->wait_event);
+
+       vstor_packet->operation = VSTOR_OPERATION_RESET_BUS;
+       vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+       vstor_packet->vm_srb.path_id = stor_device->path_id;
+
+       ret = vmbus_sendpacket(device->channel, vstor_packet,
+                              sizeof(struct vstor_packet),
+                              (unsigned long)&stor_device->reset_request,
+                              VM_PKT_DATA_INBAND,
+                              VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+       if (ret != 0)
+               goto cleanup;
+
+       t = wait_for_completion_timeout(&request->wait_event, HZ);
+       if (t == 0) {
+               ret = -ETIMEDOUT;
+               goto cleanup;
+       }
+
+       DPRINT_INFO(STORVSC, "host adapter reset completed");
+
+       /*
+        * At this point, all outstanding requests in the adapter
+        * should have been flushed out and return to us
+        */
+
+cleanup:
+       put_stor_device(device);
+       return ret;
+}
+
+
+/*
+ * storvsc_host_reset_handler - Reset the scsi HBA
+ */
+static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
 {
-       int i;
-       int j = 0;
-       unsigned long src, dest;
-       unsigned int srclen, destlen, copylen;
-       unsigned int total_copied = 0;
-       unsigned long bounce_addr = 0;
-       unsigned long dest_addr = 0;
-       unsigned long flags;
+       int ret;
+       struct hv_host_device *host_dev =
+               (struct hv_host_device *)scmnd->device->host->hostdata;
+       struct hv_device *dev = host_dev->dev;
 
-       local_irq_save(flags);
+       DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host resetting...",
+                   scmnd->device, dev);
 
-       for (i = 0; i < orig_sgl_count; i++) {
-               dest_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])),
-                                       KM_IRQ0) + orig_sgl[i].offset;
-               dest = dest_addr;
-               destlen = orig_sgl[i].length;
-               /* ASSERT(orig_sgl[i].offset + orig_sgl[i].length <= PAGE_SIZE); */
+       /* Invokes the vsc to reset the host/bus */
+       ret = storvsc_host_reset(dev);
+       if (ret != 0)
+               return ret;
 
-               if (bounce_addr == 0)
-                       bounce_addr = (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])), KM_IRQ0);
+       DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host reseted",
+                   scmnd->device, dev);
 
-               while (destlen) {
-                       src = bounce_addr + bounce_sgl[j].offset;
-                       srclen = bounce_sgl[j].length - bounce_sgl[j].offset;
+       return ret;
+}
 
-                       copylen = min(srclen, destlen);
-                       memcpy((void *)dest, (void *)src, copylen);
 
-                       total_copied += copylen;
-                       bounce_sgl[j].offset += copylen;
-                       destlen -= copylen;
-                       dest += copylen;
+/*
+ * storvsc_commmand_completion - Command completion processing
+ */
+static void storvsc_commmand_completion(struct hv_storvsc_request *request)
+{
+       struct storvsc_cmd_request *cmd_request =
+               (struct storvsc_cmd_request *)request->context;
+       struct scsi_cmnd *scmnd = cmd_request->cmd;
+       struct hv_host_device *host_dev =
+               (struct hv_host_device *)scmnd->device->host->hostdata;
+       void (*scsi_done_fn)(struct scsi_cmnd *);
+       struct scsi_sense_hdr sense_hdr;
+       struct vmscsi_request *vm_srb;
 
-                       if (bounce_sgl[j].offset == bounce_sgl[j].length) {
-                               /* full */
-                               kunmap_atomic((void *)bounce_addr, KM_IRQ0);
-                               j++;
+       if (cmd_request->bounce_sgl_count) {
 
-                               /* if we need to use another bounce buffer */
-                               if (destlen || i != orig_sgl_count - 1)
-                                       bounce_addr = (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])), KM_IRQ0);
-                       } else if (destlen == 0 && i == orig_sgl_count - 1) {
-                               /* unmap the last bounce that is < PAGE_SIZE */
-                               kunmap_atomic((void *)bounce_addr, KM_IRQ0);
-                       }
-               }
+               /* FIXME: We can optimize on writes by just skipping this */
+               copy_from_bounce_buffer(scsi_sglist(scmnd),
+                                       cmd_request->bounce_sgl,
+                                       scsi_sg_count(scmnd));
+               destroy_bounce_buffer(cmd_request->bounce_sgl,
+                                     cmd_request->bounce_sgl_count);
+       }
 
-               kunmap_atomic((void *)(dest_addr - orig_sgl[i].offset),
-                             KM_IRQ0);
+       vm_srb = &request->vstor_packet.vm_srb;
+       scmnd->result = vm_srb->scsi_status;
+
+       if (scmnd->result) {
+               if (scsi_normalize_sense(scmnd->sense_buffer,
+                               SCSI_SENSE_BUFFERSIZE, &sense_hdr))
+                       scsi_print_sense_hdr("storvsc", &sense_hdr);
        }
 
-       local_irq_restore(flags);
+       scsi_set_resid(scmnd,
+               request->data_buffer.len -
+               vm_srb->data_transfer_length);
 
-       return total_copied;
+       scsi_done_fn = scmnd->scsi_done;
+
+       scmnd->host_scribble = NULL;
+       scmnd->scsi_done = NULL;
+
+       /* !!DO NOT MODIFY the scmnd after this call */
+       scsi_done_fn(scmnd);
+
+       kmem_cache_free(host_dev->request_pool, cmd_request);
 }
 
+
 /*
  * storvsc_queuecommand - Initiate command processing
  */
@@ -684,11 +530,9 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
                                void (*done)(struct scsi_cmnd *))
 {
        int ret;
-       struct host_device_context *host_device_ctx =
-               (struct host_device_context *)scmnd->device->host->hostdata;
-       struct hv_device *device_ctx = host_device_ctx->device_ctx;
-       struct storvsc_driver_object *storvsc_drv_obj =
-               drv_to_stordrv(device_ctx->device.driver);
+       struct hv_host_device *host_dev =
+               (struct hv_host_device *)scmnd->device->host->hostdata;
+       struct hv_device *dev = host_dev->dev;
        struct hv_storvsc_request *request;
        struct storvsc_cmd_request *cmd_request;
        unsigned int request_size = 0;
@@ -697,15 +541,9 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
        unsigned int sg_count = 0;
        struct vmscsi_request *vm_srb;
 
-       DPRINT_DBG(STORVSC_DRV, "scmnd %p dir %d, use_sg %d buf %p len %d "
-                  "queue depth %d tagged %d", scmnd, scmnd->sc_data_direction,
-                  scsi_sg_count(scmnd), scsi_sglist(scmnd),
-                  scsi_bufflen(scmnd), scmnd->device->queue_depth,
-                  scmnd->device->tagged_supported);
 
        /* If retrying, no need to prep the cmd */
        if (scmnd->host_scribble) {
-               /* ASSERT(scmnd->scsi_done != NULL); */
 
                cmd_request =
                        (struct storvsc_cmd_request *)scmnd->host_scribble;
@@ -715,18 +553,13 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
                goto retry_request;
        }
 
-       /* ASSERT(scmnd->scsi_done == NULL); */
-       /* ASSERT(scmnd->host_scribble == NULL); */
-
        scmnd->scsi_done = done;
 
        request_size = sizeof(struct storvsc_cmd_request);
 
-       cmd_request = kmem_cache_zalloc(host_device_ctx->request_pool,
+       cmd_request = kmem_cache_zalloc(host_dev->request_pool,
                                       GFP_ATOMIC);
        if (!cmd_request) {
-               DPRINT_ERR(STORVSC_DRV, "scmnd (%p) - unable to allocate "
-                          "storvsc_cmd_request...marking queue busy", scmnd);
                scmnd->scsi_done = NULL;
                return SCSI_MLQUEUE_DEVICE_BUSY;
        }
@@ -741,7 +574,6 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
        request = &cmd_request->request;
        vm_srb = &request->vstor_packet.vm_srb;
 
-       DPRINT_DBG(STORVSC_DRV, "req %p size %d", request, request_size);
 
        /* Build the SRB */
        switch (scmnd->sc_data_direction) {
@@ -759,13 +591,11 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
        request->on_io_completion = storvsc_commmand_completion;
        request->context = cmd_request;/* scmnd; */
 
-       /* request->PortId = scmnd->device->channel; */
-       vm_srb->port_number = host_device_ctx->port;
+       vm_srb->port_number = host_dev->port;
        vm_srb->path_id = scmnd->device->channel;
        vm_srb->target_id = scmnd->device->id;
        vm_srb->lun = scmnd->device->lun;
 
-       /* ASSERT(scmnd->cmd_len <= 16); */
        vm_srb->cdb_length = scmnd->cmd_len;
 
        memcpy(vm_srb->cdb, scmnd->cmnd, vm_srb->cdb_length);
@@ -780,20 +610,13 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
 
                /* check if we need to bounce the sgl */
                if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) {
-                       DPRINT_INFO(STORVSC_DRV,
-                                   "need to bounce buffer for this scmnd %p",
-                                   scmnd);
                        cmd_request->bounce_sgl =
                                create_bounce_buffer(sgl, scsi_sg_count(scmnd),
                                                     scsi_bufflen(scmnd));
                        if (!cmd_request->bounce_sgl) {
-                               DPRINT_ERR(STORVSC_DRV,
-                                          "unable to create bounce buffer for "
-                                          "this scmnd %p", scmnd);
-
                                scmnd->scsi_done = NULL;
                                scmnd->host_scribble = NULL;
-                               kmem_cache_free(host_device_ctx->request_pool,
+                               kmem_cache_free(host_dev->request_pool,
                                                cmd_request);
 
                                return SCSI_MLQUEUE_HOST_BUSY;
@@ -816,14 +639,11 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
 
                request->data_buffer.offset = sgl[0].offset;
 
-               for (i = 0; i < sg_count; i++) {
-                       DPRINT_DBG(STORVSC_DRV, "sgl[%d] len %d offset %d\n",
-                                  i, sgl[i].length, sgl[i].offset);
+               for (i = 0; i < sg_count; i++)
                        request->data_buffer.pfn_array[i] =
                                page_to_pfn(sg_page((&sgl[i])));
-               }
+
        } else if (scsi_sglist(scmnd)) {
-               /* ASSERT(scsi_bufflen(scmnd) <= PAGE_SIZE); */
                request->data_buffer.offset =
                        virt_to_phys(scsi_sglist(scmnd)) & (PAGE_SIZE-1);
                request->data_buffer.pfn_array[0] =
@@ -832,13 +652,10 @@ static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
 
 retry_request:
        /* Invokes the vsc to start an IO */
-       ret = storvsc_drv_obj->on_io_request(device_ctx,
-                                          &cmd_request->request);
+       ret = storvsc_do_io(dev, &cmd_request->request);
+
        if (ret == -1) {
                /* no more space */
-               DPRINT_ERR(STORVSC_DRV,
-                          "scmnd (%p) - queue FULL...marking queue busy",
-                          scmnd);
 
                if (cmd_request->bounce_sgl_count) {
                        /*
@@ -852,7 +669,7 @@ retry_request:
                                              cmd_request->bounce_sgl_count);
                }
 
-               kmem_cache_free(host_device_ctx->request_pool, cmd_request);
+               kmem_cache_free(host_dev->request_pool, cmd_request);
 
                scmnd->scsi_done = NULL;
                scmnd->host_scribble = NULL;
@@ -865,154 +682,171 @@ retry_request:
 
 static DEF_SCSI_QCMD(storvsc_queuecommand)
 
-static int storvsc_merge_bvec(struct request_queue *q,
-                             struct bvec_merge_data *bmd, struct bio_vec *bvec)
-{
-       /* checking done by caller. */
-       return bvec->bv_len;
-}
 
-/*
- * storvsc_device_configure - Configure the specified scsi device
- */
-static int storvsc_device_alloc(struct scsi_device *sdevice)
-{
-       DPRINT_DBG(STORVSC_DRV, "sdev (%p) - setting device flag to %d",
-                  sdevice, BLIST_SPARSELUN);
+/* Scsi driver */
+static struct scsi_host_template scsi_driver = {
+       .module =               THIS_MODULE,
+       .name =                 "storvsc_host_t",
+       .bios_param =           storvsc_get_chs,
+       .queuecommand =         storvsc_queuecommand,
+       .eh_host_reset_handler =        storvsc_host_reset_handler,
+       .slave_alloc =          storvsc_device_alloc,
+       .slave_configure =      storvsc_device_configure,
+       .cmd_per_lun =          1,
+       /* 64 max_queue * 1 target */
+       .can_queue =            STORVSC_MAX_IO_REQUESTS*STORVSC_MAX_TARGETS,
+       .this_id =              -1,
+       /* no use setting to 0 since ll_blk_rw reset it to 1 */
+       /* currently 32 */
+       .sg_tablesize =         MAX_MULTIPAGE_BUFFER_COUNT,
        /*
-        * This enables luns to be located sparsely. Otherwise, we may not
-        * discovered them.
+        * ENABLE_CLUSTERING allows mutiple physically contig bio_vecs to merge
+        * into 1 sg element. If set, we must limit the max_segment_size to
+        * PAGE_SIZE, otherwise we may get 1 sg element that represents
+        * multiple
         */
-       sdevice->sdev_bflags |= BLIST_SPARSELUN | BLIST_LARGELUN;
-       return 0;
-}
+       /* physically contig pfns (ie sg[x].length > PAGE_SIZE). */
+       .use_clustering =       ENABLE_CLUSTERING,
+       /* Make sure we dont get a sg segment crosses a page boundary */
+       .dma_boundary =         PAGE_SIZE-1,
+};
 
-static int storvsc_device_configure(struct scsi_device *sdevice)
+
+/*
+ * storvsc_probe - Add a new device for this driver
+ */
+
+static int storvsc_probe(struct hv_device *device)
 {
-       DPRINT_INFO(STORVSC_DRV, "sdev (%p) - curr queue depth %d", sdevice,
-                   sdevice->queue_depth);
+       int ret;
+       struct Scsi_Host *host;
+       struct hv_host_device *host_dev;
+       struct storvsc_device_info device_info;
 
-       DPRINT_INFO(STORVSC_DRV, "sdev (%p) - setting queue depth to %d",
-                   sdevice, STORVSC_MAX_IO_REQUESTS);
-       scsi_adjust_queue_depth(sdevice, MSG_SIMPLE_TAG,
-                               STORVSC_MAX_IO_REQUESTS);
+       host = scsi_host_alloc(&scsi_driver,
+                              sizeof(struct hv_host_device));
+       if (!host)
+               return -ENOMEM;
 
-       DPRINT_INFO(STORVSC_DRV, "sdev (%p) - setting max segment size to %ld",
-                   sdevice, PAGE_SIZE);
-       blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE);
+       dev_set_drvdata(&device->device, host);
 
-       DPRINT_INFO(STORVSC_DRV, "sdev (%p) - adding merge bio vec routine",
-                   sdevice);
-       blk_queue_merge_bvec(sdevice->request_queue, storvsc_merge_bvec);
+       host_dev = (struct hv_host_device *)host->hostdata;
+       memset(host_dev, 0, sizeof(struct hv_host_device));
 
-       blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY);
-       /* sdevice->timeout = (2000 * HZ);//(75 * HZ); */
+       host_dev->port = host->host_no;
+       host_dev->dev = device;
 
-       return 0;
-}
+       host_dev->request_pool =
+                               kmem_cache_create(dev_name(&device->device),
+                                       sizeof(struct storvsc_cmd_request), 0,
+                                       SLAB_HWCACHE_ALIGN, NULL);
 
-/*
- * storvsc_host_reset_handler - Reset the scsi HBA
- */
-static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
-{
-       int ret;
-       struct host_device_context *host_device_ctx =
-               (struct host_device_context *)scmnd->device->host->hostdata;
-       struct hv_device *device_ctx = host_device_ctx->device_ctx;
+       if (!host_dev->request_pool) {
+               scsi_host_put(host);
+               return -ENOMEM;
+       }
 
-       DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host resetting...",
-                   scmnd->device, device_ctx);
+       device_info.port_number = host->host_no;
+       /* Call to the vsc driver to add the device */
+       ret = storvsc_dev_add(device, (void *)&device_info);
 
-       /* Invokes the vsc to reset the host/bus */
-       ret = stor_vsc_on_host_reset(device_ctx);
-       if (ret != 0)
-               return ret;
+       if (ret != 0) {
+               kmem_cache_destroy(host_dev->request_pool);
+               scsi_host_put(host);
+               return -1;
+       }
 
-       DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host reseted",
-                   scmnd->device, device_ctx);
+       host_dev->path = device_info.path_id;
+       host_dev->target = device_info.target_id;
+
+       /* max # of devices per target */
+       host->max_lun = STORVSC_MAX_LUNS_PER_TARGET;
+       /* max # of targets per channel */
+       host->max_id = STORVSC_MAX_TARGETS;
+       /* max # of channels */
+       host->max_channel = STORVSC_MAX_CHANNELS - 1;
+
+       /* Register the HBA and start the scsi bus scan */
+       ret = scsi_add_host(host, &device->device);
+       if (ret != 0) {
+
+               storvsc_dev_remove(device);
+
+               kmem_cache_destroy(host_dev->request_pool);
+               scsi_host_put(host);
+               return -1;
+       }
 
+       scsi_scan_host(host);
        return ret;
 }
 
-static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev,
-                          sector_t capacity, int *info)
-{
-       sector_t total_sectors = capacity;
-       sector_t cylinder_times_heads = 0;
-       sector_t temp = 0;
+/* The one and only one */
 
-       int sectors_per_track = 0;
-       int heads = 0;
-       int cylinders = 0;
-       int rem = 0;
+static struct storvsc_driver storvsc_drv = {
+       .base.probe = storvsc_probe,
+       .base.remove = storvsc_remove,
+};
 
-       if (total_sectors > (65535 * 16 * 255))
-               total_sectors = (65535 * 16 * 255);
 
-       if (total_sectors >= (65535 * 16 * 63)) {
-               sectors_per_track = 255;
-               heads = 16;
+/*
+ * storvsc_drv_init - StorVsc driver initialization.
+ */
+static int storvsc_drv_init(void)
+{
+       int ret;
+       struct storvsc_driver *storvsc_drv_obj = &storvsc_drv;
+       struct hv_driver *drv = &storvsc_drv.base;
 
-               cylinder_times_heads = total_sectors;
-               /* sector_div stores the quotient in cylinder_times_heads */
-               rem = sector_div(cylinder_times_heads, sectors_per_track);
-       } else {
-               sectors_per_track = 17;
+       storvsc_drv_obj->ring_buffer_size = storvsc_ringbuffer_size;
 
-               cylinder_times_heads = total_sectors;
-               /* sector_div stores the quotient in cylinder_times_heads */
-               rem = sector_div(cylinder_times_heads, sectors_per_track);
+       /* Callback to client driver to complete the initialization */
+       storvsc_initialize(&storvsc_drv_obj->base);
 
-               temp = cylinder_times_heads + 1023;
-               /* sector_div stores the quotient in temp */
-               rem = sector_div(temp, 1024);
+       if (storvsc_drv_obj->max_outstanding_req_per_channel <
+           STORVSC_MAX_IO_REQUESTS)
+               return -1;
 
-               heads = temp;
+       drv->driver.name = storvsc_drv_obj->base.name;
 
-               if (heads < 4)
-                       heads = 4;
 
-               if (cylinder_times_heads >= (heads * 1024) || (heads > 16)) {
-                       sectors_per_track = 31;
-                       heads = 16;
+       /* The driver belongs to vmbus */
+       ret = vmbus_child_driver_register(&drv->driver);
 
-                       cylinder_times_heads = total_sectors;
-                       /*
-                        * sector_div stores the quotient in
-                        * cylinder_times_heads
-                        */
-                       rem = sector_div(cylinder_times_heads,
-                                        sectors_per_track);
-               }
+       return ret;
+}
 
-               if (cylinder_times_heads >= (heads * 1024)) {
-                       sectors_per_track = 63;
-                       heads = 16;
+static int storvsc_drv_exit_cb(struct device *dev, void *data)
+{
+       struct device **curr = (struct device **)data;
+       *curr = dev;
+       return 1; /* stop iterating */
+}
 
-                       cylinder_times_heads = total_sectors;
-                       /*
-                        * sector_div stores the quotient in
-                        * cylinder_times_heads
-                        */
-                       rem = sector_div(cylinder_times_heads,
-                                        sectors_per_track);
-               }
-       }
+static void storvsc_drv_exit(void)
+{
+       struct hv_driver *drv = &storvsc_drv.base;
+       struct device *current_dev = NULL;
+       int ret;
 
-       temp = cylinder_times_heads;
-       /* sector_div stores the quotient in temp */
-       rem = sector_div(temp, heads);
-       cylinders = temp;
+       while (1) {
+               current_dev = NULL;
+
+               /* Get the device */
+               ret = driver_for_each_device(&drv->driver, NULL,
+                                            (void *) &current_dev,
+                                            storvsc_drv_exit_cb);
 
-       info[0] = heads;
-       info[1] = sectors_per_track;
-       info[2] = cylinders;
 
-       DPRINT_INFO(STORVSC_DRV, "CHS (%d, %d, %d)", cylinders, heads,
-                   sectors_per_track);
+               if (current_dev == NULL)
+                       break;
+
+               /* Initiate removal from the top-down */
+               device_unregister(current_dev);
+       }
 
-    return 0;
+       vmbus_child_driver_unregister(&drv->driver);
+       return;
 }
 
 static int __init storvsc_init(void)