diff options
author | Andrew Vasquez <andrew.vasquez@qlogic.com> | 2008-04-03 16:13:22 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-04-07 13:19:14 -0400 |
commit | 7d232c745ef2ce141cc9d9538421affa32846fdb (patch) | |
tree | 9581133d1a06f45f8305a19a4962386576f79ae5 | |
parent | c87a0d8c8de7e191cd59779560d8df2e935c7dc7 (diff) |
[SCSI] qla2xxx: Add Flash Descriptor Table layout support.
The Flash Descriptor Table (FDT) present on many recent HBAs
encodes flash accessing characteristics of the flash-part used on
the HBA. Use this information during flash manipulation (writes)
rather than using specific hard-coded values based on queried
manufacturer and device IDs.
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 7 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_fw.h | 32 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 1 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_sup.c | 153 |
5 files changed, 152 insertions, 43 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 047973f37847..7e6b6da6a67d 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
@@ -2521,6 +2521,13 @@ typedef struct scsi_qla_host { | |||
2521 | uint8_t fcode_revision[16]; | 2521 | uint8_t fcode_revision[16]; |
2522 | uint32_t fw_revision[4]; | 2522 | uint32_t fw_revision[4]; |
2523 | 2523 | ||
2524 | uint16_t fdt_odd_index; | ||
2525 | uint32_t fdt_wrt_disable; | ||
2526 | uint32_t fdt_erase_cmd; | ||
2527 | uint32_t fdt_block_size; | ||
2528 | uint32_t fdt_unprotect_sec_cmd; | ||
2529 | uint32_t fdt_protect_sec_cmd; | ||
2530 | |||
2524 | /* Needed for BEACON */ | 2531 | /* Needed for BEACON */ |
2525 | uint16_t beacon_blink_led; | 2532 | uint16_t beacon_blink_led; |
2526 | uint8_t beacon_color_state; | 2533 | uint8_t beacon_color_state; |
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 5d19b0e49a62..38adc0f06e93 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h | |||
@@ -1186,4 +1186,36 @@ struct vf_evfp_entry_24xx { | |||
1186 | }; | 1186 | }; |
1187 | 1187 | ||
1188 | /* END MID Support ***********************************************************/ | 1188 | /* END MID Support ***********************************************************/ |
1189 | |||
1190 | /* Flash Description Table ***************************************************/ | ||
1191 | |||
1192 | struct qla_fdt_layout { | ||
1193 | uint8_t sig[4]; | ||
1194 | uint16_t version; | ||
1195 | uint16_t len; | ||
1196 | uint16_t checksum; | ||
1197 | uint8_t unused1[2]; | ||
1198 | uint8_t model[16]; | ||
1199 | uint16_t man_id; | ||
1200 | uint16_t id; | ||
1201 | uint8_t flags; | ||
1202 | uint8_t erase_cmd; | ||
1203 | uint8_t alt_erase_cmd; | ||
1204 | uint8_t wrt_enable_cmd; | ||
1205 | uint8_t wrt_enable_bits; | ||
1206 | uint8_t wrt_sts_reg_cmd; | ||
1207 | uint8_t unprotect_sec_cmd; | ||
1208 | uint8_t read_man_id_cmd; | ||
1209 | uint32_t block_size; | ||
1210 | uint32_t alt_block_size; | ||
1211 | uint32_t flash_size; | ||
1212 | uint32_t wrt_enable_data; | ||
1213 | uint8_t read_id_addr_len; | ||
1214 | uint8_t wrt_disable_bits; | ||
1215 | uint8_t read_dev_id_len; | ||
1216 | uint8_t chip_erase_cmd; | ||
1217 | uint16_t read_timeout; | ||
1218 | uint8_t protect_sec_cmd; | ||
1219 | uint8_t unused2[65]; | ||
1220 | }; | ||
1189 | #endif | 1221 | #endif |
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 10c3f905b711..f25aa63ad191 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h | |||
@@ -300,6 +300,8 @@ extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *); | |||
300 | extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t, | 300 | extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t, |
301 | uint16_t, uint16_t); | 301 | uint16_t, uint16_t); |
302 | 302 | ||
303 | extern void qla2xxx_get_flash_info(scsi_qla_host_t *); | ||
304 | |||
303 | /* | 305 | /* |
304 | * Global Function Prototypes in qla_dbg.c source file. | 306 | * Global Function Prototypes in qla_dbg.c source file. |
305 | */ | 307 | */ |
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index d429e2f5c70e..10e6995b39a7 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c | |||
@@ -106,6 +106,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) | |||
106 | rval = qla2x00_setup_chip(ha); | 106 | rval = qla2x00_setup_chip(ha); |
107 | if (rval) | 107 | if (rval) |
108 | return (rval); | 108 | return (rval); |
109 | qla2xxx_get_flash_info(ha); | ||
109 | } | 110 | } |
110 | rval = qla2x00_init_rings(ha); | 111 | rval = qla2x00_init_rings(ha); |
111 | 112 | ||
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index c10ccc75c398..eda11f6f5e52 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c | |||
@@ -543,6 +543,96 @@ qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id, | |||
543 | } | 543 | } |
544 | } | 544 | } |
545 | 545 | ||
546 | void | ||
547 | qla2xxx_get_flash_info(scsi_qla_host_t *ha) | ||
548 | { | ||
549 | #define FLASH_BLK_SIZE_32K 0x8000 | ||
550 | #define FLASH_BLK_SIZE_64K 0x10000 | ||
551 | uint16_t cnt, chksum; | ||
552 | uint16_t *wptr; | ||
553 | struct qla_fdt_layout *fdt; | ||
554 | uint8_t man_id, flash_id; | ||
555 | |||
556 | if (!IS_QLA24XX(ha) && !IS_QLA25XX(ha)) | ||
557 | return; | ||
558 | |||
559 | wptr = (uint16_t *)ha->request_ring; | ||
560 | fdt = (struct qla_fdt_layout *)ha->request_ring; | ||
561 | ha->isp_ops->read_optrom(ha, (uint8_t *)ha->request_ring, | ||
562 | FA_FLASH_DESCR_ADDR << 2, OPTROM_BURST_SIZE); | ||
563 | if (*wptr == __constant_cpu_to_le16(0xffff)) | ||
564 | goto no_flash_data; | ||
565 | if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' || | ||
566 | fdt->sig[3] != 'D') | ||
567 | goto no_flash_data; | ||
568 | |||
569 | for (cnt = 0, chksum = 0; cnt < sizeof(struct qla_fdt_layout) >> 1; | ||
570 | cnt++) | ||
571 | chksum += le16_to_cpu(*wptr++); | ||
572 | if (chksum) { | ||
573 | DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent FDT detected: " | ||
574 | "checksum=0x%x id=%c version=0x%x.\n", chksum, fdt->sig[0], | ||
575 | le16_to_cpu(fdt->version))); | ||
576 | DEBUG9(qla2x00_dump_buffer((uint8_t *)fdt, sizeof(*fdt))); | ||
577 | goto no_flash_data; | ||
578 | } | ||
579 | |||
580 | ha->fdt_odd_index = le16_to_cpu(fdt->man_id) == 0x1f; | ||
581 | ha->fdt_wrt_disable = fdt->wrt_disable_bits; | ||
582 | ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0300 | fdt->erase_cmd); | ||
583 | ha->fdt_block_size = le32_to_cpu(fdt->block_size); | ||
584 | if (fdt->unprotect_sec_cmd) { | ||
585 | ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0300 | | ||
586 | fdt->unprotect_sec_cmd); | ||
587 | ha->fdt_protect_sec_cmd = fdt->protect_sec_cmd ? | ||
588 | flash_conf_to_access_addr(0x0300 | fdt->protect_sec_cmd): | ||
589 | flash_conf_to_access_addr(0x0336); | ||
590 | } | ||
591 | |||
592 | DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[FDT]: (0x%x/0x%x) erase=0x%x " | ||
593 | "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", | ||
594 | le16_to_cpu(fdt->man_id), le16_to_cpu(fdt->id), ha->fdt_erase_cmd, | ||
595 | ha->fdt_protect_sec_cmd, ha->fdt_unprotect_sec_cmd, | ||
596 | ha->fdt_odd_index, ha->fdt_wrt_disable, ha->fdt_block_size)); | ||
597 | return; | ||
598 | |||
599 | no_flash_data: | ||
600 | qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); | ||
601 | ha->fdt_wrt_disable = 0x9c; | ||
602 | ha->fdt_erase_cmd = flash_conf_to_access_addr(0x03d8); | ||
603 | switch (man_id) { | ||
604 | case 0xbf: /* STT flash. */ | ||
605 | if (flash_id == 0x8e) | ||
606 | ha->fdt_block_size = FLASH_BLK_SIZE_64K; | ||
607 | else | ||
608 | ha->fdt_block_size = FLASH_BLK_SIZE_32K; | ||
609 | |||
610 | if (flash_id == 0x80) | ||
611 | ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0352); | ||
612 | break; | ||
613 | case 0x13: /* ST M25P80. */ | ||
614 | ha->fdt_block_size = FLASH_BLK_SIZE_64K; | ||
615 | break; | ||
616 | case 0x1f: /* Atmel 26DF081A. */ | ||
617 | ha->fdt_odd_index = 1; | ||
618 | ha->fdt_block_size = FLASH_BLK_SIZE_64K; | ||
619 | ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0320); | ||
620 | ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0339); | ||
621 | ha->fdt_protect_sec_cmd = flash_conf_to_access_addr(0x0336); | ||
622 | break; | ||
623 | default: | ||
624 | /* Default to 64 kb sector size. */ | ||
625 | ha->fdt_block_size = FLASH_BLK_SIZE_64K; | ||
626 | break; | ||
627 | } | ||
628 | |||
629 | DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[MID]: (0x%x/0x%x) erase=0x%x " | ||
630 | "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", man_id, flash_id, | ||
631 | ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd, | ||
632 | ha->fdt_unprotect_sec_cmd, ha->fdt_odd_index, ha->fdt_wrt_disable, | ||
633 | ha->fdt_block_size)); | ||
634 | } | ||
635 | |||
546 | static void | 636 | static void |
547 | qla24xx_unprotect_flash(scsi_qla_host_t *ha) | 637 | qla24xx_unprotect_flash(scsi_qla_host_t *ha) |
548 | { | 638 | { |
@@ -553,6 +643,9 @@ qla24xx_unprotect_flash(scsi_qla_host_t *ha) | |||
553 | RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); | 643 | RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); |
554 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ | 644 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ |
555 | 645 | ||
646 | if (!ha->fdt_wrt_disable) | ||
647 | return; | ||
648 | |||
556 | /* Disable flash write-protection. */ | 649 | /* Disable flash write-protection. */ |
557 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); | 650 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); |
558 | /* Some flash parts need an additional zero-write to clear bits.*/ | 651 | /* Some flash parts need an additional zero-write to clear bits.*/ |
@@ -565,8 +658,12 @@ qla24xx_protect_flash(scsi_qla_host_t *ha) | |||
565 | uint32_t cnt; | 658 | uint32_t cnt; |
566 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | 659 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; |
567 | 660 | ||
661 | if (!ha->fdt_wrt_disable) | ||
662 | goto skip_wrt_protect; | ||
663 | |||
568 | /* Enable flash write-protection and wait for completion. */ | 664 | /* Enable flash write-protection and wait for completion. */ |
569 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c); | 665 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), |
666 | ha->fdt_wrt_disable); | ||
570 | for (cnt = 300; cnt && | 667 | for (cnt = 300; cnt && |
571 | qla24xx_read_flash_dword(ha, | 668 | qla24xx_read_flash_dword(ha, |
572 | flash_conf_to_access_addr(0x005)) & BIT_0; | 669 | flash_conf_to_access_addr(0x005)) & BIT_0; |
@@ -574,6 +671,7 @@ qla24xx_protect_flash(scsi_qla_host_t *ha) | |||
574 | udelay(10); | 671 | udelay(10); |
575 | } | 672 | } |
576 | 673 | ||
674 | skip_wrt_protect: | ||
577 | /* Disable flash write. */ | 675 | /* Disable flash write. */ |
578 | WRT_REG_DWORD(®->ctrl_status, | 676 | WRT_REG_DWORD(®->ctrl_status, |
579 | RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); | 677 | RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); |
@@ -586,9 +684,8 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | |||
586 | { | 684 | { |
587 | int ret; | 685 | int ret; |
588 | uint32_t liter, miter; | 686 | uint32_t liter, miter; |
589 | uint32_t sec_mask, rest_addr, conf_addr; | 687 | uint32_t sec_mask, rest_addr; |
590 | uint32_t fdata, findex; | 688 | uint32_t fdata, findex; |
591 | uint8_t man_id, flash_id; | ||
592 | dma_addr_t optrom_dma; | 689 | dma_addr_t optrom_dma; |
593 | void *optrom = NULL; | 690 | void *optrom = NULL; |
594 | uint32_t *s, *d; | 691 | uint32_t *s, *d; |
@@ -607,43 +704,13 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | |||
607 | } | 704 | } |
608 | } | 705 | } |
609 | 706 | ||
610 | qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); | 707 | rest_addr = (ha->fdt_block_size >> 2) - 1; |
611 | DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__, | 708 | sec_mask = 0x80000 - (ha->fdt_block_size >> 2); |
612 | ha->host_no, man_id, flash_id)); | ||
613 | |||
614 | conf_addr = flash_conf_to_access_addr(0x03d8); | ||
615 | switch (man_id) { | ||
616 | case 0xbf: /* STT flash. */ | ||
617 | if (flash_id == 0x8e) { | ||
618 | rest_addr = 0x3fff; | ||
619 | sec_mask = 0x7c000; | ||
620 | } else { | ||
621 | rest_addr = 0x1fff; | ||
622 | sec_mask = 0x7e000; | ||
623 | } | ||
624 | if (flash_id == 0x80) | ||
625 | conf_addr = flash_conf_to_access_addr(0x0352); | ||
626 | break; | ||
627 | case 0x13: /* ST M25P80. */ | ||
628 | rest_addr = 0x3fff; | ||
629 | sec_mask = 0x7c000; | ||
630 | break; | ||
631 | case 0x1f: // Atmel 26DF081A | ||
632 | rest_addr = 0x3fff; | ||
633 | sec_mask = 0x7c000; | ||
634 | conf_addr = flash_conf_to_access_addr(0x0320); | ||
635 | break; | ||
636 | default: | ||
637 | /* Default to 64 kb sector size. */ | ||
638 | rest_addr = 0x3fff; | ||
639 | sec_mask = 0x7c000; | ||
640 | break; | ||
641 | } | ||
642 | 709 | ||
643 | qla24xx_unprotect_flash(ha); | 710 | qla24xx_unprotect_flash(ha); |
644 | 711 | ||
645 | for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { | 712 | for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { |
646 | if (man_id == 0x1f) { | 713 | if (ha->fdt_odd_index) { |
647 | findex = faddr << 2; | 714 | findex = faddr << 2; |
648 | fdata = findex & sec_mask; | 715 | fdata = findex & sec_mask; |
649 | } else { | 716 | } else { |
@@ -653,13 +720,13 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | |||
653 | 720 | ||
654 | /* Are we at the beginning of a sector? */ | 721 | /* Are we at the beginning of a sector? */ |
655 | if ((findex & rest_addr) == 0) { | 722 | if ((findex & rest_addr) == 0) { |
656 | /* Do sector unprotect at 4K boundry for Atmel part. */ | 723 | /* Do sector unprotect. */ |
657 | if (man_id == 0x1f) | 724 | if (ha->fdt_unprotect_sec_cmd) |
658 | qla24xx_write_flash_dword(ha, | 725 | qla24xx_write_flash_dword(ha, |
659 | flash_conf_to_access_addr(0x0339), | 726 | ha->fdt_unprotect_sec_cmd, |
660 | (fdata & 0xff00) | ((fdata << 16) & | 727 | (fdata & 0xff00) | ((fdata << 16) & |
661 | 0xff0000) | ((fdata >> 16) & 0xff)); | 728 | 0xff0000) | ((fdata >> 16) & 0xff)); |
662 | ret = qla24xx_write_flash_dword(ha, conf_addr, | 729 | ret = qla24xx_write_flash_dword(ha, ha->fdt_erase_cmd, |
663 | (fdata & 0xff00) |((fdata << 16) & | 730 | (fdata & 0xff00) |((fdata << 16) & |
664 | 0xff0000) | ((fdata >> 16) & 0xff)); | 731 | 0xff0000) | ((fdata >> 16) & 0xff)); |
665 | if (ret != QLA_SUCCESS) { | 732 | if (ret != QLA_SUCCESS) { |
@@ -709,11 +776,11 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | |||
709 | break; | 776 | break; |
710 | } | 777 | } |
711 | 778 | ||
712 | /* Do sector protect at 4K boundry for Atmel part. */ | 779 | /* Do sector protect. */ |
713 | if (man_id == 0x1f && | 780 | if (ha->fdt_unprotect_sec_cmd && |
714 | ((faddr & rest_addr) == rest_addr)) | 781 | ((faddr & rest_addr) == rest_addr)) |
715 | qla24xx_write_flash_dword(ha, | 782 | qla24xx_write_flash_dword(ha, |
716 | flash_conf_to_access_addr(0x0336), | 783 | ha->fdt_protect_sec_cmd, |
717 | (fdata & 0xff00) | ((fdata << 16) & | 784 | (fdata & 0xff00) | ((fdata << 16) & |
718 | 0xff0000) | ((fdata >> 16) & 0xff)); | 785 | 0xff0000) | ((fdata >> 16) & 0xff)); |
719 | } | 786 | } |