qla_sup.c
来自「linux 内核源代码」· C语言 代码 · 共 2,224 行 · 第 1/4 页
C
2,224 行
/* * QLogic Fibre Channel HBA Driver * Copyright (c) 2003-2005 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */#include "qla_def.h"#include <linux/delay.h>#include <linux/vmalloc.h>#include <asm/uaccess.h>static uint16_t qla2x00_nvram_request(scsi_qla_host_t *, uint32_t);static void qla2x00_nv_deselect(scsi_qla_host_t *);static void qla2x00_nv_write(scsi_qla_host_t *, uint16_t);/* * NVRAM support routines *//** * qla2x00_lock_nvram_access() - * @ha: HA context */voidqla2x00_lock_nvram_access(scsi_qla_host_t *ha){ uint16_t data; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) { data = RD_REG_WORD(®->nvram); while (data & NVR_BUSY) { udelay(100); data = RD_REG_WORD(®->nvram); } /* Lock resource */ WRT_REG_WORD(®->u.isp2300.host_semaphore, 0x1); RD_REG_WORD(®->u.isp2300.host_semaphore); udelay(5); data = RD_REG_WORD(®->u.isp2300.host_semaphore); while ((data & BIT_0) == 0) { /* Lock failed */ udelay(100); WRT_REG_WORD(®->u.isp2300.host_semaphore, 0x1); RD_REG_WORD(®->u.isp2300.host_semaphore); udelay(5); data = RD_REG_WORD(®->u.isp2300.host_semaphore); } }}/** * qla2x00_unlock_nvram_access() - * @ha: HA context */voidqla2x00_unlock_nvram_access(scsi_qla_host_t *ha){ struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) { WRT_REG_WORD(®->u.isp2300.host_semaphore, 0); RD_REG_WORD(®->u.isp2300.host_semaphore); }}/** * qla2x00_get_nvram_word() - Calculates word position in NVRAM and calls the * request routine to get the word from NVRAM. * @ha: HA context * @addr: Address in NVRAM to read * * Returns the word read from nvram @addr. */uint16_tqla2x00_get_nvram_word(scsi_qla_host_t *ha, uint32_t addr){ uint16_t data; uint32_t nv_cmd; nv_cmd = addr << 16; nv_cmd |= NV_READ_OP; data = qla2x00_nvram_request(ha, nv_cmd); return (data);}/** * qla2x00_write_nvram_word() - Write NVRAM data. * @ha: HA context * @addr: Address in NVRAM to write * @data: word to program */voidqla2x00_write_nvram_word(scsi_qla_host_t *ha, uint32_t addr, uint16_t data){ int count; uint16_t word; uint32_t nv_cmd, wait_cnt; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; qla2x00_nv_write(ha, NVR_DATA_OUT); qla2x00_nv_write(ha, 0); qla2x00_nv_write(ha, 0); for (word = 0; word < 8; word++) qla2x00_nv_write(ha, NVR_DATA_OUT); qla2x00_nv_deselect(ha); /* Write data */ nv_cmd = (addr << 16) | NV_WRITE_OP; nv_cmd |= data; nv_cmd <<= 5; for (count = 0; count < 27; count++) { if (nv_cmd & BIT_31) qla2x00_nv_write(ha, NVR_DATA_OUT); else qla2x00_nv_write(ha, 0); nv_cmd <<= 1; } qla2x00_nv_deselect(ha); /* Wait for NVRAM to become ready */ WRT_REG_WORD(®->nvram, NVR_SELECT); RD_REG_WORD(®->nvram); /* PCI Posting. */ wait_cnt = NVR_WAIT_CNT; do { if (!--wait_cnt) { DEBUG9_10(printk("%s(%ld): NVRAM didn't go ready...\n", __func__, ha->host_no)); break; } NVRAM_DELAY(); word = RD_REG_WORD(®->nvram); } while ((word & NVR_DATA_IN) == 0); qla2x00_nv_deselect(ha); /* Disable writes */ qla2x00_nv_write(ha, NVR_DATA_OUT); for (count = 0; count < 10; count++) qla2x00_nv_write(ha, 0); qla2x00_nv_deselect(ha);}static intqla2x00_write_nvram_word_tmo(scsi_qla_host_t *ha, uint32_t addr, uint16_t data, uint32_t tmo){ int ret, count; uint16_t word; uint32_t nv_cmd; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; ret = QLA_SUCCESS; qla2x00_nv_write(ha, NVR_DATA_OUT); qla2x00_nv_write(ha, 0); qla2x00_nv_write(ha, 0); for (word = 0; word < 8; word++) qla2x00_nv_write(ha, NVR_DATA_OUT); qla2x00_nv_deselect(ha); /* Write data */ nv_cmd = (addr << 16) | NV_WRITE_OP; nv_cmd |= data; nv_cmd <<= 5; for (count = 0; count < 27; count++) { if (nv_cmd & BIT_31) qla2x00_nv_write(ha, NVR_DATA_OUT); else qla2x00_nv_write(ha, 0); nv_cmd <<= 1; } qla2x00_nv_deselect(ha); /* Wait for NVRAM to become ready */ WRT_REG_WORD(®->nvram, NVR_SELECT); RD_REG_WORD(®->nvram); /* PCI Posting. */ do { NVRAM_DELAY(); word = RD_REG_WORD(®->nvram); if (!--tmo) { ret = QLA_FUNCTION_FAILED; break; } } while ((word & NVR_DATA_IN) == 0); qla2x00_nv_deselect(ha); /* Disable writes */ qla2x00_nv_write(ha, NVR_DATA_OUT); for (count = 0; count < 10; count++) qla2x00_nv_write(ha, 0); qla2x00_nv_deselect(ha); return ret;}/** * qla2x00_nvram_request() - Sends read command to NVRAM and gets data from * NVRAM. * @ha: HA context * @nv_cmd: NVRAM command * * Bit definitions for NVRAM command: * * Bit 26 = start bit * Bit 25, 24 = opcode * Bit 23-16 = address * Bit 15-0 = write data * * Returns the word read from nvram @addr. */static uint16_tqla2x00_nvram_request(scsi_qla_host_t *ha, uint32_t nv_cmd){ uint8_t cnt; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; uint16_t data = 0; uint16_t reg_data; /* Send command to NVRAM. */ nv_cmd <<= 5; for (cnt = 0; cnt < 11; cnt++) { if (nv_cmd & BIT_31) qla2x00_nv_write(ha, NVR_DATA_OUT); else qla2x00_nv_write(ha, 0); nv_cmd <<= 1; } /* Read data from NVRAM. */ for (cnt = 0; cnt < 16; cnt++) { WRT_REG_WORD(®->nvram, NVR_SELECT | NVR_CLOCK); RD_REG_WORD(®->nvram); /* PCI Posting. */ NVRAM_DELAY(); data <<= 1; reg_data = RD_REG_WORD(®->nvram); if (reg_data & NVR_DATA_IN) data |= BIT_0; WRT_REG_WORD(®->nvram, NVR_SELECT); RD_REG_WORD(®->nvram); /* PCI Posting. */ NVRAM_DELAY(); } /* Deselect chip. */ WRT_REG_WORD(®->nvram, NVR_DESELECT); RD_REG_WORD(®->nvram); /* PCI Posting. */ NVRAM_DELAY(); return (data);}/** * qla2x00_nv_write() - Clean NVRAM operations. * @ha: HA context */static voidqla2x00_nv_deselect(scsi_qla_host_t *ha){ struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; WRT_REG_WORD(®->nvram, NVR_DESELECT); RD_REG_WORD(®->nvram); /* PCI Posting. */ NVRAM_DELAY();}/** * qla2x00_nv_write() - Prepare for NVRAM read/write operation. * @ha: HA context * @data: Serial interface selector */static voidqla2x00_nv_write(scsi_qla_host_t *ha, uint16_t data){ struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; WRT_REG_WORD(®->nvram, data | NVR_SELECT | NVR_WRT_ENABLE); RD_REG_WORD(®->nvram); /* PCI Posting. */ NVRAM_DELAY(); WRT_REG_WORD(®->nvram, data | NVR_SELECT| NVR_CLOCK | NVR_WRT_ENABLE); RD_REG_WORD(®->nvram); /* PCI Posting. */ NVRAM_DELAY(); WRT_REG_WORD(®->nvram, data | NVR_SELECT | NVR_WRT_ENABLE); RD_REG_WORD(®->nvram); /* PCI Posting. */ NVRAM_DELAY();}/** * qla2x00_clear_nvram_protection() - * @ha: HA context */static intqla2x00_clear_nvram_protection(scsi_qla_host_t *ha){ int ret, stat; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; uint32_t word, wait_cnt; uint16_t wprot, wprot_old; /* Clear NVRAM write protection. */ ret = QLA_FUNCTION_FAILED; wprot_old = cpu_to_le16(qla2x00_get_nvram_word(ha, ha->nvram_base)); stat = qla2x00_write_nvram_word_tmo(ha, ha->nvram_base, __constant_cpu_to_le16(0x1234), 100000); wprot = cpu_to_le16(qla2x00_get_nvram_word(ha, ha->nvram_base)); if (stat != QLA_SUCCESS || wprot != 0x1234) { /* Write enable. */ qla2x00_nv_write(ha, NVR_DATA_OUT); qla2x00_nv_write(ha, 0); qla2x00_nv_write(ha, 0); for (word = 0; word < 8; word++) qla2x00_nv_write(ha, NVR_DATA_OUT); qla2x00_nv_deselect(ha); /* Enable protection register. */ qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); qla2x00_nv_write(ha, NVR_PR_ENABLE); qla2x00_nv_write(ha, NVR_PR_ENABLE); for (word = 0; word < 8; word++) qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE); qla2x00_nv_deselect(ha); /* Clear protection register (ffff is cleared). */ qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); for (word = 0; word < 8; word++) qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE); qla2x00_nv_deselect(ha); /* Wait for NVRAM to become ready. */ WRT_REG_WORD(®->nvram, NVR_SELECT); RD_REG_WORD(®->nvram); /* PCI Posting. */ wait_cnt = NVR_WAIT_CNT; do { if (!--wait_cnt) { DEBUG9_10(printk("%s(%ld): NVRAM didn't go " "ready...\n", __func__, ha->host_no)); break; } NVRAM_DELAY(); word = RD_REG_WORD(®->nvram); } while ((word & NVR_DATA_IN) == 0); if (wait_cnt) ret = QLA_SUCCESS; } else qla2x00_write_nvram_word(ha, ha->nvram_base, wprot_old); return ret;}static voidqla2x00_set_nvram_protection(scsi_qla_host_t *ha, int stat){ struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; uint32_t word, wait_cnt; if (stat != QLA_SUCCESS) return; /* Set NVRAM write protection. */ /* Write enable. */ qla2x00_nv_write(ha, NVR_DATA_OUT); qla2x00_nv_write(ha, 0); qla2x00_nv_write(ha, 0); for (word = 0; word < 8; word++) qla2x00_nv_write(ha, NVR_DATA_OUT); qla2x00_nv_deselect(ha); /* Enable protection register. */ qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); qla2x00_nv_write(ha, NVR_PR_ENABLE); qla2x00_nv_write(ha, NVR_PR_ENABLE); for (word = 0; word < 8; word++) qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE); qla2x00_nv_deselect(ha); /* Enable protection register. */ qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); qla2x00_nv_write(ha, NVR_PR_ENABLE); qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); for (word = 0; word < 8; word++) qla2x00_nv_write(ha, NVR_PR_ENABLE); qla2x00_nv_deselect(ha); /* Wait for NVRAM to become ready. */ WRT_REG_WORD(®->nvram, NVR_SELECT); RD_REG_WORD(®->nvram); /* PCI Posting. */ wait_cnt = NVR_WAIT_CNT; do { if (!--wait_cnt) { DEBUG9_10(printk("%s(%ld): NVRAM didn't go ready...\n", __func__, ha->host_no)); break; } NVRAM_DELAY(); word = RD_REG_WORD(®->nvram); } while ((word & NVR_DATA_IN) == 0);}/*****************************************************************************//* Flash Manipulation Routines *//*****************************************************************************/#define OPTROM_BURST_SIZE 0x1000#define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4)static inline uint32_tflash_conf_to_access_addr(uint32_t faddr){ return FARX_ACCESS_FLASH_CONF | faddr;}static inline uint32_tflash_data_to_access_addr(uint32_t faddr){ return FARX_ACCESS_FLASH_DATA | faddr;}static inline uint32_tnvram_conf_to_access_addr(uint32_t naddr){ return FARX_ACCESS_NVRAM_CONF | naddr;}static inline uint32_tnvram_data_to_access_addr(uint32_t naddr){ return FARX_ACCESS_NVRAM_DATA | naddr;}static uint32_tqla24xx_read_flash_dword(scsi_qla_host_t *ha, uint32_t addr){ int rval; uint32_t cnt, data; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; WRT_REG_DWORD(®->flash_addr, addr & ~FARX_DATA_FLAG); /* Wait for READ cycle to complete. */ rval = QLA_SUCCESS; for (cnt = 3000; (RD_REG_DWORD(®->flash_addr) & FARX_DATA_FLAG) == 0 && rval == QLA_SUCCESS; cnt--) { if (cnt) udelay(10); else rval = QLA_FUNCTION_TIMEOUT; cond_resched(); } /* TODO: What happens if we time out? */ data = 0xDEADDEAD; if (rval == QLA_SUCCESS) data = RD_REG_DWORD(®->flash_data); return data;}uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, uint32_t dwords){ uint32_t i; /* Dword reads to flash. */ for (i = 0; i < dwords; i++, faddr++) dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, flash_data_to_access_addr(faddr))); return dwptr;}static intqla24xx_write_flash_dword(scsi_qla_host_t *ha, uint32_t addr, uint32_t data){ int rval; uint32_t cnt; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; WRT_REG_DWORD(®->flash_data, data); RD_REG_DWORD(®->flash_data); /* PCI Posting. */ WRT_REG_DWORD(®->flash_addr, addr | FARX_DATA_FLAG); /* Wait for Write cycle to complete. */ rval = QLA_SUCCESS; for (cnt = 500000; (RD_REG_DWORD(®->flash_addr) & FARX_DATA_FLAG) && rval == QLA_SUCCESS; cnt--) { if (cnt) udelay(10); else rval = QLA_FUNCTION_TIMEOUT; cond_resched(); } return rval;}static voidqla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id, uint8_t *flash_id){ uint32_t ids; ids = qla24xx_read_flash_dword(ha, flash_data_to_access_addr(0xd03ab)); *man_id = LSB(ids); *flash_id = MSB(ids); /* Check if man_id and flash_id are valid. */ if (ids != 0xDEADDEAD && (*man_id == 0 || *flash_id == 0)) { /* Read information using 0x9f opcode * Device ID, Mfg ID would be read in the format: * <Ext Dev Info><Device ID Part2><Device ID Part 1><Mfg ID> * Example: ATMEL 0x00 01 45 1F * Extract MFG and Dev ID from last two bytes. */ ids = qla24xx_read_flash_dword(ha, flash_data_to_access_addr(0xd009f)); *man_id = LSB(ids); *flash_id = MSB(ids); }}static intqla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, uint32_t dwords){ int ret; uint32_t liter, miter; uint32_t sec_mask, rest_addr, conf_addr; uint32_t fdata, findex ; uint8_t man_id, flash_id; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; dma_addr_t optrom_dma;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?