From: Sreekanth Reddy <sreekanth.re...@avagotech.com>

Gen2 HBA's uses MPI Scatter Gather Lists where as Gen3 HBA's uses
IEEE Scatter Gather Lists. So modify the common code part in such
a way that it will build IEEE SGL table for Gen3 HBA's and it will
build MPI SGL table for Gen2 HBA's.

Signed-off-by: Sreekanth Reddy <sreekanth.re...@avagotech.com>
---
 drivers/scsi/mpt3sas/mpt3sas_base.c | 181 +++++++++++++++++++++++++++++++++---
 1 file changed, 168 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c 
b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 31d0ca8..62dc312 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -1318,6 +1318,149 @@ _base_build_zero_len_sge_ieee(struct MPT3SAS_ADAPTER 
*ioc, void *paddr)
 }
 
 /**
+ * _base_build_sg_scmd - main sg creation routine
+ * @ioc: per adapter object
+ * @scmd: scsi command
+ * @smid: system request message index
+ * Context: none.
+ *
+ * The main routine that builds scatter gather table from a given
+ * scsi request sent via the .queuecommand main handler.
+ *
+ * Returns 0 success, anything else error
+ */
+static int
+_base_build_sg_scmd(struct MPT3SAS_ADAPTER *ioc,
+               struct scsi_cmnd *scmd, u16 smid)
+{
+       Mpi2SCSIIORequest_t *mpi_request;
+       dma_addr_t chain_dma;
+       struct scatterlist *sg_scmd;
+       void *sg_local, *chain;
+       u32 chain_offset;
+       u32 chain_length;
+       u32 chain_flags;
+       int sges_left;
+       u32 sges_in_segment;
+       u32 sgl_flags;
+       u32 sgl_flags_last_element;
+       u32 sgl_flags_end_buffer;
+       struct chain_tracker *chain_req;
+
+       mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
+
+       /* init scatter gather flags */
+       sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
+       if (scmd->sc_data_direction == DMA_TO_DEVICE)
+               sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
+       sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
+           << MPI2_SGE_FLAGS_SHIFT;
+       sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
+           MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
+           << MPI2_SGE_FLAGS_SHIFT;
+       sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+
+       sg_scmd = scsi_sglist(scmd);
+       sges_left = scsi_dma_map(scmd);
+       if (sges_left < 0) {
+               sdev_printk(KERN_ERR, scmd->device,
+                "pci_map_sg failed: request for %d bytes!\n",
+                scsi_bufflen(scmd));
+               return -ENOMEM;
+       }
+
+       sg_local = &mpi_request->SGL;
+       sges_in_segment = ioc->max_sges_in_main_message;
+       if (sges_left <= sges_in_segment)
+               goto fill_in_last_segment;
+
+       mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
+           (sges_in_segment * ioc->sge_size))/4;
+
+       /* fill in main message segment when there is a chain following */
+       while (sges_in_segment) {
+               if (sges_in_segment == 1)
+                       ioc->base_add_sg_single(sg_local,
+                           sgl_flags_last_element | sg_dma_len(sg_scmd),
+                           sg_dma_address(sg_scmd));
+               else
+                       ioc->base_add_sg_single(sg_local, sgl_flags |
+                           sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
+               sg_scmd = sg_next(sg_scmd);
+               sg_local += ioc->sge_size;
+               sges_left--;
+               sges_in_segment--;
+       }
+
+       /* initializing the chain flags and pointers */
+       chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
+       chain_req = _base_get_chain_buffer_tracker(ioc, smid);
+       if (!chain_req)
+               return -1;
+       chain = chain_req->chain_buffer;
+       chain_dma = chain_req->chain_buffer_dma;
+       do {
+               sges_in_segment = (sges_left <=
+                   ioc->max_sges_in_chain_message) ? sges_left :
+                   ioc->max_sges_in_chain_message;
+               chain_offset = (sges_left == sges_in_segment) ?
+                   0 : (sges_in_segment * ioc->sge_size)/4;
+               chain_length = sges_in_segment * ioc->sge_size;
+               if (chain_offset) {
+                       chain_offset = chain_offset <<
+                           MPI2_SGE_CHAIN_OFFSET_SHIFT;
+                       chain_length += ioc->sge_size;
+               }
+               ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
+                   chain_length, chain_dma);
+               sg_local = chain;
+               if (!chain_offset)
+                       goto fill_in_last_segment;
+
+               /* fill in chain segments */
+               while (sges_in_segment) {
+                       if (sges_in_segment == 1)
+                               ioc->base_add_sg_single(sg_local,
+                                   sgl_flags_last_element |
+                                   sg_dma_len(sg_scmd),
+                                   sg_dma_address(sg_scmd));
+                       else
+                               ioc->base_add_sg_single(sg_local, sgl_flags |
+                                   sg_dma_len(sg_scmd),
+                                   sg_dma_address(sg_scmd));
+                       sg_scmd = sg_next(sg_scmd);
+                       sg_local += ioc->sge_size;
+                       sges_left--;
+                       sges_in_segment--;
+               }
+
+               chain_req = _base_get_chain_buffer_tracker(ioc, smid);
+               if (!chain_req)
+                       return -1;
+               chain = chain_req->chain_buffer;
+               chain_dma = chain_req->chain_buffer_dma;
+       } while (1);
+
+
+ fill_in_last_segment:
+
+       /* fill the last segment */
+       while (sges_left) {
+               if (sges_left == 1)
+                       ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
+                           sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
+               else
+                       ioc->base_add_sg_single(sg_local, sgl_flags |
+                           sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
+               sg_scmd = sg_next(sg_scmd);
+               sg_local += ioc->sge_size;
+               sges_left--;
+       }
+
+       return 0;
+}
+
+/**
  * _base_build_sg_scmd_ieee - main sg creation routine for IEEE format
  * @ioc: per adapter object
  * @scmd: scsi command
@@ -2850,8 +2993,12 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, 
 int sleep_flag)
        /* command line tunables for max sgl entries */
        if (max_sgl_entries != -1)
                sg_tablesize = max_sgl_entries;
