|
@@ -597,9 +597,177 @@ static void storvsc_commmand_completion(struct hv_storvsc_request *request)
|
|
|
kmem_cache_free(host_dev->request_pool, cmd_request);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+/*
|
|
|
+ * storvsc_queuecommand - Initiate command processing
|
|
|
+ */
|
|
|
+static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
|
|
|
+ void (*done)(struct scsi_cmnd *))
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ struct hv_host_device *host_dev =
|
|
|
+ (struct hv_host_device *)scmnd->device->host->hostdata;
|
|
|
+ struct hv_device *dev = host_dev->dev;
|
|
|
+ struct storvsc_driver *storvsc_drv_obj =
|
|
|
+ drv_to_stordrv(dev->device.driver);
|
|
|
+ struct hv_storvsc_request *request;
|
|
|
+ struct storvsc_cmd_request *cmd_request;
|
|
|
+ unsigned int request_size = 0;
|
|
|
+ int i;
|
|
|
+ struct scatterlist *sgl;
|
|
|
+ unsigned int sg_count = 0;
|
|
|
+ struct vmscsi_request *vm_srb;
|
|
|
+
|
|
|
+
|
|
|
+ /* 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;
|
|
|
+ DPRINT_INFO(STORVSC_DRV, "retrying scmnd %p cmd_request %p",
|
|
|
+ scmnd, cmd_request);
|
|
|
+
|
|
|
+ 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_dev->request_pool,
|
|
|
+ GFP_ATOMIC);
|
|
|
+ if (!cmd_request) {
|
|
|
+ scmnd->scsi_done = NULL;
|
|
|
+ return SCSI_MLQUEUE_DEVICE_BUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Setup the cmd request */
|
|
|
+ cmd_request->bounce_sgl_count = 0;
|
|
|
+ cmd_request->bounce_sgl = NULL;
|
|
|
+ cmd_request->cmd = scmnd;
|
|
|
+
|
|
|
+ scmnd->host_scribble = (unsigned char *)cmd_request;
|
|
|
+
|
|
|
+ request = &cmd_request->request;
|
|
|
+ vm_srb = &request->vstor_packet.vm_srb;
|
|
|
+
|
|
|
+
|
|
|
+ /* Build the SRB */
|
|
|
+ switch (scmnd->sc_data_direction) {
|
|
|
+ case DMA_TO_DEVICE:
|
|
|
+ vm_srb->data_in = WRITE_TYPE;
|
|
|
+ break;
|
|
|
+ case DMA_FROM_DEVICE:
|
|
|
+ vm_srb->data_in = READ_TYPE;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ vm_srb->data_in = UNKNOWN_TYPE;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ request->on_io_completion = storvsc_commmand_completion;
|
|
|
+ request->context = cmd_request;/* scmnd; */
|
|
|
+
|
|
|
+ /* request->PortId = scmnd->device->channel; */
|
|
|
+ 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);
|
|
|
+
|
|
|
+ request->sense_buffer = scmnd->sense_buffer;
|
|
|
+
|
|
|
+
|
|
|
+ request->data_buffer.len = scsi_bufflen(scmnd);
|
|
|
+ if (scsi_sg_count(scmnd)) {
|
|
|
+ sgl = (struct scatterlist *)scsi_sglist(scmnd);
|
|
|
+ sg_count = scsi_sg_count(scmnd);
|
|
|
+
|
|
|
+ /* check if we need to bounce the sgl */
|
|
|
+ if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) {
|
|
|
+ cmd_request->bounce_sgl =
|
|
|
+ create_bounce_buffer(sgl, scsi_sg_count(scmnd),
|
|
|
+ scsi_bufflen(scmnd));
|
|
|
+ if (!cmd_request->bounce_sgl) {
|
|
|
+ scmnd->scsi_done = NULL;
|
|
|
+ scmnd->host_scribble = NULL;
|
|
|
+ kmem_cache_free(host_dev->request_pool,
|
|
|
+ cmd_request);
|
|
|
+
|
|
|
+ return SCSI_MLQUEUE_HOST_BUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ cmd_request->bounce_sgl_count =
|
|
|
+ ALIGN(scsi_bufflen(scmnd), PAGE_SIZE) >>
|
|
|
+ PAGE_SHIFT;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * FIXME: We can optimize on reads by just skipping
|
|
|
+ * this
|
|
|
+ */
|
|
|
+ copy_to_bounce_buffer(sgl, cmd_request->bounce_sgl,
|
|
|
+ scsi_sg_count(scmnd));
|
|
|
+
|
|
|
+ sgl = cmd_request->bounce_sgl;
|
|
|
+ sg_count = cmd_request->bounce_sgl_count;
|
|
|
+ }
|
|
|
+
|
|
|
+ request->data_buffer.offset = sgl[0].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] =
|
|
|
+ virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT;
|
|
|
+ }
|
|
|
+
|
|
|
+retry_request:
|
|
|
+ /* Invokes the vsc to start an IO */
|
|
|
+ ret = storvsc_drv_obj->on_io_request(dev,
|
|
|
+ &cmd_request->request);
|
|
|
+ if (ret == -1) {
|
|
|
+ /* no more space */
|
|
|
+
|
|
|
+ if (cmd_request->bounce_sgl_count) {
|
|
|
+ /*
|
|
|
+ * 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);
|
|
|
+ }
|
|
|
+
|
|
|
+ kmem_cache_free(host_dev->request_pool, cmd_request);
|
|
|
+
|
|
|
+ scmnd->scsi_done = NULL;
|
|
|
+ scmnd->host_scribble = NULL;
|
|
|
+
|
|
|
+ ret = SCSI_MLQUEUE_DEVICE_BUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static DEF_SCSI_QCMD(storvsc_queuecommand)
|
|
|
+
|
|
|
/* Static decl */
|
|
|
static int storvsc_probe(struct hv_device *dev);
|
|
|
-static int storvsc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd);
|
|
|
|
|
|
/* The one and only one */
|
|
|
static struct storvsc_driver g_storvsc_drv;
|
|
@@ -776,174 +944,6 @@ static int storvsc_probe(struct hv_device *device)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * storvsc_queuecommand - Initiate command processing
|
|
|
- */
|
|
|
-static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
|
|
|
- void (*done)(struct scsi_cmnd *))
|
|
|
-{
|
|
|
- int ret;
|
|
|
- struct hv_host_device *host_dev =
|
|
|
- (struct hv_host_device *)scmnd->device->host->hostdata;
|
|
|
- struct hv_device *dev = host_dev->dev;
|
|
|
- struct storvsc_driver *storvsc_drv_obj =
|
|
|
- drv_to_stordrv(dev->device.driver);
|
|
|
- struct hv_storvsc_request *request;
|
|
|
- struct storvsc_cmd_request *cmd_request;
|
|
|
- unsigned int request_size = 0;
|
|
|
- int i;
|
|
|
- struct scatterlist *sgl;
|
|
|
- unsigned int sg_count = 0;
|
|
|
- struct vmscsi_request *vm_srb;
|
|
|
-
|
|
|
-
|
|
|
- /* 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;
|
|
|
- DPRINT_INFO(STORVSC_DRV, "retrying scmnd %p cmd_request %p",
|
|
|
- scmnd, cmd_request);
|
|
|
-
|
|
|
- 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_dev->request_pool,
|
|
|
- GFP_ATOMIC);
|
|
|
- if (!cmd_request) {
|
|
|
- scmnd->scsi_done = NULL;
|
|
|
- return SCSI_MLQUEUE_DEVICE_BUSY;
|
|
|
- }
|
|
|
-
|
|
|
- /* Setup the cmd request */
|
|
|
- cmd_request->bounce_sgl_count = 0;
|
|
|
- cmd_request->bounce_sgl = NULL;
|
|
|
- cmd_request->cmd = scmnd;
|
|
|
-
|
|
|
- scmnd->host_scribble = (unsigned char *)cmd_request;
|
|
|
-
|
|
|
- request = &cmd_request->request;
|
|
|
- vm_srb = &request->vstor_packet.vm_srb;
|
|
|
-
|
|
|
-
|
|
|
- /* Build the SRB */
|
|
|
- switch (scmnd->sc_data_direction) {
|
|
|
- case DMA_TO_DEVICE:
|
|
|
- vm_srb->data_in = WRITE_TYPE;
|
|
|
- break;
|
|
|
- case DMA_FROM_DEVICE:
|
|
|
- vm_srb->data_in = READ_TYPE;
|
|
|
- break;
|
|
|
- default:
|
|
|
- vm_srb->data_in = UNKNOWN_TYPE;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- request->on_io_completion = storvsc_commmand_completion;
|
|
|
- request->context = cmd_request;/* scmnd; */
|
|
|
-
|
|
|
- /* request->PortId = scmnd->device->channel; */
|
|
|
- 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);
|
|
|
-
|
|
|
- request->sense_buffer = scmnd->sense_buffer;
|
|
|
-
|
|
|
-
|
|
|
- request->data_buffer.len = scsi_bufflen(scmnd);
|
|
|
- if (scsi_sg_count(scmnd)) {
|
|
|
- sgl = (struct scatterlist *)scsi_sglist(scmnd);
|
|
|
- sg_count = scsi_sg_count(scmnd);
|
|
|
-
|
|
|
- /* check if we need to bounce the sgl */
|
|
|
- if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) {
|
|
|
- cmd_request->bounce_sgl =
|
|
|
- create_bounce_buffer(sgl, scsi_sg_count(scmnd),
|
|
|
- scsi_bufflen(scmnd));
|
|
|
- if (!cmd_request->bounce_sgl) {
|
|
|
- scmnd->scsi_done = NULL;
|
|
|
- scmnd->host_scribble = NULL;
|
|
|
- kmem_cache_free(host_dev->request_pool,
|
|
|
- cmd_request);
|
|
|
-
|
|
|
- return SCSI_MLQUEUE_HOST_BUSY;
|
|
|
- }
|
|
|
-
|
|
|
- cmd_request->bounce_sgl_count =
|
|
|
- ALIGN(scsi_bufflen(scmnd), PAGE_SIZE) >>
|
|
|
- PAGE_SHIFT;
|
|
|
-
|
|
|
- /*
|
|
|
- * FIXME: We can optimize on reads by just skipping
|
|
|
- * this
|
|
|
- */
|
|
|
- copy_to_bounce_buffer(sgl, cmd_request->bounce_sgl,
|
|
|
- scsi_sg_count(scmnd));
|
|
|
-
|
|
|
- sgl = cmd_request->bounce_sgl;
|
|
|
- sg_count = cmd_request->bounce_sgl_count;
|
|
|
- }
|
|
|
-
|
|
|
- request->data_buffer.offset = sgl[0].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] =
|
|
|
- virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT;
|
|
|
- }
|
|
|
-
|
|
|
-retry_request:
|
|
|
- /* Invokes the vsc to start an IO */
|
|
|
- ret = storvsc_drv_obj->on_io_request(dev,
|
|
|
- &cmd_request->request);
|
|
|
- if (ret == -1) {
|
|
|
- /* no more space */
|
|
|
-
|
|
|
- if (cmd_request->bounce_sgl_count) {
|
|
|
- /*
|
|
|
- * 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);
|
|
|
- }
|
|
|
-
|
|
|
- kmem_cache_free(host_dev->request_pool, cmd_request);
|
|
|
-
|
|
|
- scmnd->scsi_done = NULL;
|
|
|
- scmnd->host_scribble = NULL;
|
|
|
-
|
|
|
- ret = SCSI_MLQUEUE_DEVICE_BUSY;
|
|
|
- }
|
|
|
-
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-static DEF_SCSI_QCMD(storvsc_queuecommand)
|
|
|
-
|
|
|
static int __init storvsc_init(void)
|
|
|
{
|
|
|
int ret;
|