"ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",
                    mb[1], mb[2], mb[3]);
 
+               qla2x00_post_hwe_work(ha, mb[0], mb[1], mb[2], mb[3]);
                ha->isp_ops->fw_dump(ha, 1);
 
                if (IS_FWI2_CAPABLE(ha)) {
                    ha->host_no));
                qla_printk(KERN_WARNING, ha, "ISP Request Transfer Error.\n");
 
+               qla2x00_post_hwe_work(ha, mb[0], mb[1], mb[2], mb[3]);
                set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
                break;
 
                    ha->host_no));
                qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n");
 
+               qla2x00_post_hwe_work(ha, mb[0], mb[1], mb[2], mb[3]);
                set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
                break;
 
                        if (pci_channel_offline(ha->pdev))
                                break;
 
+                       if (ha->hw_event_pause_errors == 0)
+                               qla2x00_post_hwe_work(ha, HW_EVENT_PARITY_ERR,
+                                   0, MSW(stat), LSW(stat));
+                       else if (ha->hw_event_pause_errors < 0xffffffff)
+                               ha->hw_event_pause_errors++;
+
                        hccr = RD_REG_DWORD(®->hccr);
 
                        qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
                        if (pci_channel_offline(ha->pdev))
                                break;
 
+                       if (ha->hw_event_pause_errors == 0)
+                               qla2x00_post_hwe_work(ha, HW_EVENT_PARITY_ERR,
+                                   0, MSW(stat), LSW(stat));
+                       else if (ha->hw_event_pause_errors < 0xffffffff)
+                               ha->hw_event_pause_errors++;
+
                        hccr = RD_REG_DWORD(®->hccr);
 
                        qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
 
        }
 }
 
+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)
        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;
                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) {
                            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,
 
        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;
+}