isci: fix support for arbitrarily large smp requests
[profile/ivi/kernel-adaptation-intel-automotive.git] / drivers / scsi / isci / request.c
index 3950849..1043fed 100644 (file)
@@ -2943,6 +2943,20 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
                        dma_unmap_sg(&isci_host->pdev->dev, task->scatter,
                                     request->num_sg_entries, task->data_dir);
                break;
+       case SAS_PROTOCOL_SMP: {
+               struct scatterlist *sg = &task->smp_task.smp_req;
+               struct smp_req *smp_req;
+               void *kaddr;
+
+               dma_unmap_sg(&isci_host->pdev->dev, sg, 1, DMA_TO_DEVICE);
+
+               /* need to swab it back in case the command buffer is re-used */
+               kaddr = kmap_atomic(sg_page(sg), KM_IRQ0);
+               smp_req = kaddr + sg->offset;
+               sci_swab32_cpy(smp_req, smp_req, sg->length / sizeof(u32));
+               kunmap_atomic(kaddr, KM_IRQ0);
+               break;
+       }
        default:
                break;
        }
@@ -3160,7 +3174,7 @@ scic_io_request_construct(struct scic_sds_controller *scic,
        else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP))
                memset(&sci_req->stp.cmd, 0, sizeof(sci_req->stp.cmd));
        else if (dev_is_expander(dev))
-               memset(&sci_req->smp.cmd, 0, sizeof(sci_req->smp.cmd));
+               /* pass */;
        else
                return SCI_FAILURE_UNSUPPORTED_PROTOCOL;
 
@@ -3236,30 +3250,54 @@ static enum sci_status isci_request_stp_request_construct(
        return status;
 }
 
