qla_sup.c

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

C
2,224
字号
				break;			} else if (flash_id == 0x3e) {				/*				 * Am29LV008b part - 64kb sector size with				 * 32kb,8kb,8kb,16kb sector at memory address				 * h0xf0000.				 */				rest_addr = 0xffff;				sec_mask = 0x10000;				break;			} else if (flash_id == 0x20 || flash_id == 0x6e) {				/*				 * Am29LV010 part or AM29f010 - 16kb sector				 * size.				 */				rest_addr = 0x3fff;				sec_mask = 0x1c000;				break;			} else if (flash_id == 0x6d) {				/* Am29LV001 part - 8kb sector size. */				rest_addr = 0x1fff;				sec_mask = 0x1e000;				break;			}		default:			/* Default to 16 kb sector size. */			rest_addr = 0x3fff;			sec_mask = 0x1c000;			break;		}update_flash:		if (IS_QLA2322(ha) || IS_QLA6322(ha)) {			if (qla2x00_erase_flash(ha, man_id, flash_id)) {				rval = QLA_FUNCTION_FAILED;				break;			}		}		for (addr = offset, liter = 0; liter < length; liter++,		    addr++) {			data = buf[liter];			/* Are we at the beginning of a sector? */			if ((addr & rest_addr) == 0) {				if (IS_QLA2322(ha) || IS_QLA6322(ha)) {					if (addr >= 0x10000UL) {						if (((addr >> 12) & 0xf0) &&						    ((man_id == 0x01 &&							flash_id == 0x3e) ||						     (man_id == 0x20 &&							 flash_id == 0xd2))) {							sec_number++;							if (sec_number == 1) {								rest_addr =								    0x7fff;								sec_mask =								    0x18000;							} else if (							    sec_number == 2 ||							    sec_number == 3) {								rest_addr =								    0x1fff;								sec_mask =								    0x1e000;							} else if (							    sec_number == 4) {								rest_addr =								    0x3fff;								sec_mask =								    0x1c000;							}						}					}				} else if (addr == ha->optrom_size / 2) {					WRT_REG_WORD(&reg->nvram, NVR_SELECT);					RD_REG_WORD(&reg->nvram);				}				if (flash_id == 0xda && man_id == 0xc1) {					qla2x00_write_flash_byte(ha, 0x5555,					    0xaa);					qla2x00_write_flash_byte(ha, 0x2aaa,					    0x55);					qla2x00_write_flash_byte(ha, 0x5555,					    0xa0);				} else if (!IS_QLA2322(ha) && !IS_QLA6322(ha)) {					/* Then erase it */					if (qla2x00_erase_flash_sector(ha,					    addr, sec_mask, man_id,					    flash_id)) {						rval = QLA_FUNCTION_FAILED;						break;					}					if (man_id == 0x01 && flash_id == 0x6d)						sec_number++;				}			}			if (man_id == 0x01 && flash_id == 0x6d) {				if (sec_number == 1 &&				    addr == (rest_addr - 1)) {					rest_addr = 0x0fff;					sec_mask   = 0x1f000;				} else if (sec_number == 3 && (addr & 0x7ffe)) {					rest_addr = 0x3fff;					sec_mask   = 0x1c000;				}			}			if (qla2x00_program_flash_address(ha, addr, data,			    man_id, flash_id)) {				rval = QLA_FUNCTION_FAILED;				break;			}			cond_resched();		}	} while (0);	qla2x00_flash_disable(ha);	/* Resume HBA. */	qla2x00_resume_hba(ha);	return rval;}uint8_t *qla24xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,    uint32_t offset, uint32_t length){	/* Suspend HBA. */	scsi_block_requests(ha->host);	set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);	/* Go with read. */	qla24xx_read_flash_data(ha, (uint32_t *)buf, offset >> 2, length >> 2);	/* Resume HBA. */	clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);	scsi_unblock_requests(ha->host);	return buf;}intqla24xx_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,    uint32_t offset, uint32_t length){	int rval;	/* Suspend HBA. */	scsi_block_requests(ha->host);	set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);	/* Go with write. */	rval = qla24xx_write_flash_data(ha, (uint32_t *)buf, offset >> 2,	    length >> 2);	/* Resume HBA -- RISC reset needed. */	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);	return rval;}uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,    uint32_t offset, uint32_t length){	int rval;	dma_addr_t optrom_dma;	void *optrom;	uint8_t *pbuf;	uint32_t faddr, left, burst;	if (offset & 0xfff)		goto slow_read;	if (length < OPTROM_BURST_SIZE)		goto slow_read;	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 read "		    "(%x KB).\n", OPTROM_BURST_SIZE / 1024);		goto slow_read;	}	pbuf = buf;	faddr = offset >> 2;	left = length >> 2;	burst = OPTROM_BURST_DWORDS;	while (left != 0) {		if (burst > left)			burst = left;		rval = qla2x00_dump_ram(ha, optrom_dma,		    flash_data_to_access_addr(faddr), burst);		if (rval) {			qla_printk(KERN_WARNING, ha,			    "Unable to burst-read optrom segment "			    "(%x/%x/%llx).\n", rval,			    flash_data_to_access_addr(faddr),			    (unsigned long long)optrom_dma);			qla_printk(KERN_WARNING, ha,			    "Reverting to slow-read.\n");			dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,			    optrom, optrom_dma);			goto slow_read;		}		memcpy(pbuf, optrom, burst * 4);		left -= burst;		faddr += burst;		pbuf += burst * 4;	}	dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,	    optrom_dma);	return buf;slow_read:    return qla24xx_read_optrom_data(ha, buf, offset, length);}/** * qla2x00_get_fcode_version() - Determine an FCODE image's version. * @ha: HA context * @pcids: Pointer to the FCODE PCI data structure * * The process of retrieving the FCODE version information is at best * described as interesting. * * Within the first 100h bytes of the image an ASCII string is present * which contains several pieces of information including the FCODE * version.  Unfortunately it seems the only reliable way to retrieve * the version is by scanning for another sentinel within the string, * the FCODE build date: * *	... 2.00.02 10/17/02 ... * * Returns QLA_SUCCESS on successful retrieval of version. */static voidqla2x00_get_fcode_version(scsi_qla_host_t *ha, uint32_t pcids){	int ret = QLA_FUNCTION_FAILED;	uint32_t istart, iend, iter, vend;	uint8_t do_next, rbyte, *vbyte;	memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));	/* Skip the PCI data structure. */	istart = pcids +	    ((qla2x00_read_flash_byte(ha, pcids + 0x0B) << 8) |		qla2x00_read_flash_byte(ha, pcids + 0x0A));	iend = istart + 0x100;	do {		/* Scan for the sentinel date string...eeewww. */		do_next = 0;		iter = istart;		while ((iter < iend) && !do_next) {			iter++;			if (qla2x00_read_flash_byte(ha, iter) == '/') {				if (qla2x00_read_flash_byte(ha, iter + 2) ==				    '/')					do_next++;				else if (qla2x00_read_flash_byte(ha,				    iter + 3) == '/')					do_next++;			}		}		if (!do_next)			break;		/* Backtrack to previous ' ' (space). */		do_next = 0;		while ((iter > istart) && !do_next) {			iter--;			if (qla2x00_read_flash_byte(ha, iter) == ' ')				do_next++;		}		if (!do_next)			break;		/*		 * Mark end of version tag, and find previous ' ' (space) or		 * string length (recent FCODE images -- major hack ahead!!!).		 */		vend = iter - 1;		do_next = 0;		while ((iter > istart) && !do_next) {			iter--;			rbyte = qla2x00_read_flash_byte(ha, iter);			if (rbyte == ' ' || rbyte == 0xd || rbyte == 0x10)				do_next++;		}		if (!do_next)			break;		/* Mark beginning of version tag, and copy data. */		iter++;		if ((vend - iter) &&		    ((vend - iter) < sizeof(ha->fcode_revision))) {			vbyte = ha->fcode_revision;			while (iter <= vend) {				*vbyte++ = qla2x00_read_flash_byte(ha, iter);				iter++;			}			ret = QLA_SUCCESS;		}	} while (0);	if (ret != QLA_SUCCESS)		memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));}intqla2x00_get_flash_version(scsi_qla_host_t *ha, void *mbuf){	int ret = QLA_SUCCESS;	uint8_t code_type, last_image;	uint32_t pcihdr, pcids;	uint8_t *dbyte;	uint16_t *dcode;	if (!ha->pio_address || !mbuf)		return QLA_FUNCTION_FAILED;	memset(ha->bios_revision, 0, sizeof(ha->bios_revision));	memset(ha->efi_revision, 0, sizeof(ha->efi_revision));	memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));	memset(ha->fw_revision, 0, sizeof(ha->fw_revision));	qla2x00_flash_enable(ha);	/* Begin with first PCI expansion ROM header. */	pcihdr = 0;	last_image = 1;	do {		/* Verify PCI expansion ROM header. */		if (qla2x00_read_flash_byte(ha, pcihdr) != 0x55 ||		    qla2x00_read_flash_byte(ha, pcihdr + 0x01) != 0xaa) {			/* No signature */			DEBUG2(printk("scsi(%ld): No matching ROM "			    "signature.\n", ha->host_no));			ret = QLA_FUNCTION_FAILED;			break;		}		/* Locate PCI data structure. */		pcids = pcihdr +		    ((qla2x00_read_flash_byte(ha, pcihdr + 0x19) << 8) |			qla2x00_read_flash_byte(ha, pcihdr + 0x18));		/* Validate signature of PCI data structure. */		if (qla2x00_read_flash_byte(ha, pcids) != 'P' ||		    qla2x00_read_flash_byte(ha, pcids + 0x1) != 'C' ||		    qla2x00_read_flash_byte(ha, pcids + 0x2) != 'I' ||		    qla2x00_read_flash_byte(ha, pcids + 0x3) != 'R') {			/* Incorrect header. */			DEBUG2(printk("%s(): PCI data struct not found "			    "pcir_adr=%x.\n", __func__, pcids));			ret = QLA_FUNCTION_FAILED;			break;		}		/* Read version */		code_type = qla2x00_read_flash_byte(ha, pcids + 0x14);		switch (code_type) {		case ROM_CODE_TYPE_BIOS:			/* Intel x86, PC-AT compatible. */			ha->bios_revision[0] =			    qla2x00_read_flash_byte(ha, pcids + 0x12);			ha->bios_revision[1] =			    qla2x00_read_flash_byte(ha, pcids + 0x13);			DEBUG3(printk("%s(): read BIOS %d.%d.\n", __func__,			    ha->bios_revision[1], ha->bios_revision[0]));			break;		case ROM_CODE_TYPE_FCODE:			/* Open Firmware standard for PCI (FCode). */			/* Eeeewww... */			qla2x00_get_fcode_version(ha, pcids);			break;		case ROM_CODE_TYPE_EFI:			/* Extensible Firmware Interface (EFI). */			ha->efi_revision[0] =			    qla2x00_read_flash_byte(ha, pcids + 0x12);			ha->efi_revision[1] =			    qla2x00_read_flash_byte(ha, pcids + 0x13);			DEBUG3(printk("%s(): read EFI %d.%d.\n", __func__,			    ha->efi_revision[1], ha->efi_revision[0]));			break;		default:			DEBUG2(printk("%s(): Unrecognized code type %x at "			    "pcids %x.\n", __func__, code_type, pcids));			break;		}		last_image = qla2x00_read_flash_byte(ha, pcids + 0x15) & BIT_7;		/* Locate next PCI expansion ROM. */		pcihdr += ((qla2x00_read_flash_byte(ha, pcids + 0x11) << 8) |		    qla2x00_read_flash_byte(ha, pcids + 0x10)) * 512;	} while (!last_image);	if (IS_QLA2322(ha)) {		/* Read firmware image information. */		memset(ha->fw_revision, 0, sizeof(ha->fw_revision));		dbyte = mbuf;		memset(dbyte, 0, 8);		dcode = (uint16_t *)dbyte;		qla2x00_read_flash_data(ha, dbyte, FA_RISC_CODE_ADDR * 4 + 10,		    8);		DEBUG3(printk("%s(%ld): dumping fw ver from flash:\n",		    __func__, ha->host_no));		DEBUG3(qla2x00_dump_buffer((uint8_t *)dbyte, 8));		if ((dcode[0] == 0xffff && dcode[1] == 0xffff &&		    dcode[2] == 0xffff && dcode[3] == 0xffff) ||		    (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&		    dcode[3] == 0)) {			DEBUG2(printk("%s(): Unrecognized fw revision at "			    "%x.\n", __func__, FA_RISC_CODE_ADDR * 4));		} else {			/* values are in big endian */			ha->fw_revision[0] = dbyte[0] << 16 | dbyte[1];			ha->fw_revision[1] = dbyte[2] << 16 | dbyte[3];			ha->fw_revision[2] = dbyte[4] << 16 | dbyte[5];		}	}	qla2x00_flash_disable(ha);	return ret;}intqla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf){	int ret = QLA_SUCCESS;	uint32_t pcihdr, pcids;	uint32_t *dcode;	uint8_t *bcode;	uint8_t code_type, last_image;	int i;	if (!mbuf)		return QLA_FUNCTION_FAILED;	memset(ha->bios_revision, 0, sizeof(ha->bios_revision));	memset(ha->efi_revision, 0, sizeof(ha->efi_revision));	memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));	memset(ha->fw_revision, 0, sizeof(ha->fw_revision));	dcode = mbuf;	/* Begin with first PCI expansion ROM header. */	pcihdr = 0;	last_image = 1;	do {		/* Verify PCI expansion ROM header. */		qla24xx_read_flash_data(ha, dcode, pcihdr >> 2, 0x20);		bcode = mbuf + (pcihdr % 4);		if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) {			/* No signature */			DEBUG2(printk("scsi(%ld): No matching ROM "			    "signature.\n", ha->host_no));			ret = QLA_FUNCTION_FAILED;			break;		}		/* Locate PCI data structure. */		pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]);		qla24xx_read_flash_data(ha, dcode, pcids >> 2, 0x20);		bcode = mbuf + (pcihdr % 4);		/* Validate signature of PCI data structure. */		if (bcode[0x0] != 'P' || bcode[0x1] != 'C' ||		    bcode[0x2] != 'I' || bcode[0x3] != 'R') {			/* Incorrect header. */			DEBUG2(printk("%s(): PCI data struct not found "			    "pcir_adr=%x.\n", __func__, pcids));			ret = QLA_FUNCTION_FAILED;			break;		}		/* Read version */		code_type = bcode[0x14];		switch (code_type) {		case ROM_CODE_TYPE_BIOS:			/* Intel x86, PC-AT compatible. */			ha->bios_revision[0] = bcode[0x12];			ha->bios_revision[1] = bcode[0x13];			DEBUG3(printk("%s(): read BIOS %d.%d.\n", __func__,			    ha->bios_revision[1], ha->bios_revision[0]));			break;		case ROM_CODE_TYPE_FCODE:			/* Open Firmware standard for PCI (FCode). */			ha->fcode_revision[0] = bcode[0x12];			ha->fcode_revision[1] = bcode[0x13];			DEBUG3(printk("%s(): read FCODE %d.%d.\n", __func__,			    ha->fcode_revision[1], ha->fcode_revision[0]));			break;		case ROM_CODE_TYPE_EFI:			/* Extensible Firmware Interface (EFI). */			ha->efi_revision[0] = bcode[0x12];			ha->efi_revision[1] = bcode[0x13];			DEBUG3(printk("%s(): read EFI %d.%d.\n", __func__,			    ha->efi_revision[1], ha->efi_revision[0]));			break;		default:			DEBUG2(printk("%s(): Unrecognized code type %x at "			    "pcids %x.\n", __func__, code_type, pcids));			break;		}		last_image = bcode[0x15] & BIT_7;		/* Locate next PCI expansion ROM. */		pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512;	} while (!last_image);	/* Read firmware image information. */	memset(ha->fw_revision, 0, sizeof(ha->fw_revision));	dcode = mbuf;	qla24xx_read_flash_data(ha, dcode, FA_RISC_CODE_ADDR + 4, 4);	for (i = 0; i < 4; i++)		dcode[i] = be32_to_cpu(dcode[i]);	if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&	    dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||	    (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&	    dcode[3] == 0)) {		DEBUG2(printk("%s(): Unrecognized fw version at %x.\n",		    __func__, FA_RISC_CODE_ADDR));	} else {		ha->fw_revision[0] = dcode[0];		ha->fw_revision[1] = dcode[1];		ha->fw_revision[2] = dcode[2];		ha->fw_revision[3] = dcode[3];	}	return ret;}

⌨️ 快捷键说明

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