aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx
diff options
context:
space:
mode:
authorAndrew Vasquez <andrew.vasquez@qlogic.com>2007-01-29 13:22:21 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-01-31 12:06:38 -0500
commit30c4766213aeb684ee477ac7f36703f9134ac7ad (patch)
tree91b95d4e765aa74856e4e7a4b9ee5aefb04e01dc /drivers/scsi/qla2xxx
parentd88021a6710e6ed5d1899ba2e54d4638026e277d (diff)
[SCSI] qla2xxx: Export OptionROM boot-codes version information.
This includes BIOS, EFI, FCODE and firmware versions. Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/qla2xxx')
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c49
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h11
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h3
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c347
6 files changed, 416 insertions, 0 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 7b18a6c7b7eb..78a5867bf515 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -653,6 +653,43 @@ qla2x00_beacon_store(struct class_device *cdev, const char *buf,
653 return count; 653 return count;
654} 654}
655 655
656static ssize_t
657qla2x00_optrom_bios_version_show(struct class_device *cdev, char *buf)
658{
659 scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
660
661 return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->bios_revision[1],
662 ha->bios_revision[0]);
663}
664
665static ssize_t
666qla2x00_optrom_efi_version_show(struct class_device *cdev, char *buf)
667{
668 scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
669
670 return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->efi_revision[1],
671 ha->efi_revision[0]);
672}
673
674static ssize_t
675qla2x00_optrom_fcode_version_show(struct class_device *cdev, char *buf)
676{
677 scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
678
679 return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fcode_revision[1],
680 ha->fcode_revision[0]);
681}
682
683static ssize_t
684qla2x00_optrom_fw_version_show(struct class_device *cdev, char *buf)
685{
686 scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
687
688 return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d %d\n",
689 ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[2],
690 ha->fw_revision[3]);
691}
692
656static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, 693static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show,
657 NULL); 694 NULL);
658static CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); 695static CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
@@ -669,6 +706,14 @@ static CLASS_DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show,
669 qla2x00_zio_timer_store); 706 qla2x00_zio_timer_store);
670static CLASS_DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, qla2x00_beacon_show, 707static CLASS_DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, qla2x00_beacon_show,
671 qla2x00_beacon_store); 708 qla2x00_beacon_store);
709static CLASS_DEVICE_ATTR(optrom_bios_version, S_IRUGO,
710 qla2x00_optrom_bios_version_show, NULL);
711static CLASS_DEVICE_ATTR(optrom_efi_version, S_IRUGO,
712 qla2x00_optrom_efi_version_show, NULL);
713static CLASS_DEVICE_ATTR(optrom_fcode_version, S_IRUGO,
714 qla2x00_optrom_fcode_version_show, NULL);
715static CLASS_DEVICE_ATTR(optrom_fw_version, S_IRUGO,
716 qla2x00_optrom_fw_version_show, NULL);
672 717
673struct class_device_attribute *qla2x00_host_attrs[] = { 718struct class_device_attribute *qla2x00_host_attrs[] = {
674 &class_device_attr_driver_version, 719 &class_device_attr_driver_version,
@@ -683,6 +728,10 @@ struct class_device_attribute *qla2x00_host_attrs[] = {
683 &class_device_attr_zio, 728 &class_device_attr_zio,
684 &class_device_attr_zio_timer, 729 &class_device_attr_zio_timer,
685 &class_device_attr_beacon, 730 &class_device_attr_beacon,
731 &class_device_attr_optrom_bios_version,
732 &class_device_attr_optrom_efi_version,
733 &class_device_attr_optrom_fcode_version,
734 &class_device_attr_optrom_fw_version,
686 NULL, 735 NULL,
687}; 736};
688 737
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 3b26f8e00ace..2a59faa632df 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2044,6 +2044,8 @@ struct isp_operations {
2044 uint32_t, uint32_t); 2044 uint32_t, uint32_t);
2045 int (*write_optrom) (struct scsi_qla_host *, uint8_t *, uint32_t, 2045 int (*write_optrom) (struct scsi_qla_host *, uint8_t *, uint32_t,
2046 uint32_t); 2046 uint32_t);
2047
2048 int (*get_flash_version) (struct scsi_qla_host *, void *);
2047}; 2049};
2048 2050
2049/* MSI-X Support *************************************************************/ 2051/* MSI-X Support *************************************************************/
@@ -2400,6 +2402,15 @@ typedef struct scsi_qla_host {
2400#define QLA_SREADING 1 2402#define QLA_SREADING 1
2401#define QLA_SWRITING 2 2403#define QLA_SWRITING 2
2402 2404
2405 /* PCI expansion ROM image information. */
2406#define ROM_CODE_TYPE_BIOS 0
2407#define ROM_CODE_TYPE_FCODE 1
2408#define ROM_CODE_TYPE_EFI 3
2409 uint8_t bios_revision[2];
2410 uint8_t efi_revision[2];
2411 uint8_t fcode_revision[16];
2412 uint32_t fw_revision[4];
2413
2403 /* Needed for BEACON */ 2414 /* Needed for BEACON */
2404 uint16_t beacon_blink_led; 2415 uint16_t beacon_blink_led;
2405 uint8_t beacon_color_state; 2416 uint8_t beacon_color_state;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index e6ca2bc9a28d..f8bddec4fe85 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -263,6 +263,9 @@ extern uint8_t *qla24xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
263extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *, 263extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
264 uint32_t, uint32_t); 264 uint32_t, uint32_t);
265 265
266extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *);
267extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *);
268
266/* 269/*
267 * Global Function Prototypes in qla_dbg.c source file. 270 * Global Function Prototypes in qla_dbg.c source file.
268 */ 271 */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index b6f0494e034c..570f5f8e6c28 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -84,6 +84,8 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
84 84
85 ha->isp_ops.reset_chip(ha); 85 ha->isp_ops.reset_chip(ha);
86 86
87 ha->isp_ops.get_flash_version(ha, ha->request_ring);
88
87 qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n"); 89 qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
88 90
89 ha->isp_ops.nvram_config(ha); 91 ha->isp_ops.nvram_config(ha);
@@ -3109,6 +3111,8 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
3109 } 3111 }
3110 spin_unlock_irqrestore(&ha->hardware_lock, flags); 3112 spin_unlock_irqrestore(&ha->hardware_lock, flags);
3111 3113
3114 ha->isp_ops.get_flash_version(ha, ha->request_ring);
3115
3112 ha->isp_ops.nvram_config(ha); 3116 ha->isp_ops.nvram_config(ha);
3113 3117
3114 if (!qla2x00_restart_isp(ha)) { 3118 if (!qla2x00_restart_isp(ha)) {
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 2bd70bb82aab..d35ff4a2a764 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1482,6 +1482,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
1482 ha->isp_ops.fw_dump = qla2100_fw_dump; 1482 ha->isp_ops.fw_dump = qla2100_fw_dump;
1483 ha->isp_ops.read_optrom = qla2x00_read_optrom_data; 1483 ha->isp_ops.read_optrom = qla2x00_read_optrom_data;
1484 ha->isp_ops.write_optrom = qla2x00_write_optrom_data; 1484 ha->isp_ops.write_optrom = qla2x00_write_optrom_data;
1485 ha->isp_ops.get_flash_version = qla2x00_get_flash_version;
1485 if (IS_QLA2100(ha)) { 1486 if (IS_QLA2100(ha)) {
1486 host->max_id = MAX_TARGETS_2100; 1487 host->max_id = MAX_TARGETS_2100;
1487 ha->mbx_count = MAILBOX_REGISTER_COUNT_2100; 1488 ha->mbx_count = MAILBOX_REGISTER_COUNT_2100;
@@ -1547,6 +1548,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
1547 ha->isp_ops.beacon_on = qla24xx_beacon_on; 1548 ha->isp_ops.beacon_on = qla24xx_beacon_on;
1548 ha->isp_ops.beacon_off = qla24xx_beacon_off; 1549 ha->isp_ops.beacon_off = qla24xx_beacon_off;
1549 ha->isp_ops.beacon_blink = qla24xx_beacon_blink; 1550 ha->isp_ops.beacon_blink = qla24xx_beacon_blink;
1551 ha->isp_ops.get_flash_version = qla24xx_get_flash_version;
1550 ha->gid_list_info_size = 8; 1552 ha->gid_list_info_size = 8;
1551 ha->optrom_size = OPTROM_SIZE_24XX; 1553 ha->optrom_size = OPTROM_SIZE_24XX;
1552 } 1554 }
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 7bbe751a7334..ff1dd4175a7f 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -1382,6 +1382,29 @@ qla2x00_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id,
1382 qla2x00_write_flash_byte(ha, 0x5555, 0xf0); 1382 qla2x00_write_flash_byte(ha, 0x5555, 0xf0);
1383} 1383}
1384 1384
1385static void
1386qla2x00_read_flash_data(scsi_qla_host_t *ha, uint8_t *tmp_buf, uint32_t saddr,
1387 uint32_t length)
1388{
1389 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
1390 uint32_t midpoint, ilength;
1391 uint8_t data;
1392
1393 midpoint = length / 2;
1394
1395 WRT_REG_WORD(&reg->nvram, 0);
1396 RD_REG_WORD(&reg->nvram);
1397 for (ilength = 0; ilength < length; saddr++, ilength++, tmp_buf++) {
1398 if (ilength == midpoint) {
1399 WRT_REG_WORD(&reg->nvram, NVR_SELECT);
1400 RD_REG_WORD(&reg->nvram);
1401 }
1402 data = qla2x00_read_flash_byte(ha, saddr);
1403 if (saddr % 100)
1404 udelay(10);
1405 *tmp_buf = data;
1406 }
1407}
1385 1408
1386static inline void 1409static inline void
1387qla2x00_suspend_hba(struct scsi_qla_host *ha) 1410qla2x00_suspend_hba(struct scsi_qla_host *ha)
@@ -1721,3 +1744,327 @@ qla24xx_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
1721 1744
1722 return rval; 1745 return rval;
1723} 1746}
1747
1748/**
1749 * qla2x00_get_fcode_version() - Determine an FCODE image's version.
1750 * @ha: HA context
1751 * @pcids: Pointer to the FCODE PCI data structure
1752 *
1753 * The process of retrieving the FCODE version information is at best
1754 * described as interesting.
1755 *
1756 * Within the first 100h bytes of the image an ASCII string is present
1757 * which contains several pieces of information including the FCODE
1758 * version. Unfortunately it seems the only reliable way to retrieve
1759 * the version is by scanning for another sentinel within the string,
1760 * the FCODE build date:
1761 *
1762 * ... 2.00.02 10/17/02 ...
1763 *
1764 * Returns QLA_SUCCESS on successful retrieval of version.
1765 */
1766static void
1767qla2x00_get_fcode_version(scsi_qla_host_t *ha, uint32_t pcids)
1768{
1769 int ret = QLA_FUNCTION_FAILED;
1770 uint32_t istart, iend, iter, vend;
1771 uint8_t do_next, rbyte, *vbyte;
1772
1773 memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
1774
1775 /* Skip the PCI data structure. */
1776 istart = pcids +
1777 ((qla2x00_read_flash_byte(ha, pcids + 0x0B) << 8) |
1778 qla2x00_read_flash_byte(ha, pcids + 0x0A));
1779 iend = istart + 0x100;
1780 do {
1781 /* Scan for the sentinel date string...eeewww. */
1782 do_next = 0;
1783 iter = istart;
1784 while ((iter < iend) && !do_next) {
1785 iter++;
1786 if (qla2x00_read_flash_byte(ha, iter) == '/') {
1787 if (qla2x00_read_flash_byte(ha, iter + 2) ==
1788 '/')
1789 do_next++;
1790 else if (qla2x00_read_flash_byte(ha,
1791 iter + 3) == '/')
1792 do_next++;
1793 }
1794 }
1795 if (!do_next)
1796 break;
1797
1798 /* Backtrack to previous ' ' (space). */
1799 do_next = 0;
1800 while ((iter > istart) && !do_next) {
1801 iter--;
1802 if (qla2x00_read_flash_byte(ha, iter) == ' ')
1803 do_next++;
1804 }
1805 if (!do_next)
1806 break;
1807
1808 /*
1809 * Mark end of version tag, and find previous ' ' (space) or
1810 * string length (recent FCODE images -- major hack ahead!!!).
1811 */
1812 vend = iter - 1;
1813 do_next = 0;
1814 while ((iter > istart) && !do_next) {
1815 iter--;
1816 rbyte = qla2x00_read_flash_byte(ha, iter);
1817 if (rbyte == ' ' || rbyte == 0xd || rbyte == 0x10)
1818 do_next++;
1819 }
1820 if (!do_next)
1821 break;
1822
1823 /* Mark beginning of version tag, and copy data. */
1824 iter++;
1825 if ((vend - iter) &&
1826 ((vend - iter) < sizeof(ha->fcode_revision))) {
1827 vbyte = ha->fcode_revision;
1828 while (iter <= vend) {
1829 *vbyte++ = qla2x00_read_flash_byte(ha, iter);
1830 iter++;
1831 }
1832 ret = QLA_SUCCESS;
1833 }
1834 } while (0);
1835
1836 if (ret != QLA_SUCCESS)
1837 memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
1838}
1839
1840int
1841qla2x00_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
1842{
1843 int ret = QLA_SUCCESS;
1844 uint8_t code_type, last_image;
1845 uint32_t pcihdr, pcids;
1846 uint8_t *dbyte;
1847 uint16_t *dcode;
1848
1849 if (!ha->pio_address || !mbuf)
1850 return QLA_FUNCTION_FAILED;
1851
1852 memset(ha->bios_revision, 0, sizeof(ha->bios_revision));
1853 memset(ha->efi_revision, 0, sizeof(ha->efi_revision));
1854 memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
1855 memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
1856
1857 qla2x00_flash_enable(ha);
1858
1859 /* Begin with first PCI expansion ROM header. */
1860 pcihdr = 0;
1861 last_image = 1;
1862 do {
1863 /* Verify PCI expansion ROM header. */
1864 if (qla2x00_read_flash_byte(ha, pcihdr) != 0x55 ||
1865 qla2x00_read_flash_byte(ha, pcihdr + 0x01) != 0xaa) {
1866 /* No signature */
1867 DEBUG2(printk("scsi(%ld): No matching ROM "
1868 "signature.\n", ha->host_no));
1869 ret = QLA_FUNCTION_FAILED;
1870 break;
1871 }
1872
1873 /* Locate PCI data structure. */
1874 pcids = pcihdr +
1875 ((qla2x00_read_flash_byte(ha, pcihdr + 0x19) << 8) |
1876 qla2x00_read_flash_byte(ha, pcihdr + 0x18));
1877
1878 /* Validate signature of PCI data structure. */
1879 if (qla2x00_read_flash_byte(ha, pcids) != 'P' ||
1880 qla2x00_read_flash_byte(ha, pcids + 0x1) != 'C' ||
1881 qla2x00_read_flash_byte(ha, pcids + 0x2) != 'I' ||
1882 qla2x00_read_flash_byte(ha, pcids + 0x3) != 'R') {
1883 /* Incorrect header. */
1884 DEBUG2(printk("%s(): PCI data struct not found "
1885 "pcir_adr=%x.\n", __func__, pcids));
1886 ret = QLA_FUNCTION_FAILED;
1887 break;
1888 }
1889
1890 /* Read version */
1891 code_type = qla2x00_read_flash_byte(ha, pcids + 0x14);
1892 switch (code_type) {
1893 case ROM_CODE_TYPE_BIOS:
1894 /* Intel x86, PC-AT compatible. */
1895 ha->bios_revision[0] =
1896 qla2x00_read_flash_byte(ha, pcids + 0x12);
1897 ha->bios_revision[1] =
1898 qla2x00_read_flash_byte(ha, pcids + 0x13);
1899 DEBUG3(printk("%s(): read BIOS %d.%d.\n", __func__,
1900 ha->bios_revision[1], ha->bios_revision[0]));
1901 break;
1902 case ROM_CODE_TYPE_FCODE:
1903 /* Open Firmware standard for PCI (FCode). */
1904 /* Eeeewww... */
1905 qla2x00_get_fcode_version(ha, pcids);
1906 break;
1907 case ROM_CODE_TYPE_EFI:
1908 /* Extensible Firmware Interface (EFI). */
1909 ha->efi_revision[0] =
1910 qla2x00_read_flash_byte(ha, pcids + 0x12);
1911 ha->efi_revision[1] =
1912 qla2x00_read_flash_byte(ha, pcids + 0x13);
1913 DEBUG3(printk("%s(): read EFI %d.%d.\n", __func__,
1914 ha->efi_revision[1], ha->efi_revision[0]));
1915 break;
1916 default:
1917 DEBUG2(printk("%s(): Unrecognized code type %x at "
1918 "pcids %x.\n", __func__, code_type, pcids));
1919 break;
1920 }
1921
1922 last_image = qla2x00_read_flash_byte(ha, pcids + 0x15) & BIT_7;
1923
1924 /* Locate next PCI expansion ROM. */
1925 pcihdr += ((qla2x00_read_flash_byte(ha, pcids + 0x11) << 8) |
1926 qla2x00_read_flash_byte(ha, pcids + 0x10)) * 512;
1927 } while (!last_image);
1928
1929 if (IS_QLA2322(ha)) {
1930 /* Read firmware image information. */
1931 memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
1932 dbyte = mbuf;
1933 memset(dbyte, 0, 8);
1934 dcode = (uint16_t *)dbyte;
1935
1936 qla2x00_read_flash_data(ha, dbyte, FA_RISC_CODE_ADDR * 4 + 10,
1937 8);
1938 DEBUG3(printk("%s(%ld): dumping fw ver from flash:\n",
1939 __func__, ha->host_no));
1940 DEBUG3(qla2x00_dump_buffer((uint8_t *)dbyte, 8));
1941
1942 if ((dcode[0] == 0xffff && dcode[1] == 0xffff &&
1943 dcode[2] == 0xffff && dcode[3] == 0xffff) ||
1944 (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
1945 dcode[3] == 0)) {
1946 DEBUG2(printk("%s(): Unrecognized fw revision at "
1947 "%x.\n", __func__, FA_RISC_CODE_ADDR * 4));
1948 } else {
1949 /* values are in big endian */
1950 ha->fw_revision[0] = dbyte[0] << 16 | dbyte[1];
1951 ha->fw_revision[1] = dbyte[2] << 16 | dbyte[3];
1952 ha->fw_revision[2] = dbyte[4] << 16 | dbyte[5];
1953 }
1954 }
1955
1956 qla2x00_flash_disable(ha);
1957
1958 return ret;
1959}
1960
1961int
1962qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
1963{
1964 int ret = QLA_SUCCESS;
1965 uint32_t pcihdr, pcids;
1966 uint32_t *dcode;
1967 uint8_t *bcode;
1968 uint8_t code_type, last_image;
1969 int i;
1970
1971 if (!mbuf)
1972 return QLA_FUNCTION_FAILED;
1973
1974 memset(ha->bios_revision, 0, sizeof(ha->bios_revision));
1975 memset(ha->efi_revision, 0, sizeof(ha->efi_revision));
1976 memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
1977 memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
1978
1979 dcode = mbuf;
1980
1981 /* Begin with first PCI expansion ROM header. */
1982 pcihdr = 0;
1983 last_image = 1;
1984 do {
1985 /* Verify PCI expansion ROM header. */
1986 qla24xx_read_flash_data(ha, dcode, pcihdr >> 2, 0x20);
1987 bcode = mbuf + (pcihdr % 4);
1988 if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) {
1989 /* No signature */
1990 DEBUG2(printk("scsi(%ld): No matching ROM "
1991 "signature.\n", ha->host_no));
1992 ret = QLA_FUNCTION_FAILED;
1993 break;
1994 }
1995
1996 /* Locate PCI data structure. */
1997 pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]);
1998
1999 qla24xx_read_flash_data(ha, dcode, pcids >> 2, 0x20);
2000 bcode = mbuf + (pcihdr % 4);
2001
2002 /* Validate signature of PCI data structure. */
2003 if (bcode[0x0] != 'P' || bcode[0x1] != 'C' ||
2004 bcode[0x2] != 'I' || bcode[0x3] != 'R') {
2005 /* Incorrect header. */
2006 DEBUG2(printk("%s(): PCI data struct not found "
2007 "pcir_adr=%x.\n", __func__, pcids));
2008 ret = QLA_FUNCTION_FAILED;
2009 break;
2010 }
2011
2012 /* Read version */
2013 code_type = bcode[0x14];
2014 switch (code_type) {
2015 case ROM_CODE_TYPE_BIOS:
2016 /* Intel x86, PC-AT compatible. */
2017 ha->bios_revision[0] = bcode[0x12];
2018 ha->bios_revision[1] = bcode[0x13];
2019 DEBUG3(printk("%s(): read BIOS %d.%d.\n", __func__,
2020 ha->bios_revision[1], ha->bios_revision[0]));
2021 break;
2022 case ROM_CODE_TYPE_FCODE:
2023 /* Open Firmware standard for PCI (FCode). */
2024 ha->fcode_revision[0] = bcode[0x12];
2025 ha->fcode_revision[1] = bcode[0x13];
2026 DEBUG3(printk("%s(): read FCODE %d.%d.\n", __func__,
2027 ha->fcode_revision[1], ha->fcode_revision[0]));
2028 break;
2029 case ROM_CODE_TYPE_EFI:
2030 /* Extensible Firmware Interface (EFI). */
2031 ha->efi_revision[0] = bcode[0x12];
2032 ha->efi_revision[1] = bcode[0x13];
2033 DEBUG3(printk("%s(): read EFI %d.%d.\n", __func__,
2034 ha->efi_revision[1], ha->efi_revision[0]));
2035 break;
2036 default:
2037 DEBUG2(printk("%s(): Unrecognized code type %x at "
2038 "pcids %x.\n", __func__, code_type, pcids));
2039 break;
2040 }
2041
2042 last_image = bcode[0x15] & BIT_7;
2043
2044 /* Locate next PCI expansion ROM. */
2045 pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512;
2046 } while (!last_image);
2047
2048 /* Read firmware image information. */
2049 memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
2050 dcode = mbuf;
2051
2052 qla24xx_read_flash_data(ha, dcode, FA_RISC_CODE_ADDR + 4, 4);
2053 for (i = 0; i < 4; i++)
2054 dcode[i] = be32_to_cpu(dcode[i]);
2055
2056 if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
2057 dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
2058 (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
2059 dcode[3] == 0)) {
2060 DEBUG2(printk("%s(): Unrecognized fw version at %x.\n",
2061 __func__, FA_RISC_CODE_ADDR));
2062 } else {
2063 ha->fw_revision[0] = dcode[0];
2064 ha->fw_revision[1] = dcode[1];
2065 ha->fw_revision[2] = dcode[2];
2066 ha->fw_revision[3] = dcode[3];
2067 }
2068
2069 return ret;
2070}