mpt3sas: Manage MSI-X vectors according to HBA device type
[linux-2.6-block.git] / drivers / scsi / mpt3sas / mpt3sas_base.c
index d4f1dcdb8361937c8b0cb75491ec45e1b4981188..2b33e48eea9015a9e7e249a37266b7f6c29e7a86 100644 (file)
@@ -324,7 +324,6 @@ mpt3sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc)
                panic("panic in %s\n", __func__);
 }
 
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
 /**
  * _base_sas_ioc_info - verbose translation of the ioc status
  * @ioc: per adapter object
@@ -630,7 +629,6 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc,
 
        pr_info(MPT3SAS_FMT "%s\n", ioc->name, desc);
 }
-#endif
 
 /**
  * _base_sas_log_info - verbose translation of firmware log info
@@ -710,13 +708,13 @@ _base_display_reply_info(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
                return;
        }
        ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
+
        if ((ioc_status & MPI2_IOCSTATUS_MASK) &&
            (ioc->logging_level & MPT_DEBUG_REPLY)) {
                _base_sas_ioc_info(ioc , mpi_reply,
                   mpt3sas_base_get_msg_frame(ioc, smid));
        }
-#endif
+
        if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
                loginfo = le32_to_cpu(mpi_reply->IOCLogInfo);
                _base_sas_log_info(ioc, loginfo);
@@ -783,9 +781,9 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
                return 1;
        if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION)
                return 1;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
+
        _base_display_event_data(ioc, mpi_reply);
-#endif
+
        if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED))
                goto out;
        smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx);
@@ -1319,6 +1317,149 @@ _base_build_zero_len_sge_ieee(struct MPT3SAS_ADAPTER *ioc, void *paddr)
        _base_add_sg_single_ieee(paddr, sgl_flags, 0, 0, -1);
 }
 
+/**
+ * _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
@@ -1571,6 +1712,14 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc)
        int base;
        u16 message_control;
 
+       /* Check whether controller SAS2008 B0 controller,
+        * if it is SAS2008 B0 controller use IO-APIC instead of MSIX
+        */
+       if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 &&
+           ioc->pdev->revision == SAS2_PCI_DEVICE_B0_REVISION) {
+               return -EINVAL;
+       }
+
        base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
        if (!base) {
                dfailprintk(ioc, pr_info(MPT3SAS_FMT "msix not supported\n",
@@ -1579,9 +1728,19 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc)
        }
 
        /* get msix vector count */
-
-       pci_read_config_word(ioc->pdev, base + 2, &message_control);
-       ioc->msix_vector_count = (message_control & 0x3FF) + 1;
+       /* NUMA_IO not supported for older controllers */
+       if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 ||
+           ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 ||
+           ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 ||
+           ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 ||
+           ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 ||
+           ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 ||
+           ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2)
+               ioc->msix_vector_count = 1;
+       else {
+               pci_read_config_word(ioc->pdev, base + 2, &message_control);
+               ioc->msix_vector_count = (message_control & 0x3FF) + 1;
+       }
        dinitprintk(ioc, pr_info(MPT3SAS_FMT
                "msix is supported, vector_count(%d)\n",
                ioc->name, ioc->msix_vector_count));
@@ -1643,10 +1802,10 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index, u32 vector)
        atomic_set(&reply_q->busy, 0);
        if (ioc->msix_enable)
                snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d",
-                   MPT3SAS_DRIVER_NAME, ioc->id, index);
+                   driver_name, ioc->id, index);
        else
                snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d",
-                   MPT3SAS_DRIVER_NAME, ioc->id);
+                   driver_name, ioc->id);
        r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name,
            reply_q);
        if (r) {
@@ -1872,7 +2031,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
 
 
        if (pci_request_selected_regions(pdev, ioc->bars,
-           MPT3SAS_DRIVER_NAME)) {
+           driver_name)) {
                pr_warn(MPT3SAS_FMT "pci_request_selected_regions: failed\n",
                        ioc->name);
                ioc->bars = 0;
@@ -2852,18 +3011,22 @@ _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 < MPT3SAS_MIN_PHYS_SEGMENTS)
-               sg_tablesize = MPT3SAS_MIN_PHYS_SEGMENTS;
-       else if (sg_tablesize > MPT3SAS_MAX_PHYS_SEGMENTS) {
+       if (sg_tablesize < MPT_MIN_PHYS_SEGMENTS)
+               sg_tablesize = MPT_MIN_PHYS_SEGMENTS;
+       else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) {
                sg_tablesize = min_t(unsigned short, sg_tablesize,
                                      SCSI_MAX_SG_CHAIN_SEGMENTS);
                pr_warn(MPT3SAS_FMT
                 "sg_tablesize(%u) is bigger than kernel"
                 " defined SCSI_MAX_SG_SEGMENTS(%u)\n", ioc->name,
-                sg_tablesize, MPT3SAS_MAX_PHYS_SEGMENTS);
+                sg_tablesize, MPT_MAX_PHYS_SEGMENTS);
        }
        ioc->shost->sg_tablesize = sg_tablesize;
 
@@ -4021,7 +4184,7 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
        mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER;
        mpi_request.VF_ID = 0; /* TODO */
        mpi_request.VP_ID = 0;
-       mpi_request.MsgVersion = cpu_to_le16(MPI25_VERSION);
+       mpi_request.MsgVersion = cpu_to_le16(ioc->hba_mpi_version_belonged);
        mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
 
        if (_base_is_controller_msix_enabled(ioc))
@@ -4834,7 +4997,6 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
 {
        int r, i;
        int cpu_id, last_cpu_id = 0;
-       u8 revision;
 
        dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
            __func__));
@@ -4854,20 +5016,6 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
                goto out_free_resources;
        }
 
-       /* Check whether the controller revision is C0 or above.
-        * only C0 and above revision controllers support 96 MSI-X vectors.
-        */
-       revision = ioc->pdev->revision;
-
-       if ((ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3004 ||
-            ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3008 ||
-            ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_1 ||
-            ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_2 ||
-            ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_5 ||
-            ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_6) &&
-            (revision >= 0x02))
-               ioc->msix96_vector = 1;
-
        ioc->rdpq_array_enable_assigned = 0;
        ioc->dma_mask = 0;
        r = mpt3sas_base_map_resources(ioc);
@@ -4880,17 +5028,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