|
@@ -543,6 +543,43 @@ qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void
|
|
|
+qla24xx_unprotect_flash(scsi_qla_host_t *ha)
|
|
|
+{
|
|
|
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
|
|
+
|
|
|
+ /* Enable flash write. */
|
|
|
+ WRT_REG_DWORD(®->ctrl_status,
|
|
|
+ RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE);
|
|
|
+ RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */
|
|
|
+
|
|
|
+ /* Disable flash write-protection. */
|
|
|
+ qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0);
|
|
|
+ /* Some flash parts need an additional zero-write to clear bits.*/
|
|
|
+ qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+qla24xx_protect_flash(scsi_qla_host_t *ha)
|
|
|
+{
|
|
|
+ uint32_t cnt;
|
|
|
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
|
|
+
|
|
|
+ /* Enable flash write-protection and wait for completion. */
|
|
|
+ qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c);
|
|
|
+ for (cnt = 300; cnt &&
|
|
|
+ qla24xx_read_flash_dword(ha,
|
|
|
+ flash_conf_to_access_addr(0x005)) & BIT_0;
|
|
|
+ cnt--) {
|
|
|
+ udelay(10);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Disable flash write. */
|
|
|
+ WRT_REG_DWORD(®->ctrl_status,
|
|
|
+ RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE);
|
|
|
+ RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */
|
|
|
+}
|
|
|
+
|
|
|
static int
|
|
|
qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
|
|
|
uint32_t dwords)
|
|
@@ -550,9 +587,8 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
|
|
|
int ret;
|
|
|
uint32_t liter, miter;
|
|
|
uint32_t sec_mask, rest_addr, conf_addr;
|
|
|
- uint32_t fdata, findex, cnt;
|
|
|
+ uint32_t fdata, findex;
|
|
|
uint8_t man_id, flash_id;
|
|
|
- struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
|
|
dma_addr_t optrom_dma;
|
|
|
void *optrom = NULL;
|
|
|
uint32_t *s, *d;
|
|
@@ -604,15 +640,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- /* Enable flash write. */
|
|
|
- WRT_REG_DWORD(®->ctrl_status,
|
|
|
- RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE);
|
|
|
- RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */
|
|
|
-
|
|
|
- /* Disable flash write-protection. */
|
|
|
- qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0);
|
|
|
- /* Some flash parts need an additional zero-write to clear bits.*/
|
|
|
- qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0);
|
|
|
+ qla24xx_unprotect_flash(ha);
|
|
|
|
|
|
for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
|
|
|
if (man_id == 0x1f) {
|
|
@@ -690,19 +718,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
|
|
|
0xff0000) | ((fdata >> 16) & 0xff));
|
|
|
}
|
|
|
|
|
|
- /* Enable flash write-protection and wait for completion. */
|
|
|
- qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c);
|
|
|
- for (cnt = 300; cnt &&
|
|
|
- qla24xx_read_flash_dword(ha,
|
|
|
- flash_conf_to_access_addr(0x005)) & BIT_0;
|
|
|
- cnt--) {
|
|
|
- udelay(10);
|
|
|
- }
|
|
|
-
|
|
|
- /* Disable flash write. */
|
|
|
- WRT_REG_DWORD(®->ctrl_status,
|
|
|
- RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE);
|
|
|
- RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */
|
|
|
+ qla24xx_protect_flash(ha);
|
|
|
|
|
|
if (optrom)
|
|
|
dma_free_coherent(&ha->pdev->dev,
|
|
@@ -2221,3 +2237,107 @@ qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
+
|
|
|
+static int
|
|
|
+qla2xxx_hw_event_store(scsi_qla_host_t *ha, uint32_t *fdata)
|
|
|
+{
|
|
|
+ uint32_t d[2], faddr;
|
|
|
+
|
|
|
+ /* Locate first empty entry. */
|
|
|
+ for (;;) {
|
|
|
+ if (ha->hw_event_ptr >=
|
|
|
+ ha->hw_event_start + FA_HW_EVENT_SIZE) {
|
|
|
+ DEBUG2(qla_printk(KERN_WARNING, ha,
|
|
|
+ "HW event -- Log Full!\n"));
|
|
|
+ return QLA_MEMORY_ALLOC_FAILED;
|
|
|
+ }
|
|
|
+
|
|
|
+ qla24xx_read_flash_data(ha, d, ha->hw_event_ptr, 2);
|
|
|
+ faddr = flash_data_to_access_addr(ha->hw_event_ptr);
|
|
|
+ ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE;
|
|
|
+ if (d[0] == __constant_cpu_to_le32(0xffffffff) &&
|
|
|
+ d[1] == __constant_cpu_to_le32(0xffffffff)) {
|
|
|
+ qla24xx_unprotect_flash(ha);
|
|
|
+
|
|
|
+ qla24xx_write_flash_dword(ha, faddr++,
|
|
|
+ cpu_to_le32(jiffies));
|
|
|
+ qla24xx_write_flash_dword(ha, faddr++, 0);
|
|
|
+ qla24xx_write_flash_dword(ha, faddr++, *fdata++);
|
|
|
+ qla24xx_write_flash_dword(ha, faddr++, *fdata);
|
|
|
+
|
|
|
+ qla24xx_protect_flash(ha);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return QLA_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+int
|
|
|
+qla2xxx_hw_event_log(scsi_qla_host_t *ha, uint16_t code, uint16_t d1,
|
|
|
+ uint16_t d2, uint16_t d3)
|
|
|
+{
|
|
|
+#define QMARK(a, b, c, d) \
|
|
|
+ cpu_to_le32(LSB(a) << 24 | LSB(b) << 16 | LSB(c) << 8 | LSB(d))
|
|
|
+
|
|
|
+ int rval;
|
|
|
+ uint32_t marker[2], fdata[4];
|
|
|
+
|
|
|
+ if (ha->hw_event_start == 0)
|
|
|
+ return QLA_FUNCTION_FAILED;
|
|
|
+
|
|
|
+ DEBUG2(qla_printk(KERN_WARNING, ha,
|
|
|
+ "HW event -- code=%x, d1=%x, d2=%x, d3=%x.\n", code, d1, d2, d3));
|
|
|
+
|
|
|
+ /* If marker not already found, locate or write. */
|
|
|
+ if (!ha->flags.hw_event_marker_found) {
|
|
|
+ /* Create marker. */
|
|
|
+ marker[0] = QMARK('L', ha->fw_major_version,
|
|
|
+ ha->fw_minor_version, ha->fw_subminor_version);
|
|
|
+ marker[1] = QMARK(QLA_DRIVER_MAJOR_VER, QLA_DRIVER_MINOR_VER,
|
|
|
+ QLA_DRIVER_PATCH_VER, QLA_DRIVER_BETA_VER);
|
|
|
+
|
|
|
+ /* Locate marker. */
|
|
|
+ ha->hw_event_ptr = ha->hw_event_start;
|
|
|
+ for (;;) {
|
|
|
+ qla24xx_read_flash_data(ha, fdata, ha->hw_event_ptr,
|
|
|
+ 4);
|
|
|
+ if (fdata[0] == __constant_cpu_to_le32(0xffffffff) &&
|
|
|
+ fdata[1] == __constant_cpu_to_le32(0xffffffff))
|
|
|
+ break;
|
|
|
+ ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE;
|
|
|
+ if (ha->hw_event_ptr >=
|
|
|
+ ha->hw_event_start + FA_HW_EVENT_SIZE) {
|
|
|
+ DEBUG2(qla_printk(KERN_WARNING, ha,
|
|
|
+ "HW event -- Log Full!\n"));
|
|
|
+ return QLA_MEMORY_ALLOC_FAILED;
|
|
|
+ }
|
|
|
+ if (fdata[2] == marker[0] && fdata[3] == marker[1]) {
|
|
|
+ ha->flags.hw_event_marker_found = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* No marker, write it. */
|
|
|
+ if (!ha->flags.hw_event_marker_found) {
|
|
|
+ rval = qla2xxx_hw_event_store(ha, marker);
|
|
|
+ if (rval != QLA_SUCCESS) {
|
|
|
+ DEBUG2(qla_printk(KERN_WARNING, ha,
|
|
|
+ "HW event -- Failed marker write=%x.!\n",
|
|
|
+ rval));
|
|
|
+ return rval;
|
|
|
+ }
|
|
|
+ ha->flags.hw_event_marker_found = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Store error. */
|
|
|
+ fdata[0] = cpu_to_le32(code << 16 | d1);
|
|
|
+ fdata[1] = cpu_to_le32(d2 << 16 | d3);
|
|
|
+ rval = qla2xxx_hw_event_store(ha, fdata);
|
|
|
+ if (rval != QLA_SUCCESS) {
|
|
|
+ DEBUG2(qla_printk(KERN_WARNING, ha,
|
|
|
+ "HW event -- Failed error write=%x.!\n",
|
|
|
+ rval));
|
|
|
+ }
|
|
|
+
|
|
|
+ return rval;
|
|
|
+}
|