qla_sup.c

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

C
2,224
字号
	return QLA_SUCCESS;}intqla24xx_beacon_off(struct scsi_qla_host *ha){	uint32_t gpio_data;	unsigned long flags;	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;	ha->beacon_blink_led = 0;	ha->beacon_color_state = QLA_LED_ALL_ON;	ha->isp_ops->beacon_blink(ha);	/* Will flip to all off. */	/* Give control back to firmware. */	spin_lock_irqsave(&ha->hardware_lock, flags);	gpio_data = RD_REG_DWORD(&reg->gpiod);	/* Disable 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);	ha->fw_options[1] &= ~ADD_FO1_DISABLE_GPIO_LED_CTRL;	if (qla2x00_set_fw_options(ha, ha->fw_options) != QLA_SUCCESS) {		qla_printk(KERN_WARNING, ha,		    "Unable to update fw options (beacon off).\n");		return QLA_FUNCTION_FAILED;	}	if (qla2x00_get_fw_options(ha, ha->fw_options) != QLA_SUCCESS) {		qla_printk(KERN_WARNING, ha,		    "Unable to get fw options (beacon off).\n");		return QLA_FUNCTION_FAILED;	}	return QLA_SUCCESS;}/* * Flash support routines *//** * qla2x00_flash_enable() - Setup flash for reading and writing. * @ha: HA context */static voidqla2x00_flash_enable(scsi_qla_host_t *ha){	uint16_t data;	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;	data = RD_REG_WORD(&reg->ctrl_status);	data |= CSR_FLASH_ENABLE;	WRT_REG_WORD(&reg->ctrl_status, data);	RD_REG_WORD(&reg->ctrl_status);		/* PCI Posting. */}/** * qla2x00_flash_disable() - Disable flash and allow RISC to run. * @ha: HA context */static voidqla2x00_flash_disable(scsi_qla_host_t *ha){	uint16_t data;	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;	data = RD_REG_WORD(&reg->ctrl_status);	data &= ~(CSR_FLASH_ENABLE);	WRT_REG_WORD(&reg->ctrl_status, data);	RD_REG_WORD(&reg->ctrl_status);		/* PCI Posting. */}/** * qla2x00_read_flash_byte() - Reads a byte from flash * @ha: HA context * @addr: Address in flash to read * * A word is read from the chip, but, only the lower byte is valid. * * Returns the byte read from flash @addr. */static uint8_tqla2x00_read_flash_byte(scsi_qla_host_t *ha, uint32_t addr){	uint16_t data;	uint16_t bank_select;	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;	bank_select = RD_REG_WORD(&reg->ctrl_status);	if (IS_QLA2322(ha) || IS_QLA6322(ha)) {		/* Specify 64K address range: */		/*  clear out Module Select and Flash Address bits [19:16]. */		bank_select &= ~0xf8;		bank_select |= addr >> 12 & 0xf0;		bank_select |= CSR_FLASH_64K_BANK;		WRT_REG_WORD(&reg->ctrl_status, bank_select);		RD_REG_WORD(&reg->ctrl_status);	/* PCI Posting. */		WRT_REG_WORD(&reg->flash_address, (uint16_t)addr);		data = RD_REG_WORD(&reg->flash_data);		return (uint8_t)data;	}	/* Setup bit 16 of flash address. */	if ((addr & BIT_16) && ((bank_select & CSR_FLASH_64K_BANK) == 0)) {		bank_select |= CSR_FLASH_64K_BANK;		WRT_REG_WORD(&reg->ctrl_status, bank_select);		RD_REG_WORD(&reg->ctrl_status);	/* PCI Posting. */	} else if (((addr & BIT_16) == 0) &&	    (bank_select & CSR_FLASH_64K_BANK)) {		bank_select &= ~(CSR_FLASH_64K_BANK);		WRT_REG_WORD(&reg->ctrl_status, bank_select);		RD_REG_WORD(&reg->ctrl_status);	/* PCI Posting. */	}	/* Always perform IO mapped accesses to the FLASH registers. */	if (ha->pio_address) {		uint16_t data2;		reg = (struct device_reg_2xxx __iomem *)ha->pio_address;		WRT_REG_WORD_PIO(&reg->flash_address, (uint16_t)addr);		do {			data = RD_REG_WORD_PIO(&reg->flash_data);			barrier();			cpu_relax();			data2 = RD_REG_WORD_PIO(&reg->flash_data);		} while (data != data2);	} else {		WRT_REG_WORD(&reg->flash_address, (uint16_t)addr);		data = qla2x00_debounce_register(&reg->flash_data);	}	return (uint8_t)data;}/** * qla2x00_write_flash_byte() - Write a byte to flash * @ha: HA context * @addr: Address in flash to write * @data: Data to write */static voidqla2x00_write_flash_byte(scsi_qla_host_t *ha, uint32_t addr, uint8_t data){	uint16_t bank_select;	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;	bank_select = RD_REG_WORD(&reg->ctrl_status);	if (IS_QLA2322(ha) || IS_QLA6322(ha)) {		/* Specify 64K address range: */		/*  clear out Module Select and Flash Address bits [19:16]. */		bank_select &= ~0xf8;		bank_select |= addr >> 12 & 0xf0;		bank_select |= CSR_FLASH_64K_BANK;		WRT_REG_WORD(&reg->ctrl_status, bank_select);		RD_REG_WORD(&reg->ctrl_status);	/* PCI Posting. */		WRT_REG_WORD(&reg->flash_address, (uint16_t)addr);		RD_REG_WORD(&reg->ctrl_status);		/* PCI Posting. */		WRT_REG_WORD(&reg->flash_data, (uint16_t)data);		RD_REG_WORD(&reg->ctrl_status);		/* PCI Posting. */		return;	}	/* Setup bit 16 of flash address. */	if ((addr & BIT_16) && ((bank_select & CSR_FLASH_64K_BANK) == 0)) {		bank_select |= CSR_FLASH_64K_BANK;		WRT_REG_WORD(&reg->ctrl_status, bank_select);		RD_REG_WORD(&reg->ctrl_status);	/* PCI Posting. */	} else if (((addr & BIT_16) == 0) &&	    (bank_select & CSR_FLASH_64K_BANK)) {		bank_select &= ~(CSR_FLASH_64K_BANK);		WRT_REG_WORD(&reg->ctrl_status, bank_select);		RD_REG_WORD(&reg->ctrl_status);	/* PCI Posting. */	}	/* Always perform IO mapped accesses to the FLASH registers. */	if (ha->pio_address) {		reg = (struct device_reg_2xxx __iomem *)ha->pio_address;		WRT_REG_WORD_PIO(&reg->flash_address, (uint16_t)addr);		WRT_REG_WORD_PIO(&reg->flash_data, (uint16_t)data);	} else {		WRT_REG_WORD(&reg->flash_address, (uint16_t)addr);		RD_REG_WORD(&reg->ctrl_status);		/* PCI Posting. */		WRT_REG_WORD(&reg->flash_data, (uint16_t)data);		RD_REG_WORD(&reg->ctrl_status);		/* PCI Posting. */	}}/** * qla2x00_poll_flash() - Polls flash for completion. * @ha: HA context * @addr: Address in flash to poll * @poll_data: Data to be polled * @man_id: Flash manufacturer ID * @flash_id: Flash ID * * This function polls the device until bit 7 of what is read matches data * bit 7 or until data bit 5 becomes a 1.  If that hapens, the flash ROM timed * out (a fatal error).  The flash book recommeds reading bit 7 again after * reading bit 5 as a 1. * * Returns 0 on success, else non-zero. */static intqla2x00_poll_flash(scsi_qla_host_t *ha, uint32_t addr, uint8_t poll_data,    uint8_t man_id, uint8_t flash_id){	int status;	uint8_t flash_data;	uint32_t cnt;	status = 1;	/* Wait for 30 seconds for command to finish. */	poll_data &= BIT_7;	for (cnt = 3000000; cnt; cnt--) {		flash_data = qla2x00_read_flash_byte(ha, addr);		if ((flash_data & BIT_7) == poll_data) {			status = 0;			break;		}		if (man_id != 0x40 && man_id != 0xda) {			if ((flash_data & BIT_5) && cnt > 2)				cnt = 2;		}		udelay(10);		barrier();		cond_resched();	}	return status;}/** * qla2x00_program_flash_address() - Programs a flash address * @ha: HA context * @addr: Address in flash to program * @data: Data to be written in flash * @man_id: Flash manufacturer ID * @flash_id: Flash ID * * Returns 0 on success, else non-zero. */static intqla2x00_program_flash_address(scsi_qla_host_t *ha, uint32_t addr, uint8_t data,    uint8_t man_id, uint8_t flash_id){	/* Write Program Command Sequence. */	if (IS_OEM_001(ha)) {		qla2x00_write_flash_byte(ha, 0xaaa, 0xaa);		qla2x00_write_flash_byte(ha, 0x555, 0x55);		qla2x00_write_flash_byte(ha, 0xaaa, 0xa0);		qla2x00_write_flash_byte(ha, addr, data);	} else {		if (man_id == 0xda && flash_id == 0xc1) {			qla2x00_write_flash_byte(ha, addr, data);			if (addr & 0x7e)				return 0;		} else {			qla2x00_write_flash_byte(ha, 0x5555, 0xaa);			qla2x00_write_flash_byte(ha, 0x2aaa, 0x55);			qla2x00_write_flash_byte(ha, 0x5555, 0xa0);			qla2x00_write_flash_byte(ha, addr, data);		}	}	udelay(150);	/* Wait for write to complete. */	return qla2x00_poll_flash(ha, addr, data, man_id, flash_id);}/** * qla2x00_erase_flash() - Erase the flash. * @ha: HA context * @man_id: Flash manufacturer ID * @flash_id: Flash ID * * Returns 0 on success, else non-zero. */static intqla2x00_erase_flash(scsi_qla_host_t *ha, uint8_t man_id, uint8_t flash_id){	/* Individual Sector Erase Command Sequence */	if (IS_OEM_001(ha)) {		qla2x00_write_flash_byte(ha, 0xaaa, 0xaa);		qla2x00_write_flash_byte(ha, 0x555, 0x55);		qla2x00_write_flash_byte(ha, 0xaaa, 0x80);		qla2x00_write_flash_byte(ha, 0xaaa, 0xaa);		qla2x00_write_flash_byte(ha, 0x555, 0x55);		qla2x00_write_flash_byte(ha, 0xaaa, 0x10);	} else {		qla2x00_write_flash_byte(ha, 0x5555, 0xaa);		qla2x00_write_flash_byte(ha, 0x2aaa, 0x55);		qla2x00_write_flash_byte(ha, 0x5555, 0x80);		qla2x00_write_flash_byte(ha, 0x5555, 0xaa);		qla2x00_write_flash_byte(ha, 0x2aaa, 0x55);		qla2x00_write_flash_byte(ha, 0x5555, 0x10);	}	udelay(150);	/* Wait for erase to complete. */	return qla2x00_poll_flash(ha, 0x00, 0x80, man_id, flash_id);}/** * qla2x00_erase_flash_sector() - Erase a flash sector. * @ha: HA context * @addr: Flash sector to erase * @sec_mask: Sector address mask * @man_id: Flash manufacturer ID * @flash_id: Flash ID * * Returns 0 on success, else non-zero. */static intqla2x00_erase_flash_sector(scsi_qla_host_t *ha, uint32_t addr,    uint32_t sec_mask, uint8_t man_id, uint8_t flash_id){	/* Individual Sector Erase Command Sequence */	qla2x00_write_flash_byte(ha, 0x5555, 0xaa);	qla2x00_write_flash_byte(ha, 0x2aaa, 0x55);	qla2x00_write_flash_byte(ha, 0x5555, 0x80);	qla2x00_write_flash_byte(ha, 0x5555, 0xaa);	qla2x00_write_flash_byte(ha, 0x2aaa, 0x55);	if (man_id == 0x1f && flash_id == 0x13)		qla2x00_write_flash_byte(ha, addr & sec_mask, 0x10);	else		qla2x00_write_flash_byte(ha, addr & sec_mask, 0x30);	udelay(150);	/* Wait for erase to complete. */	return qla2x00_poll_flash(ha, addr, 0x80, man_id, flash_id);}/** * qla2x00_get_flash_manufacturer() - Read manufacturer ID from flash chip. * @man_id: Flash manufacturer ID * @flash_id: Flash ID */static voidqla2x00_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id,    uint8_t *flash_id){	qla2x00_write_flash_byte(ha, 0x5555, 0xaa);	qla2x00_write_flash_byte(ha, 0x2aaa, 0x55);	qla2x00_write_flash_byte(ha, 0x5555, 0x90);	*man_id = qla2x00_read_flash_byte(ha, 0x0000);	*flash_id = qla2x00_read_flash_byte(ha, 0x0001);	qla2x00_write_flash_byte(ha, 0x5555, 0xaa);	qla2x00_write_flash_byte(ha, 0x2aaa, 0x55);	qla2x00_write_flash_byte(ha, 0x5555, 0xf0);}static voidqla2x00_read_flash_data(scsi_qla_host_t *ha, uint8_t *tmp_buf, uint32_t saddr,        uint32_t length){	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;	uint32_t midpoint, ilength;	uint8_t data;	midpoint = length / 2;	WRT_REG_WORD(&reg->nvram, 0);	RD_REG_WORD(&reg->nvram);	for (ilength = 0; ilength < length; saddr++, ilength++, tmp_buf++) {		if (ilength == midpoint) {			WRT_REG_WORD(&reg->nvram, NVR_SELECT);			RD_REG_WORD(&reg->nvram);		}		data = qla2x00_read_flash_byte(ha, saddr);		if (saddr % 100)			udelay(10);		*tmp_buf = data;		cond_resched();	}}static inline voidqla2x00_suspend_hba(struct scsi_qla_host *ha){	int cnt;	unsigned long flags;	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;	/* Suspend HBA. */	scsi_block_requests(ha->host);	ha->isp_ops->disable_intrs(ha);	set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);	/* Pause RISC. */	spin_lock_irqsave(&ha->hardware_lock, flags);	WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);	RD_REG_WORD(&reg->hccr);	if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {		for (cnt = 0; cnt < 30000; cnt++) {			if ((RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) != 0)				break;			udelay(100);		}	} else {		udelay(10);	}	spin_unlock_irqrestore(&ha->hardware_lock, flags);}static inline voidqla2x00_resume_hba(struct scsi_qla_host *ha){	/* Resume HBA. */	clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);	set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);	qla2xxx_wake_dpc(ha);	qla2x00_wait_for_hba_online(ha);	scsi_unblock_requests(ha->host);}uint8_t *qla2x00_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,    uint32_t offset, uint32_t length){	uint32_t addr, midpoint;	uint8_t *data;	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;	/* Suspend HBA. */	qla2x00_suspend_hba(ha);	/* Go with read. */	midpoint = ha->optrom_size / 2;	qla2x00_flash_enable(ha);	WRT_REG_WORD(&reg->nvram, 0);	RD_REG_WORD(&reg->nvram);		/* PCI Posting. */	for (addr = offset, data = buf; addr < length; addr++, data++) {		if (addr == midpoint) {			WRT_REG_WORD(&reg->nvram, NVR_SELECT);			RD_REG_WORD(&reg->nvram);	/* PCI Posting. */		}		*data = qla2x00_read_flash_byte(ha, addr);	}	qla2x00_flash_disable(ha);	/* Resume HBA. */	qla2x00_resume_hba(ha);	return buf;}intqla2x00_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,    uint32_t offset, uint32_t length){	int rval;	uint8_t man_id, flash_id, sec_number, data;	uint16_t wd;	uint32_t addr, liter, sec_mask, rest_addr;	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;	/* Suspend HBA. */	qla2x00_suspend_hba(ha);	rval = QLA_SUCCESS;	sec_number = 0;	/* Reset ISP chip. */	WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);	pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);	/* Go with write. */	qla2x00_flash_enable(ha);	do {	/* Loop once to provide quick error exit */		/* Structure of flash memory based on manufacturer */		if (IS_OEM_001(ha)) {			/* OEM variant with special flash part. */			man_id = flash_id = 0;			rest_addr = 0xffff;			sec_mask   = 0x10000;			goto update_flash;		}		qla2x00_get_flash_manufacturer(ha, &man_id, &flash_id);		switch (man_id) {		case 0x20: /* ST flash. */			if (flash_id == 0xd2 || flash_id == 0xe3) {				/*				 * ST m29w008at part - 64kb sector size with				 * 32kb,8kb,8kb,16kb sectors at memory address				 * 0xf0000.				 */				rest_addr = 0xffff;				sec_mask = 0x10000;				break;   			}			/*			 * ST m29w010b part - 16kb sector size			 * Default to 16kb sectors			 */			rest_addr = 0x3fff;			sec_mask = 0x1c000;			break;		case 0x40: /* Mostel flash. */			/* Mostel v29c51001 part - 512 byte sector size. */			rest_addr = 0x1ff;			sec_mask = 0x1fe00;			break;		case 0xbf: /* SST flash. */			/* SST39sf10 part - 4kb sector size. */			rest_addr = 0xfff;			sec_mask = 0x1f000;			break;		case 0xda: /* Winbond flash. */			/* Winbond W29EE011 part - 256 byte sector size. */			rest_addr = 0x7f;			sec_mask = 0x1ff80;			break;		case 0xc2: /* Macronix flash. */			/* 64k sector size. */			if (flash_id == 0x38 || flash_id == 0x4f) {				rest_addr = 0xffff;				sec_mask = 0x10000;				break;			}			/* Fall through... */		case 0x1f: /* Atmel flash. */			/* 512k sector size. */			if (flash_id == 0x13) {				rest_addr = 0x7fffffff;				sec_mask =   0x80000000;				break;			}			/* Fall through... */		case 0x01: /* AMD flash. */			if (flash_id == 0x38 || flash_id == 0x40 ||			    flash_id == 0x4f) {				/* Am29LV081 part - 64kb sector size. */				/* Am29LV002BT part - 64kb sector size. */				rest_addr = 0xffff;				sec_mask = 0x10000;

⌨️ 快捷键说明

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