diff options
author | Andrew Vasquez <andrew.vasquez@qlogic.com> | 2008-04-03 16:13:19 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-04-07 13:19:13 -0400 |
commit | cb8dacbf1110d8bd39413f3116ff1720f757854e (patch) | |
tree | 8d58f215c7a1091f7e760359c56d1316d9c80f7d /drivers/scsi/qla2xxx | |
parent | 0971de7f56f809f40edae6fd372745e429e970e9 (diff) |
[SCSI] qla2xxx: Add hardware trace-logging support.
Recent ISPs have a region within FLASH which acts as a repository
for the logging of serious hardware and software failures.
Currently, the region is large enough to support up to 255
entries.
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/qla2xxx')
-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 | } | ||