aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx/qla_sup.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_sup.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c315
1 files changed, 251 insertions, 64 deletions
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 26822c8807ee..1728ab3ccb20 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * QLogic Fibre Channel HBA Driver 2 * QLogic Fibre Channel HBA Driver
3 * Copyright (c) 2003-2005 QLogic Corporation 3 * Copyright (c) 2003-2008 QLogic Corporation
4 * 4 *
5 * See LICENSE.qla2xxx for copyright and licensing details. 5 * See LICENSE.qla2xxx for copyright and licensing details.
6 */ 6 */
@@ -543,79 +543,174 @@ qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id,
543 } 543 }
544} 544}
545 545
546static int 546void
547qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, 547qla2xxx_get_flash_info(scsi_qla_host_t *ha)
548 uint32_t dwords)
549{ 548{
550 int ret; 549#define FLASH_BLK_SIZE_32K 0x8000
551 uint32_t liter, miter; 550#define FLASH_BLK_SIZE_64K 0x10000
552 uint32_t sec_mask, rest_addr, conf_addr; 551 uint16_t cnt, chksum;
553 uint32_t fdata, findex, cnt; 552 uint16_t *wptr;
553 struct qla_fdt_layout *fdt;
554 uint8_t man_id, flash_id; 554 uint8_t man_id, flash_id;
555 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
556 dma_addr_t optrom_dma;
557 void *optrom = NULL;
558 uint32_t *s, *d;
559 555
560 ret = QLA_SUCCESS; 556 if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha))
557 return;
561 558
562 /* Prepare burst-capable write on supported ISPs. */ 559 wptr = (uint16_t *)ha->request_ring;
563 if (IS_QLA25XX(ha) && !(faddr & 0xfff) && 560 fdt = (struct qla_fdt_layout *)ha->request_ring;
564 dwords > OPTROM_BURST_DWORDS) { 561 ha->isp_ops->read_optrom(ha, (uint8_t *)ha->request_ring,
565 optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, 562 FA_FLASH_DESCR_ADDR << 2, OPTROM_BURST_SIZE);
566 &optrom_dma, GFP_KERNEL); 563 if (*wptr == __constant_cpu_to_le16(0xffff))
567 if (!optrom) { 564 goto no_flash_data;
568 qla_printk(KERN_DEBUG, ha, 565 if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' ||
569 "Unable to allocate memory for optrom burst write " 566 fdt->sig[3] != 'D')
570 "(%x KB).\n", OPTROM_BURST_SIZE / 1024); 567 goto no_flash_data;
571 } 568
569 for (cnt = 0, chksum = 0; cnt < sizeof(struct qla_fdt_layout) >> 1;
570 cnt++)
571 chksum += le16_to_cpu(*wptr++);
572 if (chksum) {
573 DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent FDT detected: "
574 "checksum=0x%x id=%c version=0x%x.\n", chksum, fdt->sig[0],
575 le16_to_cpu(fdt->version)));
576 DEBUG9(qla2x00_dump_buffer((uint8_t *)fdt, sizeof(*fdt)));
577 goto no_flash_data;
572 } 578 }
573 579
574 qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); 580 ha->fdt_odd_index = le16_to_cpu(fdt->man_id) == 0x1f;
575 DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__, 581 ha->fdt_wrt_disable = fdt->wrt_disable_bits;
576 ha->host_no, man_id, flash_id)); 582 ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0300 | fdt->erase_cmd);
583 ha->fdt_block_size = le32_to_cpu(fdt->block_size);
584 if (fdt->unprotect_sec_cmd) {
585 ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0300 |
586 fdt->unprotect_sec_cmd);
587 ha->fdt_protect_sec_cmd = fdt->protect_sec_cmd ?
588 flash_conf_to_access_addr(0x0300 | fdt->protect_sec_cmd):
589 flash_conf_to_access_addr(0x0336);
590 }
577 591
578 conf_addr = flash_conf_to_access_addr(0x03d8); 592 DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[FDT]: (0x%x/0x%x) erase=0x%x "
593 "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n",
594 le16_to_cpu(fdt->man_id), le16_to_cpu(fdt->id), ha->fdt_erase_cmd,
595 ha->fdt_protect_sec_cmd, ha->fdt_unprotect_sec_cmd,
596 ha->fdt_odd_index, ha->fdt_wrt_disable, ha->fdt_block_size));
597 return;
598
599no_flash_data:
600 qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id);
601 ha->fdt_wrt_disable = 0x9c;
602 ha->fdt_erase_cmd = flash_conf_to_access_addr(0x03d8);
579 switch (man_id) { 603 switch (man_id) {
580 case 0xbf: /* STT flash. */ 604 case 0xbf: /* STT flash. */
581 if (flash_id == 0x8e) { 605 if (flash_id == 0x8e)
582 rest_addr = 0x3fff; 606 ha->fdt_block_size = FLASH_BLK_SIZE_64K;
583 sec_mask = 0x7c000; 607 else
584 } else { 608 ha->fdt_block_size = FLASH_BLK_SIZE_32K;
585 rest_addr = 0x1fff; 609
586 sec_mask = 0x7e000;
587 }
588 if (flash_id == 0x80) 610 if (flash_id == 0x80)
589 conf_addr = flash_conf_to_access_addr(0x0352); 611 ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0352);
590 break; 612 break;
591 case 0x13: /* ST M25P80. */ 613 case 0x13: /* ST M25P80. */
592 rest_addr = 0x3fff; 614 ha->fdt_block_size = FLASH_BLK_SIZE_64K;
593 sec_mask = 0x7c000;
594 break; 615 break;
595 case 0x1f: // Atmel 26DF081A 616 case 0x1f: /* Atmel 26DF081A. */
596 rest_addr = 0x3fff; 617 ha->fdt_odd_index = 1;
597 sec_mask = 0x7c000; 618 ha->fdt_block_size = FLASH_BLK_SIZE_64K;
598 conf_addr = flash_conf_to_access_addr(0x0320); 619 ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0320);
620 ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0339);
621 ha->fdt_protect_sec_cmd = flash_conf_to_access_addr(0x0336);
599 break; 622 break;
600 default: 623 default:
601 /* Default to 64 kb sector size. */ 624 /* Default to 64 kb sector size. */
602 rest_addr = 0x3fff; 625 ha->fdt_block_size = FLASH_BLK_SIZE_64K;
603 sec_mask = 0x7c000;
604 break; 626 break;
605 } 627 }
606 628
629 DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[MID]: (0x%x/0x%x) erase=0x%x "
630 "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", man_id, flash_id,
631 ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd,
632 ha->fdt_unprotect_sec_cmd, ha->fdt_odd_index, ha->fdt_wrt_disable,
633 ha->fdt_block_size));
634}
635
636static void
637qla24xx_unprotect_flash(scsi_qla_host_t *ha)
638{
639 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
640
607 /* Enable flash write. */ 641 /* Enable flash write. */
608 WRT_REG_DWORD(&reg->ctrl_status, 642 WRT_REG_DWORD(&reg->ctrl_status,
609 RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE); 643 RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE);
610 RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */ 644 RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */
611 645
646 if (!ha->fdt_wrt_disable)
647 return;
648
612 /* Disable flash write-protection. */ 649 /* Disable flash write-protection. */
613 qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); 650 qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0);
614 /* Some flash parts need an additional zero-write to clear bits.*/ 651 /* Some flash parts need an additional zero-write to clear bits.*/
615 qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); 652 qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0);
653}
654
655static void
656qla24xx_protect_flash(scsi_qla_host_t *ha)
657{
658 uint32_t cnt;
659 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
660
661 if (!ha->fdt_wrt_disable)
662 goto skip_wrt_protect;
663
664 /* Enable flash write-protection and wait for completion. */
665 qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101),
666 ha->fdt_wrt_disable);
667 for (cnt = 300; cnt &&
668 qla24xx_read_flash_dword(ha,
669 flash_conf_to_access_addr(0x005)) & BIT_0;
670 cnt--) {
671 udelay(10);
672 }
673
674skip_wrt_protect:
675 /* Disable flash write. */
676 WRT_REG_DWORD(&reg->ctrl_status,
677 RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
678 RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */
679}
680
681static int
682qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
683 uint32_t dwords)
684{
685 int ret;
686 uint32_t liter, miter;
687 uint32_t sec_mask, rest_addr;
688 uint32_t fdata, findex;
689 dma_addr_t optrom_dma;
690 void *optrom = NULL;
691 uint32_t *s, *d;
692
693 ret = QLA_SUCCESS;
694
695 /* Prepare burst-capable write on supported ISPs. */
696 if (IS_QLA25XX(ha) && !(faddr & 0xfff) &&
697 dwords > OPTROM_BURST_DWORDS) {
698 optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
699 &optrom_dma, GFP_KERNEL);
700 if (!optrom) {
701 qla_printk(KERN_DEBUG, ha,
702 "Unable to allocate memory for optrom burst write "
703 "(%x KB).\n", OPTROM_BURST_SIZE / 1024);
704 }
705 }
706
707 rest_addr = (ha->fdt_block_size >> 2) - 1;
708 sec_mask = 0x80000 - (ha->fdt_block_size >> 2);
709
710 qla24xx_unprotect_flash(ha);
616 711
617 for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { 712 for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
618 if (man_id == 0x1f) { 713 if (ha->fdt_odd_index) {
619 findex = faddr << 2; 714 findex = faddr << 2;
620 fdata = findex & sec_mask; 715 fdata = findex & sec_mask;
621 } else { 716 } else {
@@ -625,13 +720,13 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
625 720
626 /* Are we at the beginning of a sector? */ 721 /* Are we at the beginning of a sector? */
627 if ((findex & rest_addr) == 0) { 722 if ((findex & rest_addr) == 0) {
628 /* Do sector unprotect at 4K boundry for Atmel part. */ 723 /* Do sector unprotect. */
629 if (man_id == 0x1f) 724 if (ha->fdt_unprotect_sec_cmd)
630 qla24xx_write_flash_dword(ha, 725 qla24xx_write_flash_dword(ha,
631 flash_conf_to_access_addr(0x0339), 726 ha->fdt_unprotect_sec_cmd,
632 (fdata & 0xff00) | ((fdata << 16) & 727 (fdata & 0xff00) | ((fdata << 16) &
633 0xff0000) | ((fdata >> 16) & 0xff)); 728 0xff0000) | ((fdata >> 16) & 0xff));
634 ret = qla24xx_write_flash_dword(ha, conf_addr, 729 ret = qla24xx_write_flash_dword(ha, ha->fdt_erase_cmd,
635 (fdata & 0xff00) |((fdata << 16) & 730 (fdata & 0xff00) |((fdata << 16) &
636 0xff0000) | ((fdata >> 16) & 0xff)); 731 0xff0000) | ((fdata >> 16) & 0xff));
637 if (ret != QLA_SUCCESS) { 732 if (ret != QLA_SUCCESS) {
@@ -681,28 +776,16 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
681 break; 776 break;
682 } 777 }
683 778
684 /* Do sector protect at 4K boundry for Atmel part. */ 779 /* Do sector protect. */
685 if (man_id == 0x1f && 780 if (ha->fdt_unprotect_sec_cmd &&
686 ((faddr & rest_addr) == rest_addr)) 781 ((faddr & rest_addr) == rest_addr))
687 qla24xx_write_flash_dword(ha, 782 qla24xx_write_flash_dword(ha,
688 flash_conf_to_access_addr(0x0336), 783 ha->fdt_protect_sec_cmd,
689 (fdata & 0xff00) | ((fdata << 16) & 784 (fdata & 0xff00) | ((fdata << 16) &
690 0xff0000) | ((fdata >> 16) & 0xff)); 785 0xff0000) | ((fdata >> 16) & 0xff));
691 } 786 }
692 787
693 /* Enable flash write-protection and wait for completion. */ 788 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(&reg->ctrl_status,
704 RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
705 RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */
706 789
707 if (optrom) 790 if (optrom)
708 dma_free_coherent(&ha->pdev->dev, 791 dma_free_coherent(&ha->pdev->dev,
@@ -2221,3 +2304,107 @@ qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
2221 2304
2222 return ret; 2305 return ret;
2223} 2306}
2307
2308static int
2309qla2xxx_hw_event_store(scsi_qla_host_t *ha, uint32_t *fdata)
2310{
2311 uint32_t d[2], faddr;
2312
2313 /* Locate first empty entry. */
2314 for (;;) {
2315 if (ha->hw_event_ptr >=
2316 ha->hw_event_start + FA_HW_EVENT_SIZE) {
2317 DEBUG2(qla_printk(KERN_WARNING, ha,
2318 "HW event -- Log Full!\n"));
2319 return QLA_MEMORY_ALLOC_FAILED;
2320 }
2321
2322 qla24xx_read_flash_data(ha, d, ha->hw_event_ptr, 2);
2323 faddr = flash_data_to_access_addr(ha->hw_event_ptr);
2324 ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE;
2325 if (d[0] == __constant_cpu_to_le32(0xffffffff) &&
2326 d[1] == __constant_cpu_to_le32(0xffffffff)) {
2327 qla24xx_unprotect_flash(ha);
2328
2329 qla24xx_write_flash_dword(ha, faddr++,
2330 cpu_to_le32(jiffies));
2331 qla24xx_write_flash_dword(ha, faddr++, 0);
2332 qla24xx_write_flash_dword(ha, faddr++, *fdata++);
2333 qla24xx_write_flash_dword(ha, faddr++, *fdata);
2334
2335 qla24xx_protect_flash(ha);
2336 break;
2337 }
2338 }
2339 return QLA_SUCCESS;
2340}
2341
2342int
2343qla2xxx_hw_event_log(scsi_qla_host_t *ha, uint16_t code, uint16_t d1,
2344 uint16_t d2, uint16_t d3)
2345{
2346#define QMARK(a, b, c, d) \
2347 cpu_to_le32(LSB(a) << 24 | LSB(b) << 16 | LSB(c) << 8 | LSB(d))
2348
2349 int rval;
2350 uint32_t marker[2], fdata[4];
2351
2352 if (ha->hw_event_start == 0)
2353 return QLA_FUNCTION_FAILED;
2354
2355 DEBUG2(qla_printk(KERN_WARNING, ha,
2356 "HW event -- code=%x, d1=%x, d2=%x, d3=%x.\n", code, d1, d2, d3));
2357
2358 /* If marker not already found, locate or write. */
2359 if (!ha->flags.hw_event_marker_found) {
2360 /* Create marker. */
2361 marker[0] = QMARK('L', ha->fw_major_version,
2362 ha->fw_minor_version, ha->fw_subminor_version);
2363 marker[1] = QMARK(QLA_DRIVER_MAJOR_VER, QLA_DRIVER_MINOR_VER,
2364 QLA_DRIVER_PATCH_VER, QLA_DRIVER_BETA_VER);
2365
2366 /* Locate marker. */
2367 ha->hw_event_ptr = ha->hw_event_start;
2368 for (;;) {
2369 qla24xx_read_flash_data(ha, fdata, ha->hw_event_ptr,
2370 4);
2371 if (fdata[0] == __constant_cpu_to_le32(0xffffffff) &&
2372 fdata[1] == __constant_cpu_to_le32(0xffffffff))
2373 break;
2374 ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE;
2375 if (ha->hw_event_ptr >=
2376 ha->hw_event_start + FA_HW_EVENT_SIZE) {
2377 DEBUG2(qla_printk(KERN_WARNING, ha,
2378 "HW event -- Log Full!\n"));
2379 return QLA_MEMORY_ALLOC_FAILED;
2380 }
2381 if (fdata[2] == marker[0] && fdata[3] == marker[1]) {
2382 ha->flags.hw_event_marker_found = 1;
2383 break;
2384 }
2385 }
2386 /* No marker, write it. */
2387 if (!ha->flags.hw_event_marker_found) {
2388 rval = qla2xxx_hw_event_store(ha, marker);
2389 if (rval != QLA_SUCCESS) {
2390 DEBUG2(qla_printk(KERN_WARNING, ha,
2391 "HW event -- Failed marker write=%x.!\n",
2392 rval));
2393 return rval;
2394 }
2395 ha->flags.hw_event_marker_found = 1;
2396 }
2397 }
2398
2399 /* Store error. */
2400 fdata[0] = cpu_to_le32(code << 16 | d1);
2401 fdata[1] = cpu_to_le32(d2 << 16 | d3);
2402 rval = qla2xxx_hw_event_store(ha, fdata);
2403 if (rval != QLA_SUCCESS) {
2404 DEBUG2(qla_printk(KERN_WARNING, ha,
2405 "HW event -- Failed error write=%x.!\n",
2406 rval));
2407 }
2408
2409 return rval;
2410}