isci: fix support for arbitrarily large smp requests
Dan Williams [Thu, 16 Jun 2011 23:59:56 +0000 (16:59 -0700)]
Instead of duplicating the smp request buffer reuse the one provided by
libsas.  This future proofs the driver to support arbitrarily large smp
requests, and shrinks the request structure size by ~700 bytes.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>

drivers/scsi/isci/request.c
drivers/scsi/isci/request.h
drivers/scsi/isci/sas.h

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",
index 324fb7b..7c8b59a 100644 (file)
@@ -244,7 +244,6 @@ struct scic_sds_request {
                } ssp;
 
                struct {
-                       struct smp_req cmd;
                        struct smp_resp rsp;
                } smp;
 
index 822a8db..462b151 100644 (file)
@@ -190,8 +190,6 @@ struct smp_req_phycntl {
        u8 _r_h[3];                     /* bytes 37-39 */
 }  __packed;
 
-#define SMP_REQ_VENDOR_SPECIFIC_MAX_LEN 1016
-
 /*
  * struct smp_req - This structure simply unionizes the existing request
  *    structures into a common request type.
@@ -203,14 +201,7 @@ struct smp_req {
        u8 func;                /* byte 1 */
        u8 alloc_resp_len;      /* byte 2 */
        u8 req_len;             /* byte 3 */
-
-       union { /* bytes 4-N */
-               u32 smp_req_gen;
-               struct smp_req_phy_id phy_id;
-               struct smp_req_phycntl phy_cntl;
-               struct smp_req_conf_rtinfo conf_rt_info;
-               u8 vendor[SMP_REQ_VENDOR_SPECIFIC_MAX_LEN];
-       };
+       u8 req_data[0];
 }  __packed;
 
 #define SMP_RESP_HDR_SZ        4