diff options
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 10 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_fw.h | 14 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 5 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 11 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 15 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 8 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 23 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_sup.c | 168 |
8 files changed, 229 insertions, 25 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 35c730a3f0da..13ffedaf8cba 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
| @@ -2118,6 +2118,7 @@ struct qla_msix_entry { | |||
| 2118 | /* Work events. */ | 2118 | /* Work events. */ |
| 2119 | enum qla_work_type { | 2119 | enum qla_work_type { |
| 2120 | QLA_EVT_AEN, | 2120 | QLA_EVT_AEN, |
| 2121 | QLA_EVT_HWE_LOG, | ||
| 2121 | }; | 2122 | }; |
| 2122 | 2123 | ||
| 2123 | 2124 | ||
| @@ -2132,6 +2133,10 @@ struct qla_work_evt { | |||
| 2132 | enum fc_host_event_code code; | 2133 | enum fc_host_event_code code; |
| 2133 | u32 data; | 2134 | u32 data; |
| 2134 | } aen; | 2135 | } aen; |
| 2136 | struct { | ||
| 2137 | uint16_t code; | ||
| 2138 | uint16_t d1, d2, d3; | ||
| 2139 | } hwe; | ||
| 2135 | } u; | 2140 | } u; |
| 2136 | }; | 2141 | }; |
| 2137 | 2142 | ||
| @@ -2173,6 +2178,7 @@ typedef struct scsi_qla_host { | |||
| 2173 | uint32_t vsan_enabled :1; | 2178 | uint32_t vsan_enabled :1; |
| 2174 | uint32_t npiv_supported :1; | 2179 | uint32_t npiv_supported :1; |
| 2175 | uint32_t fce_enabled :1; | 2180 | uint32_t fce_enabled :1; |
| 2181 | uint32_t hw_event_marker_found :1; | ||
| 2176 | } flags; | 2182 | } flags; |
| 2177 | 2183 | ||
| 2178 | atomic_t loop_state; | 2184 | atomic_t loop_state; |
| @@ -2478,6 +2484,10 @@ typedef struct scsi_qla_host { | |||
| 2478 | uint64_t fce_wr, fce_rd; | 2484 | uint64_t fce_wr, fce_rd; |
| 2479 | struct mutex fce_mutex; | 2485 | struct mutex fce_mutex; |
| 2480 | 2486 | ||
| 2487 | uint32_t hw_event_start; | ||
| 2488 | uint32_t hw_event_ptr; | ||
| 2489 | uint32_t hw_event_pause_errors; | ||
| 2490 | |||
| 2481 | uint8_t host_str[16]; | 2491 | uint8_t host_str[16]; |
| 2482 | uint32_t pci_attr; | 2492 | uint32_t pci_attr; |
| 2483 | uint16_t chip_revision; | 2493 | uint16_t chip_revision; |
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 4ae26533fe12..5d19b0e49a62 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h | |||
| @@ -793,7 +793,19 @@ struct device_reg_24xx { | |||
| 793 | #define FA_VPD_NVRAM_ADDR 0x48000 | 793 | #define FA_VPD_NVRAM_ADDR 0x48000 |
| 794 | #define FA_FEATURE_ADDR 0x4C000 | 794 | #define FA_FEATURE_ADDR 0x4C000 |
| 795 | #define FA_FLASH_DESCR_ADDR 0x50000 | 795 | #define FA_FLASH_DESCR_ADDR 0x50000 |
| 796 | #define FA_HW_EVENT_ADDR 0x54000 | 796 | #define FA_HW_EVENT0_ADDR 0x54000 |
| 797 | #define FA_HW_EVENT1_ADDR 0x54200 | ||
| 798 | #define FA_HW_EVENT_SIZE 0x200 | ||
| 799 | #define FA_HW_EVENT_ENTRY_SIZE 4 | ||
| 800 | /* | ||
| 801 | * Flash Error Log Event Codes. | ||
| 802 | */ | ||
| 803 | #define HW_EVENT_RESET_ERR 0xF00B | ||
| 804 | #define HW_EVENT_ISP_ERR 0xF020 | ||
| 805 | #define HW_EVENT_PARITY_ERR 0xF022 | ||
| 806 | #define HW_EVENT_NVRAM_CHKSUM_ERR 0xF023 | ||
| 807 | #define HW_EVENT_FLASH_FW_ERR 0xF024 | ||
| 808 | |||
| 797 | #define FA_BOOT_LOG_ADDR 0x58000 | 809 | #define FA_BOOT_LOG_ADDR 0x58000 |
| 798 | #define FA_FW_DUMP0_ADDR 0x60000 | 810 | #define FA_FW_DUMP0_ADDR 0x60000 |
| 799 | #define FA_FW_DUMP1_ADDR 0x70000 | 811 | #define FA_FW_DUMP1_ADDR 0x70000 |
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index ee52f3e51cc6..276bd26c0c8e 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h | |||
| @@ -69,6 +69,8 @@ extern int qla2x00_loop_reset(scsi_qla_host_t *); | |||
| 69 | extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); | 69 | extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); |
| 70 | extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum | 70 | extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum |
| 71 | fc_host_event_code, u32); | 71 | fc_host_event_code, u32); |
| 72 | extern int qla2x00_post_hwe_work(struct scsi_qla_host *, uint16_t , uint16_t, | ||
| 73 | uint16_t, uint16_t); | ||
| 72 | 74 | ||
| 73 | /* | 75 | /* |
| 74 | * Global Functions in qla_mid.c source file. | 76 | * Global Functions in qla_mid.c source file. |
| @@ -298,6 +300,9 @@ extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *, | |||
| 298 | extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *); | 300 | extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *); |
| 299 | extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *); | 301 | extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *); |
| 300 | 302 | ||
| 303 | extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t, | ||
| 304 | uint16_t, uint16_t); | ||
| 305 | |||
| 301 | /* | 306 | /* |
| 302 | * Global Function Prototypes in qla_dbg.c source file. | 307 | * Global Function Prototypes in qla_dbg.c source file. |
| 303 | */ | 308 | */ |
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index e773697cd8d5..e9a7c2d13855 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c | |||
| @@ -500,6 +500,7 @@ qla2x00_reset_chip(scsi_qla_host_t *ha) | |||
| 500 | static inline void | 500 | static inline void |
| 501 | qla24xx_reset_risc(scsi_qla_host_t *ha) | 501 | qla24xx_reset_risc(scsi_qla_host_t *ha) |
| 502 | { | 502 | { |
| 503 | int hw_evt = 0; | ||
| 503 | unsigned long flags = 0; | 504 | unsigned long flags = 0; |
| 504 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | 505 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; |
| 505 | uint32_t cnt, d2; | 506 | uint32_t cnt, d2; |
| @@ -528,6 +529,8 @@ qla24xx_reset_risc(scsi_qla_host_t *ha) | |||
| 528 | d2 = (uint32_t) RD_REG_WORD(®->mailbox0); | 529 | d2 = (uint32_t) RD_REG_WORD(®->mailbox0); |
| 529 | barrier(); | 530 | barrier(); |
| 530 | } | 531 | } |
| 532 | if (cnt == 0) | ||
| 533 | hw_evt = 1; | ||
| 531 | 534 | ||
| 532 | /* Wait for soft-reset to complete. */ | 535 | /* Wait for soft-reset to complete. */ |
| 533 | d2 = RD_REG_DWORD(®->ctrl_status); | 536 | d2 = RD_REG_DWORD(®->ctrl_status); |
| @@ -536,6 +539,10 @@ qla24xx_reset_risc(scsi_qla_host_t *ha) | |||
| 536 | d2 = RD_REG_DWORD(®->ctrl_status); | 539 | d2 = RD_REG_DWORD(®->ctrl_status); |
| 537 | barrier(); | 540 | barrier(); |
| 538 | } | 541 | } |
| 542 | if (cnt == 0 || hw_evt) | ||
| 543 | qla2xxx_hw_event_log(ha, HW_EVENT_RESET_ERR, | ||
| 544 | RD_REG_WORD(®->mailbox1), RD_REG_WORD(®->mailbox2), | ||
| 545 | RD_REG_WORD(®->mailbox3)); | ||
| 539 | 546 | ||
| 540 | WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET); | 547 | WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET); |
| 541 | RD_REG_DWORD(®->hccr); | 548 | RD_REG_DWORD(®->hccr); |
| @@ -1555,6 +1562,10 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) | |||
| 1555 | qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet " | 1562 | qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet " |
| 1556 | "invalid -- WWPN) defaults.\n"); | 1563 | "invalid -- WWPN) defaults.\n"); |
| 1557 | 1564 | ||
| 1565 | if (chksum) | ||
| 1566 | qla2xxx_hw_event_log(ha, HW_EVENT_NVRAM_CHKSUM_ERR, 0, | ||
| 1567 | MSW(chksum), LSW(chksum)); | ||
| 1568 | |||
| 1558 | /* | 1569 | /* |
| 1559 | * Set default initialization control block. | 1570 | * Set default initialization control block. |
| 1560 | */ | 1571 | */ |
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index e9d8a79dd6a4..088464251d7e 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c | |||
| @@ -349,6 +349,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) | |||
| 349 | "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n", | 349 | "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n", |
| 350 | mb[1], mb[2], mb[3]); | 350 | mb[1], mb[2], mb[3]); |
| 351 | 351 | ||
| 352 | qla2x00_post_hwe_work(ha, mb[0], mb[1], mb[2], mb[3]); | ||
| 352 | ha->isp_ops->fw_dump(ha, 1); | 353 | ha->isp_ops->fw_dump(ha, 1); |
| 353 | 354 | ||
| 354 | if (IS_FWI2_CAPABLE(ha)) { | 355 | if (IS_FWI2_CAPABLE(ha)) { |
| @@ -373,6 +374,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) | |||
| 373 | ha->host_no)); | 374 | ha->host_no)); |
| 374 | qla_printk(KERN_WARNING, ha, "ISP Request Transfer Error.\n"); | 375 | qla_printk(KERN_WARNING, ha, "ISP Request Transfer Error.\n"); |
| 375 | 376 | ||
| 377 | qla2x00_post_hwe_work(ha, mb[0], mb[1], mb[2], mb[3]); | ||
| 376 | set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); | 378 | set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); |
| 377 | break; | 379 | break; |
| 378 | 380 | ||
| @@ -381,6 +383,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) | |||
| 381 | ha->host_no)); | 383 | ha->host_no)); |
| 382 | qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n"); | 384 | qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n"); |
| 383 | 385 | ||
| 386 | qla2x00_post_hwe_work(ha, mb[0], mb[1], mb[2], mb[3]); | ||
| 384 | set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); | 387 | set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); |
| 385 | break; | 388 | break; |
| 386 | 389 | ||
| @@ -1558,6 +1561,12 @@ qla24xx_intr_handler(int irq, void *dev_id) | |||
| 1558 | if (pci_channel_offline(ha->pdev)) | 1561 | if (pci_channel_offline(ha->pdev)) |
| 1559 | break; | 1562 | break; |
| 1560 | 1563 | ||
| 1564 | if (ha->hw_event_pause_errors == 0) | ||
| 1565 | qla2x00_post_hwe_work(ha, HW_EVENT_PARITY_ERR, | ||
| 1566 | 0, MSW(stat), LSW(stat)); | ||
| 1567 | else if (ha->hw_event_pause_errors < 0xffffffff) | ||
| 1568 | ha->hw_event_pause_errors++; | ||
| 1569 | |||
| 1561 | hccr = RD_REG_DWORD(®->hccr); | 1570 | hccr = RD_REG_DWORD(®->hccr); |
| 1562 | 1571 | ||
| 1563 | qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " | 1572 | qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " |
| @@ -1693,6 +1702,12 @@ qla24xx_msix_default(int irq, void *dev_id) | |||
| 1693 | if (pci_channel_offline(ha->pdev)) | 1702 | if (pci_channel_offline(ha->pdev)) |
| 1694 | break; | 1703 | break; |
| 1695 | 1704 | ||
| 1705 | if (ha->hw_event_pause_errors == 0) | ||
| 1706 | qla2x00_post_hwe_work(ha, HW_EVENT_PARITY_ERR, | ||
| 1707 | 0, MSW(stat), LSW(stat)); | ||
| 1708 | else if (ha->hw_event_pause_errors < 0xffffffff) | ||
| 1709 | ha->hw_event_pause_errors++; | ||
| 1710 | |||
| 1696 | hccr = RD_REG_DWORD(®->hccr); | 1711 | hccr = RD_REG_DWORD(®->hccr); |
| 1697 | 1712 | ||
| 1698 | qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " | 1713 | qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " |
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 898847e4b363..b25c15a86c7f 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c | |||
| @@ -587,6 +587,14 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *ha) | |||
| 587 | if (mcp->mb[5] != 0xA5A5 || mcp->mb[6] != 0x5A5A || | 587 | if (mcp->mb[5] != 0xA5A5 || mcp->mb[6] != 0x5A5A || |
| 588 | mcp->mb[7] != 0x2525) | 588 | mcp->mb[7] != 0x2525) |
| 589 | rval = QLA_FUNCTION_FAILED; | 589 | rval = QLA_FUNCTION_FAILED; |
| 590 | if (rval == QLA_FUNCTION_FAILED) { | ||
| 591 | struct device_reg_24xx __iomem *reg = | ||
| 592 | &ha->iobase->isp24; | ||
| 593 | |||
| 594 | qla2xxx_hw_event_log(ha, HW_EVENT_ISP_ERR, 0, | ||
| 595 | LSW(RD_REG_DWORD(®->hccr)), | ||
| 596 | LSW(RD_REG_DWORD(®->istatus))); | ||
| 597 | } | ||
| 590 | } | 598 | } |
| 591 | 599 | ||
| 592 | if (rval != QLA_SUCCESS) { | 600 | if (rval != QLA_SUCCESS) { |
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index eb77067533ab..3d290417bfc6 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
| @@ -1690,6 +1690,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1690 | ha->gid_list_info_size = 8; | 1690 | ha->gid_list_info_size = 8; |
| 1691 | ha->optrom_size = OPTROM_SIZE_25XX; | 1691 | ha->optrom_size = OPTROM_SIZE_25XX; |
| 1692 | ha->isp_ops = &qla25xx_isp_ops; | 1692 | ha->isp_ops = &qla25xx_isp_ops; |
| 1693 | ha->hw_event_start = PCI_FUNC(pdev->devfn) ? | ||
| 1694 | FA_HW_EVENT1_ADDR: FA_HW_EVENT0_ADDR; | ||
| 1693 | } | 1695 | } |
| 1694 | host->can_queue = ha->request_q_length + 128; | 1696 | host->can_queue = ha->request_q_length + 128; |
| 1695 | 1697 | ||
| @@ -2244,6 +2246,23 @@ qla2x00_post_aen_work(struct scsi_qla_host *ha, enum fc_host_event_code code, | |||
| 2244 | return qla2x00_post_work(ha, e, 1); | 2246 | return qla2x00_post_work(ha, e, 1); |
| 2245 | } | 2247 | } |
| 2246 | 2248 | ||
| 2249 | int | ||
| 2250 | qla2x00_post_hwe_work(struct scsi_qla_host *ha, uint16_t code, uint16_t d1, | ||
| 2251 | uint16_t d2, uint16_t d3) | ||
| 2252 | { | ||
| 2253 | struct qla_work_evt *e; | ||
| 2254 | |||
| 2255 | e = qla2x00_alloc_work(ha, QLA_EVT_HWE_LOG, 1); | ||
| 2256 | if (!e) | ||
| 2257 | return QLA_FUNCTION_FAILED; | ||
| 2258 | |||
| 2259 | e->u.hwe.code = code; | ||
| 2260 | e->u.hwe.d1 = d1; | ||
| 2261 | e->u.hwe.d2 = d2; | ||
| 2262 | e->u.hwe.d3 = d3; | ||
| 2263 | return qla2x00_post_work(ha, e, 1); | ||
| 2264 | } | ||
| 2265 | |||
| 2247 | static void | 2266 | static void |
| 2248 | qla2x00_do_work(struct scsi_qla_host *ha) | 2267 | qla2x00_do_work(struct scsi_qla_host *ha) |
| 2249 | { | 2268 | { |
| @@ -2260,6 +2279,10 @@ qla2x00_do_work(struct scsi_qla_host *ha) | |||
| 2260 | fc_host_post_event(ha->host, fc_get_event_number(), | 2279 | fc_host_post_event(ha->host, fc_get_event_number(), |
| 2261 | e->u.aen.code, e->u.aen.data); | 2280 | e->u.aen.code, e->u.aen.data); |
| 2262 | break; | 2281 | break; |
| 2282 | case QLA_EVT_HWE_LOG: | ||
| 2283 | qla2xxx_hw_event_log(ha, e->u.hwe.code, e->u.hwe.d1, | ||
| 2284 | e->u.hwe.d2, e->u.hwe.d3); | ||
| 2285 | break; | ||
| 2263 | } | 2286 | } |
| 2264 | if (e->flags & QLA_EVT_FLAG_FREE) | 2287 | if (e->flags & QLA_EVT_FLAG_FREE) |
| 2265 | kfree(e); | 2288 | kfree(e); |
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 317cd8f96340..c10ccc75c398 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c | |||
| @@ -543,6 +543,43 @@ qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id, | |||
| 543 | } | 543 | } |
| 544 | } | 544 | } |
| 545 | 545 | ||
| 546 | static void | ||
| 547 | qla24xx_unprotect_flash(scsi_qla_host_t *ha) | ||
| 548 | { | ||
| 549 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
| 550 | |||
| 551 | /* Enable flash write. */ | ||
| 552 | WRT_REG_DWORD(®->ctrl_status, | ||
| 553 | RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); | ||
| 554 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ | ||
| 555 | |||
| 556 | /* Disable flash write-protection. */ | ||
| 557 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); | ||
| 558 | /* Some flash parts need an additional zero-write to clear bits.*/ | ||
| 559 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); | ||
| 560 | } | ||
| 561 | |||
| 562 | static void | ||
| 563 | qla24xx_protect_flash(scsi_qla_host_t *ha) | ||
| 564 | { | ||
| 565 | uint32_t cnt; | ||
| 566 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
| 567 | |||
| 568 | /* Enable flash write-protection and wait for completion. */ | ||
| 569 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c); | ||
| 570 | for (cnt = 300; cnt && | ||
| 571 | qla24xx_read_flash_dword(ha, | ||
| 572 | flash_conf_to_access_addr(0x005)) & BIT_0; | ||
| 573 | cnt--) { | ||
| 574 | udelay(10); | ||
| 575 | } | ||
| 576 | |||
| 577 | /* Disable flash write. */ | ||
| 578 | WRT_REG_DWORD(®->ctrl_status, | ||
| 579 | RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); | ||
| 580 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ | ||
| 581 | } | ||
| 582 | |||
| 546 | static int | 583 | static int |
| 547 | qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | 584 | qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, |
| 548 | uint32_t dwords) | 585 | uint32_t dwords) |
| @@ -550,9 +587,8 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | |||
| 550 | int ret; | 587 | int ret; |
| 551 | uint32_t liter, miter; | 588 | uint32_t liter, miter; |
| 552 | uint32_t sec_mask, rest_addr, conf_addr; | 589 | uint32_t sec_mask, rest_addr, conf_addr; |
| 553 | uint32_t fdata, findex, cnt; | 590 | uint32_t fdata, findex; |
| 554 | uint8_t man_id, flash_id; | 591 | uint8_t man_id, flash_id; |
| 555 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
| 556 | dma_addr_t optrom_dma; | 592 | dma_addr_t optrom_dma; |
| 557 | void *optrom = NULL; | 593 | void *optrom = NULL; |
| 558 | uint32_t *s, *d; | 594 | uint32_t *s, *d; |
| @@ -604,15 +640,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | |||
| 604 | break; | 640 | break; |
| 605 | } | 641 | } |
| 606 | 642 | ||
| 607 | /* Enable flash write. */ | 643 | qla24xx_unprotect_flash(ha); |
| 608 | WRT_REG_DWORD(®->ctrl_status, | ||
| 609 | RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); | ||
| 610 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ | ||
| 611 | |||
| 612 | /* Disable flash write-protection. */ | ||
| 613 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); | ||
| 614 | /* Some flash parts need an additional zero-write to clear bits.*/ | ||
| 615 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); | ||
| 616 | 644 | ||
| 617 | for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { | 645 | for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { |
| 618 | if (man_id == 0x1f) { | 646 | if (man_id == 0x1f) { |
| @@ -690,19 +718,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | |||
| 690 | 0xff0000) | ((fdata >> 16) & 0xff)); | 718 | 0xff0000) | ((fdata >> 16) & 0xff)); |
| 691 | } | 719 | } |
| 692 | 720 | ||
| 693 | /* Enable flash write-protection and wait for completion. */ | 721 | qla24xx_protect_flash(ha); |
| 694 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c); | ||
| 695 | for (cnt = 300; cnt && | ||
| 696 | qla24xx_read_flash_dword(ha, | ||
| 697 | flash_conf_to_access_addr(0x005)) & BIT_0; | ||
| 698 | cnt--) { | ||
| 699 | udelay(10); | ||
| 700 | } | ||
| 701 | |||
| 702 | /* Disable flash write. */ | ||
| 703 | WRT_REG_DWORD(®->ctrl_status, | ||
| 704 | RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); | ||
| 705 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ | ||
| 706 | 722 | ||
| 707 | if (optrom) | 723 | if (optrom) |
| 708 | dma_free_coherent(&ha->pdev->dev, | 724 | dma_free_coherent(&ha->pdev->dev, |
| @@ -2221,3 +2237,107 @@ qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf) | |||
| 2221 | 2237 | ||
| 2222 | return ret; | 2238 | return ret; |
| 2223 | } | 2239 | } |
| 2240 | |||
| 2241 | static int | ||
| 2242 | qla2xxx_hw_event_store(scsi_qla_host_t *ha, uint32_t *fdata) | ||
| 2243 | { | ||
| 2244 | uint32_t d[2], faddr; | ||
| 2245 | |||
| 2246 | /* Locate first empty entry. */ | ||
| 2247 | for (;;) { | ||
| 2248 | if (ha->hw_event_ptr >= | ||
| 2249 | ha->hw_event_start + FA_HW_EVENT_SIZE) { | ||
| 2250 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
| 2251 | "HW event -- Log Full!\n")); | ||
| 2252 | return QLA_MEMORY_ALLOC_FAILED; | ||
| 2253 | } | ||
| 2254 | |||
| 2255 | qla24xx_read_flash_data(ha, d, ha->hw_event_ptr, 2); | ||
| 2256 | faddr = flash_data_to_access_addr(ha->hw_event_ptr); | ||
| 2257 | ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE; | ||
| 2258 | if (d[0] == __constant_cpu_to_le32(0xffffffff) && | ||
| 2259 | d[1] == __constant_cpu_to_le32(0xffffffff)) { | ||
| 2260 | qla24xx_unprotect_flash(ha); | ||
| 2261 | |||
| 2262 | qla24xx_write_flash_dword(ha, faddr++, | ||
| 2263 | cpu_to_le32(jiffies)); | ||
| 2264 | qla24xx_write_flash_dword(ha, faddr++, 0); | ||
| 2265 | qla24xx_write_flash_dword(ha, faddr++, *fdata++); | ||
| 2266 | qla24xx_write_flash_dword(ha, faddr++, *fdata); | ||
| 2267 | |||
| 2268 | qla24xx_protect_flash(ha); | ||
| 2269 | break; | ||
| 2270 | } | ||
| 2271 | } | ||
| 2272 | return QLA_SUCCESS; | ||
| 2273 | } | ||
| 2274 | |||
| 2275 | int | ||
| 2276 | qla2xxx_hw_event_log(scsi_qla_host_t *ha, uint16_t code, uint16_t d1, | ||
| 2277 | uint16_t d2, uint16_t d3) | ||
| 2278 | { | ||
| 2279 | #define QMARK(a, b, c, d) \ | ||
| 2280 | cpu_to_le32(LSB(a) << 24 | LSB(b) << 16 | LSB(c) << 8 | LSB(d)) | ||
| 2281 | |||
| 2282 | int rval; | ||
| 2283 | uint32_t marker[2], fdata[4]; | ||
| 2284 | |||
| 2285 | if (ha->hw_event_start == 0) | ||
| 2286 | return QLA_FUNCTION_FAILED; | ||
| 2287 | |||
| 2288 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
| 2289 | "HW event -- code=%x, d1=%x, d2=%x, d3=%x.\n", code, d1, d2, d3)); | ||
| 2290 | |||
| 2291 | /* If marker not already found, locate or write. */ | ||
| 2292 | if (!ha->flags.hw_event_marker_found) { | ||
| 2293 | /* Create marker. */ | ||
| 2294 | marker[0] = QMARK('L', ha->fw_major_version, | ||
| 2295 | ha->fw_minor_version, ha->fw_subminor_version); | ||
| 2296 | marker[1] = QMARK(QLA_DRIVER_MAJOR_VER, QLA_DRIVER_MINOR_VER, | ||
| 2297 | QLA_DRIVER_PATCH_VER, QLA_DRIVER_BETA_VER); | ||
| 2298 | |||
| 2299 | /* Locate marker. */ | ||
| 2300 | ha->hw_event_ptr = ha->hw_event_start; | ||
| 2301 | for (;;) { | ||
| 2302 | qla24xx_read_flash_data(ha, fdata, ha->hw_event_ptr, | ||
| 2303 | 4); | ||
| 2304 | if (fdata[0] == __constant_cpu_to_le32(0xffffffff) && | ||
| 2305 | fdata[1] == __constant_cpu_to_le32(0xffffffff)) | ||
| 2306 | break; | ||
| 2307 | ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE; | ||
| 2308 | if (ha->hw_event_ptr >= | ||
| 2309 | ha->hw_event_start + FA_HW_EVENT_SIZE) { | ||
| 2310 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
| 2311 | "HW event -- Log Full!\n")); | ||
| 2312 | return QLA_MEMORY_ALLOC_FAILED; | ||
| 2313 | } | ||
| 2314 | if (fdata[2] == marker[0] && fdata[3] == marker[1]) { | ||
| 2315 | ha->flags.hw_event_marker_found = 1; | ||
| 2316 | break; | ||
| 2317 | } | ||
| 2318 | } | ||
| 2319 | /* No marker, write it. */ | ||
| 2320 | if (!ha->flags.hw_event_marker_found) { | ||
| 2321 | rval = qla2xxx_hw_event_store(ha, marker); | ||
| 2322 | if (rval != QLA_SUCCESS) { | ||
| 2323 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
| 2324 | "HW event -- Failed marker write=%x.!\n", | ||
| 2325 | rval)); | ||
| 2326 | return rval; | ||
| 2327 | } | ||
| 2328 | ha->flags.hw_event_marker_found = 1; | ||
| 2329 | } | ||
| 2330 | } | ||
| 2331 | |||
| 2332 | /* Store error. */ | ||
| 2333 | fdata[0] = cpu_to_le32(code << 16 | d1); | ||
| 2334 | fdata[1] = cpu_to_le32(d2 << 16 | d3); | ||
| 2335 | rval = qla2xxx_hw_event_store(ha, fdata); | ||
| 2336 | if (rval != QLA_SUCCESS) { | ||
| 2337 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
| 2338 | "HW event -- Failed error write=%x.!\n", | ||
| 2339 | rval)); | ||
| 2340 | } | ||
| 2341 | |||
| 2342 | return rval; | ||
| 2343 | } | ||
