qla_attr.c

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

C
1,253
字号
/* * 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/kthread.h>#include <linux/vmalloc.h>int qla24xx_vport_disable(struct fc_vport *, bool);/* SYSFS attributes --------------------------------------------------------- */static ssize_tqla2x00_sysfs_read_fw_dump(struct kobject *kobj,			   struct bin_attribute *bin_attr,			   char *buf, loff_t off, size_t count){	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,	    struct device, kobj)));	char *rbuf = (char *)ha->fw_dump;	if (ha->fw_dump_reading == 0)		return 0;	if (off > ha->fw_dump_len)                return 0;	if (off + count > ha->fw_dump_len)		count = ha->fw_dump_len - off;	memcpy(buf, &rbuf[off], count);	return (count);}static ssize_tqla2x00_sysfs_write_fw_dump(struct kobject *kobj,			    struct bin_attribute *bin_attr,			    char *buf, loff_t off, size_t count){	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,	    struct device, kobj)));	int reading;	if (off != 0)		return (0);	reading = simple_strtol(buf, NULL, 10);	switch (reading) {	case 0:		if (!ha->fw_dump_reading)			break;		qla_printk(KERN_INFO, ha,		    "Firmware dump cleared on (%ld).\n", ha->host_no);		ha->fw_dump_reading = 0;		ha->fw_dumped = 0;		break;	case 1:		if (ha->fw_dumped && !ha->fw_dump_reading) {			ha->fw_dump_reading = 1;			qla_printk(KERN_INFO, ha,			    "Raw firmware dump ready for read on (%ld).\n",			    ha->host_no);		}		break;	case 2:		qla2x00_alloc_fw_dump(ha);		break;	}	return (count);}static struct bin_attribute sysfs_fw_dump_attr = {	.attr = {		.name = "fw_dump",		.mode = S_IRUSR | S_IWUSR,	},	.size = 0,	.read = qla2x00_sysfs_read_fw_dump,	.write = qla2x00_sysfs_write_fw_dump,};static ssize_tqla2x00_sysfs_read_nvram(struct kobject *kobj,			 struct bin_attribute *bin_attr,			 char *buf, loff_t off, size_t count){	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,	    struct device, kobj)));	int		size = ha->nvram_size;	char		*nvram_cache = ha->nvram;	if (!capable(CAP_SYS_ADMIN) || off > size || count == 0)		return 0;	if (off + count > size) {		size -= off;		count = size;	}	/* Read NVRAM data from cache. */	memcpy(buf, &nvram_cache[off], count);	return count;}static ssize_tqla2x00_sysfs_write_nvram(struct kobject *kobj,			  struct bin_attribute *bin_attr,			  char *buf, loff_t off, size_t count){	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,	    struct device, kobj)));	uint16_t	cnt;	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->nvram_size)		return 0;	/* Checksum NVRAM. */	if (IS_FWI2_CAPABLE(ha)) {		uint32_t *iter;		uint32_t chksum;		iter = (uint32_t *)buf;		chksum = 0;		for (cnt = 0; cnt < ((count >> 2) - 1); cnt++)			chksum += le32_to_cpu(*iter++);		chksum = ~chksum + 1;		*iter = cpu_to_le32(chksum);	} else {		uint8_t *iter;		uint8_t chksum;		iter = (uint8_t *)buf;		chksum = 0;		for (cnt = 0; cnt < count - 1; cnt++)			chksum += *iter++;		chksum = ~chksum + 1;		*iter = chksum;	}	/* Write NVRAM. */	ha->isp_ops->write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count);	ha->isp_ops->read_nvram(ha, (uint8_t *)ha->nvram, ha->nvram_base,	    count);	set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);	return (count);}static struct bin_attribute sysfs_nvram_attr = {	.attr = {		.name = "nvram",		.mode = S_IRUSR | S_IWUSR,	},	.size = 512,	.read = qla2x00_sysfs_read_nvram,	.write = qla2x00_sysfs_write_nvram,};static ssize_tqla2x00_sysfs_read_optrom(struct kobject *kobj,			  struct bin_attribute *bin_attr,			  char *buf, loff_t off, size_t count){	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,	    struct device, kobj)));	if (ha->optrom_state != QLA_SREADING)		return 0;	if (off > ha->optrom_region_size)		return 0;	if (off + count > ha->optrom_region_size)		count = ha->optrom_region_size - off;	memcpy(buf, &ha->optrom_buffer[off], count);	return count;}static ssize_tqla2x00_sysfs_write_optrom(struct kobject *kobj,			   struct bin_attribute *bin_attr,			   char *buf, loff_t off, size_t count){	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,	    struct device, kobj)));	if (ha->optrom_state != QLA_SWRITING)		return -EINVAL;	if (off > ha->optrom_region_size)		return -ERANGE;	if (off + count > ha->optrom_region_size)		count = ha->optrom_region_size - off;	memcpy(&ha->optrom_buffer[off], buf, count);	return count;}static struct bin_attribute sysfs_optrom_attr = {	.attr = {		.name = "optrom",		.mode = S_IRUSR | S_IWUSR,	},	.size = 0,	.read = qla2x00_sysfs_read_optrom,	.write = qla2x00_sysfs_write_optrom,};static ssize_tqla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,			       struct bin_attribute *bin_attr,			       char *buf, loff_t off, size_t count){	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,	    struct device, kobj)));	uint32_t start = 0;	uint32_t size = ha->optrom_size;	int val, valid;	if (off)		return 0;	if (sscanf(buf, "%d:%x:%x", &val, &start, &size) < 1)		return -EINVAL;	if (start > ha->optrom_size)		return -EINVAL;	switch (val) {	case 0:		if (ha->optrom_state != QLA_SREADING &&		    ha->optrom_state != QLA_SWRITING)			break;		ha->optrom_state = QLA_SWAITING;		DEBUG2(qla_printk(KERN_INFO, ha,		    "Freeing flash region allocation -- 0x%x bytes.\n",		    ha->optrom_region_size));		vfree(ha->optrom_buffer);		ha->optrom_buffer = NULL;		break;	case 1:		if (ha->optrom_state != QLA_SWAITING)			break;		if (start & 0xfff) {			qla_printk(KERN_WARNING, ha,			    "Invalid start region 0x%x/0x%x.\n", start, size);			return -EINVAL;		}		ha->optrom_region_start = start;		ha->optrom_region_size = start + size > ha->optrom_size ?		    ha->optrom_size - start : size;		ha->optrom_state = QLA_SREADING;		ha->optrom_buffer = vmalloc(ha->optrom_region_size);		if (ha->optrom_buffer == NULL) {			qla_printk(KERN_WARNING, ha,			    "Unable to allocate memory for optrom retrieval "			    "(%x).\n", ha->optrom_region_size);			ha->optrom_state = QLA_SWAITING;			return count;		}		DEBUG2(qla_printk(KERN_INFO, ha,		    "Reading flash region -- 0x%x/0x%x.\n",		    ha->optrom_region_start, ha->optrom_region_size));		memset(ha->optrom_buffer, 0, ha->optrom_region_size);		ha->isp_ops->read_optrom(ha, ha->optrom_buffer,		    ha->optrom_region_start, ha->optrom_region_size);		break;	case 2:		if (ha->optrom_state != QLA_SWAITING)			break;		/*		 * We need to be more restrictive on which FLASH regions are		 * allowed to be updated via user-space.  Regions accessible		 * via this method include:		 *		 * ISP21xx/ISP22xx/ISP23xx type boards:		 *		 * 	0x000000 -> 0x020000 -- Boot code.		 *		 * ISP2322/ISP24xx type boards:		 *		 * 	0x000000 -> 0x07ffff -- Boot code.		 * 	0x080000 -> 0x0fffff -- Firmware.		 *		 * ISP25xx type boards:		 *		 * 	0x000000 -> 0x07ffff -- Boot code.		 * 	0x080000 -> 0x0fffff -- Firmware.		 * 	0x120000 -> 0x12ffff -- VPD and HBA parameters.		 */		valid = 0;		if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)			valid = 1;		else if (start == (FA_BOOT_CODE_ADDR*4) ||		    start == (FA_RISC_CODE_ADDR*4))			valid = 1;		else if (IS_QLA25XX(ha) && start == (FA_VPD_NVRAM_ADDR*4))		    valid = 1;		if (!valid) {			qla_printk(KERN_WARNING, ha,			    "Invalid start region 0x%x/0x%x.\n", start, size);			return -EINVAL;		}		ha->optrom_region_start = start;		ha->optrom_region_size = start + size > ha->optrom_size ?		    ha->optrom_size - start : size;		ha->optrom_state = QLA_SWRITING;		ha->optrom_buffer = vmalloc(ha->optrom_region_size);		if (ha->optrom_buffer == NULL) {			qla_printk(KERN_WARNING, ha,			    "Unable to allocate memory for optrom update "			    "(%x).\n", ha->optrom_region_size);			ha->optrom_state = QLA_SWAITING;			return count;		}		DEBUG2(qla_printk(KERN_INFO, ha,		    "Staging flash region write -- 0x%x/0x%x.\n",		    ha->optrom_region_start, ha->optrom_region_size));		memset(ha->optrom_buffer, 0, ha->optrom_region_size);		break;	case 3:		if (ha->optrom_state != QLA_SWRITING)			break;		DEBUG2(qla_printk(KERN_INFO, ha,		    "Writing flash region -- 0x%x/0x%x.\n",		    ha->optrom_region_start, ha->optrom_region_size));		ha->isp_ops->write_optrom(ha, ha->optrom_buffer,		    ha->optrom_region_start, ha->optrom_region_size);		break;	default:		count = -EINVAL;	}	return count;}static struct bin_attribute sysfs_optrom_ctl_attr = {	.attr = {		.name = "optrom_ctl",		.mode = S_IWUSR,	},	.size = 0,	.write = qla2x00_sysfs_write_optrom_ctl,};static ssize_tqla2x00_sysfs_read_vpd(struct kobject *kobj,		       struct bin_attribute *bin_attr,		       char *buf, loff_t off, size_t count){	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,	    struct device, kobj)));	int           size = ha->vpd_size;	char          *vpd_cache = ha->vpd;	if (!capable(CAP_SYS_ADMIN) || off > size || count == 0)		return 0;	if (off + count > size) {		size -= off;		count = size;	}	/* Read NVRAM data from cache. */	memcpy(buf, &vpd_cache[off], count);	return count;}static ssize_tqla2x00_sysfs_write_vpd(struct kobject *kobj,			struct bin_attribute *bin_attr,			char *buf, loff_t off, size_t count){	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,	    struct device, kobj)));	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size)		return 0;	/* Write NVRAM. */	ha->isp_ops->write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count);	ha->isp_ops->read_nvram(ha, (uint8_t *)ha->vpd, ha->vpd_base, count);	return count;}static struct bin_attribute sysfs_vpd_attr = {	.attr = {		.name = "vpd",		.mode = S_IRUSR | S_IWUSR,	},	.size = 0,	.read = qla2x00_sysfs_read_vpd,	.write = qla2x00_sysfs_write_vpd,};static ssize_t

⌨️ 快捷键说明

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