aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorAndrew Vasquez <andrew.vasquez@qlogic.com>2008-04-03 16:13:22 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-04-07 13:19:14 -0400
commit7d232c745ef2ce141cc9d9538421affa32846fdb (patch)
tree9581133d1a06f45f8305a19a4962386576f79ae5 /drivers/scsi
parentc87a0d8c8de7e191cd59779560d8df2e935c7dc7 (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>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h7
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h32
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c1
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c153
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
1192struct 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 *);
300extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t, 300extern 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
303extern 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
546void
547qla2xxx_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
599no_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
546static void 636static void
547qla24xx_unprotect_flash(scsi_qla_host_t *ha) 637qla24xx_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(&reg->ctrl_status) | CSRX_FLASH_ENABLE); 643 RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE);
554 RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */ 644 RD_REG_DWORD(&reg->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
674skip_wrt_protect:
577 /* Disable flash write. */ 675 /* Disable flash write. */
578 WRT_REG_DWORD(&reg->ctrl_status, 676 WRT_REG_DWORD(&reg->ctrl_status,
579 RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE); 677 RD_REG_DWORD(&reg->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 }