-/*
- * This function will fill in the SCU Task Context for a SMP request. The
- *    following important settings are utilized: -# task_type ==
- *    SCU_TASK_TYPE_SMP.  This simply indicates that a normal request type
- *    (i.e. non-raw frame) is being utilized to perform task management. -#
- *    control_frame == 1.  This ensures that the proper endianess is set so
- *    that the bytes are transmitted in the right order for a smp request frame.
- * @sci_req: This parameter specifies the smp request object being
- *    constructed.
- *
- */
-static void
-scu_smp_request_construct_task_context(struct scic_sds_request *sci_req,
-                                      ssize_t req_len)
+static enum sci_status
+scic_io_request_construct_smp(struct device *dev,
+                             struct scic_sds_request *sci_req,
+                             struct sas_task *task)
 {
-       dma_addr_t dma_addr;
+       struct scatterlist *sg = &task->smp_task.smp_req;
        struct scic_sds_remote_device *sci_dev;
-       struct scic_sds_port *sci_port;
        struct scu_task_context *task_context;
-       ssize_t word_cnt = sizeof(struct smp_req) / sizeof(u32);
+       struct scic_sds_port *sci_port;
+       struct smp_req *smp_req;
+       void *kaddr;
+       u8 req_len;
+       u32 cmd;
+
+       kaddr = kmap_atomic(sg_page(sg), KM_IRQ0);
+       smp_req = kaddr + sg->offset;
+       /*
+        * Look at the SMP requests' header fields; for certain SAS 1.x SMP
+        * functions under SAS 2.0, a zero request length really indicates
+        * a non-zero default length.
+        */
+       if (smp_req->req_len == 0) {
+               switch (smp_req->func) {
+               case SMP_DISCOVER:
+               case SMP_REPORT_PHY_ERR_LOG:
+               case SMP_REPORT_PHY_SATA:
+               case SMP_REPORT_ROUTE_INFO:
+                       smp_req->req_len = 2;
+                       break;
+               case SMP_CONF_ROUTE_INFO:
+               case SMP_PHY_CONTROL:
+               case SMP_PHY_TEST_FUNCTION:
+                       smp_req->req_len = 9;
+                       break;
+                       /* Default - zero is a valid default for 2.0. */
+               }
+       }
+       req_len = smp_req->req_len;
+       sci_swab32_cpy(smp_req, smp_req, sg->length / sizeof(u32));
+       cmd = *(u32 *) smp_req;
+       kunmap_atomic(kaddr, KM_IRQ0);
+
+       if (!dma_map_sg(dev, sg, 1, DMA_TO_DEVICE))
+               return SCI_FAILURE;
+
+       sci_req->protocol = SCIC_SMP_PROTOCOL;
 
        /* byte swap the smp request. */
-       sci_swab32_cpy(&sci_req->smp.cmd, &sci_req->smp.cmd,
-                      word_cnt);
 
        task_context = scic_sds_request_get_task_context(sci_req);
 
@@ -3307,7 +3345,7 @@ scu_smp_request_construct_task_context(struct scic_sds_request *sci_req,
         * 18h ~ 30h, protocol specific
         * since commandIU has been build by framework at this point, we just
         * copy the frist DWord from command IU to this location. */
-       memcpy(&task_context->type.smp, &sci_req->smp.cmd, sizeof(u32));
+       memcpy(&task_context->type.smp, &cmd, sizeof(u32));
 
        /*
         * 40h
@@ -3347,48 +3385,12 @@ scu_smp_request_construct_task_context(struct scic_sds_request *sci_req,
         * Copy the physical address for the command buffer to the SCU Task
         * Context command buffer should not contain command header.
         */
-       dma_addr = scic_io_request_get_dma_addr(sci_req,
-                                               ((char *) &sci_req->smp.cmd) +
-                                               sizeof(u32));
-
-       task_context->command_iu_upper = upper_32_bits(dma_addr);
-       task_context->command_iu_lower = lower_32_bits(dma_addr);
+       task_context->command_iu_upper = upper_32_bits(sg_dma_address(sg));
+       task_context->command_iu_lower = lower_32_bits(sg_dma_address(sg) + sizeof(u32));
 
        /* SMP response comes as UF, so no need to set response IU address. */
        task_context->response_iu_upper = 0;
        task_context->response_iu_lower = 0;
-}
-
-static enum sci_status
-scic_io_request_construct_smp(struct scic_sds_request *sci_req)
-{
-       struct smp_req *smp_req = &sci_req->smp.cmd;
-
-       sci_req->protocol = SCIC_SMP_PROTOCOL;
-
-       /*
-        * Look at the SMP requests' header fields; for certain SAS 1.x SMP
-        * functions under SAS 2.0, a zero request length really indicates
-        * a non-zero default length.
-        */
-       if (smp_req->req_len == 0) {
-               switch (smp_req->func) {
-               case SMP_DISCOVER:
-               case SMP_REPORT_PHY_ERR_LOG:
-               case SMP_REPORT_PHY_SATA:
-               case SMP_REPORT_ROUTE_INFO:
-                       smp_req->req_len = 2;
-                       break;
-               case SMP_CONF_ROUTE_INFO:
-               case SMP_PHY_CONTROL:
-               case SMP_PHY_TEST_FUNCTION:
-                       smp_req->req_len = 9;
-                       break;
-                       /* Default - zero is a valid default for 2.0. */
-               }
-       }
-
-       scu_smp_request_construct_task_context(sci_req, smp_req->req_len);
 
        sci_change_state(&sci_req->sm, SCI_REQ_CONSTRUCTED);
 
@@ -3404,24 +3406,12 @@ scic_io_request_construct_smp(struct scic_sds_request *sci_req)
  */
 static enum sci_status isci_smp_request_build(struct isci_request *ireq)
 {
-       enum sci_status status = SCI_FAILURE;
        struct sas_task *task = isci_request_access_task(ireq);
+       struct device *dev = &ireq->isci_host->pdev->dev;
        struct scic_sds_request *sci_req = &ireq->sci;
+       enum sci_status status = SCI_FAILURE;
 
-       dev_dbg(&ireq->isci_host->pdev->dev,
-               "%s: request = %p\n", __func__, ireq);
-
-       dev_dbg(&ireq->isci_host->pdev->dev,
-               "%s: smp_req len = %d\n",
-               __func__,
-               task->smp_task.smp_req.length);
-
-       /* copy the smp_command to the address; */
-       sg_copy_to_buffer(&task->smp_task.smp_req, 1,
-                         &sci_req->smp.cmd,
-                         sizeof(struct smp_req));
-
-       status = scic_io_request_construct_smp(sci_req);
+       status = scic_io_request_construct_smp(dev, sci_req, task);
        if (status != SCI_SUCCESS)
                dev_warn(&ireq->isci_host->pdev->dev,
                         "%s: failed with status = %d\n",