diff options
author | James Smart <james.smart@emulex.com> | 2012-10-31 14:44:33 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-11-26 23:59:43 -0500 |
commit | c71ab8616d62d8d857c438f058839d9a0282e64c (patch) | |
tree | 1c5f1029704ad8c64c13d15e274a77760bd46dbb /drivers/scsi | |
parent | 286aa031664ba5223bcb3dfd49a9e2d89d6b3aec (diff) |
[SCSI] lpfc 8.3.36: Fixed boot from san failure
Fixed boot from san failure when SLI4 FC device presented on the same PCI bus
The request_firmware interface can induce delays while looking
for firmware files, even if no fw file is present. In some situations
the delays exceeded scan_wait timeouts, resulting in situations in which
the boot device had not been discovered in time. Boot Device does not
need to be on a lpfc device.
Change request_firmware use to be module paramater driven. Default is to
not attempt firmware download on boot. Add sysfs parameter to invoke
firmware update.
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 73 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 55 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 3 |
5 files changed, 120 insertions, 13 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 69b59935b53f..d0ed6c19a9aa 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h | |||
@@ -714,6 +714,7 @@ struct lpfc_hba { | |||
714 | uint32_t cfg_log_verbose; | 714 | uint32_t cfg_log_verbose; |
715 | uint32_t cfg_aer_support; | 715 | uint32_t cfg_aer_support; |
716 | uint32_t cfg_sriov_nr_virtfn; | 716 | uint32_t cfg_sriov_nr_virtfn; |
717 | uint32_t cfg_request_firmware_upgrade; | ||
717 | uint32_t cfg_iocb_cnt; | 718 | uint32_t cfg_iocb_cnt; |
718 | uint32_t cfg_suppress_link_up; | 719 | uint32_t cfg_suppress_link_up; |
719 | #define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */ | 720 | #define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */ |
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index ad16e54ac383..a71c7ebe7b74 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -3618,6 +3618,77 @@ 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 | /** | 3620 | /** |
3621 | * lpfc_request_firmware_store - Request for Linux generic firmware upgrade | ||
3622 | * | ||
3623 | * @dev: class device that is converted into a Scsi_host. | ||
3624 | * @attr: device attribute, not used. | ||
3625 | * @buf: containing the string the number of vfs to be enabled. | ||
3626 | * @count: unused variable. | ||
3627 | * | ||
3628 | * Description: | ||
3629 | * | ||
3630 | * Returns: | ||
3631 | * length of the buf on success if val is in range the intended mode | ||
3632 | * is supported. | ||
3633 | * -EINVAL if val out of range or intended mode is not supported. | ||
3634 | **/ | ||
3635 | static ssize_t | ||
3636 | lpfc_request_firmware_upgrade_store(struct device *dev, | ||
3637 | struct device_attribute *attr, | ||
3638 | const char *buf, size_t count) | ||
3639 | { | ||
3640 | struct Scsi_Host *shost = class_to_shost(dev); | ||
3641 | struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; | ||
3642 | struct lpfc_hba *phba = vport->phba; | ||
3643 | int val = 0, rc = -EINVAL; | ||
3644 | |||
3645 | /* Sanity check on user data */ | ||
3646 | if (!isdigit(buf[0])) | ||
3647 | return -EINVAL; | ||
3648 | if (sscanf(buf, "%i", &val) != 1) | ||
3649 | return -EINVAL; | ||
3650 | if (val != 1) | ||
3651 | return -EINVAL; | ||
3652 | |||
3653 | rc = lpfc_sli4_request_firmware_update(phba, RUN_FW_UPGRADE); | ||
3654 | if (rc) | ||
3655 | rc = -EPERM; | ||
3656 | else | ||
3657 | rc = strlen(buf); | ||
3658 | return rc; | ||
3659 | } | ||
3660 | |||
3661 | static int lpfc_req_fw_upgrade; | ||
3662 | module_param(lpfc_req_fw_upgrade, int, S_IRUGO|S_IWUSR); | ||
3663 | MODULE_PARM_DESC(lpfc_req_fw_upgrade, "Enable Linux generic firmware upgrade"); | ||
3664 | lpfc_param_show(request_firmware_upgrade) | ||
3665 | |||
3666 | /** | ||
3667 | * lpfc_request_firmware_upgrade_init - Enable initial linux generic fw upgrade | ||
3668 | * @phba: lpfc_hba pointer. | ||
3669 | * @val: 0 or 1. | ||
3670 | * | ||
3671 | * Description: | ||
3672 | * Set the initial Linux generic firmware upgrade enable or disable flag. | ||
3673 | * | ||
3674 | * Returns: | ||
3675 | * zero if val saved. | ||
3676 | * -EINVAL val out of range | ||
3677 | **/ | ||
3678 | static int | ||
3679 | lpfc_request_firmware_upgrade_init(struct lpfc_hba *phba, int val) | ||
3680 | { | ||
3681 | if (val >= 0 && val <= 1) { | ||
3682 | phba->cfg_request_firmware_upgrade = val; | ||
3683 | return 0; | ||
3684 | } | ||
3685 | return -EINVAL; | ||
3686 | } | ||
3687 | static DEVICE_ATTR(lpfc_req_fw_upgrade, S_IRUGO | S_IWUSR, | ||
3688 | lpfc_request_firmware_upgrade_show, | ||
3689 | lpfc_request_firmware_upgrade_store); | ||
3690 | |||
3691 | /** | ||
3621 | * lpfc_fcp_imax_store | 3692 | * lpfc_fcp_imax_store |
3622 | * | 3693 | * |
3623 | * @dev: class device that is converted into a Scsi_host. | 3694 | * @dev: class device that is converted into a Scsi_host. |
@@ -4069,6 +4140,7 @@ struct device_attribute *lpfc_hba_attrs[] = { | |||
4069 | &dev_attr_lpfc_aer_support, | 4140 | &dev_attr_lpfc_aer_support, |
4070 | &dev_attr_lpfc_aer_state_cleanup, | 4141 | &dev_attr_lpfc_aer_state_cleanup, |
4071 | &dev_attr_lpfc_sriov_nr_virtfn, | 4142 | &dev_attr_lpfc_sriov_nr_virtfn, |
4143 | &dev_attr_lpfc_req_fw_upgrade, | ||
4072 | &dev_attr_lpfc_suppress_link_up, | 4144 | &dev_attr_lpfc_suppress_link_up, |
4073 | &dev_attr_lpfc_iocb_cnt, | 4145 | &dev_attr_lpfc_iocb_cnt, |
4074 | &dev_attr_iocb_hw, | 4146 | &dev_attr_iocb_hw, |
@@ -5051,6 +5123,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) | |||
5051 | lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); | 5123 | lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); |
5052 | lpfc_aer_support_init(phba, lpfc_aer_support); | 5124 | lpfc_aer_support_init(phba, lpfc_aer_support); |
5053 | lpfc_sriov_nr_virtfn_init(phba, lpfc_sriov_nr_virtfn); | 5125 | lpfc_sriov_nr_virtfn_init(phba, lpfc_sriov_nr_virtfn); |
5126 | lpfc_request_firmware_upgrade_init(phba, lpfc_req_fw_upgrade); | ||
5054 | lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up); | 5127 | lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up); |
5055 | lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt); | 5128 | lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt); |
5056 | phba->cfg_enable_dss = 1; | 5129 | phba->cfg_enable_dss = 1; |
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 4380a44000bc..69d66e3662cb 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
@@ -468,3 +468,4 @@ void lpfc_sli4_node_prep(struct lpfc_hba *); | |||
468 | int lpfc_sli4_xri_sgl_update(struct lpfc_hba *); | 468 | int lpfc_sli4_xri_sgl_update(struct lpfc_hba *); |
469 | void lpfc_free_sgl_list(struct lpfc_hba *, struct list_head *); | 469 | void lpfc_free_sgl_list(struct lpfc_hba *, struct list_head *); |
470 | uint32_t lpfc_sli_port_speed_get(struct lpfc_hba *); | 470 | uint32_t lpfc_sli_port_speed_get(struct lpfc_hba *); |
471 | int lpfc_sli4_request_firmware_update(struct lpfc_hba *, uint8_t); | ||
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 7dc4218d9c4c..d89569307416 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -9450,7 +9450,7 @@ lpfc_write_firmware(const struct firmware *fw, void *context) | |||
9450 | struct lpfc_dmabuf *dmabuf, *next; | 9450 | struct lpfc_dmabuf *dmabuf, *next; |
9451 | uint32_t offset = 0, temp_offset = 0; | 9451 | uint32_t offset = 0, temp_offset = 0; |
9452 | 9452 | ||
9453 | /* It can be null, sanity check */ | 9453 | /* It can be null in no-wait mode, sanity check */ |
9454 | if (!fw) { | 9454 | if (!fw) { |
9455 | rc = -ENXIO; | 9455 | rc = -ENXIO; |
9456 | goto out; | 9456 | goto out; |
@@ -9528,11 +9528,48 @@ release_out: | |||
9528 | release_firmware(fw); | 9528 | release_firmware(fw); |
9529 | out: | 9529 | out: |
9530 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | 9530 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, |
9531 | "3024 Firmware update done: %d.", rc); | 9531 | "3024 Firmware update done: %d.\n", rc); |
9532 | return; | 9532 | return; |
9533 | } | 9533 | } |
9534 | 9534 | ||
9535 | /** | 9535 | /** |
9536 | * lpfc_sli4_request_firmware_update - Request linux generic firmware upgrade | ||
9537 | * @phba: pointer to lpfc hba data structure. | ||
9538 | * | ||
9539 | * This routine is called to perform Linux generic firmware upgrade on device | ||
9540 | * that supports such feature. | ||
9541 | **/ | ||
9542 | int | ||
9543 | lpfc_sli4_request_firmware_update(struct lpfc_hba *phba, uint8_t fw_upgrade) | ||
9544 | { | ||
9545 | uint8_t file_name[ELX_MODEL_NAME_SIZE]; | ||
9546 | int ret; | ||
9547 | const struct firmware *fw; | ||
9548 | |||
9549 | /* Only supported on SLI4 interface type 2 for now */ | ||
9550 | if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != | ||
9551 | LPFC_SLI_INTF_IF_TYPE_2) | ||
9552 | return -EPERM; | ||
9553 | |||
9554 | snprintf(file_name, ELX_MODEL_NAME_SIZE, "%s.grp", phba->ModelName); | ||
9555 | |||
9556 | if (fw_upgrade == INT_FW_UPGRADE) { | ||
9557 | ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, | ||
9558 | file_name, &phba->pcidev->dev, | ||
9559 | GFP_KERNEL, (void *)phba, | ||
9560 | lpfc_write_firmware); | ||
9561 | } else if (fw_upgrade == RUN_FW_UPGRADE) { | ||
9562 | ret = request_firmware(&fw, file_name, &phba->pcidev->dev); | ||
9563 | if (!ret) | ||
9564 | lpfc_write_firmware(fw, (void *)phba); | ||
9565 | } else { | ||
9566 | ret = -EINVAL; | ||
9567 | } | ||
9568 | |||
9569 | return ret; | ||
9570 | } | ||
9571 | |||
9572 | /** | ||
9536 | * lpfc_pci_probe_one_s4 - PCI probe func to reg SLI-4 device to PCI subsys | 9573 | * lpfc_pci_probe_one_s4 - PCI probe func to reg SLI-4 device to PCI subsys |
9537 | * @pdev: pointer to PCI device | 9574 | * @pdev: pointer to PCI device |
9538 | * @pid: pointer to PCI device identifier | 9575 | * @pid: pointer to PCI device identifier |
@@ -9560,7 +9597,6 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
9560 | uint32_t cfg_mode, intr_mode; | 9597 | uint32_t cfg_mode, intr_mode; |
9561 | int mcnt; | 9598 | int mcnt; |
9562 | int adjusted_fcp_io_channel; | 9599 | int adjusted_fcp_io_channel; |
9563 | uint8_t file_name[ELX_MODEL_NAME_SIZE]; | ||
9564 | 9600 | ||
9565 | /* Allocate memory for HBA structure */ | 9601 | /* Allocate memory for HBA structure */ |
9566 | phba = lpfc_hba_alloc(pdev); | 9602 | phba = lpfc_hba_alloc(pdev); |
@@ -9703,16 +9739,9 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
9703 | /* Perform post initialization setup */ | 9739 | /* Perform post initialization setup */ |
9704 | lpfc_post_init_setup(phba); | 9740 | lpfc_post_init_setup(phba); |
9705 | 9741 | ||
9706 | /* check for firmware upgrade or downgrade (if_type 2 only) */ | 9742 | /* check for firmware upgrade or downgrade */ |
9707 | if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == | 9743 | if (phba->cfg_request_firmware_upgrade) |
9708 | LPFC_SLI_INTF_IF_TYPE_2) { | 9744 | ret = lpfc_sli4_request_firmware_update(phba, INT_FW_UPGRADE); |
9709 | snprintf(file_name, ELX_MODEL_NAME_SIZE, "%s.grp", | ||
9710 | phba->ModelName); | ||
9711 | ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, | ||
9712 | file_name, &phba->pcidev->dev, | ||
9713 | GFP_KERNEL, (void *)phba, | ||
9714 | lpfc_write_firmware); | ||
9715 | } | ||
9716 | 9745 | ||
9717 | /* Check if there are static vports to be created. */ | 9746 | /* Check if there are static vports to be created. */ |
9718 | lpfc_create_static_vport(phba); | 9747 | lpfc_create_static_vport(phba); |
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index f44a06a4c6e7..44c427a45d66 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h | |||
@@ -82,6 +82,9 @@ | |||
82 | 82 | ||
83 | #define LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT 12000 | 83 | #define LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT 12000 |
84 | 84 | ||
85 | #define INT_FW_UPGRADE 0 | ||
86 | #define RUN_FW_UPGRADE 1 | ||
87 | |||
85 | enum lpfc_sli4_queue_type { | 88 | enum lpfc_sli4_queue_type { |
86 | LPFC_EQ, | 89 | LPFC_EQ, |
87 | LPFC_GCQ, | 90 | LPFC_GCQ, |