📄 qla_init.c
字号:
/* * QLOGIC LINUX SOFTWARE * * QLogic ISP2x00 device driver for Linux 2.6.x * Copyright (C) 2003-2004 QLogic Corporation * (www.qlogic.com) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * */#include "qla_def.h"#include <linux/delay.h>#include "qla_devtbl.h"/* XXX(hch): this is ugly, but we don't want to pull in exioctl.h */#ifndef EXT_IS_LUN_BIT_SET#define EXT_IS_LUN_BIT_SET(P,L) \ (((P)->mask[L/8] & (0x80 >> (L%8)))?1:0)#define EXT_SET_LUN_BIT(P,L) \ ((P)->mask[L/8] |= (0x80 >> (L%8)))#endif/** QLogic ISP2x00 Hardware Support Function Prototypes.*/static int qla2x00_pci_config(scsi_qla_host_t *);static int qla2x00_isp_firmware(scsi_qla_host_t *);static void qla2x00_reset_chip(scsi_qla_host_t *);static int qla2x00_chip_diag(scsi_qla_host_t *);static void qla2x00_resize_request_q(scsi_qla_host_t *);static int qla2x00_setup_chip(scsi_qla_host_t *);static void qla2x00_init_response_q_entries(scsi_qla_host_t *);static int qla2x00_init_rings(scsi_qla_host_t *);static int qla2x00_fw_ready(scsi_qla_host_t *);static int qla2x00_configure_hba(scsi_qla_host_t *);static int qla2x00_nvram_config(scsi_qla_host_t *);static void qla2x00_init_tgt_map(scsi_qla_host_t *);static int qla2x00_configure_loop(scsi_qla_host_t *);static int qla2x00_configure_local_loop(scsi_qla_host_t *);static void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);static void qla2x00_lun_discovery(scsi_qla_host_t *, fc_port_t *);static int qla2x00_rpt_lun_discovery(scsi_qla_host_t *, fc_port_t *, inq_cmd_rsp_t *, dma_addr_t);static int qla2x00_report_lun(scsi_qla_host_t *, fc_port_t *);static fc_lun_t *qla2x00_cfg_lun(scsi_qla_host_t *, fc_port_t *, uint16_t, inq_cmd_rsp_t *, dma_addr_t);static fc_lun_t * qla2x00_add_lun(fc_port_t *, uint16_t);static int qla2x00_inquiry(scsi_qla_host_t *, fc_port_t *, uint16_t, inq_cmd_rsp_t *, dma_addr_t);static int qla2x00_configure_fabric(scsi_qla_host_t *);static int qla2x00_find_all_fabric_devs(scsi_qla_host_t *, struct list_head *);static int qla2x00_device_resync(scsi_qla_host_t *);static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);static void qla2x00_config_os(scsi_qla_host_t *ha);static uint16_t qla2x00_fcport_bind(scsi_qla_host_t *ha, fc_port_t *fcport);static os_lun_t * qla2x00_fclun_bind(scsi_qla_host_t *, fc_port_t *, fc_lun_t *);static void qla2x00_lun_free(scsi_qla_host_t *, uint16_t, uint16_t);static int qla2x00_restart_isp(scsi_qla_host_t *);static void qla2x00_reset_adapter(scsi_qla_host_t *);static os_tgt_t *qla2x00_tgt_alloc(scsi_qla_host_t *, uint16_t);static os_lun_t *qla2x00_lun_alloc(scsi_qla_host_t *, uint16_t, uint16_t);/****************************************************************************//* QLogic ISP2x00 Hardware Support Functions. *//****************************************************************************//** qla2x00_initialize_adapter* Initialize board.** Input:* ha = adapter block pointer.** Returns:* 0 = success*/intqla2x00_initialize_adapter(scsi_qla_host_t *ha){ int rval; uint8_t restart_risc = 0; uint8_t retry; uint32_t wait_time; /* Clear adapter flags. */ ha->flags.online = 0; ha->flags.reset_active = 0; atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME); atomic_set(&ha->loop_state, LOOP_DOWN); ha->device_flags = 0; ha->sns_retry_cnt = 0; ha->dpc_flags = 0; ha->failback_delay = 0; ha->flags.management_server_logged_in = 0; ha->marker_needed = 0; ha->mbx_flags = 0; ha->isp_abort_cnt = 0; ha->beacon_blink_led = 0; rval = qla2x00_pci_config(ha); if (rval) { DEBUG2(printk("scsi(%ld): Unable to configure PCI space=n", ha->host_no)); return (rval); } qla2x00_reset_chip(ha); /* Initialize target map database. */ qla2x00_init_tgt_map(ha); qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n"); qla2x00_nvram_config(ha); qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n"); retry = 10; /* * Try to configure the loop. */ do { restart_risc = 0; /* If firmware needs to be loaded */ if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) { if ((rval = qla2x00_chip_diag(ha)) == QLA_SUCCESS) { rval = qla2x00_setup_chip(ha); } } if (rval == QLA_SUCCESS && (rval = qla2x00_init_rings(ha)) == QLA_SUCCESS) {check_fw_ready_again: /* * Wait for a successful LIP up to a maximum * of (in seconds): RISC login timeout value, * RISC retry count value, and port down retry * value OR a minimum of 4 seconds OR If no * cable, only 5 seconds. */ rval = qla2x00_fw_ready(ha); if (rval == QLA_SUCCESS) { clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); /* * Wait at most MAX_TARGET RSCNs for a stable * link. */ wait_time = 256; do { clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); rval = qla2x00_configure_loop(ha); if (test_and_clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) { restart_risc = 1; break; } /* * If loop state change while we were * discoverying devices then wait for * LIP to complete */ if (atomic_read(&ha->loop_state) == LOOP_DOWN && retry--) { goto check_fw_ready_again; } wait_time--; } while (!atomic_read(&ha->loop_down_timer) && retry && wait_time && (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))); if (wait_time == 0) rval = QLA_FUNCTION_FAILED; if (ha->mem_err) restart_risc = 1; } else if (ha->device_flags & DFLG_NO_CABLE) /* If no cable, then all is good. */ rval = QLA_SUCCESS; } } while (restart_risc && retry--); if (rval == QLA_SUCCESS) { clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); ha->marker_needed = 1; qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); ha->marker_needed = 0; ha->flags.online = 1; } else { DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__)); } return (rval);}/** * qla2x00_pci_config() - Setup device PCI configuration registers. * @ha: HA context * * Returns 0 on success. */static intqla2x00_pci_config(scsi_qla_host_t *ha){ uint16_t w, mwi; unsigned long flags = 0; uint32_t cnt; qla_printk(KERN_INFO, ha, "Configuring PCI space...\n"); /* * Turn on PCI master; for system BIOSes that don't turn it on by * default. */ pci_set_master(ha->pdev); mwi = 0; if (pci_set_mwi(ha->pdev)) mwi = PCI_COMMAND_INVALIDATE; pci_read_config_word(ha->pdev, PCI_REVISION_ID, &ha->revision); if (!ha->iobase) return (QLA_FUNCTION_FAILED); /* * We want to respect framework's setting of PCI configuration space * command register and also want to make sure that all bits of * interest to us are properly set in command register. */ pci_read_config_word(ha->pdev, PCI_COMMAND, &w); w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); /* Get PCI bus information. */ spin_lock_irqsave(&ha->hardware_lock, flags); ha->pci_attr = RD_REG_WORD(&ha->iobase->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) { pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80); /* PCI Specification Revision 2.3 changes */ if (IS_QLA2322(ha) || IS_QLA6322(ha)) /* Command Register - Reset Interrupt Disable. */ w &= ~PCI_COMMAND_INTX_DISABLE; /* * If this is a 2300 card and not 2312, reset the * COMMAND_INVALIDATE due to a bug in the 2300. Unfortunately, * the 2310 also reports itself as a 2300 so we need to get the * fb revision level -- a 6 indicates it really is a 2300 and * not a 2310. */ if (IS_QLA2300(ha)) { spin_lock_irqsave(&ha->hardware_lock, flags); /* Pause RISC. */ WRT_REG_WORD(&ha->iobase->hccr, HCCR_PAUSE_RISC); for (cnt = 0; cnt < 30000; cnt++) { if ((RD_REG_WORD(&ha->iobase->hccr) & HCCR_RISC_PAUSE) != 0) break; udelay(10); } /* Select FPM registers. */ WRT_REG_WORD(&ha->iobase->ctrl_status, 0x20); RD_REG_WORD(&ha->iobase->ctrl_status); /* Get the fb rev level */ ha->fb_rev = RD_FB_CMD_REG(ha, ha->iobase); if (ha->fb_rev == FPM_2300) w &= ~PCI_COMMAND_INVALIDATE; /* Deselect FPM registers. */ WRT_REG_WORD(&ha->iobase->ctrl_status, 0x0); RD_REG_WORD(&ha->iobase->ctrl_status); /* Release RISC module. */ WRT_REG_WORD(&ha->iobase->hccr, HCCR_RELEASE_RISC); for (cnt = 0; cnt < 30000; cnt++) { if ((RD_REG_WORD(&ha->iobase->hccr) & HCCR_RISC_PAUSE) == 0) break; udelay(10); } spin_unlock_irqrestore(&ha->hardware_lock, flags); } } pci_write_config_word(ha->pdev, PCI_COMMAND, w); /* Reset expansion ROM address decode enable */ pci_read_config_word(ha->pdev, PCI_ROM_ADDRESS, &w); w &= ~PCI_ROM_ADDRESS_ENABLE; pci_write_config_word(ha->pdev, PCI_ROM_ADDRESS, w); return (QLA_SUCCESS);}/** * qla2x00_isp_firmware() - Choose firmware image. * @ha: HA context * * Returns 0 on success. */static intqla2x00_isp_firmware(scsi_qla_host_t *ha){ int rval; /* Assume loading risc code */ rval = QLA_FUNCTION_FAILED; if (ha->flags.disable_risc_code_load) { DEBUG2(printk("scsi(%ld): RISC CODE NOT loaded\n", ha->host_no)); qla_printk(KERN_INFO, ha, "RISC CODE NOT loaded\n"); /* Verify checksum of loaded RISC code. */ rval = qla2x00_verify_checksum(ha); } if (rval) { DEBUG2_3(printk("scsi(%ld): **** Load RISC code ****\n", ha->host_no)); } return (rval);}/** * qla2x00_reset_chip() - Reset ISP chip. * @ha: HA context * * Returns 0 on success. */static voidqla2x00_reset_chip(scsi_qla_host_t *ha) { unsigned long flags = 0; device_reg_t __iomem *reg = ha->iobase; uint32_t cnt; unsigned long mbx_flags = 0; uint16_t cmd; /* Disable ISP interrupts. */ qla2x00_disable_intrs(ha); spin_lock_irqsave(&ha->hardware_lock, flags); /* Turn off master enable */ cmd = 0; pci_read_config_word(ha->pdev, PCI_COMMAND, &cmd); cmd &= ~PCI_COMMAND_MASTER; pci_write_config_word(ha->pdev, PCI_COMMAND, cmd); if (!IS_QLA2100(ha)) { /* Pause RISC. */ WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); if (IS_QLA2200(ha) || IS_QLA2300(ha)) { for (cnt = 0; cnt < 30000; cnt++) { if ((RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) != 0) break; udelay(100); } } else { RD_REG_WORD(®->hccr); /* PCI Posting. */ udelay(10); } /* Select FPM registers. */ WRT_REG_WORD(®->ctrl_status, 0x20); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ /* FPM Soft Reset. */ WRT_REG_WORD(®->fpm_diag_config, 0x100); RD_REG_WORD(®->fpm_diag_config); /* PCI Posting. */ /* Toggle Fpm Reset. */ if (!IS_QLA2200(ha)) { WRT_REG_WORD(®->fpm_diag_config, 0x0); RD_REG_WORD(®->fpm_diag_config); /* PCI Posting. */ } /* Select frame buffer registers. */ WRT_REG_WORD(®->ctrl_status, 0x10); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ /* Reset frame buffer FIFOs. */ if (IS_QLA2200(ha)) { WRT_FB_CMD_REG(ha, reg, 0xa000); RD_FB_CMD_REG(ha, reg); /* PCI Posting. */ } else { WRT_FB_CMD_REG(ha, reg, 0x00fc); /* Read back fb_cmd until zero or 3 seconds max */ for (cnt = 0; cnt < 3000; cnt++) { if ((RD_FB_CMD_REG(ha, reg) & 0xff) == 0) break; udelay(100); } } /* Select RISC module registers. */ WRT_REG_WORD(®->ctrl_status, 0); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ /* Reset RISC processor. */ WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); RD_REG_WORD(®->hccr); /* PCI Posting. */ /* Release RISC processor. */ WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); RD_REG_WORD(®->hccr); /* PCI Posting. */ } WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); WRT_REG_WORD(®->hccr, HCCR_CLR_HOST_INT); /* Reset ISP chip. */ WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); /* Wait for RISC to recover from reset. */ if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) { /* * It is necessary to for a delay here since the card doesn't * respond to PCI reads during a reset. On some architectures * this will result in an MCA. */ udelay(20); for (cnt = 30000; cnt; cnt--) { if ((RD_REG_WORD(®->ctrl_status) & CSR_ISP_SOFT_RESET) == 0) break; udelay(100); } } else udelay(10); /* Reset RISC processor. */ WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); WRT_REG_WORD(®->semaphore, 0); /* Release RISC processor. */ WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); RD_REG_WORD(®->hccr); /* PCI Posting. */ if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) { for (cnt = 0; cnt < 30000; cnt++) { if (!(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags); if (RD_MAILBOX_REG(ha, reg, 0) != MBS_BUSY) { if (!(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) spin_unlock_irqrestore( &ha->mbx_reg_lock, mbx_flags); break; } if (!(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) spin_unlock_irqrestore(&ha->mbx_reg_lock, mbx_flags); udelay(100); } } else udelay(100); /* Turn on master enable */ cmd |= PCI_COMMAND_MASTER; pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -