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/qla_sup.c | |
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/qla_sup.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_sup.c | 168 |
1 files changed, 144 insertions, 24 deletions
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 | } | ||