diff options
author | Andrew Vasquez <andrew.vasquez@qlogic.com> | 2007-09-20 17:07:33 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.localdomain> | 2007-10-12 14:49:38 -0400 |
commit | 338c9161e406591afbc1a6635a68d3b6d5362e00 (patch) | |
tree | 6bb711ac12bac66447ca924e56a9b616d6acd1e6 /drivers/scsi/qla2xxx/qla_sup.c | |
parent | c81d04c9e27966c0e4c5650d130f209bff9671f9 (diff) |
[SCSI] qla2xxx: Add flash burst-read/write support.
Newer ISPs support a mechanism to read and write flash-memory via
the firmware LOAD/DUMP memory mailbox command routines. When
supported, utilizing these mechanisms significantly reduces
overall access times.
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_sup.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_sup.c | 221 |
1 files changed, 166 insertions, 55 deletions
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index a925a3f179f9..ad3d1de51d8c 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c | |||
@@ -425,6 +425,9 @@ qla2x00_set_nvram_protection(scsi_qla_host_t *ha, int stat) | |||
425 | /* Flash Manipulation Routines */ | 425 | /* Flash Manipulation Routines */ |
426 | /*****************************************************************************/ | 426 | /*****************************************************************************/ |
427 | 427 | ||
428 | #define OPTROM_BURST_SIZE 0x1000 | ||
429 | #define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4) | ||
430 | |||
428 | static inline uint32_t | 431 | static inline uint32_t |
429 | flash_conf_to_access_addr(uint32_t faddr) | 432 | flash_conf_to_access_addr(uint32_t faddr) |
430 | { | 433 | { |
@@ -544,41 +547,59 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | |||
544 | uint32_t dwords) | 547 | uint32_t dwords) |
545 | { | 548 | { |
546 | int ret; | 549 | int ret; |
547 | uint32_t liter; | 550 | uint32_t liter, miter; |
548 | uint32_t sec_mask, rest_addr, conf_addr, sec_end_mask; | 551 | uint32_t sec_mask, rest_addr, conf_addr; |
549 | uint32_t fdata, findex ; | 552 | uint32_t fdata, findex ; |
550 | uint8_t man_id, flash_id; | 553 | uint8_t man_id, flash_id; |
551 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | 554 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; |
555 | dma_addr_t optrom_dma; | ||
556 | void *optrom = NULL; | ||
557 | uint32_t *s, *d; | ||
552 | 558 | ||
553 | ret = QLA_SUCCESS; | 559 | ret = QLA_SUCCESS; |
554 | 560 | ||
561 | /* Prepare burst-capable write on supported ISPs. */ | ||
562 | if (IS_QLA25XX(ha) && !(faddr & ~OPTROM_BURST_SIZE) && | ||
563 | dwords > OPTROM_BURST_DWORDS) { | ||
564 | optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, | ||
565 | &optrom_dma, GFP_KERNEL); | ||
566 | if (!optrom) { | ||
567 | qla_printk(KERN_DEBUG, ha, | ||
568 | "Unable to allocate memory for optrom burst write " | ||
569 | "(%x KB).\n", OPTROM_BURST_SIZE / 1024); | ||
570 | } | ||
571 | } | ||
572 | |||
555 | qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); | 573 | qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); |
556 | DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__, | 574 | DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__, |
557 | ha->host_no, man_id, flash_id)); | 575 | ha->host_no, man_id, flash_id)); |
558 | 576 | ||
559 | sec_end_mask = 0; | ||
560 | conf_addr = flash_conf_to_access_addr(0x03d8); | 577 | conf_addr = flash_conf_to_access_addr(0x03d8); |
561 | switch (man_id) { | 578 | switch (man_id) { |
562 | case 0xbf: /* STT flash. */ | 579 | case 0xbf: /* STT flash. */ |
563 | rest_addr = 0x1fff; | 580 | if (flash_id == 0x8e) { |
564 | sec_mask = 0x3e000; | 581 | rest_addr = 0x3fff; |
582 | sec_mask = 0x7c000; | ||
583 | } else { | ||
584 | rest_addr = 0x1fff; | ||
585 | sec_mask = 0x7e000; | ||
586 | } | ||
565 | if (flash_id == 0x80) | 587 | if (flash_id == 0x80) |
566 | conf_addr = flash_conf_to_access_addr(0x0352); | 588 | conf_addr = flash_conf_to_access_addr(0x0352); |
567 | break; | 589 | break; |
568 | case 0x13: /* ST M25P80. */ | 590 | case 0x13: /* ST M25P80. */ |
569 | rest_addr = 0x3fff; | 591 | rest_addr = 0x3fff; |
570 | sec_mask = 0x3c000; | 592 | sec_mask = 0x7c000; |
571 | break; | 593 | break; |
572 | case 0x1f: // Atmel 26DF081A | 594 | case 0x1f: // Atmel 26DF081A |
573 | rest_addr = 0x0fff; | 595 | rest_addr = 0x3fff; |
574 | sec_mask = 0xff000; | 596 | sec_mask = 0x7c000; |
575 | sec_end_mask = 0x003ff; | ||
576 | conf_addr = flash_conf_to_access_addr(0x0320); | 597 | conf_addr = flash_conf_to_access_addr(0x0320); |
577 | break; | 598 | break; |
578 | default: | 599 | default: |
579 | /* Default to 64 kb sector size. */ | 600 | /* Default to 64 kb sector size. */ |
580 | rest_addr = 0x3fff; | 601 | rest_addr = 0x3fff; |
581 | sec_mask = 0x3c000; | 602 | sec_mask = 0x7c000; |
582 | break; | 603 | break; |
583 | } | 604 | } |
584 | 605 | ||
@@ -592,56 +613,81 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | |||
592 | /* Some flash parts need an additional zero-write to clear bits.*/ | 613 | /* Some flash parts need an additional zero-write to clear bits.*/ |
593 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); | 614 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); |
594 | 615 | ||
595 | do { /* Loop once to provide quick error exit. */ | 616 | for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { |
596 | for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { | 617 | if (man_id == 0x1f) { |
597 | if (man_id == 0x1f) { | 618 | findex = faddr << 2; |
598 | findex = faddr << 2; | 619 | fdata = findex & sec_mask; |
599 | fdata = findex & sec_mask; | 620 | } else { |
600 | } else { | 621 | findex = faddr; |
601 | findex = faddr; | 622 | fdata = (findex & sec_mask) << 2; |
602 | fdata = (findex & sec_mask) << 2; | 623 | } |
603 | } | ||
604 | 624 | ||
605 | /* Are we at the beginning of a sector? */ | 625 | /* Are we at the beginning of a sector? */ |
606 | if ((findex & rest_addr) == 0) { | 626 | if ((findex & rest_addr) == 0) { |
607 | /* | 627 | /* Do sector unprotect at 4K boundry for Atmel part. */ |
608 | * Do sector unprotect at 4K boundry for Atmel | 628 | if (man_id == 0x1f) |
609 | * part. | 629 | qla24xx_write_flash_dword(ha, |
610 | */ | 630 | flash_conf_to_access_addr(0x0339), |
611 | if (man_id == 0x1f) | 631 | (fdata & 0xff00) | ((fdata << 16) & |
612 | qla24xx_write_flash_dword(ha, | ||
613 | flash_conf_to_access_addr(0x0339), | ||
614 | (fdata & 0xff00) | ((fdata << 16) & | ||
615 | 0xff0000) | ((fdata >> 16) & 0xff)); | ||
616 | ret = qla24xx_write_flash_dword(ha, conf_addr, | ||
617 | (fdata & 0xff00) |((fdata << 16) & | ||
618 | 0xff0000) | ((fdata >> 16) & 0xff)); | 632 | 0xff0000) | ((fdata >> 16) & 0xff)); |
619 | if (ret != QLA_SUCCESS) { | 633 | ret = qla24xx_write_flash_dword(ha, conf_addr, |
620 | DEBUG9(printk("%s(%ld) Unable to flash " | 634 | (fdata & 0xff00) |((fdata << 16) & |
621 | "sector: address=%x.\n", __func__, | 635 | 0xff0000) | ((fdata >> 16) & 0xff)); |
622 | ha->host_no, faddr)); | 636 | if (ret != QLA_SUCCESS) { |
623 | break; | 637 | DEBUG9(printk("%s(%ld) Unable to flash " |
624 | } | 638 | "sector: address=%x.\n", __func__, |
639 | ha->host_no, faddr)); | ||
640 | break; | ||
625 | } | 641 | } |
626 | ret = qla24xx_write_flash_dword(ha, | 642 | } |
643 | |||
644 | /* Go with burst-write. */ | ||
645 | if (optrom && (liter + OPTROM_BURST_DWORDS) < dwords) { | ||
646 | /* Copy data to DMA'ble buffer. */ | ||
647 | for (miter = 0, s = optrom, d = dwptr; | ||
648 | miter < OPTROM_BURST_DWORDS; miter++, s++, d++) | ||
649 | *s = cpu_to_le32(*d); | ||
650 | |||
651 | ret = qla2x00_load_ram(ha, optrom_dma, | ||
627 | flash_data_to_access_addr(faddr), | 652 | flash_data_to_access_addr(faddr), |
628 | cpu_to_le32(*dwptr)); | 653 | OPTROM_BURST_DWORDS); |
629 | if (ret != QLA_SUCCESS) { | 654 | if (ret != QLA_SUCCESS) { |
630 | DEBUG9(printk("%s(%ld) Unable to program flash " | 655 | qla_printk(KERN_WARNING, ha, |
631 | "address=%x data=%x.\n", __func__, | 656 | "Unable to burst-write optrom segment " |
632 | ha->host_no, faddr, *dwptr)); | 657 | "(%x/%x/%llx).\n", ret, |
633 | break; | 658 | flash_data_to_access_addr(faddr), |
659 | optrom_dma); | ||
660 | qla_printk(KERN_WARNING, ha, | ||
661 | "Reverting to slow-write.\n"); | ||
662 | |||
663 | dma_free_coherent(&ha->pdev->dev, | ||
664 | OPTROM_BURST_SIZE, optrom, optrom_dma); | ||
665 | optrom = NULL; | ||
666 | } else { | ||
667 | liter += OPTROM_BURST_DWORDS - 1; | ||
668 | faddr += OPTROM_BURST_DWORDS - 1; | ||
669 | dwptr += OPTROM_BURST_DWORDS - 1; | ||
670 | continue; | ||
634 | } | 671 | } |
672 | } | ||
635 | 673 | ||
636 | /* Do sector protect at 4K boundry for Atmel part. */ | 674 | ret = qla24xx_write_flash_dword(ha, |
637 | if (man_id == 0x1f && | 675 | flash_data_to_access_addr(faddr), cpu_to_le32(*dwptr)); |
638 | ((faddr & sec_end_mask) == 0x3ff)) | 676 | if (ret != QLA_SUCCESS) { |
639 | qla24xx_write_flash_dword(ha, | 677 | DEBUG9(printk("%s(%ld) Unable to program flash " |
640 | flash_conf_to_access_addr(0x0336), | 678 | "address=%x data=%x.\n", __func__, |
641 | (fdata & 0xff00) | ((fdata << 16) & | 679 | ha->host_no, faddr, *dwptr)); |
642 | 0xff0000) | ((fdata >> 16) & 0xff)); | 680 | break; |
643 | } | 681 | } |
644 | } while (0); | 682 | |
683 | /* Do sector protect at 4K boundry for Atmel part. */ | ||
684 | if (man_id == 0x1f && | ||
685 | ((faddr & rest_addr) == rest_addr)) | ||
686 | qla24xx_write_flash_dword(ha, | ||
687 | flash_conf_to_access_addr(0x0336), | ||
688 | (fdata & 0xff00) | ((fdata << 16) & | ||
689 | 0xff0000) | ((fdata >> 16) & 0xff)); | ||
690 | } | ||
645 | 691 | ||
646 | /* Enable flash write-protection. */ | 692 | /* Enable flash write-protection. */ |
647 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c); | 693 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c); |
@@ -651,6 +697,10 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | |||
651 | RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); | 697 | RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); |
652 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ | 698 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ |
653 | 699 | ||
700 | if (optrom) | ||
701 | dma_free_coherent(&ha->pdev->dev, | ||
702 | OPTROM_BURST_SIZE, optrom, optrom_dma); | ||
703 | |||
654 | return ret; | 704 | return ret; |
655 | } | 705 | } |
656 | 706 | ||
@@ -1728,7 +1778,6 @@ qla24xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, | |||
1728 | { | 1778 | { |
1729 | /* Suspend HBA. */ | 1779 | /* Suspend HBA. */ |
1730 | scsi_block_requests(ha->host); | 1780 | scsi_block_requests(ha->host); |
1731 | ha->isp_ops->disable_intrs(ha); | ||
1732 | set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); | 1781 | set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); |
1733 | 1782 | ||
1734 | /* Go with read. */ | 1783 | /* Go with read. */ |
@@ -1736,7 +1785,6 @@ qla24xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, | |||
1736 | 1785 | ||
1737 | /* Resume HBA. */ | 1786 | /* Resume HBA. */ |
1738 | clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); | 1787 | clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); |
1739 | ha->isp_ops->enable_intrs(ha); | ||
1740 | scsi_unblock_requests(ha->host); | 1788 | scsi_unblock_requests(ha->host); |
1741 | 1789 | ||
1742 | return buf; | 1790 | return buf; |
@@ -1750,7 +1798,6 @@ qla24xx_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, | |||
1750 | 1798 | ||
1751 | /* Suspend HBA. */ | 1799 | /* Suspend HBA. */ |
1752 | scsi_block_requests(ha->host); | 1800 | scsi_block_requests(ha->host); |
1753 | ha->isp_ops->disable_intrs(ha); | ||
1754 | set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); | 1801 | set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); |
1755 | 1802 | ||
1756 | /* Go with write. */ | 1803 | /* Go with write. */ |
@@ -1767,6 +1814,70 @@ qla24xx_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, | |||
1767 | return rval; | 1814 | return rval; |
1768 | } | 1815 | } |
1769 | 1816 | ||
1817 | uint8_t * | ||
1818 | qla25xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, | ||
1819 | uint32_t offset, uint32_t length) | ||
1820 | { | ||
1821 | int rval; | ||
1822 | dma_addr_t optrom_dma; | ||
1823 | void *optrom; | ||
1824 | uint8_t *pbuf; | ||
1825 | uint32_t faddr, left, burst; | ||
1826 | |||
1827 | if (offset & ~OPTROM_BURST_SIZE) | ||
1828 | goto slow_read; | ||
1829 | if (length < OPTROM_BURST_SIZE) | ||
1830 | goto slow_read; | ||
1831 | |||
1832 | optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, | ||
1833 | &optrom_dma, GFP_KERNEL); | ||
1834 | if (!optrom) { | ||
1835 | qla_printk(KERN_DEBUG, ha, | ||
1836 | "Unable to allocate memory for optrom burst read " | ||
1837 | "(%x KB).\n", OPTROM_BURST_SIZE / 1024); | ||
1838 | |||
1839 | goto slow_read; | ||
1840 | } | ||
1841 | |||
1842 | pbuf = buf; | ||
1843 | faddr = offset >> 2; | ||
1844 | left = length >> 2; | ||
1845 | burst = OPTROM_BURST_DWORDS; | ||
1846 | while (left != 0) { | ||
1847 | if (burst > left) | ||
1848 | burst = left; | ||
1849 | |||
1850 | rval = qla2x00_dump_ram(ha, optrom_dma, | ||
1851 | flash_data_to_access_addr(faddr), burst); | ||
1852 | if (rval) { | ||
1853 | qla_printk(KERN_WARNING, ha, | ||
1854 | "Unable to burst-read optrom segment " | ||
1855 | "(%x/%x/%llx).\n", rval, | ||
1856 | flash_data_to_access_addr(faddr), optrom_dma); | ||
1857 | qla_printk(KERN_WARNING, ha, | ||
1858 | "Reverting to slow-read.\n"); | ||
1859 | |||
1860 | dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, | ||
1861 | optrom, optrom_dma); | ||
1862 | goto slow_read; | ||
1863 | } | ||
1864 | |||
1865 | memcpy(pbuf, optrom, burst * 4); | ||
1866 | |||
1867 | left -= burst; | ||
1868 | faddr += burst; | ||
1869 | pbuf += burst * 4; | ||
1870 | } | ||
1871 | |||
1872 | dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom, | ||
1873 | optrom_dma); | ||
1874 | |||
1875 | return buf; | ||
1876 | |||
1877 | slow_read: | ||
1878 | return qla24xx_read_optrom_data(ha, buf, offset, length); | ||
1879 | } | ||
1880 | |||
1770 | /** | 1881 | /** |
1771 | * qla2x00_get_fcode_version() - Determine an FCODE image's version. | 1882 | * qla2x00_get_fcode_version() - Determine an FCODE image's version. |
1772 | * @ha: HA context | 1883 | * @ha: HA context |