qla_sup.c

来自「linux 内核源代码」· C语言 代码 · 共 2,224 行 · 第 1/4 页

C
2,224
字号
	void *optrom = NULL;	uint32_t *s, *d;	ret = QLA_SUCCESS;	/* Prepare burst-capable write on supported ISPs. */	if (IS_QLA25XX(ha) && !(faddr & 0xfff) &&	    dwords > OPTROM_BURST_DWORDS) {		optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,		    &optrom_dma, GFP_KERNEL);		if (!optrom) {			qla_printk(KERN_DEBUG, ha,			    "Unable to allocate memory for optrom burst write "			    "(%x KB).\n", OPTROM_BURST_SIZE / 1024);		}	}	qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id);	DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__,	    ha->host_no, man_id, flash_id));	conf_addr = flash_conf_to_access_addr(0x03d8);	switch (man_id) {	case 0xbf: /* STT flash. */		if (flash_id == 0x8e) {			rest_addr = 0x3fff;			sec_mask = 0x7c000;		} else {			rest_addr = 0x1fff;			sec_mask = 0x7e000;		}		if (flash_id == 0x80)			conf_addr = flash_conf_to_access_addr(0x0352);		break;	case 0x13: /* ST M25P80. */		rest_addr = 0x3fff;		sec_mask = 0x7c000;		break;	case 0x1f: // Atmel 26DF081A		rest_addr = 0x3fff;		sec_mask = 0x7c000;		conf_addr = flash_conf_to_access_addr(0x0320);		break;	default:		/* Default to 64 kb sector size. */		rest_addr = 0x3fff;		sec_mask = 0x7c000;		break;	}	/* Enable flash write. */	WRT_REG_DWORD(&reg->ctrl_status,	    RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE);	RD_REG_DWORD(&reg->ctrl_status);	/* PCI Posting. */	/* Disable flash write-protection. */	qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0);	/* Some flash parts need an additional zero-write to clear bits.*/	qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0);	for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {		if (man_id == 0x1f) {			findex = faddr << 2;			fdata = findex & sec_mask;		} else {			findex = faddr;			fdata = (findex & sec_mask) << 2;		}		/* Are we at the beginning of a sector? */		if ((findex & rest_addr) == 0) {			/* Do sector unprotect at 4K boundry for Atmel part. */			if (man_id == 0x1f)				qla24xx_write_flash_dword(ha,				    flash_conf_to_access_addr(0x0339),				    (fdata & 0xff00) | ((fdata << 16) &				    0xff0000) | ((fdata >> 16) & 0xff));			ret = qla24xx_write_flash_dword(ha, conf_addr,			    (fdata & 0xff00) |((fdata << 16) &			    0xff0000) | ((fdata >> 16) & 0xff));			if (ret != QLA_SUCCESS) {				DEBUG9(printk("%s(%ld) Unable to flash "				    "sector: address=%x.\n", __func__,				    ha->host_no, faddr));				break;			}		}		/* Go with burst-write. */		if (optrom && (liter + OPTROM_BURST_DWORDS) <= dwords) {			/* Copy data to DMA'ble buffer. */			for (miter = 0, s = optrom, d = dwptr;			    miter < OPTROM_BURST_DWORDS; miter++, s++, d++)				*s = cpu_to_le32(*d);			ret = qla2x00_load_ram(ha, optrom_dma,			    flash_data_to_access_addr(faddr),			    OPTROM_BURST_DWORDS);			if (ret != QLA_SUCCESS) {				qla_printk(KERN_WARNING, ha,				    "Unable to burst-write optrom segment "				    "(%x/%x/%llx).\n", ret,				    flash_data_to_access_addr(faddr),				    (unsigned long long)optrom_dma);				qla_printk(KERN_WARNING, ha,				    "Reverting to slow-write.\n");				dma_free_coherent(&ha->pdev->dev,				    OPTROM_BURST_SIZE, optrom, optrom_dma);				optrom = NULL;			} else {				liter += OPTROM_BURST_DWORDS - 1;				faddr += OPTROM_BURST_DWORDS - 1;				dwptr += OPTROM_BURST_DWORDS - 1;				continue;			}		}		ret = qla24xx_write_flash_dword(ha,		    flash_data_to_access_addr(faddr), cpu_to_le32(*dwptr));		if (ret != QLA_SUCCESS) {			DEBUG9(printk("%s(%ld) Unable to program flash "			    "address=%x data=%x.\n", __func__,			    ha->host_no, faddr, *dwptr));			break;		}		/* Do sector protect at 4K boundry for Atmel part. */		if (man_id == 0x1f &&		    ((faddr & rest_addr) == rest_addr))			qla24xx_write_flash_dword(ha,			    flash_conf_to_access_addr(0x0336),			    (fdata & 0xff00) | ((fdata << 16) &			    0xff0000) | ((fdata >> 16) & 0xff));	}	/* Enable flash write-protection. */	qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c);	/* Disable flash write. */	WRT_REG_DWORD(&reg->ctrl_status,	    RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);	RD_REG_DWORD(&reg->ctrl_status);	/* PCI Posting. */	if (optrom)		dma_free_coherent(&ha->pdev->dev,		    OPTROM_BURST_SIZE, optrom, optrom_dma);	return ret;}uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,    uint32_t bytes){	uint32_t i;	uint16_t *wptr;	/* Word reads to NVRAM via registers. */	wptr = (uint16_t *)buf;	qla2x00_lock_nvram_access(ha);	for (i = 0; i < bytes >> 1; i++, naddr++)		wptr[i] = cpu_to_le16(qla2x00_get_nvram_word(ha,		    naddr));	qla2x00_unlock_nvram_access(ha);	return buf;}uint8_t *qla24xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,    uint32_t bytes){	uint32_t i;	uint32_t *dwptr;	/* Dword reads to flash. */	dwptr = (uint32_t *)buf;	for (i = 0; i < bytes >> 2; i++, naddr++)		dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,		    nvram_data_to_access_addr(naddr)));	return buf;}intqla2x00_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,    uint32_t bytes){	int ret, stat;	uint32_t i;	uint16_t *wptr;	unsigned long flags;	ret = QLA_SUCCESS;	spin_lock_irqsave(&ha->hardware_lock, flags);	qla2x00_lock_nvram_access(ha);	/* Disable NVRAM write-protection. */	stat = qla2x00_clear_nvram_protection(ha);	wptr = (uint16_t *)buf;	for (i = 0; i < bytes >> 1; i++, naddr++) {		qla2x00_write_nvram_word(ha, naddr,		    cpu_to_le16(*wptr));		wptr++;	}	/* Enable NVRAM write-protection. */	qla2x00_set_nvram_protection(ha, stat);	qla2x00_unlock_nvram_access(ha);	spin_unlock_irqrestore(&ha->hardware_lock, flags);	return ret;}intqla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,    uint32_t bytes){	int ret;	uint32_t i;	uint32_t *dwptr;	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;	unsigned long flags;	ret = QLA_SUCCESS;	spin_lock_irqsave(&ha->hardware_lock, flags);	/* Enable flash write. */	WRT_REG_DWORD(&reg->ctrl_status,	    RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE);	RD_REG_DWORD(&reg->ctrl_status);	/* PCI Posting. */	/* Disable NVRAM write-protection. */	qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101),	    0);	qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101),	    0);	/* Dword writes to flash. */	dwptr = (uint32_t *)buf;	for (i = 0; i < bytes >> 2; i++, naddr++, dwptr++) {		ret = qla24xx_write_flash_dword(ha,		    nvram_data_to_access_addr(naddr),		    cpu_to_le32(*dwptr));		if (ret != QLA_SUCCESS) {			DEBUG9(printk("%s(%ld) Unable to program "			    "nvram address=%x data=%x.\n", __func__,			    ha->host_no, naddr, *dwptr));			break;		}	}	/* Enable NVRAM write-protection. */	qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101),	    0x8c);	/* Disable flash write. */	WRT_REG_DWORD(&reg->ctrl_status,	    RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);	RD_REG_DWORD(&reg->ctrl_status);	/* PCI Posting. */	spin_unlock_irqrestore(&ha->hardware_lock, flags);	return ret;}uint8_t *qla25xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,    uint32_t bytes){	uint32_t i;	uint32_t *dwptr;	/* Dword reads to flash. */	dwptr = (uint32_t *)buf;	for (i = 0; i < bytes >> 2; i++, naddr++)		dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,		    flash_data_to_access_addr(FA_VPD_NVRAM_ADDR | naddr)));	return buf;}intqla25xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,    uint32_t bytes){#define RMW_BUFFER_SIZE	(64 * 1024)	uint8_t *dbuf;	dbuf = vmalloc(RMW_BUFFER_SIZE);	if (!dbuf)		return QLA_MEMORY_ALLOC_FAILED;	ha->isp_ops->read_optrom(ha, dbuf, FA_VPD_NVRAM_ADDR << 2,	    RMW_BUFFER_SIZE);	memcpy(dbuf + (naddr << 2), buf, bytes);	ha->isp_ops->write_optrom(ha, dbuf, FA_VPD_NVRAM_ADDR << 2,	    RMW_BUFFER_SIZE);	vfree(dbuf);	return QLA_SUCCESS;}static inline voidqla2x00_flip_colors(scsi_qla_host_t *ha, uint16_t *pflags){	if (IS_QLA2322(ha)) {		/* Flip all colors. */		if (ha->beacon_color_state == QLA_LED_ALL_ON) {			/* Turn off. */			ha->beacon_color_state = 0;			*pflags = GPIO_LED_ALL_OFF;		} else {			/* Turn on. */			ha->beacon_color_state = QLA_LED_ALL_ON;			*pflags = GPIO_LED_RGA_ON;		}	} else {		/* Flip green led only. */		if (ha->beacon_color_state == QLA_LED_GRN_ON) {			/* Turn off. */			ha->beacon_color_state = 0;			*pflags = GPIO_LED_GREEN_OFF_AMBER_OFF;		} else {			/* Turn on. */			ha->beacon_color_state = QLA_LED_GRN_ON;			*pflags = GPIO_LED_GREEN_ON_AMBER_OFF;		}	}}voidqla2x00_beacon_blink(struct scsi_qla_host *ha){	uint16_t gpio_enable;	uint16_t gpio_data;	uint16_t led_color = 0;	unsigned long flags;	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;	if (ha->pio_address)		reg = (struct device_reg_2xxx __iomem *)ha->pio_address;	spin_lock_irqsave(&ha->hardware_lock, flags);	/* Save the Original GPIOE. */	if (ha->pio_address) {		gpio_enable = RD_REG_WORD_PIO(&reg->gpioe);		gpio_data = RD_REG_WORD_PIO(&reg->gpiod);	} else {		gpio_enable = RD_REG_WORD(&reg->gpioe);		gpio_data = RD_REG_WORD(&reg->gpiod);	}	/* Set the modified gpio_enable values */	gpio_enable |= GPIO_LED_MASK;	if (ha->pio_address) {		WRT_REG_WORD_PIO(&reg->gpioe, gpio_enable);	} else {		WRT_REG_WORD(&reg->gpioe, gpio_enable);		RD_REG_WORD(&reg->gpioe);	}	qla2x00_flip_colors(ha, &led_color);	/* Clear out any previously set LED color. */	gpio_data &= ~GPIO_LED_MASK;	/* Set the new input LED color to GPIOD. */	gpio_data |= led_color;	/* Set the modified gpio_data values */	if (ha->pio_address) {		WRT_REG_WORD_PIO(&reg->gpiod, gpio_data);	} else {		WRT_REG_WORD(&reg->gpiod, gpio_data);		RD_REG_WORD(&reg->gpiod);	}	spin_unlock_irqrestore(&ha->hardware_lock, flags);}intqla2x00_beacon_on(struct scsi_qla_host *ha){	uint16_t gpio_enable;	uint16_t gpio_data;	unsigned long flags;	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;	ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;	ha->fw_options[1] |= FO1_DISABLE_GPIO6_7;	if (qla2x00_set_fw_options(ha, ha->fw_options) != QLA_SUCCESS) {		qla_printk(KERN_WARNING, ha,		    "Unable to update fw options (beacon on).\n");		return QLA_FUNCTION_FAILED;	}	if (ha->pio_address)		reg = (struct device_reg_2xxx __iomem *)ha->pio_address;	/* Turn off LEDs. */	spin_lock_irqsave(&ha->hardware_lock, flags);	if (ha->pio_address) {		gpio_enable = RD_REG_WORD_PIO(&reg->gpioe);		gpio_data = RD_REG_WORD_PIO(&reg->gpiod);	} else {		gpio_enable = RD_REG_WORD(&reg->gpioe);		gpio_data = RD_REG_WORD(&reg->gpiod);	}	gpio_enable |= GPIO_LED_MASK;	/* Set the modified gpio_enable values. */	if (ha->pio_address) {		WRT_REG_WORD_PIO(&reg->gpioe, gpio_enable);	} else {		WRT_REG_WORD(&reg->gpioe, gpio_enable);		RD_REG_WORD(&reg->gpioe);	}	/* Clear out previously set LED colour. */	gpio_data &= ~GPIO_LED_MASK;	if (ha->pio_address) {		WRT_REG_WORD_PIO(&reg->gpiod, gpio_data);	} else {		WRT_REG_WORD(&reg->gpiod, gpio_data);		RD_REG_WORD(&reg->gpiod);	}	spin_unlock_irqrestore(&ha->hardware_lock, flags);	/*	 * Let the per HBA timer kick off the blinking process based on	 * the following flags. No need to do anything else now.	 */	ha->beacon_blink_led = 1;	ha->beacon_color_state = 0;	return QLA_SUCCESS;}intqla2x00_beacon_off(struct scsi_qla_host *ha){	int rval = QLA_SUCCESS;	ha->beacon_blink_led = 0;	/* Set the on flag so when it gets flipped it will be off. */	if (IS_QLA2322(ha))		ha->beacon_color_state = QLA_LED_ALL_ON;	else		ha->beacon_color_state = QLA_LED_GRN_ON;	ha->isp_ops->beacon_blink(ha);	/* This turns green LED off */	ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;	ha->fw_options[1] &= ~FO1_DISABLE_GPIO6_7;	rval = qla2x00_set_fw_options(ha, ha->fw_options);	if (rval != QLA_SUCCESS)		qla_printk(KERN_WARNING, ha,		    "Unable to update fw options (beacon off).\n");	return rval;}static inline voidqla24xx_flip_colors(scsi_qla_host_t *ha, uint16_t *pflags){	/* Flip all colors. */	if (ha->beacon_color_state == QLA_LED_ALL_ON) {		/* Turn off. */		ha->beacon_color_state = 0;		*pflags = 0;	} else {		/* Turn on. */		ha->beacon_color_state = QLA_LED_ALL_ON;		*pflags = GPDX_LED_YELLOW_ON | GPDX_LED_AMBER_ON;	}}voidqla24xx_beacon_blink(struct scsi_qla_host *ha){	uint16_t led_color = 0;	uint32_t gpio_data;	unsigned long flags;	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;	/* Save the Original GPIOD. */	spin_lock_irqsave(&ha->hardware_lock, flags);	gpio_data = RD_REG_DWORD(&reg->gpiod);	/* Enable the gpio_data reg for update. */	gpio_data |= GPDX_LED_UPDATE_MASK;	WRT_REG_DWORD(&reg->gpiod, gpio_data);	gpio_data = RD_REG_DWORD(&reg->gpiod);	/* Set the color bits. */	qla24xx_flip_colors(ha, &led_color);	/* Clear out any previously set LED color. */	gpio_data &= ~GPDX_LED_COLOR_MASK;	/* Set the new input LED color to GPIOD. */	gpio_data |= led_color;	/* Set the modified gpio_data values. */	WRT_REG_DWORD(&reg->gpiod, gpio_data);	gpio_data = RD_REG_DWORD(&reg->gpiod);	spin_unlock_irqrestore(&ha->hardware_lock, flags);}intqla24xx_beacon_on(struct scsi_qla_host *ha){	uint32_t gpio_data;	unsigned long flags;	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;	if (ha->beacon_blink_led == 0) {		/* Enable firmware for update */		ha->fw_options[1] |= ADD_FO1_DISABLE_GPIO_LED_CTRL;		if (qla2x00_set_fw_options(ha, ha->fw_options) != QLA_SUCCESS)			return QLA_FUNCTION_FAILED;		if (qla2x00_get_fw_options(ha, ha->fw_options) !=		    QLA_SUCCESS) {			qla_printk(KERN_WARNING, ha,			    "Unable to update fw options (beacon on).\n");			return QLA_FUNCTION_FAILED;		}		spin_lock_irqsave(&ha->hardware_lock, flags);		gpio_data = RD_REG_DWORD(&reg->gpiod);		/* Enable the gpio_data reg for update. */		gpio_data |= GPDX_LED_UPDATE_MASK;		WRT_REG_DWORD(&reg->gpiod, gpio_data);		RD_REG_DWORD(&reg->gpiod);		spin_unlock_irqrestore(&ha->hardware_lock, flags);	}	/* So all colors blink together. */	ha->beacon_color_state = 0;	/* Let the per HBA timer kick off the blinking process. */	ha->beacon_blink_led = 1;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?