diff options
author | James Smart <james.smart@emulex.com> | 2012-06-12 13:54:50 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-07-20 03:58:29 -0400 |
commit | 173edbb2c326ce4839bae8caa868fe83ce46dda3 (patch) | |
tree | 5d307e89546f9745346b04978ab9821e2d2aaab9 /drivers/scsi/lpfc | |
parent | 3a70730aa06c37d46086ecdbca7107531fe2d2c5 (diff) |
[SCSI] lpfc 8.3.32: Fix ability to change FCP EQ delay multiplier
Fix fcp_imax module parameter to dynamically change FCP EQ delay multiplier
Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 93 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 22 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 77 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 1 |
4 files changed, 185 insertions, 8 deletions
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 5eb2bc116183..adef5bb2100e 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -3617,6 +3617,91 @@ lpfc_sriov_nr_virtfn_init(struct lpfc_hba *phba, int val) | |||
3617 | static DEVICE_ATTR(lpfc_sriov_nr_virtfn, S_IRUGO | S_IWUSR, | 3617 | static DEVICE_ATTR(lpfc_sriov_nr_virtfn, S_IRUGO | S_IWUSR, |
3618 | lpfc_sriov_nr_virtfn_show, lpfc_sriov_nr_virtfn_store); | 3618 | lpfc_sriov_nr_virtfn_show, lpfc_sriov_nr_virtfn_store); |
3619 | 3619 | ||
3620 | /** | ||
3621 | * lpfc_fcp_imax_store | ||
3622 | * | ||
3623 | * @dev: class device that is converted into a Scsi_host. | ||
3624 | * @attr: device attribute, not used. | ||
3625 | * @buf: string with the number of fast-path FCP interrupts per second. | ||
3626 | * @count: unused variable. | ||
3627 | * | ||
3628 | * Description: | ||
3629 | * If val is in a valid range [636,651042], then set the adapter's | ||
3630 | * maximum number of fast-path FCP interrupts per second. | ||
3631 | * | ||
3632 | * Returns: | ||
3633 | * length of the buf on success if val is in range the intended mode | ||
3634 | * is supported. | ||
3635 | * -EINVAL if val out of range or intended mode is not supported. | ||
3636 | **/ | ||
3637 | static ssize_t | ||
3638 | lpfc_fcp_imax_store(struct device *dev, struct device_attribute *attr, | ||
3639 | const char *buf, size_t count) | ||
3640 | { | ||
3641 | struct Scsi_Host *shost = class_to_shost(dev); | ||
3642 | struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; | ||
3643 | struct lpfc_hba *phba = vport->phba; | ||
3644 | int val = 0, i; | ||
3645 | |||
3646 | /* Sanity check on user data */ | ||
3647 | if (!isdigit(buf[0])) | ||
3648 | return -EINVAL; | ||
3649 | if (sscanf(buf, "%i", &val) != 1) | ||
3650 | return -EINVAL; | ||
3651 | |||
3652 | /* Value range is [636,651042] */ | ||
3653 | if (val < LPFC_MIM_IMAX || val > LPFC_DMULT_CONST) | ||
3654 | return -EINVAL; | ||
3655 | |||
3656 | phba->cfg_fcp_imax = (uint32_t)val; | ||
3657 | for (i = 0; i < phba->cfg_fcp_eq_count; i += LPFC_MAX_EQ_DELAY) | ||
3658 | lpfc_modify_fcp_eq_delay(phba, i); | ||
3659 | |||
3660 | return strlen(buf); | ||
3661 | } | ||
3662 | |||
3663 | /* | ||
3664 | # lpfc_fcp_imax: The maximum number of fast-path FCP interrupts per second | ||
3665 | # | ||
3666 | # Value range is [636,651042]. Default value is 10000. | ||
3667 | */ | ||
3668 | static int lpfc_fcp_imax = LPFC_FP_DEF_IMAX; | ||
3669 | module_param(lpfc_fcp_imax, int, S_IRUGO|S_IWUSR); | ||
3670 | MODULE_PARM_DESC(lpfc_fcp_imax, | ||
3671 | "Set the maximum number of fast-path FCP interrupts per second"); | ||
3672 | lpfc_param_show(fcp_imax) | ||
3673 | |||
3674 | /** | ||
3675 | * lpfc_fcp_imax_init - Set the initial sr-iov virtual function enable | ||
3676 | * @phba: lpfc_hba pointer. | ||
3677 | * @val: link speed value. | ||
3678 | * | ||
3679 | * Description: | ||
3680 | * If val is in a valid range [636,651042], then initialize the adapter's | ||
3681 | * maximum number of fast-path FCP interrupts per second. | ||
3682 | * | ||
3683 | * Returns: | ||
3684 | * zero if val saved. | ||
3685 | * -EINVAL val out of range | ||
3686 | **/ | ||
3687 | static int | ||
3688 | lpfc_fcp_imax_init(struct lpfc_hba *phba, int val) | ||
3689 | { | ||
3690 | if (val >= LPFC_MIM_IMAX && val <= LPFC_DMULT_CONST) { | ||
3691 | phba->cfg_fcp_imax = val; | ||
3692 | return 0; | ||
3693 | } | ||
3694 | |||
3695 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
3696 | "3016 fcp_imax: %d out of range, using default\n", val); | ||
3697 | phba->cfg_fcp_imax = LPFC_FP_DEF_IMAX; | ||
3698 | |||
3699 | return 0; | ||
3700 | } | ||
3701 | |||
3702 | static DEVICE_ATTR(lpfc_fcp_imax, S_IRUGO | S_IWUSR, | ||
3703 | lpfc_fcp_imax_show, lpfc_fcp_imax_store); | ||
3704 | |||
3620 | /* | 3705 | /* |
3621 | # lpfc_fcp_class: Determines FC class to use for the FCP protocol. | 3706 | # lpfc_fcp_class: Determines FC class to use for the FCP protocol. |
3622 | # Value range is [2,3]. Default value is 3. | 3707 | # Value range is [2,3]. Default value is 3. |
@@ -3758,14 +3843,6 @@ LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or " | |||
3758 | "MSI-X (2), if possible"); | 3843 | "MSI-X (2), if possible"); |
3759 | 3844 | ||
3760 | /* | 3845 | /* |
3761 | # lpfc_fcp_imax: Set the maximum number of fast-path FCP interrupts per second | ||
3762 | # | ||
3763 | # Value range is [636,651042]. Default value is 10000. | ||
3764 | */ | ||
3765 | LPFC_ATTR_R(fcp_imax, LPFC_FP_DEF_IMAX, LPFC_MIM_IMAX, LPFC_DMULT_CONST, | ||
3766 | "Set the maximum number of fast-path FCP interrupts per second"); | ||
3767 | |||
3768 | /* | ||
3769 | # lpfc_fcp_wq_count: Set the number of fast-path FCP work queues | 3846 | # lpfc_fcp_wq_count: Set the number of fast-path FCP work queues |
3770 | # | 3847 | # |
3771 | # Value range is [1,31]. Default value is 4. | 3848 | # Value range is [1,31]. Default value is 4. |
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index f1946dfda5b4..a631ebf4158d 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h | |||
@@ -874,6 +874,7 @@ struct mbox_header { | |||
874 | #define LPFC_MBOX_OPCODE_MQ_CREATE 0x15 | 874 | #define LPFC_MBOX_OPCODE_MQ_CREATE 0x15 |
875 | #define LPFC_MBOX_OPCODE_GET_CNTL_ATTRIBUTES 0x20 | 875 | #define LPFC_MBOX_OPCODE_GET_CNTL_ATTRIBUTES 0x20 |
876 | #define LPFC_MBOX_OPCODE_NOP 0x21 | 876 | #define LPFC_MBOX_OPCODE_NOP 0x21 |
877 | #define LPFC_MBOX_OPCODE_MODIFY_EQ_DELAY 0x29 | ||
877 | #define LPFC_MBOX_OPCODE_MQ_DESTROY 0x35 | 878 | #define LPFC_MBOX_OPCODE_MQ_DESTROY 0x35 |
878 | #define LPFC_MBOX_OPCODE_CQ_DESTROY 0x36 | 879 | #define LPFC_MBOX_OPCODE_CQ_DESTROY 0x36 |
879 | #define LPFC_MBOX_OPCODE_EQ_DESTROY 0x37 | 880 | #define LPFC_MBOX_OPCODE_EQ_DESTROY 0x37 |
@@ -940,6 +941,13 @@ struct eq_context { | |||
940 | uint32_t reserved3; | 941 | uint32_t reserved3; |
941 | }; | 942 | }; |
942 | 943 | ||
944 | struct eq_delay_info { | ||
945 | uint32_t eq_id; | ||
946 | uint32_t phase; | ||
947 | uint32_t delay_multi; | ||
948 | }; | ||
949 | #define LPFC_MAX_EQ_DELAY 8 | ||
950 | |||
943 | struct sgl_page_pairs { | 951 | struct sgl_page_pairs { |
944 | uint32_t sgl_pg0_addr_lo; | 952 | uint32_t sgl_pg0_addr_lo; |
945 | uint32_t sgl_pg0_addr_hi; | 953 | uint32_t sgl_pg0_addr_hi; |
@@ -1002,6 +1010,19 @@ struct lpfc_mbx_eq_create { | |||
1002 | } u; | 1010 | } u; |
1003 | }; | 1011 | }; |
1004 | 1012 | ||
1013 | struct lpfc_mbx_modify_eq_delay { | ||
1014 | struct mbox_header header; | ||
1015 | union { | ||
1016 | struct { | ||
1017 | uint32_t num_eq; | ||
1018 | struct eq_delay_info eq[LPFC_MAX_EQ_DELAY]; | ||
1019 | } request; | ||
1020 | struct { | ||
1021 | uint32_t word0; | ||
1022 | } response; | ||
1023 | } u; | ||
1024 | }; | ||
1025 | |||
1005 | struct lpfc_mbx_eq_destroy { | 1026 | struct lpfc_mbx_eq_destroy { |
1006 | struct mbox_header header; | 1027 | struct mbox_header header; |
1007 | union { | 1028 | union { |
@@ -2875,6 +2896,7 @@ struct lpfc_mqe { | |||
2875 | struct lpfc_mbx_mq_create mq_create; | 2896 | struct lpfc_mbx_mq_create mq_create; |
2876 | struct lpfc_mbx_mq_create_ext mq_create_ext; | 2897 | struct lpfc_mbx_mq_create_ext mq_create_ext; |
2877 | struct lpfc_mbx_eq_create eq_create; | 2898 | struct lpfc_mbx_eq_create eq_create; |
2899 | struct lpfc_mbx_modify_eq_delay eq_delay; | ||
2878 | struct lpfc_mbx_cq_create cq_create; | 2900 | struct lpfc_mbx_cq_create cq_create; |
2879 | struct lpfc_mbx_wq_create wq_create; | 2901 | struct lpfc_mbx_wq_create wq_create; |
2880 | struct lpfc_mbx_rq_create rq_create; | 2902 | struct lpfc_mbx_rq_create rq_create; |
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 3333e64703a3..9cbd20b1328b 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -12048,6 +12048,83 @@ out_fail: | |||
12048 | } | 12048 | } |
12049 | 12049 | ||
12050 | /** | 12050 | /** |
12051 | * lpfc_modify_fcp_eq_delay - Modify Delay Multiplier on FCP EQs | ||
12052 | * @phba: HBA structure that indicates port to create a queue on. | ||
12053 | * @startq: The starting FCP EQ to modify | ||
12054 | * | ||
12055 | * This function sends an MODIFY_EQ_DELAY mailbox command to the HBA. | ||
12056 | * | ||
12057 | * The @phba struct is used to send mailbox command to HBA. The @startq | ||
12058 | * is used to get the starting FCP EQ to change. | ||
12059 | * This function is asynchronous and will wait for the mailbox | ||
12060 | * command to finish before continuing. | ||
12061 | * | ||
12062 | * On success this function will return a zero. If unable to allocate enough | ||
12063 | * memory this function will return -ENOMEM. If the queue create mailbox command | ||
12064 | * fails this function will return -ENXIO. | ||
12065 | **/ | ||
12066 | uint32_t | ||
12067 | lpfc_modify_fcp_eq_delay(struct lpfc_hba *phba, uint16_t startq) | ||
12068 | { | ||
12069 | struct lpfc_mbx_modify_eq_delay *eq_delay; | ||
12070 | LPFC_MBOXQ_t *mbox; | ||
12071 | struct lpfc_queue *eq; | ||
12072 | int cnt, rc, length, status = 0; | ||
12073 | uint32_t shdr_status, shdr_add_status; | ||
12074 | int fcp_eqidx; | ||
12075 | union lpfc_sli4_cfg_shdr *shdr; | ||
12076 | uint16_t dmult; | ||
12077 | |||
12078 | if (startq >= phba->cfg_fcp_eq_count) | ||
12079 | return 0; | ||
12080 | |||
12081 | mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | ||
12082 | if (!mbox) | ||
12083 | return -ENOMEM; | ||
12084 | length = (sizeof(struct lpfc_mbx_modify_eq_delay) - | ||
12085 | sizeof(struct lpfc_sli4_cfg_mhdr)); | ||
12086 | lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, | ||
12087 | LPFC_MBOX_OPCODE_MODIFY_EQ_DELAY, | ||
12088 | length, LPFC_SLI4_MBX_EMBED); | ||
12089 | eq_delay = &mbox->u.mqe.un.eq_delay; | ||
12090 | |||
12091 | /* Calculate delay multiper from maximum interrupt per second */ | ||
12092 | dmult = LPFC_DMULT_CONST/phba->cfg_fcp_imax - 1; | ||
12093 | |||
12094 | cnt = 0; | ||
12095 | for (fcp_eqidx = startq; fcp_eqidx < phba->cfg_fcp_eq_count; | ||
12096 | fcp_eqidx++) { | ||
12097 | eq = phba->sli4_hba.fp_eq[fcp_eqidx]; | ||
12098 | if (!eq) | ||
12099 | continue; | ||
12100 | eq_delay->u.request.eq[cnt].eq_id = eq->queue_id; | ||
12101 | eq_delay->u.request.eq[cnt].phase = 0; | ||
12102 | eq_delay->u.request.eq[cnt].delay_multi = dmult; | ||
12103 | cnt++; | ||
12104 | if (cnt >= LPFC_MAX_EQ_DELAY) | ||
12105 | break; | ||
12106 | } | ||
12107 | eq_delay->u.request.num_eq = cnt; | ||
12108 | |||
12109 | mbox->vport = phba->pport; | ||
12110 | mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | ||
12111 | mbox->context1 = NULL; | ||
12112 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); | ||
12113 | shdr = (union lpfc_sli4_cfg_shdr *) &eq_delay->header.cfg_shdr; | ||
12114 | shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); | ||
12115 | shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); | ||
12116 | if (shdr_status || shdr_add_status || rc) { | ||
12117 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
12118 | "2512 MODIFY_EQ_DELAY mailbox failed with " | ||
12119 | "status x%x add_status x%x, mbx status x%x\n", | ||
12120 | shdr_status, shdr_add_status, rc); | ||
12121 | status = -ENXIO; | ||
12122 | } | ||
12123 | mempool_free(mbox, phba->mbox_mem_pool); | ||
12124 | return status; | ||
12125 | } | ||
12126 | |||
12127 | /** | ||
12051 | * lpfc_eq_create - Create an Event Queue on the HBA | 12128 | * lpfc_eq_create - Create an Event Queue on the HBA |
12052 | * @phba: HBA structure that indicates port to create a queue on. | 12129 | * @phba: HBA structure that indicates port to create a queue on. |
12053 | * @eq: The queue structure to use to create the event queue. | 12130 | * @eq: The queue structure to use to create the event queue. |
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index a4a77080091b..ec756118c5c1 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h | |||
@@ -598,6 +598,7 @@ struct lpfc_queue *lpfc_sli4_queue_alloc(struct lpfc_hba *, uint32_t, | |||
598 | uint32_t); | 598 | uint32_t); |
599 | void lpfc_sli4_queue_free(struct lpfc_queue *); | 599 | void lpfc_sli4_queue_free(struct lpfc_queue *); |
600 | uint32_t lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint16_t); | 600 | uint32_t lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint16_t); |
601 | uint32_t lpfc_modify_fcp_eq_delay(struct lpfc_hba *, uint16_t); | ||
601 | uint32_t lpfc_cq_create(struct lpfc_hba *, struct lpfc_queue *, | 602 | uint32_t lpfc_cq_create(struct lpfc_hba *, struct lpfc_queue *, |
602 | struct lpfc_queue *, uint32_t, uint32_t); | 603 | struct lpfc_queue *, uint32_t, uint32_t); |
603 | int32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *, | 604 | int32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *, |