diff options
author | Harish Zunjarrao <harish.zunjarrao@qlogic.com> | 2010-05-28 18:08:23 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-27 13:01:24 -0400 |
commit | 9c2b297572bf3cc36d26520cd8f7e7ef4cb857f8 (patch) | |
tree | d98ce47df96e627f275a88cfebfc6b18408d834b /drivers/scsi/qla2xxx | |
parent | b0cd579cde8ee0c7ed52239531ba09bcbc5b54c2 (diff) |
[SCSI] qla2xxx: Support for loading Unified ROM Image (URI) format firmware file.
Used bootloder address from FLT while loading FW from flash as well.
Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/qla2xxx')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 3 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_nx.c | 184 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_nx.h | 35 |
3 files changed, 215 insertions, 7 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 2895855adc9a..f0e792a82dde 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
@@ -2788,6 +2788,9 @@ struct qla_hw_data { | |||
2788 | uint16_t gbl_dsd_avail; | 2788 | uint16_t gbl_dsd_avail; |
2789 | struct list_head gbl_dsd_list; | 2789 | struct list_head gbl_dsd_list; |
2790 | #define NUM_DSD_CHAIN 4096 | 2790 | #define NUM_DSD_CHAIN 4096 |
2791 | |||
2792 | uint8_t fw_type; | ||
2793 | __le32 file_prd_off; /* File firmware product offset */ | ||
2791 | }; | 2794 | }; |
2792 | 2795 | ||
2793 | /* | 2796 | /* |
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index eb12bf260a17..1a9a7343dffa 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c | |||
@@ -1407,7 +1407,8 @@ qla82xx_fw_load_from_flash(struct qla_hw_data *ha) | |||
1407 | { | 1407 | { |
1408 | int i; | 1408 | int i; |
1409 | long size = 0; | 1409 | long size = 0; |
1410 | long flashaddr = BOOTLD_START, memaddr = BOOTLD_START; | 1410 | long flashaddr = ha->flt_region_bootload << 2; |
1411 | long memaddr = BOOTLD_START; | ||
1411 | u64 data; | 1412 | u64 data; |
1412 | u32 high, low; | 1413 | u32 high, low; |
1413 | size = (IMAGE_START - BOOTLD_START) / 8; | 1414 | size = (IMAGE_START - BOOTLD_START) / 8; |
@@ -1677,6 +1678,94 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha, | |||
1677 | return ret; | 1678 | return ret; |
1678 | } | 1679 | } |
1679 | 1680 | ||
1681 | static struct qla82xx_uri_table_desc * | ||
1682 | qla82xx_get_table_desc(const u8 *unirom, int section) | ||
1683 | { | ||
1684 | uint32_t i; | ||
1685 | struct qla82xx_uri_table_desc *directory = | ||
1686 | (struct qla82xx_uri_table_desc *)&unirom[0]; | ||
1687 | __le32 offset; | ||
1688 | __le32 tab_type; | ||
1689 | __le32 entries = cpu_to_le32(directory->num_entries); | ||
1690 | |||
1691 | for (i = 0; i < entries; i++) { | ||
1692 | offset = cpu_to_le32(directory->findex) + | ||
1693 | (i * cpu_to_le32(directory->entry_size)); | ||
1694 | tab_type = cpu_to_le32(*((u32 *)&unirom[offset] + 8)); | ||
1695 | |||
1696 | if (tab_type == section) | ||
1697 | return (struct qla82xx_uri_table_desc *)&unirom[offset]; | ||
1698 | } | ||
1699 | |||
1700 | return NULL; | ||
1701 | } | ||
1702 | |||
1703 | static struct qla82xx_uri_data_desc * | ||
1704 | qla82xx_get_data_desc(struct qla_hw_data *ha, | ||
1705 | u32 section, u32 idx_offset) | ||
1706 | { | ||
1707 | const u8 *unirom = ha->hablob->fw->data; | ||
1708 | int idx = cpu_to_le32(*((int *)&unirom[ha->file_prd_off] + idx_offset)); | ||
1709 | struct qla82xx_uri_table_desc *tab_desc = NULL; | ||
1710 | __le32 offset; | ||
1711 | |||
1712 | tab_desc = qla82xx_get_table_desc(unirom, section); | ||
1713 | if (!tab_desc) | ||
1714 | return NULL; | ||
1715 | |||
1716 | offset = cpu_to_le32(tab_desc->findex) + | ||
1717 | (cpu_to_le32(tab_desc->entry_size) * idx); | ||
1718 | |||
1719 | return (struct qla82xx_uri_data_desc *)&unirom[offset]; | ||
1720 | } | ||
1721 | |||
1722 | static u8 * | ||
1723 | qla82xx_get_bootld_offset(struct qla_hw_data *ha) | ||
1724 | { | ||
1725 | u32 offset = BOOTLD_START; | ||
1726 | struct qla82xx_uri_data_desc *uri_desc = NULL; | ||
1727 | |||
1728 | if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) { | ||
1729 | uri_desc = qla82xx_get_data_desc(ha, | ||
1730 | QLA82XX_URI_DIR_SECT_BOOTLD, QLA82XX_URI_BOOTLD_IDX_OFF); | ||
1731 | if (uri_desc) | ||
1732 | offset = cpu_to_le32(uri_desc->findex); | ||
1733 | } | ||
1734 | |||
1735 | return (u8 *)&ha->hablob->fw->data[offset]; | ||
1736 | } | ||
1737 | |||
1738 | static __le32 | ||
1739 | qla82xx_get_fw_size(struct qla_hw_data *ha) | ||
1740 | { | ||
1741 | struct qla82xx_uri_data_desc *uri_desc = NULL; | ||
1742 | |||
1743 | if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) { | ||
1744 | uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW, | ||
1745 | QLA82XX_URI_FIRMWARE_IDX_OFF); | ||
1746 | if (uri_desc) | ||
1747 | return cpu_to_le32(uri_desc->size); | ||
1748 | } | ||
1749 | |||
1750 | return cpu_to_le32(*(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET]); | ||
1751 | } | ||
1752 | |||
1753 | static u8 * | ||
1754 | qla82xx_get_fw_offs(struct qla_hw_data *ha) | ||
1755 | { | ||
1756 | u32 offset = IMAGE_START; | ||
1757 | struct qla82xx_uri_data_desc *uri_desc = NULL; | ||
1758 | |||
1759 | if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) { | ||
1760 | uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW, | ||
1761 | QLA82XX_URI_FIRMWARE_IDX_OFF); | ||
1762 | if (uri_desc) | ||
1763 | offset = cpu_to_le32(uri_desc->findex); | ||
1764 | } | ||
1765 | |||
1766 | return (u8 *)&ha->hablob->fw->data[offset]; | ||
1767 | } | ||
1768 | |||
1680 | /* PCI related functions */ | 1769 | /* PCI related functions */ |
1681 | char * | 1770 | char * |
1682 | qla82xx_pci_info_str(struct scsi_qla_host *vha, char *str) | 1771 | qla82xx_pci_info_str(struct scsi_qla_host *vha, char *str) |
@@ -1878,19 +1967,19 @@ int qla82xx_fw_load_from_blob(struct qla_hw_data *ha) | |||
1878 | 1967 | ||
1879 | size = (IMAGE_START - BOOTLD_START) / 8; | 1968 | size = (IMAGE_START - BOOTLD_START) / 8; |
1880 | 1969 | ||
1881 | ptr64 = (u64 *)&ha->hablob->fw->data[BOOTLD_START]; | 1970 | ptr64 = (u64 *)qla82xx_get_bootld_offset(ha); |
1882 | flashaddr = BOOTLD_START; | 1971 | flashaddr = BOOTLD_START; |
1883 | 1972 | ||
1884 | for (i = 0; i < size; i++) { | 1973 | for (i = 0; i < size; i++) { |
1885 | data = cpu_to_le64(ptr64[i]); | 1974 | data = cpu_to_le64(ptr64[i]); |
1886 | qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8); | 1975 | if (qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8)) |
1976 | return -EIO; | ||
1887 | flashaddr += 8; | 1977 | flashaddr += 8; |
1888 | } | 1978 | } |
1889 | 1979 | ||
1890 | size = *(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET]; | ||
1891 | size = (__force u32)cpu_to_le32(size) / 8; | ||
1892 | ptr64 = (u64 *)&ha->hablob->fw->data[IMAGE_START]; | ||
1893 | flashaddr = FLASH_ADDR_START; | 1980 | flashaddr = FLASH_ADDR_START; |
1981 | size = (__force u32)qla82xx_get_fw_size(ha) / 8; | ||
1982 | ptr64 = (u64 *)qla82xx_get_fw_offs(ha); | ||
1894 | 1983 | ||
1895 | for (i = 0; i < size; i++) { | 1984 | for (i = 0; i < size; i++) { |
1896 | data = cpu_to_le64(ptr64[i]); | 1985 | data = cpu_to_le64(ptr64[i]); |
@@ -1899,19 +1988,88 @@ int qla82xx_fw_load_from_blob(struct qla_hw_data *ha) | |||
1899 | return -EIO; | 1988 | return -EIO; |
1900 | flashaddr += 8; | 1989 | flashaddr += 8; |
1901 | } | 1990 | } |
1991 | udelay(100); | ||
1902 | 1992 | ||
1903 | /* Write a magic value to CAMRAM register | 1993 | /* Write a magic value to CAMRAM register |
1904 | * at a specified offset to indicate | 1994 | * at a specified offset to indicate |
1905 | * that all data is written and | 1995 | * that all data is written and |
1906 | * ready for firmware to initialize. | 1996 | * ready for firmware to initialize. |
1907 | */ | 1997 | */ |
1908 | qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), 0x12345678); | 1998 | qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), QLA82XX_BDINFO_MAGIC); |
1909 | 1999 | ||
2000 | read_lock(&ha->hw_lock); | ||
1910 | if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { | 2001 | if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { |
1911 | qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); | 2002 | qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); |
1912 | qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); | 2003 | qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); |
1913 | } else | 2004 | } else |
1914 | qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d); | 2005 | qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d); |
2006 | read_unlock(&ha->hw_lock); | ||
2007 | return 0; | ||
2008 | } | ||
2009 | |||
2010 | static int | ||
2011 | qla82xx_set_product_offset(struct qla_hw_data *ha) | ||
2012 | { | ||
2013 | struct qla82xx_uri_table_desc *ptab_desc = NULL; | ||
2014 | const uint8_t *unirom = ha->hablob->fw->data; | ||
2015 | uint32_t i; | ||
2016 | __le32 entries; | ||
2017 | __le32 flags, file_chiprev, offset; | ||
2018 | uint8_t chiprev = ha->chip_revision; | ||
2019 | /* Hardcoding mn_present flag for P3P */ | ||
2020 | int mn_present = 0; | ||
2021 | uint32_t flagbit; | ||
2022 | |||
2023 | ptab_desc = qla82xx_get_table_desc(unirom, | ||
2024 | QLA82XX_URI_DIR_SECT_PRODUCT_TBL); | ||
2025 | if (!ptab_desc) | ||
2026 | return -1; | ||
2027 | |||
2028 | entries = cpu_to_le32(ptab_desc->num_entries); | ||
2029 | |||
2030 | for (i = 0; i < entries; i++) { | ||
2031 | offset = cpu_to_le32(ptab_desc->findex) + | ||
2032 | (i * cpu_to_le32(ptab_desc->entry_size)); | ||
2033 | flags = cpu_to_le32(*((int *)&unirom[offset] + | ||
2034 | QLA82XX_URI_FLAGS_OFF)); | ||
2035 | file_chiprev = cpu_to_le32(*((int *)&unirom[offset] + | ||
2036 | QLA82XX_URI_CHIP_REV_OFF)); | ||
2037 | |||
2038 | flagbit = mn_present ? 1 : 2; | ||
2039 | |||
2040 | if ((chiprev == file_chiprev) && ((1ULL << flagbit) & flags)) { | ||
2041 | ha->file_prd_off = offset; | ||
2042 | return 0; | ||
2043 | } | ||
2044 | } | ||
2045 | return -1; | ||
2046 | } | ||
2047 | |||
2048 | int | ||
2049 | qla82xx_validate_firmware_blob(scsi_qla_host_t *vha, uint8_t fw_type) | ||
2050 | { | ||
2051 | __le32 val; | ||
2052 | uint32_t min_size; | ||
2053 | struct qla_hw_data *ha = vha->hw; | ||
2054 | const struct firmware *fw = ha->hablob->fw; | ||
2055 | |||
2056 | ha->fw_type = fw_type; | ||
2057 | |||
2058 | if (fw_type == QLA82XX_UNIFIED_ROMIMAGE) { | ||
2059 | if (qla82xx_set_product_offset(ha)) | ||
2060 | return -EINVAL; | ||
2061 | |||
2062 | min_size = QLA82XX_URI_FW_MIN_SIZE; | ||
2063 | } else { | ||
2064 | val = cpu_to_le32(*(u32 *)&fw->data[QLA82XX_FW_MAGIC_OFFSET]); | ||
2065 | if ((__force u32)val != QLA82XX_BDINFO_MAGIC) | ||
2066 | return -EINVAL; | ||
2067 | |||
2068 | min_size = QLA82XX_FW_MIN_SIZE; | ||
2069 | } | ||
2070 | |||
2071 | if (fw->size < min_size) | ||
2072 | return -EINVAL; | ||
1915 | return 0; | 2073 | return 0; |
1916 | } | 2074 | } |
1917 | 2075 | ||
@@ -2470,6 +2628,18 @@ try_blob_fw: | |||
2470 | goto fw_load_failed; | 2628 | goto fw_load_failed; |
2471 | } | 2629 | } |
2472 | 2630 | ||
2631 | /* Validating firmware blob */ | ||
2632 | if (qla82xx_validate_firmware_blob(vha, | ||
2633 | QLA82XX_FLASH_ROMIMAGE)) { | ||
2634 | /* Fallback to URI format */ | ||
2635 | if (qla82xx_validate_firmware_blob(vha, | ||
2636 | QLA82XX_UNIFIED_ROMIMAGE)) { | ||
2637 | qla_printk(KERN_ERR, ha, | ||
2638 | "No valid firmware image found!!!"); | ||
2639 | return QLA_FUNCTION_FAILED; | ||
2640 | } | ||
2641 | } | ||
2642 | |||
2473 | if (qla82xx_fw_load_from_blob(ha) == QLA_SUCCESS) { | 2643 | if (qla82xx_fw_load_from_blob(ha) == QLA_SUCCESS) { |
2474 | qla_printk(KERN_ERR, ha, | 2644 | qla_printk(KERN_ERR, ha, |
2475 | "%s: Firmware loaded successfully " | 2645 | "%s: Firmware loaded successfully " |
diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index aa95d3816d6c..9a9127efadaf 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h | |||
@@ -773,13 +773,48 @@ struct qla82xx_legacy_intr_set { | |||
773 | .pci_int_reg = ISR_MSI_INT_TRIGGER(7) }, \ | 773 | .pci_int_reg = ISR_MSI_INT_TRIGGER(7) }, \ |
774 | } | 774 | } |
775 | 775 | ||
776 | #define BRDCFG_START 0x4000 | ||
776 | #define BOOTLD_START 0x10000 | 777 | #define BOOTLD_START 0x10000 |
777 | #define IMAGE_START 0x100000 | 778 | #define IMAGE_START 0x100000 |
778 | #define FLASH_ADDR_START 0x43000 | 779 | #define FLASH_ADDR_START 0x43000 |
779 | 780 | ||
780 | /* Magic number to let user know flash is programmed */ | 781 | /* Magic number to let user know flash is programmed */ |
781 | #define QLA82XX_BDINFO_MAGIC 0x12345678 | 782 | #define QLA82XX_BDINFO_MAGIC 0x12345678 |
783 | #define QLA82XX_FW_MAGIC_OFFSET (BRDCFG_START + 0x128) | ||
782 | #define FW_SIZE_OFFSET (0x3e840c) | 784 | #define FW_SIZE_OFFSET (0x3e840c) |
785 | #define QLA82XX_FW_MIN_SIZE 0x3fffff | ||
786 | |||
787 | /* UNIFIED ROMIMAGE START */ | ||
788 | #define QLA82XX_URI_FW_MIN_SIZE 0xc8000 | ||
789 | #define QLA82XX_URI_DIR_SECT_PRODUCT_TBL 0x0 | ||
790 | #define QLA82XX_URI_DIR_SECT_BOOTLD 0x6 | ||
791 | #define QLA82XX_URI_DIR_SECT_FW 0x7 | ||
792 | |||
793 | /* Offsets */ | ||
794 | #define QLA82XX_URI_CHIP_REV_OFF 10 | ||
795 | #define QLA82XX_URI_FLAGS_OFF 11 | ||
796 | #define QLA82XX_URI_BIOS_VERSION_OFF 12 | ||
797 | #define QLA82XX_URI_BOOTLD_IDX_OFF 27 | ||
798 | #define QLA82XX_URI_FIRMWARE_IDX_OFF 29 | ||
799 | |||
800 | struct qla82xx_uri_table_desc{ | ||
801 | uint32_t findex; | ||
802 | uint32_t num_entries; | ||
803 | uint32_t entry_size; | ||
804 | uint32_t reserved[5]; | ||
805 | }; | ||
806 | |||
807 | struct qla82xx_uri_data_desc{ | ||
808 | uint32_t findex; | ||
809 | uint32_t size; | ||
810 | uint32_t reserved[5]; | ||
811 | }; | ||
812 | |||
813 | /* UNIFIED ROMIMAGE END */ | ||
814 | |||
815 | #define QLA82XX_UNIFIED_ROMIMAGE 3 | ||
816 | #define QLA82XX_FLASH_ROMIMAGE 4 | ||
817 | #define QLA82XX_UNKNOWN_ROMIMAGE 0xff | ||
783 | 818 | ||
784 | #define QLA82XX_IS_REVISION_P3PLUS(_rev_) ((_rev_) >= 0x50) | 819 | #define QLA82XX_IS_REVISION_P3PLUS(_rev_) ((_rev_) >= 0x50) |
785 | #define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0) | 820 | #define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0) |