diff options
author | Andrew Vasquez <andrew.vasquez@qlogic.com> | 2005-07-06 13:31:37 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2005-07-14 11:02:06 -0400 |
commit | 0107109ed69c9e04b6fa35ac41d870c74dcce3fc (patch) | |
tree | 4abc6e4e4b37a69bca4c863972af655dc92c78ea /drivers | |
parent | 9a853f71804d80e862362f6d0743d06955305752 (diff) |
[SCSI] qla2xxx: Add ISP24xx initialization routines.
Add ISP24xx initialization routines.
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 9 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 973 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 1 |
3 files changed, 848 insertions, 135 deletions
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index d153d543a672..fcb42f56b5e2 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h | |||
@@ -35,13 +35,22 @@ extern int qla2x00_initialize_adapter(scsi_qla_host_t *); | |||
35 | 35 | ||
36 | extern int qla2100_pci_config(struct scsi_qla_host *); | 36 | extern int qla2100_pci_config(struct scsi_qla_host *); |
37 | extern int qla2300_pci_config(struct scsi_qla_host *); | 37 | extern int qla2300_pci_config(struct scsi_qla_host *); |
38 | extern int qla24xx_pci_config(scsi_qla_host_t *); | ||
38 | extern void qla2x00_reset_chip(struct scsi_qla_host *); | 39 | extern void qla2x00_reset_chip(struct scsi_qla_host *); |
40 | extern void qla24xx_reset_chip(struct scsi_qla_host *); | ||
39 | extern int qla2x00_chip_diag(struct scsi_qla_host *); | 41 | extern int qla2x00_chip_diag(struct scsi_qla_host *); |
42 | extern int qla24xx_chip_diag(struct scsi_qla_host *); | ||
40 | extern void qla2x00_config_rings(struct scsi_qla_host *); | 43 | extern void qla2x00_config_rings(struct scsi_qla_host *); |
44 | extern void qla24xx_config_rings(struct scsi_qla_host *); | ||
41 | extern void qla2x00_reset_adapter(struct scsi_qla_host *); | 45 | extern void qla2x00_reset_adapter(struct scsi_qla_host *); |
46 | extern void qla24xx_reset_adapter(struct scsi_qla_host *); | ||
42 | extern int qla2x00_nvram_config(struct scsi_qla_host *); | 47 | extern int qla2x00_nvram_config(struct scsi_qla_host *); |
48 | extern int qla24xx_nvram_config(struct scsi_qla_host *); | ||
43 | extern void qla2x00_update_fw_options(struct scsi_qla_host *); | 49 | extern void qla2x00_update_fw_options(struct scsi_qla_host *); |
50 | extern void qla24xx_update_fw_options(scsi_qla_host_t *); | ||
44 | extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *); | 51 | extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *); |
52 | extern int qla24xx_load_risc_flash(scsi_qla_host_t *, uint32_t *); | ||
53 | extern int qla24xx_load_risc_hotplug(scsi_qla_host_t *, uint32_t *); | ||
45 | 54 | ||
46 | extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, int); | 55 | extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, int); |
47 | 56 | ||
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index b0419661981e..786f2648114d 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c | |||
@@ -19,6 +19,8 @@ | |||
19 | #include "qla_def.h" | 19 | #include "qla_def.h" |
20 | 20 | ||
21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
22 | #include <linux/vmalloc.h> | ||
23 | #include <linux/firmware.h> | ||
22 | #include <scsi/scsi_transport_fc.h> | 24 | #include <scsi/scsi_transport_fc.h> |
23 | 25 | ||
24 | #include "qla_devtbl.h" | 26 | #include "qla_devtbl.h" |
@@ -87,6 +89,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) | |||
87 | ha->isp_abort_cnt = 0; | 89 | ha->isp_abort_cnt = 0; |
88 | ha->beacon_blink_led = 0; | 90 | ha->beacon_blink_led = 0; |
89 | 91 | ||
92 | qla_printk(KERN_INFO, ha, "Configuring PCI space...\n"); | ||
90 | rval = ha->isp_ops.pci_config(ha); | 93 | rval = ha->isp_ops.pci_config(ha); |
91 | if (rval) { | 94 | if (rval) { |
92 | DEBUG2(printk("scsi(%ld): Unable to configure PCI space=n", | 95 | DEBUG2(printk("scsi(%ld): Unable to configure PCI space=n", |
@@ -97,6 +100,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) | |||
97 | ha->isp_ops.reset_chip(ha); | 100 | ha->isp_ops.reset_chip(ha); |
98 | 101 | ||
99 | qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n"); | 102 | qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n"); |
103 | |||
100 | ha->isp_ops.nvram_config(ha); | 104 | ha->isp_ops.nvram_config(ha); |
101 | 105 | ||
102 | qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n"); | 106 | qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n"); |
@@ -129,6 +133,9 @@ check_fw_ready_again: | |||
129 | if (rval == QLA_SUCCESS) { | 133 | if (rval == QLA_SUCCESS) { |
130 | clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); | 134 | clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); |
131 | 135 | ||
136 | /* Issue a marker after FW becomes ready. */ | ||
137 | qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); | ||
138 | |||
132 | /* | 139 | /* |
133 | * Wait at most MAX_TARGET RSCNs for a stable | 140 | * Wait at most MAX_TARGET RSCNs for a stable |
134 | * link. | 141 | * link. |
@@ -172,7 +179,6 @@ check_fw_ready_again: | |||
172 | 179 | ||
173 | if (rval == QLA_SUCCESS) { | 180 | if (rval == QLA_SUCCESS) { |
174 | clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); | 181 | clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); |
175 | ha->marker_needed = 1; | ||
176 | qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); | 182 | qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); |
177 | ha->marker_needed = 0; | 183 | ha->marker_needed = 0; |
178 | 184 | ||
@@ -197,8 +203,6 @@ qla2100_pci_config(scsi_qla_host_t *ha) | |||
197 | unsigned long flags; | 203 | unsigned long flags; |
198 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; | 204 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; |
199 | 205 | ||
200 | qla_printk(KERN_INFO, ha, "Configuring PCI space...\n"); | ||
201 | |||
202 | pci_set_master(ha->pdev); | 206 | pci_set_master(ha->pdev); |
203 | mwi = 0; | 207 | mwi = 0; |
204 | if (pci_set_mwi(ha->pdev)) | 208 | if (pci_set_mwi(ha->pdev)) |
@@ -236,8 +240,6 @@ qla2300_pci_config(scsi_qla_host_t *ha) | |||
236 | uint32_t cnt; | 240 | uint32_t cnt; |
237 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; | 241 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; |
238 | 242 | ||
239 | qla_printk(KERN_INFO, ha, "Configuring PCI space...\n"); | ||
240 | |||
241 | pci_set_master(ha->pdev); | 243 | pci_set_master(ha->pdev); |
242 | mwi = 0; | 244 | mwi = 0; |
243 | if (pci_set_mwi(ha->pdev)) | 245 | if (pci_set_mwi(ha->pdev)) |
@@ -312,6 +314,70 @@ qla2300_pci_config(scsi_qla_host_t *ha) | |||
312 | } | 314 | } |
313 | 315 | ||
314 | /** | 316 | /** |
317 | * qla24xx_pci_config() - Setup ISP24xx PCI configuration registers. | ||
318 | * @ha: HA context | ||
319 | * | ||
320 | * Returns 0 on success. | ||
321 | */ | ||
322 | int | ||
323 | qla24xx_pci_config(scsi_qla_host_t *ha) | ||
324 | { | ||
325 | uint16_t w, mwi; | ||
326 | unsigned long flags = 0; | ||
327 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
328 | int pcix_cmd_reg, pcie_dctl_reg; | ||
329 | |||
330 | pci_set_master(ha->pdev); | ||
331 | mwi = 0; | ||
332 | if (pci_set_mwi(ha->pdev)) | ||
333 | mwi = PCI_COMMAND_INVALIDATE; | ||
334 | pci_read_config_word(ha->pdev, PCI_REVISION_ID, &ha->revision); | ||
335 | |||
336 | pci_read_config_word(ha->pdev, PCI_COMMAND, &w); | ||
337 | w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); | ||
338 | w &= ~PCI_COMMAND_INTX_DISABLE; | ||
339 | pci_write_config_word(ha->pdev, PCI_COMMAND, w); | ||
340 | |||
341 | pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80); | ||
342 | |||
343 | /* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */ | ||
344 | pcix_cmd_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX); | ||
345 | if (pcix_cmd_reg) { | ||
346 | uint16_t pcix_cmd; | ||
347 | |||
348 | pcix_cmd_reg += PCI_X_CMD; | ||
349 | pci_read_config_word(ha->pdev, pcix_cmd_reg, &pcix_cmd); | ||
350 | pcix_cmd &= ~PCI_X_CMD_MAX_READ; | ||
351 | pcix_cmd |= 0x0008; | ||
352 | pci_write_config_word(ha->pdev, pcix_cmd_reg, pcix_cmd); | ||
353 | } | ||
354 | |||
355 | /* PCIe -- adjust Maximum Read Request Size (2048). */ | ||
356 | pcie_dctl_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP); | ||
357 | if (pcie_dctl_reg) { | ||
358 | uint16_t pcie_dctl; | ||
359 | |||
360 | pcie_dctl_reg += PCI_EXP_DEVCTL; | ||
361 | pci_read_config_word(ha->pdev, pcie_dctl_reg, &pcie_dctl); | ||
362 | pcie_dctl &= ~PCI_EXP_DEVCTL_READRQ; | ||
363 | pcie_dctl |= 0x4000; | ||
364 | pci_write_config_word(ha->pdev, pcie_dctl_reg, pcie_dctl); | ||
365 | } | ||
366 | |||
367 | /* Reset expansion ROM address decode enable */ | ||
368 | pci_read_config_word(ha->pdev, PCI_ROM_ADDRESS, &w); | ||
369 | w &= ~PCI_ROM_ADDRESS_ENABLE; | ||
370 | pci_write_config_word(ha->pdev, PCI_ROM_ADDRESS, w); | ||
371 | |||
372 | /* Get PCI bus information. */ | ||
373 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
374 | ha->pci_attr = RD_REG_DWORD(®->ctrl_status); | ||
375 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
376 | |||
377 | return QLA_SUCCESS; | ||
378 | } | ||
379 | |||
380 | /** | ||
315 | * qla2x00_isp_firmware() - Choose firmware image. | 381 | * qla2x00_isp_firmware() - Choose firmware image. |
316 | * @ha: HA context | 382 | * @ha: HA context |
317 | * | 383 | * |
@@ -498,6 +564,61 @@ qla2x00_reset_chip(scsi_qla_host_t *ha) | |||
498 | } | 564 | } |
499 | 565 | ||
500 | /** | 566 | /** |
567 | * qla24xx_reset_chip() - Reset ISP24xx chip. | ||
568 | * @ha: HA context | ||
569 | * | ||
570 | * Returns 0 on success. | ||
571 | */ | ||
572 | void | ||
573 | qla24xx_reset_chip(scsi_qla_host_t *ha) | ||
574 | { | ||
575 | unsigned long flags = 0; | ||
576 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
577 | uint32_t cnt, d2; | ||
578 | |||
579 | ha->isp_ops.disable_intrs(ha); | ||
580 | |||
581 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
582 | |||
583 | /* Reset RISC. */ | ||
584 | WRT_REG_DWORD(®->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); | ||
585 | for (cnt = 0; cnt < 30000; cnt++) { | ||
586 | if ((RD_REG_DWORD(®->ctrl_status) & CSRX_DMA_ACTIVE) == 0) | ||
587 | break; | ||
588 | |||
589 | udelay(10); | ||
590 | } | ||
591 | |||
592 | WRT_REG_DWORD(®->ctrl_status, | ||
593 | CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); | ||
594 | udelay(20); | ||
595 | d2 = RD_REG_DWORD(®->ctrl_status); | ||
596 | for (cnt = 6000000 ; cnt && (d2 & CSRX_ISP_SOFT_RESET); cnt--) { | ||
597 | udelay(5); | ||
598 | d2 = RD_REG_DWORD(®->ctrl_status); | ||
599 | barrier(); | ||
600 | } | ||
601 | |||
602 | WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET); | ||
603 | RD_REG_DWORD(®->hccr); | ||
604 | |||
605 | WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); | ||
606 | RD_REG_DWORD(®->hccr); | ||
607 | |||
608 | WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_RESET); | ||
609 | RD_REG_DWORD(®->hccr); | ||
610 | |||
611 | d2 = (uint32_t) RD_REG_WORD(®->mailbox0); | ||
612 | for (cnt = 6000000 ; cnt && d2; cnt--) { | ||
613 | udelay(5); | ||
614 | d2 = (uint32_t) RD_REG_WORD(®->mailbox0); | ||
615 | barrier(); | ||
616 | } | ||
617 | |||
618 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
619 | } | ||
620 | |||
621 | /** | ||
501 | * qla2x00_chip_diag() - Test chip for proper operation. | 622 | * qla2x00_chip_diag() - Test chip for proper operation. |
502 | * @ha: HA context | 623 | * @ha: HA context |
503 | * | 624 | * |
@@ -623,6 +744,91 @@ chip_diag_failed: | |||
623 | } | 744 | } |
624 | 745 | ||
625 | /** | 746 | /** |
747 | * qla24xx_chip_diag() - Test ISP24xx for proper operation. | ||
748 | * @ha: HA context | ||
749 | * | ||
750 | * Returns 0 on success. | ||
751 | */ | ||
752 | int | ||
753 | qla24xx_chip_diag(scsi_qla_host_t *ha) | ||
754 | { | ||
755 | int rval; | ||
756 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
757 | unsigned long flags = 0; | ||
758 | uint32_t cnt, d2; | ||
759 | |||
760 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
761 | |||
762 | /* Reset RISC. */ | ||
763 | WRT_REG_DWORD(®->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); | ||
764 | for (cnt = 0; cnt < 30000; cnt++) { | ||
765 | if ((RD_REG_DWORD(®->ctrl_status) & | ||
766 | CSRX_DMA_ACTIVE) == 0) | ||
767 | break; | ||
768 | |||
769 | udelay(10); | ||
770 | } | ||
771 | |||
772 | WRT_REG_DWORD(®->ctrl_status, | ||
773 | CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); | ||
774 | udelay(20); | ||
775 | d2 = RD_REG_DWORD(®->ctrl_status); | ||
776 | for (cnt = 6000000 ; cnt && (d2 & CSRX_ISP_SOFT_RESET); cnt--) { | ||
777 | udelay(5); | ||
778 | d2 = RD_REG_DWORD(®->ctrl_status); | ||
779 | barrier(); | ||
780 | } | ||
781 | |||
782 | WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET); | ||
783 | RD_REG_DWORD(®->hccr); | ||
784 | |||
785 | WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); | ||
786 | RD_REG_DWORD(®->hccr); | ||
787 | |||
788 | WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_RESET); | ||
789 | RD_REG_DWORD(®->hccr); | ||
790 | |||
791 | d2 = (uint32_t) RD_REG_WORD(®->mailbox0); | ||
792 | for (cnt = 6000000 ; cnt && d2; cnt--) { | ||
793 | udelay(5); | ||
794 | d2 = (uint32_t) RD_REG_WORD(®->mailbox0); | ||
795 | barrier(); | ||
796 | } | ||
797 | |||
798 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
799 | |||
800 | ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024; | ||
801 | |||
802 | rval = qla2x00_mbx_reg_test(ha); | ||
803 | if (rval) { | ||
804 | DEBUG(printk("scsi(%ld): Failed mailbox send register test\n", | ||
805 | ha->host_no)); | ||
806 | qla_printk(KERN_WARNING, ha, | ||
807 | "Failed mailbox send register test\n"); | ||
808 | } else { | ||
809 | /* Flag a successful rval */ | ||
810 | rval = QLA_SUCCESS; | ||
811 | } | ||
812 | |||
813 | return rval; | ||
814 | } | ||
815 | |||
816 | static void | ||
817 | qla2x00_alloc_fw_dump(scsi_qla_host_t *ha) | ||
818 | { | ||
819 | ha->fw_dumped = 0; | ||
820 | ha->fw_dump24_len = sizeof(struct qla24xx_fw_dump); | ||
821 | ha->fw_dump24_len += (ha->fw_memory_size - 0x100000) * sizeof(uint32_t); | ||
822 | ha->fw_dump24 = vmalloc(ha->fw_dump24_len); | ||
823 | if (ha->fw_dump24) | ||
824 | qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware " | ||
825 | "dump...\n", ha->fw_dump24_len / 1024); | ||
826 | else | ||
827 | qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for " | ||
828 | "firmware dump!!!\n", ha->fw_dump24_len / 1024); | ||
829 | } | ||
830 | |||
831 | /** | ||
626 | * qla2x00_resize_request_q() - Resize request queue given available ISP memory. | 832 | * qla2x00_resize_request_q() - Resize request queue given available ISP memory. |
627 | * @ha: HA context | 833 | * @ha: HA context |
628 | * | 834 | * |
@@ -641,6 +847,9 @@ qla2x00_resize_request_q(scsi_qla_host_t *ha) | |||
641 | if (IS_QLA2100(ha) || IS_QLA2200(ha)) | 847 | if (IS_QLA2100(ha) || IS_QLA2200(ha)) |
642 | return; | 848 | return; |
643 | 849 | ||
850 | if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) | ||
851 | qla2x00_alloc_fw_dump(ha); | ||
852 | |||
644 | /* Retrieve IOCB counts available to the firmware. */ | 853 | /* Retrieve IOCB counts available to the firmware. */ |
645 | rval = qla2x00_get_resource_cnts(ha, NULL, NULL, NULL, &fw_iocb_cnt); | 854 | rval = qla2x00_get_resource_cnts(ha, NULL, NULL, NULL, &fw_iocb_cnt); |
646 | if (rval) | 855 | if (rval) |
@@ -684,91 +893,22 @@ qla2x00_resize_request_q(scsi_qla_host_t *ha) | |||
684 | static int | 893 | static int |
685 | qla2x00_setup_chip(scsi_qla_host_t *ha) | 894 | qla2x00_setup_chip(scsi_qla_host_t *ha) |
686 | { | 895 | { |
687 | int rval; | 896 | int rval; |
688 | uint16_t cnt; | 897 | uint32_t srisc_address = 0; |
689 | uint16_t *risc_code; | ||
690 | unsigned long risc_address; | ||
691 | unsigned long risc_code_size; | ||
692 | int num; | ||
693 | int i; | ||
694 | uint16_t *req_ring; | ||
695 | struct qla_fw_info *fw_iter; | ||
696 | |||
697 | rval = QLA_SUCCESS; | ||
698 | 898 | ||
699 | /* Load firmware sequences */ | 899 | /* Load firmware sequences */ |
700 | fw_iter = ha->brd_info->fw_info; | 900 | rval = ha->isp_ops.load_risc(ha, &srisc_address); |
701 | while (fw_iter->addressing != FW_INFO_ADDR_NOMORE) { | 901 | if (rval == QLA_SUCCESS) { |
702 | risc_code = fw_iter->fwcode; | ||
703 | risc_code_size = *fw_iter->fwlen; | ||
704 | |||
705 | if (fw_iter->addressing == FW_INFO_ADDR_NORMAL) { | ||
706 | risc_address = *fw_iter->fwstart; | ||
707 | } else { | ||
708 | /* Extended address */ | ||
709 | risc_address = *fw_iter->lfwstart; | ||
710 | } | ||
711 | |||
712 | num = 0; | ||
713 | rval = 0; | ||
714 | while (risc_code_size > 0 && !rval) { | ||
715 | cnt = (uint16_t)(ha->fw_transfer_size >> 1); | ||
716 | if (cnt > risc_code_size) | ||
717 | cnt = risc_code_size; | ||
718 | |||
719 | DEBUG7(printk("scsi(%ld): Loading risc segment@ " | ||
720 | "addr %p, number of bytes 0x%x, offset 0x%lx.\n", | ||
721 | ha->host_no, risc_code, cnt, risc_address)); | ||
722 | |||
723 | req_ring = (uint16_t *)ha->request_ring; | ||
724 | for (i = 0; i < cnt; i++) | ||
725 | req_ring[i] = cpu_to_le16(risc_code[i]); | ||
726 | |||
727 | if (fw_iter->addressing == FW_INFO_ADDR_NORMAL) { | ||
728 | rval = qla2x00_load_ram(ha, | ||
729 | ha->request_dma, risc_address, cnt); | ||
730 | } else { | ||
731 | rval = qla2x00_load_ram_ext(ha, | ||
732 | ha->request_dma, risc_address, cnt); | ||
733 | } | ||
734 | if (rval) { | ||
735 | DEBUG(printk("scsi(%ld): [ERROR] Failed to " | ||
736 | "load segment %d of firmware\n", | ||
737 | ha->host_no, num)); | ||
738 | qla_printk(KERN_WARNING, ha, | ||
739 | "[ERROR] Failed to load " | ||
740 | "segment %d of firmware\n", num); | ||
741 | |||
742 | qla2x00_dump_regs(ha); | ||
743 | break; | ||
744 | } | ||
745 | |||
746 | risc_code += cnt; | ||
747 | risc_address += cnt; | ||
748 | risc_code_size -= cnt; | ||
749 | num++; | ||
750 | } | ||
751 | |||
752 | /* Next firmware sequence */ | ||
753 | fw_iter++; | ||
754 | } | ||
755 | |||
756 | /* Verify checksum of loaded RISC code. */ | ||
757 | if (!rval) { | ||
758 | DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC " | 902 | DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC " |
759 | "code.\n", ha->host_no)); | 903 | "code.\n", ha->host_no)); |
760 | 904 | ||
761 | rval = qla2x00_verify_checksum(ha, | 905 | rval = qla2x00_verify_checksum(ha, srisc_address); |
762 | IS_QLA24XX(ha) || IS_QLA25XX(ha) ? RISC_SADDRESS : | ||
763 | *ha->brd_info->fw_info[0].fwstart); | ||
764 | if (rval == QLA_SUCCESS) { | 906 | if (rval == QLA_SUCCESS) { |
765 | /* Start firmware execution. */ | 907 | /* Start firmware execution. */ |
766 | DEBUG(printk("scsi(%ld): Checksum OK, start " | 908 | DEBUG(printk("scsi(%ld): Checksum OK, start " |
767 | "firmware.\n", ha->host_no)); | 909 | "firmware.\n", ha->host_no)); |
768 | 910 | ||
769 | rval = qla2x00_execute_fw(ha, | 911 | rval = qla2x00_execute_fw(ha, srisc_address); |
770 | IS_QLA24XX(ha) || IS_QLA25XX(ha) ? RISC_SADDRESS : | ||
771 | *ha->brd_info->fw_info[0].fwstart); | ||
772 | /* Retrieve firmware information. */ | 912 | /* Retrieve firmware information. */ |
773 | if (rval == QLA_SUCCESS && ha->fw_major_version == 0) { | 913 | if (rval == QLA_SUCCESS && ha->fw_major_version == 0) { |
774 | qla2x00_get_fw_version(ha, | 914 | qla2x00_get_fw_version(ha, |
@@ -893,6 +1033,23 @@ qla2x00_update_fw_options(scsi_qla_host_t *ha) | |||
893 | } | 1033 | } |
894 | 1034 | ||
895 | void | 1035 | void |
1036 | qla24xx_update_fw_options(scsi_qla_host_t *ha) | ||
1037 | { | ||
1038 | int rval; | ||
1039 | |||
1040 | /* Update Serial Link options. */ | ||
1041 | if ((ha->fw_seriallink_options24[0] & BIT_0) == 0) | ||
1042 | return; | ||
1043 | |||
1044 | rval = qla2x00_set_serdes_params(ha, ha->fw_seriallink_options24[1], | ||
1045 | ha->fw_seriallink_options24[2], ha->fw_seriallink_options24[3]); | ||
1046 | if (rval != QLA_SUCCESS) { | ||
1047 | qla_printk(KERN_WARNING, ha, | ||
1048 | "Unable to update Serial Link options (%x).\n", rval); | ||
1049 | } | ||
1050 | } | ||
1051 | |||
1052 | void | ||
896 | qla2x00_config_rings(struct scsi_qla_host *ha) | 1053 | qla2x00_config_rings(struct scsi_qla_host *ha) |
897 | { | 1054 | { |
898 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; | 1055 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; |
@@ -914,6 +1071,30 @@ qla2x00_config_rings(struct scsi_qla_host *ha) | |||
914 | RD_REG_WORD(ISP_RSP_Q_OUT(ha, reg)); /* PCI Posting. */ | 1071 | RD_REG_WORD(ISP_RSP_Q_OUT(ha, reg)); /* PCI Posting. */ |
915 | } | 1072 | } |
916 | 1073 | ||
1074 | void | ||
1075 | qla24xx_config_rings(struct scsi_qla_host *ha) | ||
1076 | { | ||
1077 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
1078 | struct init_cb_24xx *icb; | ||
1079 | |||
1080 | /* Setup ring parameters in initialization control block. */ | ||
1081 | icb = (struct init_cb_24xx *)ha->init_cb; | ||
1082 | icb->request_q_outpointer = __constant_cpu_to_le16(0); | ||
1083 | icb->response_q_inpointer = __constant_cpu_to_le16(0); | ||
1084 | icb->request_q_length = cpu_to_le16(ha->request_q_length); | ||
1085 | icb->response_q_length = cpu_to_le16(ha->response_q_length); | ||
1086 | icb->request_q_address[0] = cpu_to_le32(LSD(ha->request_dma)); | ||
1087 | icb->request_q_address[1] = cpu_to_le32(MSD(ha->request_dma)); | ||
1088 | icb->response_q_address[0] = cpu_to_le32(LSD(ha->response_dma)); | ||
1089 | icb->response_q_address[1] = cpu_to_le32(MSD(ha->response_dma)); | ||
1090 | |||
1091 | WRT_REG_DWORD(®->req_q_in, 0); | ||
1092 | WRT_REG_DWORD(®->req_q_out, 0); | ||
1093 | WRT_REG_DWORD(®->rsp_q_in, 0); | ||
1094 | WRT_REG_DWORD(®->rsp_q_out, 0); | ||
1095 | RD_REG_DWORD(®->rsp_q_out); | ||
1096 | } | ||
1097 | |||
917 | /** | 1098 | /** |
918 | * qla2x00_init_rings() - Initializes firmware. | 1099 | * qla2x00_init_rings() - Initializes firmware. |
919 | * @ha: HA context | 1100 | * @ha: HA context |
@@ -960,7 +1141,7 @@ qla2x00_init_rings(scsi_qla_host_t *ha) | |||
960 | ha->isp_ops.update_fw_options(ha); | 1141 | ha->isp_ops.update_fw_options(ha); |
961 | 1142 | ||
962 | DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no)); | 1143 | DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no)); |
963 | rval = qla2x00_init_firmware(ha, sizeof(init_cb_t)); | 1144 | rval = qla2x00_init_firmware(ha, ha->init_cb_size); |
964 | if (rval) { | 1145 | if (rval) { |
965 | DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n", | 1146 | DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n", |
966 | ha->host_no)); | 1147 | ha->host_no)); |
@@ -1195,38 +1376,33 @@ qla2x00_configure_hba(scsi_qla_host_t *ha) | |||
1195 | int | 1376 | int |
1196 | qla2x00_nvram_config(scsi_qla_host_t *ha) | 1377 | qla2x00_nvram_config(scsi_qla_host_t *ha) |
1197 | { | 1378 | { |
1198 | int rval; | 1379 | int rval; |
1199 | uint8_t chksum = 0; | 1380 | uint8_t chksum = 0; |
1200 | uint16_t cnt; | 1381 | uint16_t cnt; |
1201 | uint8_t *dptr1, *dptr2; | 1382 | uint8_t *dptr1, *dptr2; |
1202 | init_cb_t *icb = ha->init_cb; | 1383 | init_cb_t *icb = ha->init_cb; |
1203 | nvram_t *nv = (nvram_t *)ha->request_ring; | 1384 | nvram_t *nv = (nvram_t *)ha->request_ring; |
1204 | uint16_t *wptr = (uint16_t *)ha->request_ring; | 1385 | uint8_t *ptr = (uint8_t *)ha->request_ring; |
1205 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; | 1386 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; |
1206 | uint8_t timer_mode; | 1387 | uint8_t timer_mode; |
1207 | 1388 | ||
1208 | rval = QLA_SUCCESS; | 1389 | rval = QLA_SUCCESS; |
1209 | 1390 | ||
1210 | /* Determine NVRAM starting address. */ | 1391 | /* Determine NVRAM starting address. */ |
1392 | ha->nvram_size = sizeof(nvram_t); | ||
1211 | ha->nvram_base = 0; | 1393 | ha->nvram_base = 0; |
1212 | if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) | 1394 | if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) |
1213 | if ((RD_REG_WORD(®->ctrl_status) >> 14) == 1) | 1395 | if ((RD_REG_WORD(®->ctrl_status) >> 14) == 1) |
1214 | ha->nvram_base = 0x80; | 1396 | ha->nvram_base = 0x80; |
1215 | 1397 | ||
1216 | /* Get NVRAM data and calculate checksum. */ | 1398 | /* Get NVRAM data and calculate checksum. */ |
1217 | qla2x00_lock_nvram_access(ha); | 1399 | ha->isp_ops.read_nvram(ha, ptr, ha->nvram_base, ha->nvram_size); |
1218 | for (cnt = 0; cnt < sizeof(nvram_t)/2; cnt++) { | 1400 | for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++) |
1219 | *wptr = cpu_to_le16(qla2x00_get_nvram_word(ha, | 1401 | chksum += *ptr++; |
1220 | (cnt+ha->nvram_base))); | ||
1221 | chksum += (uint8_t)*wptr; | ||
1222 | chksum += (uint8_t)(*wptr >> 8); | ||
1223 | wptr++; | ||
1224 | } | ||
1225 | qla2x00_unlock_nvram_access(ha); | ||
1226 | 1402 | ||
1227 | DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no)); | 1403 | DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no)); |
1228 | DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring, | 1404 | DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring, |
1229 | sizeof(nvram_t))); | 1405 | ha->nvram_size)); |
1230 | 1406 | ||
1231 | /* Bad NVRAM data, set defaults parameters. */ | 1407 | /* Bad NVRAM data, set defaults parameters. */ |
1232 | if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || | 1408 | if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || |
@@ -1241,7 +1417,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) | |||
1241 | /* | 1417 | /* |
1242 | * Set default initialization control block. | 1418 | * Set default initialization control block. |
1243 | */ | 1419 | */ |
1244 | memset(nv, 0, sizeof(nvram_t)); | 1420 | memset(nv, 0, ha->nvram_size); |
1245 | nv->parameter_block_version = ICB_VERSION; | 1421 | nv->parameter_block_version = ICB_VERSION; |
1246 | 1422 | ||
1247 | if (IS_QLA23XX(ha)) { | 1423 | if (IS_QLA23XX(ha)) { |
@@ -1301,7 +1477,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) | |||
1301 | #endif | 1477 | #endif |
1302 | 1478 | ||
1303 | /* Reset Initialization control block */ | 1479 | /* Reset Initialization control block */ |
1304 | memset(icb, 0, sizeof(init_cb_t)); | 1480 | memset(icb, 0, ha->init_cb_size); |
1305 | 1481 | ||
1306 | /* | 1482 | /* |
1307 | * Setup driver NVRAM options. | 1483 | * Setup driver NVRAM options. |
@@ -1314,6 +1490,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) | |||
1314 | if (IS_QLA23XX(ha)) { | 1490 | if (IS_QLA23XX(ha)) { |
1315 | nv->firmware_options[0] |= BIT_2; | 1491 | nv->firmware_options[0] |= BIT_2; |
1316 | nv->firmware_options[0] &= ~BIT_3; | 1492 | nv->firmware_options[0] &= ~BIT_3; |
1493 | nv->add_firmware_options[1] |= BIT_5 | BIT_4; | ||
1317 | 1494 | ||
1318 | if (IS_QLA2300(ha)) { | 1495 | if (IS_QLA2300(ha)) { |
1319 | if (ha->fb_rev == FPM_2310) { | 1496 | if (ha->fb_rev == FPM_2310) { |
@@ -1941,10 +2118,15 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) | |||
1941 | fc_port_t *fcport, *fcptemp; | 2118 | fc_port_t *fcport, *fcptemp; |
1942 | uint16_t next_loopid; | 2119 | uint16_t next_loopid; |
1943 | uint16_t mb[MAILBOX_REGISTER_COUNT]; | 2120 | uint16_t mb[MAILBOX_REGISTER_COUNT]; |
2121 | uint16_t loop_id; | ||
1944 | LIST_HEAD(new_fcports); | 2122 | LIST_HEAD(new_fcports); |
1945 | 2123 | ||
1946 | /* If FL port exists, then SNS is present */ | 2124 | /* If FL port exists, then SNS is present */ |
1947 | rval = qla2x00_get_port_name(ha, SNS_FL_PORT, NULL, 0); | 2125 | if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) |
2126 | loop_id = NPH_F_PORT; | ||
2127 | else | ||
2128 | loop_id = SNS_FL_PORT; | ||
2129 | rval = qla2x00_get_port_name(ha, loop_id, NULL, 0); | ||
1948 | if (rval != QLA_SUCCESS) { | 2130 | if (rval != QLA_SUCCESS) { |
1949 | DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL " | 2131 | DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL " |
1950 | "Port\n", ha->host_no)); | 2132 | "Port\n", ha->host_no)); |
@@ -1961,12 +2143,16 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) | |||
1961 | } | 2143 | } |
1962 | do { | 2144 | do { |
1963 | /* Ensure we are logged into the SNS. */ | 2145 | /* Ensure we are logged into the SNS. */ |
1964 | ha->isp_ops.fabric_login(ha, SIMPLE_NAME_SERVER, 0xff, 0xff, | 2146 | if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) |
2147 | loop_id = NPH_SNS; | ||
2148 | else | ||
2149 | loop_id = SIMPLE_NAME_SERVER; | ||
2150 | ha->isp_ops.fabric_login(ha, loop_id, 0xff, 0xff, | ||
1965 | 0xfc, mb, BIT_1 | BIT_0); | 2151 | 0xfc, mb, BIT_1 | BIT_0); |
1966 | if (mb[0] != MBS_COMMAND_COMPLETE) { | 2152 | if (mb[0] != MBS_COMMAND_COMPLETE) { |
1967 | DEBUG2(qla_printk(KERN_INFO, ha, | 2153 | DEBUG2(qla_printk(KERN_INFO, ha, |
1968 | "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x " | 2154 | "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x " |
1969 | "mb[2]=%x mb[6]=%x mb[7]=%x\n", SIMPLE_NAME_SERVER, | 2155 | "mb[2]=%x mb[6]=%x mb[7]=%x\n", loop_id, |
1970 | mb[0], mb[1], mb[2], mb[6], mb[7])); | 2156 | mb[0], mb[1], mb[2], mb[6], mb[7])); |
1971 | return (QLA_SUCCESS); | 2157 | return (QLA_SUCCESS); |
1972 | } | 2158 | } |
@@ -2050,7 +2236,6 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) | |||
2050 | break; | 2236 | break; |
2051 | } | 2237 | } |
2052 | } | 2238 | } |
2053 | |||
2054 | /* Login and update database */ | 2239 | /* Login and update database */ |
2055 | qla2x00_fabric_dev_login(ha, fcport, &next_loopid); | 2240 | qla2x00_fabric_dev_login(ha, fcport, &next_loopid); |
2056 | } | 2241 | } |
@@ -2164,7 +2349,6 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) | |||
2164 | 2349 | ||
2165 | /* Starting free loop ID. */ | 2350 | /* Starting free loop ID. */ |
2166 | loop_id = ha->min_external_loopid; | 2351 | loop_id = ha->min_external_loopid; |
2167 | |||
2168 | for (; loop_id <= ha->last_loop_id; loop_id++) { | 2352 | for (; loop_id <= ha->last_loop_id; loop_id++) { |
2169 | if (qla2x00_is_reserved_id(ha, loop_id)) | 2353 | if (qla2x00_is_reserved_id(ha, loop_id)) |
2170 | continue; | 2354 | continue; |
@@ -2450,6 +2634,7 @@ qla2x00_device_resync(scsi_qla_host_t *ha) | |||
2450 | case 0: | 2634 | case 0: |
2451 | if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && | 2635 | if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && |
2452 | !IS_QLA6312(ha) && !IS_QLA6322(ha) && | 2636 | !IS_QLA6312(ha) && !IS_QLA6322(ha) && |
2637 | !IS_QLA24XX(ha) && !IS_QLA25XX(ha) && | ||
2453 | ha->flags.init_done) { | 2638 | ha->flags.init_done) { |
2454 | /* Handle port RSCN via asyncronous IOCBs */ | 2639 | /* Handle port RSCN via asyncronous IOCBs */ |
2455 | rval2 = qla2x00_handle_port_rscn(ha, rscn_entry, | 2640 | rval2 = qla2x00_handle_port_rscn(ha, rscn_entry, |
@@ -2518,17 +2703,24 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *ha, fc_port_t *fcport, | |||
2518 | { | 2703 | { |
2519 | int rval; | 2704 | int rval; |
2520 | int retry; | 2705 | int retry; |
2706 | uint8_t opts; | ||
2521 | 2707 | ||
2522 | rval = QLA_SUCCESS; | 2708 | rval = QLA_SUCCESS; |
2523 | retry = 0; | 2709 | retry = 0; |
2524 | 2710 | ||
2525 | rval = qla2x00_fabric_login(ha, fcport, next_loopid); | 2711 | rval = qla2x00_fabric_login(ha, fcport, next_loopid); |
2526 | if (rval == QLA_SUCCESS) { | 2712 | if (rval == QLA_SUCCESS) { |
2527 | rval = qla2x00_get_port_database(ha, fcport, 0); | 2713 | /* Send an ADISC to tape devices.*/ |
2714 | opts = 0; | ||
2715 | if (fcport->flags & FCF_TAPE_PRESENT) | ||
2716 | opts |= BIT_1; | ||
2717 | rval = qla2x00_get_port_database(ha, fcport, opts); | ||
2528 | if (rval != QLA_SUCCESS) { | 2718 | if (rval != QLA_SUCCESS) { |
2529 | ha->isp_ops.fabric_logout(ha, fcport->loop_id, | 2719 | ha->isp_ops.fabric_logout(ha, fcport->loop_id, |
2530 | fcport->d_id.b.domain, fcport->d_id.b.area, | 2720 | fcport->d_id.b.domain, fcport->d_id.b.area, |
2531 | fcport->d_id.b.al_pa); | 2721 | fcport->d_id.b.al_pa); |
2722 | qla2x00_mark_device_lost(ha, fcport, 1); | ||
2723 | |||
2532 | } else { | 2724 | } else { |
2533 | qla2x00_update_fcport(ha, fcport); | 2725 | qla2x00_update_fcport(ha, fcport); |
2534 | } | 2726 | } |
@@ -2576,10 +2768,10 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport, | |||
2576 | if (mb[0] == MBS_PORT_ID_USED) { | 2768 | if (mb[0] == MBS_PORT_ID_USED) { |
2577 | /* | 2769 | /* |
2578 | * Device has another loop ID. The firmware team | 2770 | * Device has another loop ID. The firmware team |
2579 | * recommends us to perform an implicit login with the | 2771 | * recommends the driver perform an implicit login with |
2580 | * specified ID again. The ID we just used is save here | 2772 | * the specified ID again. The ID we just used is save |
2581 | * so we return with an ID that can be tried by the | 2773 | * here so we return with an ID that can be tried by |
2582 | * next login. | 2774 | * the next login. |
2583 | */ | 2775 | */ |
2584 | retry++; | 2776 | retry++; |
2585 | tmp_loopid = fcport->loop_id; | 2777 | tmp_loopid = fcport->loop_id; |
@@ -2723,14 +2915,11 @@ qla2x00_loop_resync(scsi_qla_host_t *ha) | |||
2723 | /* Wait at most MAX_TARGET RSCNs for a stable link. */ | 2915 | /* Wait at most MAX_TARGET RSCNs for a stable link. */ |
2724 | wait_time = 256; | 2916 | wait_time = 256; |
2725 | do { | 2917 | do { |
2726 | /* v2.19.05b6 */ | ||
2727 | atomic_set(&ha->loop_state, LOOP_UPDATE); | 2918 | atomic_set(&ha->loop_state, LOOP_UPDATE); |
2728 | 2919 | ||
2729 | /* | 2920 | /* Issue a marker after FW becomes ready. */ |
2730 | * Issue marker command only when we are going | 2921 | qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); |
2731 | * to start the I/O . | 2922 | ha->marker_needed = 0; |
2732 | */ | ||
2733 | ha->marker_needed = 1; | ||
2734 | 2923 | ||
2735 | /* Remap devices on Loop. */ | 2924 | /* Remap devices on Loop. */ |
2736 | clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); | 2925 | clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); |
@@ -2862,7 +3051,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) | |||
2862 | } else { /* schedule another ISP abort */ | 3051 | } else { /* schedule another ISP abort */ |
2863 | ha->isp_abort_cnt--; | 3052 | ha->isp_abort_cnt--; |
2864 | DEBUG(printk("qla%ld: ISP abort - " | 3053 | DEBUG(printk("qla%ld: ISP abort - " |
2865 | "retry remainning %d\n", | 3054 | "retry remaining %d\n", |
2866 | ha->host_no, ha->isp_abort_cnt);) | 3055 | ha->host_no, ha->isp_abort_cnt);) |
2867 | status = 1; | 3056 | status = 1; |
2868 | } | 3057 | } |
@@ -2919,9 +3108,15 @@ qla2x00_restart_isp(scsi_qla_host_t *ha) | |||
2919 | 3108 | ||
2920 | spin_lock_irqsave(&ha->hardware_lock, flags); | 3109 | spin_lock_irqsave(&ha->hardware_lock, flags); |
2921 | 3110 | ||
2922 | /* Disable SRAM, Instruction RAM and GP RAM parity. */ | 3111 | if (!IS_QLA24XX(ha) && !IS_QLA25XX(ha)) { |
2923 | WRT_REG_WORD(®->hccr, (HCCR_ENABLE_PARITY + 0x0)); | 3112 | /* |
2924 | RD_REG_WORD(®->hccr); /* PCI Posting. */ | 3113 | * Disable SRAM, Instruction RAM and GP RAM |
3114 | * parity. | ||
3115 | */ | ||
3116 | WRT_REG_WORD(®->hccr, | ||
3117 | (HCCR_ENABLE_PARITY + 0x0)); | ||
3118 | RD_REG_WORD(®->hccr); | ||
3119 | } | ||
2925 | 3120 | ||
2926 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 3121 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
2927 | 3122 | ||
@@ -2929,16 +3124,21 @@ qla2x00_restart_isp(scsi_qla_host_t *ha) | |||
2929 | 3124 | ||
2930 | spin_lock_irqsave(&ha->hardware_lock, flags); | 3125 | spin_lock_irqsave(&ha->hardware_lock, flags); |
2931 | 3126 | ||
2932 | /* Enable proper parity */ | 3127 | if (!IS_QLA24XX(ha) && !IS_QLA25XX(ha)) { |
2933 | if (IS_QLA2300(ha)) | 3128 | /* Enable proper parity */ |
2934 | /* SRAM parity */ | 3129 | if (IS_QLA2300(ha)) |
2935 | WRT_REG_WORD(®->hccr, | 3130 | /* SRAM parity */ |
2936 | (HCCR_ENABLE_PARITY + 0x1)); | 3131 | WRT_REG_WORD(®->hccr, |
2937 | else | 3132 | (HCCR_ENABLE_PARITY + 0x1)); |
2938 | /* SRAM, Instruction RAM and GP RAM parity */ | 3133 | else |
2939 | WRT_REG_WORD(®->hccr, | 3134 | /* |
2940 | (HCCR_ENABLE_PARITY + 0x7)); | 3135 | * SRAM, Instruction RAM and GP RAM |
2941 | RD_REG_WORD(®->hccr); /* PCI Posting. */ | 3136 | * parity. |
3137 | */ | ||
3138 | WRT_REG_WORD(®->hccr, | ||
3139 | (HCCR_ENABLE_PARITY + 0x7)); | ||
3140 | RD_REG_WORD(®->hccr); | ||
3141 | } | ||
2942 | 3142 | ||
2943 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 3143 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
2944 | } | 3144 | } |
@@ -2949,9 +3149,11 @@ qla2x00_restart_isp(scsi_qla_host_t *ha) | |||
2949 | clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); | 3149 | clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); |
2950 | if (!(status = qla2x00_fw_ready(ha))) { | 3150 | if (!(status = qla2x00_fw_ready(ha))) { |
2951 | DEBUG(printk("%s(): Start configure loop, " | 3151 | DEBUG(printk("%s(): Start configure loop, " |
2952 | "status = %d\n", | 3152 | "status = %d\n", __func__, status);) |
2953 | __func__, | 3153 | |
2954 | status);) | 3154 | /* Issue a marker after FW becomes ready. */ |
3155 | qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); | ||
3156 | |||
2955 | ha->flags.online = 1; | 3157 | ha->flags.online = 1; |
2956 | /* Wait at most MAX_TARGET RSCNs for a stable link. */ | 3158 | /* Wait at most MAX_TARGET RSCNs for a stable link. */ |
2957 | wait_time = 256; | 3159 | wait_time = 256; |
@@ -2992,7 +3194,6 @@ qla2x00_reset_adapter(scsi_qla_host_t *ha) | |||
2992 | ha->flags.online = 0; | 3194 | ha->flags.online = 0; |
2993 | ha->isp_ops.disable_intrs(ha); | 3195 | ha->isp_ops.disable_intrs(ha); |
2994 | 3196 | ||
2995 | /* Reset RISC processor. */ | ||
2996 | spin_lock_irqsave(&ha->hardware_lock, flags); | 3197 | spin_lock_irqsave(&ha->hardware_lock, flags); |
2997 | WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); | 3198 | WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); |
2998 | RD_REG_WORD(®->hccr); /* PCI Posting. */ | 3199 | RD_REG_WORD(®->hccr); /* PCI Posting. */ |
@@ -3000,3 +3201,505 @@ qla2x00_reset_adapter(scsi_qla_host_t *ha) | |||
3000 | RD_REG_WORD(®->hccr); /* PCI Posting. */ | 3201 | RD_REG_WORD(®->hccr); /* PCI Posting. */ |
3001 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 3202 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
3002 | } | 3203 | } |
3204 | |||
3205 | void | ||
3206 | qla24xx_reset_adapter(scsi_qla_host_t *ha) | ||
3207 | { | ||
3208 | unsigned long flags = 0; | ||
3209 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
3210 | |||
3211 | ha->flags.online = 0; | ||
3212 | ha->isp_ops.disable_intrs(ha); | ||
3213 | |||
3214 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
3215 | WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET); | ||
3216 | RD_REG_DWORD(®->hccr); | ||
3217 | WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); | ||
3218 | RD_REG_DWORD(®->hccr); | ||
3219 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
3220 | } | ||
3221 | |||
3222 | int | ||
3223 | qla24xx_nvram_config(scsi_qla_host_t *ha) | ||
3224 | { | ||
3225 | int rval; | ||
3226 | struct init_cb_24xx *icb; | ||
3227 | struct nvram_24xx *nv; | ||
3228 | uint32_t *dptr; | ||
3229 | uint8_t *dptr1, *dptr2; | ||
3230 | uint32_t chksum; | ||
3231 | uint16_t cnt; | ||
3232 | |||
3233 | rval = QLA_SUCCESS; | ||
3234 | icb = (struct init_cb_24xx *)ha->init_cb; | ||
3235 | nv = (struct nvram_24xx *)ha->request_ring; | ||
3236 | |||
3237 | /* Determine NVRAM starting address. */ | ||
3238 | ha->nvram_size = sizeof(struct nvram_24xx); | ||
3239 | ha->nvram_base = FA_NVRAM_FUNC0_ADDR; | ||
3240 | if (PCI_FUNC(ha->pdev->devfn)) | ||
3241 | ha->nvram_base = FA_NVRAM_FUNC1_ADDR; | ||
3242 | |||
3243 | /* Get NVRAM data and calculate checksum. */ | ||
3244 | dptr = (uint32_t *)nv; | ||
3245 | ha->isp_ops.read_nvram(ha, (uint8_t *)dptr, ha->nvram_base, | ||
3246 | ha->nvram_size); | ||
3247 | for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++) | ||
3248 | chksum += le32_to_cpu(*dptr++); | ||
3249 | |||
3250 | DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no)); | ||
3251 | DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring, | ||
3252 | ha->nvram_size)); | ||
3253 | |||
3254 | /* Bad NVRAM data, set defaults parameters. */ | ||
3255 | if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P' | ||
3256 | || nv->id[3] != ' ' || | ||
3257 | nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) { | ||
3258 | /* Reset NVRAM data. */ | ||
3259 | qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: " | ||
3260 | "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0], | ||
3261 | le16_to_cpu(nv->nvram_version)); | ||
3262 | qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet " | ||
3263 | "invalid -- WWPN) defaults.\n"); | ||
3264 | |||
3265 | /* | ||
3266 | * Set default initialization control block. | ||
3267 | */ | ||
3268 | memset(nv, 0, ha->nvram_size); | ||
3269 | nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION); | ||
3270 | nv->version = __constant_cpu_to_le16(ICB_VERSION); | ||
3271 | nv->frame_payload_size = __constant_cpu_to_le16(2048); | ||
3272 | nv->execution_throttle = __constant_cpu_to_le16(0xFFFF); | ||
3273 | nv->exchange_count = __constant_cpu_to_le16(0); | ||
3274 | nv->hard_address = __constant_cpu_to_le16(124); | ||
3275 | nv->port_name[0] = 0x21; | ||
3276 | nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn); | ||
3277 | nv->port_name[2] = 0x00; | ||
3278 | nv->port_name[3] = 0xe0; | ||
3279 | nv->port_name[4] = 0x8b; | ||
3280 | nv->port_name[5] = 0x1c; | ||
3281 | nv->port_name[6] = 0x55; | ||
3282 | nv->port_name[7] = 0x86; | ||
3283 | nv->node_name[0] = 0x20; | ||
3284 | nv->node_name[1] = 0x00; | ||
3285 | nv->node_name[2] = 0x00; | ||
3286 | nv->node_name[3] = 0xe0; | ||
3287 | nv->node_name[4] = 0x8b; | ||
3288 | nv->node_name[5] = 0x1c; | ||
3289 | nv->node_name[6] = 0x55; | ||
3290 | nv->node_name[7] = 0x86; | ||
3291 | nv->login_retry_count = __constant_cpu_to_le16(8); | ||
3292 | nv->link_down_timeout = __constant_cpu_to_le16(200); | ||
3293 | nv->interrupt_delay_timer = __constant_cpu_to_le16(0); | ||
3294 | nv->login_timeout = __constant_cpu_to_le16(0); | ||
3295 | nv->firmware_options_1 = | ||
3296 | __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1); | ||
3297 | nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4); | ||
3298 | nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12); | ||
3299 | nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13); | ||
3300 | nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10); | ||
3301 | nv->efi_parameters = __constant_cpu_to_le32(0); | ||
3302 | nv->reset_delay = 5; | ||
3303 | nv->max_luns_per_target = __constant_cpu_to_le16(128); | ||
3304 | nv->port_down_retry_count = __constant_cpu_to_le16(30); | ||
3305 | nv->link_down_timeout = __constant_cpu_to_le16(30); | ||
3306 | |||
3307 | rval = 1; | ||
3308 | } | ||
3309 | |||
3310 | /* Reset Initialization control block */ | ||
3311 | memset(icb, 0, sizeof(struct init_cb_24xx)); | ||
3312 | |||
3313 | /* Copy 1st segment. */ | ||
3314 | dptr1 = (uint8_t *)icb; | ||
3315 | dptr2 = (uint8_t *)&nv->version; | ||
3316 | cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version; | ||
3317 | while (cnt--) | ||
3318 | *dptr1++ = *dptr2++; | ||
3319 | |||
3320 | icb->login_retry_count = nv->login_retry_count; | ||
3321 | icb->link_down_timeout = nv->link_down_timeout; | ||
3322 | |||
3323 | /* Copy 2nd segment. */ | ||
3324 | dptr1 = (uint8_t *)&icb->interrupt_delay_timer; | ||
3325 | dptr2 = (uint8_t *)&nv->interrupt_delay_timer; | ||
3326 | cnt = (uint8_t *)&icb->reserved_3 - | ||
3327 | (uint8_t *)&icb->interrupt_delay_timer; | ||
3328 | while (cnt--) | ||
3329 | *dptr1++ = *dptr2++; | ||
3330 | |||
3331 | /* | ||
3332 | * Setup driver NVRAM options. | ||
3333 | */ | ||
3334 | if (memcmp(nv->model_name, BINZERO, sizeof(nv->model_name)) != 0) { | ||
3335 | char *st, *en; | ||
3336 | uint16_t index; | ||
3337 | |||
3338 | strncpy(ha->model_number, nv->model_name, | ||
3339 | sizeof(nv->model_name)); | ||
3340 | st = en = ha->model_number; | ||
3341 | en += sizeof(nv->model_name) - 1; | ||
3342 | while (en > st) { | ||
3343 | if (*en != 0x20 && *en != 0x00) | ||
3344 | break; | ||
3345 | *en-- = '\0'; | ||
3346 | } | ||
3347 | |||
3348 | index = (ha->pdev->subsystem_device & 0xff); | ||
3349 | if (index < QLA_MODEL_NAMES) | ||
3350 | ha->model_desc = qla2x00_model_desc[index]; | ||
3351 | } else | ||
3352 | strcpy(ha->model_number, "QLA2462"); | ||
3353 | |||
3354 | /* Prepare nodename */ | ||
3355 | if ((icb->firmware_options_1 & BIT_14) == 0) { | ||
3356 | /* | ||
3357 | * Firmware will apply the following mask if the nodename was | ||
3358 | * not provided. | ||
3359 | */ | ||
3360 | memcpy(icb->node_name, icb->port_name, WWN_SIZE); | ||
3361 | icb->node_name[0] &= 0xF0; | ||
3362 | } | ||
3363 | |||
3364 | /* Set host adapter parameters. */ | ||
3365 | ha->flags.disable_risc_code_load = 0; | ||
3366 | ha->flags.enable_lip_reset = 1; | ||
3367 | ha->flags.enable_lip_full_login = 1; | ||
3368 | ha->flags.enable_target_reset = 1; | ||
3369 | ha->flags.enable_led_scheme = 0; | ||
3370 | |||
3371 | ha->operating_mode = | ||
3372 | (icb->firmware_options_2 & (BIT_6 | BIT_5 | BIT_4)) >> 4; | ||
3373 | |||
3374 | memcpy(ha->fw_seriallink_options24, nv->seriallink_options, | ||
3375 | sizeof(ha->fw_seriallink_options24)); | ||
3376 | |||
3377 | /* save HBA serial number */ | ||
3378 | ha->serial0 = icb->port_name[5]; | ||
3379 | ha->serial1 = icb->port_name[6]; | ||
3380 | ha->serial2 = icb->port_name[7]; | ||
3381 | ha->node_name = icb->node_name; | ||
3382 | ha->port_name = icb->port_name; | ||
3383 | |||
3384 | ha->retry_count = le16_to_cpu(nv->login_retry_count); | ||
3385 | |||
3386 | /* Set minimum login_timeout to 4 seconds. */ | ||
3387 | if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout) | ||
3388 | nv->login_timeout = cpu_to_le16(ql2xlogintimeout); | ||
3389 | if (le16_to_cpu(nv->login_timeout) < 4) | ||
3390 | nv->login_timeout = __constant_cpu_to_le16(4); | ||
3391 | ha->login_timeout = le16_to_cpu(nv->login_timeout); | ||
3392 | icb->login_timeout = cpu_to_le16(nv->login_timeout); | ||
3393 | |||
3394 | /* Set minimum RATOV to 200 tenths of a second. */ | ||
3395 | ha->r_a_tov = 200; | ||
3396 | |||
3397 | ha->loop_reset_delay = nv->reset_delay; | ||
3398 | |||
3399 | /* Link Down Timeout = 0: | ||
3400 | * | ||
3401 | * When Port Down timer expires we will start returning | ||
3402 | * I/O's to OS with "DID_NO_CONNECT". | ||
3403 | * | ||
3404 | * Link Down Timeout != 0: | ||
3405 | * | ||
3406 | * The driver waits for the link to come up after link down | ||
3407 | * before returning I/Os to OS with "DID_NO_CONNECT". | ||
3408 | */ | ||
3409 | if (le16_to_cpu(nv->link_down_timeout) == 0) { | ||
3410 | ha->loop_down_abort_time = | ||
3411 | (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT); | ||
3412 | } else { | ||
3413 | ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout); | ||
3414 | ha->loop_down_abort_time = | ||
3415 | (LOOP_DOWN_TIME - ha->link_down_timeout); | ||
3416 | } | ||
3417 | |||
3418 | /* Need enough time to try and get the port back. */ | ||
3419 | ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count); | ||
3420 | if (qlport_down_retry) | ||
3421 | ha->port_down_retry_count = qlport_down_retry; | ||
3422 | |||
3423 | /* Set login_retry_count */ | ||
3424 | ha->login_retry_count = le16_to_cpu(nv->login_retry_count); | ||
3425 | if (ha->port_down_retry_count == | ||
3426 | le16_to_cpu(nv->port_down_retry_count) && | ||
3427 | ha->port_down_retry_count > 3) | ||
3428 | ha->login_retry_count = ha->port_down_retry_count; | ||
3429 | else if (ha->port_down_retry_count > (int)ha->login_retry_count) | ||
3430 | ha->login_retry_count = ha->port_down_retry_count; | ||
3431 | if (ql2xloginretrycount) | ||
3432 | ha->login_retry_count = ql2xloginretrycount; | ||
3433 | |||
3434 | if (rval) { | ||
3435 | DEBUG2_3(printk(KERN_WARNING | ||
3436 | "scsi(%ld): NVRAM configuration failed!\n", ha->host_no)); | ||
3437 | } | ||
3438 | return (rval); | ||
3439 | } | ||
3440 | |||
3441 | int | ||
3442 | qla2x00_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr) | ||
3443 | { | ||
3444 | int rval; | ||
3445 | uint16_t cnt; | ||
3446 | uint16_t *risc_code; | ||
3447 | unsigned long risc_address; | ||
3448 | unsigned long risc_code_size; | ||
3449 | int num; | ||
3450 | int i; | ||
3451 | uint16_t *req_ring; | ||
3452 | struct qla_fw_info *fw_iter; | ||
3453 | |||
3454 | rval = QLA_SUCCESS; | ||
3455 | |||
3456 | /* Load firmware sequences */ | ||
3457 | fw_iter = ha->brd_info->fw_info; | ||
3458 | *srisc_addr = *ha->brd_info->fw_info->fwstart; | ||
3459 | while (fw_iter->addressing != FW_INFO_ADDR_NOMORE) { | ||
3460 | risc_code = fw_iter->fwcode; | ||
3461 | risc_code_size = *fw_iter->fwlen; | ||
3462 | |||
3463 | if (fw_iter->addressing == FW_INFO_ADDR_NORMAL) { | ||
3464 | risc_address = *fw_iter->fwstart; | ||
3465 | } else { | ||
3466 | /* Extended address */ | ||
3467 | risc_address = *fw_iter->lfwstart; | ||
3468 | } | ||
3469 | |||
3470 | num = 0; | ||
3471 | rval = 0; | ||
3472 | while (risc_code_size > 0 && !rval) { | ||
3473 | cnt = (uint16_t)(ha->fw_transfer_size >> 1); | ||
3474 | if (cnt > risc_code_size) | ||
3475 | cnt = risc_code_size; | ||
3476 | |||
3477 | DEBUG7(printk("scsi(%ld): Loading risc segment@ " | ||
3478 | "addr %p, number of bytes 0x%x, offset 0x%lx.\n", | ||
3479 | ha->host_no, risc_code, cnt, risc_address)); | ||
3480 | |||
3481 | req_ring = (uint16_t *)ha->request_ring; | ||
3482 | for (i = 0; i < cnt; i++) | ||
3483 | req_ring[i] = cpu_to_le16(risc_code[i]); | ||
3484 | |||
3485 | if (fw_iter->addressing == FW_INFO_ADDR_NORMAL) { | ||
3486 | rval = qla2x00_load_ram(ha, ha->request_dma, | ||
3487 | risc_address, cnt); | ||
3488 | } else { | ||
3489 | rval = qla2x00_load_ram_ext(ha, | ||
3490 | ha->request_dma, risc_address, cnt); | ||
3491 | } | ||
3492 | if (rval) { | ||
3493 | DEBUG(printk("scsi(%ld): [ERROR] Failed to " | ||
3494 | "load segment %d of firmware\n", | ||
3495 | ha->host_no, num)); | ||
3496 | qla_printk(KERN_WARNING, ha, | ||
3497 | "[ERROR] Failed to load segment %d of " | ||
3498 | "firmware\n", num); | ||
3499 | |||
3500 | qla2x00_dump_regs(ha); | ||
3501 | break; | ||
3502 | } | ||
3503 | |||
3504 | risc_code += cnt; | ||
3505 | risc_address += cnt; | ||
3506 | risc_code_size -= cnt; | ||
3507 | num++; | ||
3508 | } | ||
3509 | |||
3510 | /* Next firmware sequence */ | ||
3511 | fw_iter++; | ||
3512 | } | ||
3513 | |||
3514 | return (rval); | ||
3515 | } | ||
3516 | |||
3517 | int | ||
3518 | qla24xx_load_risc_flash(scsi_qla_host_t *ha, uint32_t *srisc_addr) | ||
3519 | { | ||
3520 | int rval; | ||
3521 | int segments, fragment; | ||
3522 | uint32_t faddr; | ||
3523 | uint32_t *dcode, dlen; | ||
3524 | uint32_t risc_addr; | ||
3525 | uint32_t risc_size; | ||
3526 | uint32_t i; | ||
3527 | |||
3528 | rval = QLA_SUCCESS; | ||
3529 | |||
3530 | segments = FA_RISC_CODE_SEGMENTS; | ||
3531 | faddr = FA_RISC_CODE_ADDR; | ||
3532 | dcode = (uint32_t *)ha->request_ring; | ||
3533 | *srisc_addr = 0; | ||
3534 | |||
3535 | /* Validate firmware image by checking version. */ | ||
3536 | qla24xx_read_flash_data(ha, dcode, faddr + 4, 4); | ||
3537 | for (i = 0; i < 4; i++) | ||
3538 | dcode[i] = be32_to_cpu(dcode[i]); | ||
3539 | if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff && | ||
3540 | dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) || | ||
3541 | (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 && | ||
3542 | dcode[3] == 0)) { | ||
3543 | qla_printk(KERN_WARNING, ha, | ||
3544 | "Unable to verify integrity of flash firmware image!\n"); | ||
3545 | qla_printk(KERN_WARNING, ha, | ||
3546 | "Firmware data: %08x %08x %08x %08x!\n", dcode[0], | ||
3547 | dcode[1], dcode[2], dcode[3]); | ||
3548 | |||
3549 | return QLA_FUNCTION_FAILED; | ||
3550 | } | ||
3551 | |||
3552 | while (segments && rval == QLA_SUCCESS) { | ||
3553 | /* Read segment's load information. */ | ||
3554 | qla24xx_read_flash_data(ha, dcode, faddr, 4); | ||
3555 | |||
3556 | risc_addr = be32_to_cpu(dcode[2]); | ||
3557 | *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr; | ||
3558 | risc_size = be32_to_cpu(dcode[3]); | ||
3559 | |||
3560 | fragment = 0; | ||
3561 | while (risc_size > 0 && rval == QLA_SUCCESS) { | ||
3562 | dlen = (uint32_t)(ha->fw_transfer_size >> 2); | ||
3563 | if (dlen > risc_size) | ||
3564 | dlen = risc_size; | ||
3565 | |||
3566 | DEBUG7(printk("scsi(%ld): Loading risc segment@ risc " | ||
3567 | "addr %x, number of dwords 0x%x, offset 0x%x.\n", | ||
3568 | ha->host_no, risc_addr, dlen, faddr)); | ||
3569 | |||
3570 | qla24xx_read_flash_data(ha, dcode, faddr, dlen); | ||
3571 | for (i = 0; i < dlen; i++) | ||
3572 | dcode[i] = swab32(dcode[i]); | ||
3573 | |||
3574 | rval = qla2x00_load_ram_ext(ha, ha->request_dma, | ||
3575 | risc_addr, dlen); | ||
3576 | if (rval) { | ||
3577 | DEBUG(printk("scsi(%ld):[ERROR] Failed to load " | ||
3578 | "segment %d of firmware\n", ha->host_no, | ||
3579 | fragment)); | ||
3580 | qla_printk(KERN_WARNING, ha, | ||
3581 | "[ERROR] Failed to load segment %d of " | ||
3582 | "firmware\n", fragment); | ||
3583 | break; | ||
3584 | } | ||
3585 | |||
3586 | faddr += dlen; | ||
3587 | risc_addr += dlen; | ||
3588 | risc_size -= dlen; | ||
3589 | fragment++; | ||
3590 | } | ||
3591 | |||
3592 | /* Next segment. */ | ||
3593 | segments--; | ||
3594 | } | ||
3595 | |||
3596 | return rval; | ||
3597 | } | ||
3598 | |||
3599 | int | ||
3600 | qla24xx_load_risc_hotplug(scsi_qla_host_t *ha, uint32_t *srisc_addr) | ||
3601 | { | ||
3602 | int rval; | ||
3603 | int segments, fragment; | ||
3604 | uint32_t *dcode, dlen; | ||
3605 | uint32_t risc_addr; | ||
3606 | uint32_t risc_size; | ||
3607 | uint32_t i; | ||
3608 | const struct firmware *fw_entry; | ||
3609 | uint32_t *fwcode, fwclen; | ||
3610 | |||
3611 | if (request_firmware(&fw_entry, ha->brd_info->fw_fname, | ||
3612 | &ha->pdev->dev)) { | ||
3613 | qla_printk(KERN_ERR, ha, | ||
3614 | "Firmware image file not available: '%s'\n", | ||
3615 | ha->brd_info->fw_fname); | ||
3616 | return QLA_FUNCTION_FAILED; | ||
3617 | } | ||
3618 | |||
3619 | rval = QLA_SUCCESS; | ||
3620 | |||
3621 | segments = FA_RISC_CODE_SEGMENTS; | ||
3622 | dcode = (uint32_t *)ha->request_ring; | ||
3623 | *srisc_addr = 0; | ||
3624 | fwcode = (uint32_t *)fw_entry->data; | ||
3625 | fwclen = 0; | ||
3626 | |||
3627 | /* Validate firmware image by checking version. */ | ||
3628 | if (fw_entry->size < 8 * sizeof(uint32_t)) { | ||
3629 | qla_printk(KERN_WARNING, ha, | ||
3630 | "Unable to verify integrity of flash firmware image " | ||
3631 | "(%Zd)!\n", fw_entry->size); | ||
3632 | goto fail_fw_integrity; | ||
3633 | } | ||
3634 | for (i = 0; i < 4; i++) | ||
3635 | dcode[i] = be32_to_cpu(fwcode[i + 4]); | ||
3636 | if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff && | ||
3637 | dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) || | ||
3638 | (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 && | ||
3639 | dcode[3] == 0)) { | ||
3640 | qla_printk(KERN_WARNING, ha, | ||
3641 | "Unable to verify integrity of flash firmware image!\n"); | ||
3642 | qla_printk(KERN_WARNING, ha, | ||
3643 | "Firmware data: %08x %08x %08x %08x!\n", dcode[0], | ||
3644 | dcode[1], dcode[2], dcode[3]); | ||
3645 | goto fail_fw_integrity; | ||
3646 | } | ||
3647 | |||
3648 | while (segments && rval == QLA_SUCCESS) { | ||
3649 | risc_addr = be32_to_cpu(fwcode[2]); | ||
3650 | *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr; | ||
3651 | risc_size = be32_to_cpu(fwcode[3]); | ||
3652 | |||
3653 | /* Validate firmware image size. */ | ||
3654 | fwclen += risc_size * sizeof(uint32_t); | ||
3655 | if (fw_entry->size < fwclen) { | ||
3656 | qla_printk(KERN_WARNING, ha, | ||
3657 | "Unable to verify integrity of flash firmware " | ||
3658 | "image (%Zd)!\n", fw_entry->size); | ||
3659 | goto fail_fw_integrity; | ||
3660 | } | ||
3661 | |||
3662 | fragment = 0; | ||
3663 | while (risc_size > 0 && rval == QLA_SUCCESS) { | ||
3664 | dlen = (uint32_t)(ha->fw_transfer_size >> 2); | ||
3665 | if (dlen > risc_size) | ||
3666 | dlen = risc_size; | ||
3667 | |||
3668 | DEBUG7(printk("scsi(%ld): Loading risc segment@ risc " | ||
3669 | "addr %x, number of dwords 0x%x.\n", ha->host_no, | ||
3670 | risc_addr, dlen)); | ||
3671 | |||
3672 | for (i = 0; i < dlen; i++) | ||
3673 | dcode[i] = swab32(fwcode[i]); | ||
3674 | |||
3675 | rval = qla2x00_load_ram_ext(ha, ha->request_dma, | ||
3676 | risc_addr, dlen); | ||
3677 | if (rval) { | ||
3678 | DEBUG(printk("scsi(%ld):[ERROR] Failed to load " | ||
3679 | "segment %d of firmware\n", ha->host_no, | ||
3680 | fragment)); | ||
3681 | qla_printk(KERN_WARNING, ha, | ||
3682 | "[ERROR] Failed to load segment %d of " | ||
3683 | "firmware\n", fragment); | ||
3684 | break; | ||
3685 | } | ||
3686 | |||
3687 | fwcode += dlen; | ||
3688 | risc_addr += dlen; | ||
3689 | risc_size -= dlen; | ||
3690 | fragment++; | ||
3691 | } | ||
3692 | |||
3693 | /* Next segment. */ | ||
3694 | segments--; | ||
3695 | } | ||
3696 | |||
3697 | release_firmware(fw_entry); | ||
3698 | return rval; | ||
3699 | |||
3700 | fail_fw_integrity: | ||
3701 | |||
3702 | release_firmware(fw_entry); | ||
3703 | return QLA_FUNCTION_FAILED; | ||
3704 | |||
3705 | } | ||
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 9e6d05119253..973871833e32 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
@@ -1175,6 +1175,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) | |||
1175 | ha->isp_ops.reset_adapter = qla2x00_reset_adapter; | 1175 | ha->isp_ops.reset_adapter = qla2x00_reset_adapter; |
1176 | ha->isp_ops.nvram_config = qla2x00_nvram_config; | 1176 | ha->isp_ops.nvram_config = qla2x00_nvram_config; |
1177 | ha->isp_ops.update_fw_options = qla2x00_update_fw_options; | 1177 | ha->isp_ops.update_fw_options = qla2x00_update_fw_options; |
1178 | ha->isp_ops.load_risc = qla2x00_load_risc; | ||
1178 | ha->isp_ops.pci_info_str = qla2x00_pci_info_str; | 1179 | ha->isp_ops.pci_info_str = qla2x00_pci_info_str; |
1179 | ha->isp_ops.fw_version_str = qla2x00_fw_version_str; | 1180 | ha->isp_ops.fw_version_str = qla2x00_fw_version_str; |
1180 | ha->isp_ops.intr_handler = qla2100_intr_handler; | 1181 | ha->isp_ops.intr_handler = qla2100_intr_handler; |