Commit 7d232c74 authored by Andrew Vasquez's avatar Andrew Vasquez Committed by James Bottomley

[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: default avatarAndrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent c87a0d8c
...@@ -2521,6 +2521,13 @@ typedef struct scsi_qla_host { ...@@ -2521,6 +2521,13 @@ typedef struct scsi_qla_host {
uint8_t fcode_revision[16]; uint8_t fcode_revision[16];
uint32_t fw_revision[4]; uint32_t fw_revision[4];
uint16_t fdt_odd_index;
uint32_t fdt_wrt_disable;
uint32_t fdt_erase_cmd;
uint32_t fdt_block_size;
uint32_t fdt_unprotect_sec_cmd;
uint32_t fdt_protect_sec_cmd;
/* Needed for BEACON */ /* Needed for BEACON */
uint16_t beacon_blink_led; uint16_t beacon_blink_led;
uint8_t beacon_color_state; uint8_t beacon_color_state;
......
...@@ -1186,4 +1186,36 @@ struct vf_evfp_entry_24xx { ...@@ -1186,4 +1186,36 @@ struct vf_evfp_entry_24xx {
}; };
/* END MID Support ***********************************************************/ /* END MID Support ***********************************************************/
/* Flash Description Table ***************************************************/
struct qla_fdt_layout {
uint8_t sig[4];
uint16_t version;
uint16_t len;
uint16_t checksum;
uint8_t unused1[2];
uint8_t model[16];
uint16_t man_id;
uint16_t id;
uint8_t flags;
uint8_t erase_cmd;
uint8_t alt_erase_cmd;
uint8_t wrt_enable_cmd;
uint8_t wrt_enable_bits;
uint8_t wrt_sts_reg_cmd;
uint8_t unprotect_sec_cmd;
uint8_t read_man_id_cmd;
uint32_t block_size;
uint32_t alt_block_size;
uint32_t flash_size;
uint32_t wrt_enable_data;
uint8_t read_id_addr_len;
uint8_t wrt_disable_bits;
uint8_t read_dev_id_len;
uint8_t chip_erase_cmd;
uint16_t read_timeout;
uint8_t protect_sec_cmd;
uint8_t unused2[65];
};
#endif #endif
...@@ -300,6 +300,8 @@ extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *); ...@@ -300,6 +300,8 @@ extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *);
extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t, extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t,
uint16_t, uint16_t); uint16_t, uint16_t);
extern void qla2xxx_get_flash_info(scsi_qla_host_t *);
/* /*
* Global Function Prototypes in qla_dbg.c source file. * Global Function Prototypes in qla_dbg.c source file.
*/ */
......
...@@ -106,6 +106,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) ...@@ -106,6 +106,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
rval = qla2x00_setup_chip(ha); rval = qla2x00_setup_chip(ha);
if (rval) if (rval)
return (rval); return (rval);
qla2xxx_get_flash_info(ha);
} }
rval = qla2x00_init_rings(ha); rval = qla2x00_init_rings(ha);
......
...@@ -543,6 +543,96 @@ qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id, ...@@ -543,6 +543,96 @@ qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id,
} }
} }
void
qla2xxx_get_flash_info(scsi_qla_host_t *ha)
{
#define FLASH_BLK_SIZE_32K 0x8000
#define FLASH_BLK_SIZE_64K 0x10000
uint16_t cnt, chksum;
uint16_t *wptr;
struct qla_fdt_layout *fdt;
uint8_t man_id, flash_id;
if (!IS_QLA24XX(ha) && !IS_QLA25XX(ha))
return;
wptr = (uint16_t *)ha->request_ring;
fdt = (struct qla_fdt_layout *)ha->request_ring;
ha->isp_ops->read_optrom(ha, (uint8_t *)ha->request_ring,
FA_FLASH_DESCR_ADDR << 2, OPTROM_BURST_SIZE);
if (*wptr == __constant_cpu_to_le16(0xffff))
goto no_flash_data;
if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' ||
fdt->sig[3] != 'D')
goto no_flash_data;
for (cnt = 0, chksum = 0; cnt < sizeof(struct qla_fdt_layout) >> 1;
cnt++)
chksum += le16_to_cpu(*wptr++);
if (chksum) {
DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent FDT detected: "
"checksum=0x%x id=%c version=0x%x.\n", chksum, fdt->sig[0],
le16_to_cpu(fdt->version)));
DEBUG9(qla2x00_dump_buffer((uint8_t *)fdt, sizeof(*fdt)));
goto no_flash_data;
}
ha->fdt_odd_index = le16_to_cpu(fdt->man_id) == 0x1f;
ha->fdt_wrt_disable = fdt->wrt_disable_bits;
ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0300 | fdt->erase_cmd);
ha->fdt_block_size = le32_to_cpu(fdt->block_size);
if (fdt->unprotect_sec_cmd) {
ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0300 |
fdt->unprotect_sec_cmd);
ha->fdt_protect_sec_cmd = fdt->protect_sec_cmd ?
flash_conf_to_access_addr(0x0300 | fdt->protect_sec_cmd):
flash_conf_to_access_addr(0x0336);
}
DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[FDT]: (0x%x/0x%x) erase=0x%x "
"pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n",
le16_to_cpu(fdt->man_id), le16_to_cpu(fdt->id), ha->fdt_erase_cmd,
ha->fdt_protect_sec_cmd, ha->fdt_unprotect_sec_cmd,
ha->fdt_odd_index, ha->fdt_wrt_disable, ha->fdt_block_size));
return;
no_flash_data:
qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id);
ha->fdt_wrt_disable = 0x9c;
ha->fdt_erase_cmd = flash_conf_to_access_addr(0x03d8);
switch (man_id) {
case 0xbf: /* STT flash. */
if (flash_id == 0x8e)
ha->fdt_block_size = FLASH_BLK_SIZE_64K;
else
ha->fdt_block_size = FLASH_BLK_SIZE_32K;
if (flash_id == 0x80)
ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0352);
break;
case 0x13: /* ST M25P80. */
ha->fdt_block_size = FLASH_BLK_SIZE_64K;
break;
case 0x1f: /* Atmel 26DF081A. */
ha->fdt_odd_index = 1;
ha->fdt_block_size = FLASH_BLK_SIZE_64K;
ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0320);
ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0339);
ha->fdt_protect_sec_cmd = flash_conf_to_access_addr(0x0336);
break;
default:
/* Default to 64 kb sector size. */
ha->fdt_block_size = FLASH_BLK_SIZE_64K;
break;
}
DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[MID]: (0x%x/0x%x) erase=0x%x "
"pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", man_id, flash_id,
ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd,
ha->fdt_unprotect_sec_cmd, ha->fdt_odd_index, ha->fdt_wrt_disable,
ha->fdt_block_size));
}
static void static void
qla24xx_unprotect_flash(scsi_qla_host_t *ha) qla24xx_unprotect_flash(scsi_qla_host_t *ha)
{ {
...@@ -553,6 +643,9 @@ qla24xx_unprotect_flash(scsi_qla_host_t *ha) ...@@ -553,6 +643,9 @@ qla24xx_unprotect_flash(scsi_qla_host_t *ha)
RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE); RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE);
RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */ RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */
if (!ha->fdt_wrt_disable)
return;
/* Disable flash write-protection. */ /* Disable flash write-protection. */
qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0);
/* Some flash parts need an additional zero-write to clear bits.*/ /* Some flash parts need an additional zero-write to clear bits.*/
...@@ -565,8 +658,12 @@ qla24xx_protect_flash(scsi_qla_host_t *ha) ...@@ -565,8 +658,12 @@ qla24xx_protect_flash(scsi_qla_host_t *ha)
uint32_t cnt; uint32_t cnt;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
if (!ha->fdt_wrt_disable)
goto skip_wrt_protect;
/* Enable flash write-protection and wait for completion. */ /* Enable flash write-protection and wait for completion. */
qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c); qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101),
ha->fdt_wrt_disable);
for (cnt = 300; cnt && for (cnt = 300; cnt &&
qla24xx_read_flash_dword(ha, qla24xx_read_flash_dword(ha,
flash_conf_to_access_addr(0x005)) & BIT_0; flash_conf_to_access_addr(0x005)) & BIT_0;
...@@ -574,6 +671,7 @@ qla24xx_protect_flash(scsi_qla_host_t *ha) ...@@ -574,6 +671,7 @@ qla24xx_protect_flash(scsi_qla_host_t *ha)
udelay(10); udelay(10);
} }
skip_wrt_protect:
/* Disable flash write. */ /* Disable flash write. */
WRT_REG_DWORD(&reg->ctrl_status, WRT_REG_DWORD(&reg->ctrl_status,
RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE); 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,9 +684,8 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
{ {
int ret; int ret;
uint32_t liter, miter; uint32_t liter, miter;
uint32_t sec_mask, rest_addr, conf_addr; uint32_t sec_mask, rest_addr;
uint32_t fdata, findex; uint32_t fdata, findex;
uint8_t man_id, flash_id;
dma_addr_t optrom_dma; dma_addr_t optrom_dma;
void *optrom = NULL; void *optrom = NULL;
uint32_t *s, *d; uint32_t *s, *d;
...@@ -607,43 +704,13 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, ...@@ -607,43 +704,13 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
} }
} }
qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); rest_addr = (ha->fdt_block_size >> 2) - 1;
DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__, sec_mask = 0x80000 - (ha->fdt_block_size >> 2);
ha->host_no, man_id, flash_id));
conf_addr = flash_conf_to_access_addr(0x03d8);
switch (man_id) {
case 0xbf: /* STT flash. */
if (flash_id == 0x8e) {
rest_addr = 0x3fff;
sec_mask = 0x7c000;
} else {
rest_addr = 0x1fff;
sec_mask = 0x7e000;
}
if (flash_id == 0x80)
conf_addr = flash_conf_to_access_addr(0x0352);
break;
case 0x13: /* ST M25P80. */
rest_addr = 0x3fff;
sec_mask = 0x7c000;
break;
case 0x1f: // Atmel 26DF081A
rest_addr = 0x3fff;
sec_mask = 0x7c000;
conf_addr = flash_conf_to_access_addr(0x0320);
break;
default:
/* Default to 64 kb sector size. */
rest_addr = 0x3fff;
sec_mask = 0x7c000;
break;
}
qla24xx_unprotect_flash(ha); qla24xx_unprotect_flash(ha);
for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
if (man_id == 0x1f) { if (ha->fdt_odd_index) {
findex = faddr << 2; findex = faddr << 2;
fdata = findex & sec_mask; fdata = findex & sec_mask;
} else { } else {
...@@ -653,13 +720,13 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, ...@@ -653,13 +720,13 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
/* Are we at the beginning of a sector? */ /* Are we at the beginning of a sector? */
if ((findex & rest_addr) == 0) { if ((findex & rest_addr) == 0) {
/* Do sector unprotect at 4K boundry for Atmel part. */ /* Do sector unprotect. */
if (man_id == 0x1f) if (ha->fdt_unprotect_sec_cmd)
qla24xx_write_flash_dword(ha, qla24xx_write_flash_dword(ha,
flash_conf_to_access_addr(0x0339), ha->fdt_unprotect_sec_cmd,
(fdata & 0xff00) | ((fdata << 16) & (fdata & 0xff00) | ((fdata << 16) &
0xff0000) | ((fdata >> 16) & 0xff)); 0xff0000) | ((fdata >> 16) & 0xff));
ret = qla24xx_write_flash_dword(ha, conf_addr, ret = qla24xx_write_flash_dword(ha, ha->fdt_erase_cmd,
(fdata & 0xff00) |((fdata << 16) & (fdata & 0xff00) |((fdata << 16) &
0xff0000) | ((fdata >> 16) & 0xff)); 0xff0000) | ((fdata >> 16) & 0xff));
if (ret != QLA_SUCCESS) { if (ret != QLA_SUCCESS) {
...@@ -709,11 +776,11 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, ...@@ -709,11 +776,11 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
break; break;
} }
/* Do sector protect at 4K boundry for Atmel part. */ /* Do sector protect. */
if (man_id == 0x1f && if (ha->fdt_unprotect_sec_cmd &&
((faddr & rest_addr) == rest_addr)) ((faddr & rest_addr) == rest_addr))
qla24xx_write_flash_dword(ha, qla24xx_write_flash_dword(ha,
flash_conf_to_access_addr(0x0336), ha->fdt_protect_sec_cmd,
(fdata & 0xff00) | ((fdata << 16) & (fdata & 0xff00) | ((fdata << 16) &
0xff0000) | ((fdata >> 16) & 0xff)); 0xff0000) | ((fdata >> 16) & 0xff));
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment