diff options
author | James Smart <james.smart@emulex.com> | 2011-05-24 11:42:45 -0400 |
---|---|---|
committer | James Bottomley <jbottomley@parallels.com> | 2011-05-26 23:49:37 -0400 |
commit | 52d5244096017bbd11164479116baceaede342b0 (patch) | |
tree | 1e61c05ab7f1babd2ed44f6136bc6f9384d9f786 /drivers/scsi/lpfc/lpfc_init.c | |
parent | 912e3acde60b3b9ebf46c5ec5ae6bd01b80132c8 (diff) |
[SCSI] lpfc 8.3.24: Add request-firmware support
Add request-firmware support:
- Add support for request_firmware interface for INTF2 SLI4 ports.
- Add ability to reset SLI4 INTF2 ports.
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/lpfc_init.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index e81912cd257e..2b535cff4b2a 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/ctype.h> | 30 | #include <linux/ctype.h> |
31 | #include <linux/aer.h> | 31 | #include <linux/aer.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/firmware.h> | ||
33 | 34 | ||
34 | #include <scsi/scsi.h> | 35 | #include <scsi/scsi.h> |
35 | #include <scsi/scsi_device.h> | 36 | #include <scsi/scsi_device.h> |
@@ -8775,6 +8776,97 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba) | |||
8775 | } | 8776 | } |
8776 | 8777 | ||
8777 | /** | 8778 | /** |
8779 | * lpfc_write_firmware - attempt to write a firmware image to the port | ||
8780 | * @phba: pointer to lpfc hba data structure. | ||
8781 | * @fw: pointer to firmware image returned from request_firmware. | ||
8782 | * | ||
8783 | * returns the number of bytes written if write is successful. | ||
8784 | * returns a negative error value if there were errors. | ||
8785 | * returns 0 if firmware matches currently active firmware on port. | ||
8786 | **/ | ||
8787 | int | ||
8788 | lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw) | ||
8789 | { | ||
8790 | char fwrev[32]; | ||
8791 | struct lpfc_grp_hdr *image = (struct lpfc_grp_hdr *)fw->data; | ||
8792 | struct list_head dma_buffer_list; | ||
8793 | int i, rc = 0; | ||
8794 | struct lpfc_dmabuf *dmabuf, *next; | ||
8795 | uint32_t offset = 0, temp_offset = 0; | ||
8796 | |||
8797 | INIT_LIST_HEAD(&dma_buffer_list); | ||
8798 | if ((image->magic_number != LPFC_GROUP_OJECT_MAGIC_NUM) || | ||
8799 | (bf_get(lpfc_grp_hdr_file_type, image) != LPFC_FILE_TYPE_GROUP) || | ||
8800 | (bf_get(lpfc_grp_hdr_id, image) != LPFC_FILE_ID_GROUP) || | ||
8801 | (image->size != fw->size)) { | ||
8802 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
8803 | "3022 Invalid FW image found. " | ||
8804 | "Magic:%d Type:%x ID:%x\n", | ||
8805 | image->magic_number, | ||
8806 | bf_get(lpfc_grp_hdr_file_type, image), | ||
8807 | bf_get(lpfc_grp_hdr_id, image)); | ||
8808 | return -EINVAL; | ||
8809 | } | ||
8810 | lpfc_decode_firmware_rev(phba, fwrev, 1); | ||
8811 | if (strncmp(fwrev, image->rev_name, strnlen(fwrev, 16))) { | ||
8812 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
8813 | "3023 Updating Firmware. Current Version:%s " | ||
8814 | "New Version:%s\n", | ||
8815 | fwrev, image->rev_name); | ||
8816 | for (i = 0; i < LPFC_MBX_WR_CONFIG_MAX_BDE; i++) { | ||
8817 | dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), | ||
8818 | GFP_KERNEL); | ||
8819 | if (!dmabuf) { | ||
8820 | rc = -ENOMEM; | ||
8821 | goto out; | ||
8822 | } | ||
8823 | dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, | ||
8824 | SLI4_PAGE_SIZE, | ||
8825 | &dmabuf->phys, | ||
8826 | GFP_KERNEL); | ||
8827 | if (!dmabuf->virt) { | ||
8828 | kfree(dmabuf); | ||
8829 | rc = -ENOMEM; | ||
8830 | goto out; | ||
8831 | } | ||
8832 | list_add_tail(&dmabuf->list, &dma_buffer_list); | ||
8833 | } | ||
8834 | while (offset < fw->size) { | ||
8835 | temp_offset = offset; | ||
8836 | list_for_each_entry(dmabuf, &dma_buffer_list, list) { | ||
8837 | if (offset + SLI4_PAGE_SIZE > fw->size) { | ||
8838 | temp_offset += fw->size - offset; | ||
8839 | memcpy(dmabuf->virt, | ||
8840 | fw->data + temp_offset, | ||
8841 | fw->size - offset); | ||
8842 | break; | ||
8843 | } | ||
8844 | temp_offset += SLI4_PAGE_SIZE; | ||
8845 | memcpy(dmabuf->virt, fw->data + temp_offset, | ||
8846 | SLI4_PAGE_SIZE); | ||
8847 | } | ||
8848 | rc = lpfc_wr_object(phba, &dma_buffer_list, | ||
8849 | (fw->size - offset), &offset); | ||
8850 | if (rc) { | ||
8851 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
8852 | "3024 Firmware update failed. " | ||
8853 | "%d\n", rc); | ||
8854 | goto out; | ||
8855 | } | ||
8856 | } | ||
8857 | rc = offset; | ||
8858 | } | ||
8859 | out: | ||
8860 | list_for_each_entry_safe(dmabuf, next, &dma_buffer_list, list) { | ||
8861 | list_del(&dmabuf->list); | ||
8862 | dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE, | ||
8863 | dmabuf->virt, dmabuf->phys); | ||
8864 | kfree(dmabuf); | ||
8865 | } | ||
8866 | return rc; | ||
8867 | } | ||
8868 | |||
8869 | /** | ||
8778 | * lpfc_pci_probe_one_s4 - PCI probe func to reg SLI-4 device to PCI subsys | 8870 | * lpfc_pci_probe_one_s4 - PCI probe func to reg SLI-4 device to PCI subsys |
8779 | * @pdev: pointer to PCI device | 8871 | * @pdev: pointer to PCI device |
8780 | * @pid: pointer to PCI device identifier | 8872 | * @pid: pointer to PCI device identifier |
@@ -8803,6 +8895,8 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
8803 | int mcnt; | 8895 | int mcnt; |
8804 | int adjusted_fcp_eq_count; | 8896 | int adjusted_fcp_eq_count; |
8805 | int fcp_qidx; | 8897 | int fcp_qidx; |
8898 | const struct firmware *fw; | ||
8899 | uint8_t file_name[16]; | ||
8806 | 8900 | ||
8807 | /* Allocate memory for HBA structure */ | 8901 | /* Allocate memory for HBA structure */ |
8808 | phba = lpfc_hba_alloc(pdev); | 8902 | phba = lpfc_hba_alloc(pdev); |
@@ -8957,6 +9051,14 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
8957 | /* Perform post initialization setup */ | 9051 | /* Perform post initialization setup */ |
8958 | lpfc_post_init_setup(phba); | 9052 | lpfc_post_init_setup(phba); |
8959 | 9053 | ||
9054 | /* check for firmware upgrade or downgrade */ | ||
9055 | snprintf(file_name, 16, "%s.grp", phba->ModelName); | ||
9056 | error = request_firmware(&fw, file_name, &phba->pcidev->dev); | ||
9057 | if (!error) { | ||
9058 | lpfc_write_firmware(phba, fw); | ||
9059 | release_firmware(fw); | ||
9060 | } | ||
9061 | |||
8960 | /* Check if there are static vports to be created. */ | 9062 | /* Check if there are static vports to be created. */ |
8961 | lpfc_create_static_vport(phba); | 9063 | lpfc_create_static_vport(phba); |
8962 | 9064 | ||