-       else
-               sg_tablesize = MPT3SAS_SG_DEPTH;
+       else {
+               if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+                       sg_tablesize = MPT2SAS_SG_DEPTH;
+               else
+                       sg_tablesize = MPT3SAS_SG_DEPTH;
+       }
 
        if (sg_tablesize < MPT_MIN_PHYS_SEGMENTS)
                sg_tablesize = MPT_MIN_PHYS_SEGMENTS;
@@ -4878,17 +5025,25 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
        if (r)
                goto out_free_resources;
 
-       /*
-        * In SAS3.0,
-        * SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and
-        * Target Status - all require the IEEE formated scatter gather
-        * elements.
-        */
-
-       ioc->build_sg_scmd = &_base_build_sg_scmd_ieee;
-       ioc->build_sg = &_base_build_sg_ieee;
-       ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee;
-       ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t);
+       switch (ioc->hba_mpi_version_belonged) {
+       case MPI2_VERSION:
+               ioc->build_sg_scmd = &_base_build_sg_scmd;
+               ioc->build_sg = &_base_build_sg;
+               ioc->build_zero_len_sge = &_base_build_zero_len_sge;
+               break;
+       case MPI25_VERSION:
+               /*
+                * In SAS3.0,
+                * SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and
+                * Target Status - all require the IEEE formated scatter gather
+                * elements.
+                */
+               ioc->build_sg_scmd = &_base_build_sg_scmd_ieee;
+               ioc->build_sg = &_base_build_sg_ieee;
+               ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee;
+               ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t);
+               break;
+       }
 
        /*
         * These function pointers for other requests that don't
-- 
2.0.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to