⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  drivers/s390/cio/chp.c * *    Copyright IBM Corp. 1999,2007 *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com) *		 Arnd Bergmann (arndb@de.ibm.com) *		 Peter Oberparleiter <peter.oberparleiter@de.ibm.com> */#include <linux/bug.h>#include <linux/workqueue.h>#include <linux/spinlock.h>#include <linux/init.h>#include <linux/jiffies.h>#include <linux/wait.h>#include <linux/mutex.h>#include <linux/errno.h>#include <asm/chpid.h>#include <asm/sclp.h>#include "cio.h"#include "css.h"#include "ioasm.h"#include "cio_debug.h"#include "chp.h"#define to_channelpath(device) container_of(device, struct channel_path, dev)#define CHP_INFO_UPDATE_INTERVAL	1*HZenum cfg_task_t {	cfg_none,	cfg_configure,	cfg_deconfigure};/* Map for pending configure tasks. */static enum cfg_task_t chp_cfg_task[__MAX_CSSID + 1][__MAX_CHPID + 1];static DEFINE_MUTEX(cfg_lock);static int cfg_busy;/* Map for channel-path status. */static struct sclp_chp_info chp_info;static DEFINE_MUTEX(info_lock);/* Time after which channel-path status may be outdated. */static unsigned long chp_info_expires;/* Workqueue to perform pending configure tasks. */static struct workqueue_struct *chp_wq;static struct work_struct cfg_work;/* Wait queue for configure completion events. */static wait_queue_head_t cfg_wait_queue;/* Return channel_path struct for given chpid. */static inline struct channel_path *chpid_to_chp(struct chp_id chpid){	return channel_subsystems[chpid.cssid]->chps[chpid.id];}/* Set vary state for given chpid. */static void set_chp_logically_online(struct chp_id chpid, int onoff){	chpid_to_chp(chpid)->state = onoff;}/* On succes return 0 if channel-path is varied offline, 1 if it is varied * online. Return -ENODEV if channel-path is not registered. */int chp_get_status(struct chp_id chpid){	return (chpid_to_chp(chpid) ? chpid_to_chp(chpid)->state : -ENODEV);}/** * chp_get_sch_opm - return opm for subchannel * @sch: subchannel * * Calculate and return the operational path mask (opm) based on the chpids * used by the subchannel and the status of the associated channel-paths. */u8 chp_get_sch_opm(struct subchannel *sch){	struct chp_id chpid;	int opm;	int i;	opm = 0;	chp_id_init(&chpid);	for (i = 0; i < 8; i++) {		opm <<= 1;		chpid.id = sch->schib.pmcw.chpid[i];		if (chp_get_status(chpid) != 0)			opm |= 1;	}	return opm;}/** * chp_is_registered - check if a channel-path is registered * @chpid: channel-path ID * * Return non-zero if a channel-path with the given chpid is registered, * zero otherwise. */int chp_is_registered(struct chp_id chpid){	return chpid_to_chp(chpid) != NULL;}/* * Function: s390_vary_chpid * Varies the specified chpid online or offline */static int s390_vary_chpid(struct chp_id chpid, int on){	char dbf_text[15];	int status;	sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid,		chpid.id);	CIO_TRACE_EVENT(2, dbf_text);	status = chp_get_status(chpid);	if (!on && !status) {		printk(KERN_ERR "cio: chpid %x.%02x is already offline\n",		       chpid.cssid, chpid.id);		return -EINVAL;	}	set_chp_logically_online(chpid, on);	chsc_chp_vary(chpid, on);	return 0;}/* * Channel measurement related functions */static ssize_t chp_measurement_chars_read(struct kobject *kobj,					  struct bin_attribute *bin_attr,					  char *buf, loff_t off, size_t count){	struct channel_path *chp;	struct device *device;	unsigned int size;	device = container_of(kobj, struct device, kobj);	chp = to_channelpath(device);	if (!chp->cmg_chars)		return 0;	size = sizeof(struct cmg_chars);	if (off > size)		return 0;	if (off + count > size)		count = size - off;	memcpy(buf, chp->cmg_chars + off, count);	return count;}static struct bin_attribute chp_measurement_chars_attr = {	.attr = {		.name = "measurement_chars",		.mode = S_IRUSR,	},	.size = sizeof(struct cmg_chars),	.read = chp_measurement_chars_read,};static void chp_measurement_copy_block(struct cmg_entry *buf,				       struct channel_subsystem *css,				       struct chp_id chpid){	void *area;	struct cmg_entry *entry, reference_buf;	int idx;	if (chpid.id < 128) {		area = css->cub_addr1;		idx = chpid.id;	} else {		area = css->cub_addr2;		idx = chpid.id - 128;	}	entry = area + (idx * sizeof(struct cmg_entry));	do {		memcpy(buf, entry, sizeof(*entry));		memcpy(&reference_buf, entry, sizeof(*entry));	} while (reference_buf.values[0] != buf->values[0]);}static ssize_t chp_measurement_read(struct kobject *kobj,				    struct bin_attribute *bin_attr,				    char *buf, loff_t off, size_t count){	struct channel_path *chp;	struct channel_subsystem *css;	struct device *device;	unsigned int size;	device = container_of(kobj, struct device, kobj);	chp = to_channelpath(device);	css = to_css(chp->dev.parent);	size = sizeof(struct cmg_entry);	/* Only allow single reads. */	if (off || count < size)		return 0;	chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->chpid);	count = size;	return count;}static struct bin_attribute chp_measurement_attr = {	.attr = {		.name = "measurement",		.mode = S_IRUSR,	},	.size = sizeof(struct cmg_entry),	.read = chp_measurement_read,};void chp_remove_cmg_attr(struct channel_path *chp){	device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);	device_remove_bin_file(&chp->dev, &chp_measurement_attr);}int chp_add_cmg_attr(struct channel_path *chp){	int ret;	ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr);	if (ret)		return ret;	ret = device_create_bin_file(&chp->dev, &chp_measurement_attr);	if (ret)		device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);	return ret;}/* * Files for the channel path entries. */static ssize_t chp_status_show(struct device *dev,			       struct device_attribute *attr, char *buf){	struct channel_path *chp = to_channelpath(dev);	if (!chp)		return 0;	return (chp_get_status(chp->chpid) ? sprintf(buf, "online\n") :		sprintf(buf, "offline\n"));}static ssize_t chp_status_write(struct device *dev,				struct device_attribute *attr,				const char *buf, size_t count){	struct channel_path *cp = to_channelpath(dev);	char cmd[10];	int num_args;	int error;	num_args = sscanf(buf, "%5s", cmd);	if (!num_args)		return count;	if (!strnicmp(cmd, "on", 2) || !strcmp(cmd, "1"))		error = s390_vary_chpid(cp->chpid, 1);	else if (!strnicmp(cmd, "off", 3) || !strcmp(cmd, "0"))		error = s390_vary_chpid(cp->chpid, 0);	else		error = -EINVAL;	return error < 0 ? error : count;}static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write);static ssize_t chp_configure_show(struct device *dev,				  struct device_attribute *attr, char *buf){	struct channel_path *cp;	int status;	cp = to_channelpath(dev);	status = chp_info_get_status(cp->chpid);	if (status < 0)		return status;	return snprintf(buf, PAGE_SIZE, "%d\n", status);}static int cfg_wait_idle(void);static ssize_t chp_configure_write(struct device *dev,				   struct device_attribute *attr,				   const char *buf, size_t count){	struct channel_path *cp;	int val;	char delim;	if (sscanf(buf, "%d %c", &val, &delim) != 1)		return -EINVAL;	if (val != 0 && val != 1)		return -EINVAL;	cp = to_channelpath(dev);	chp_cfg_schedule(cp->chpid, val);	cfg_wait_idle();	return count;}static DEVICE_ATTR(configure, 0644, chp_configure_show, chp_configure_write);static ssize_t chp_type_show(struct device *dev, struct device_attribute *attr,			     char *buf){	struct channel_path *chp = to_channelpath(dev);	if (!chp)		return 0;	return sprintf(buf, "%x\n", chp->desc.desc);}static DEVICE_ATTR(type, 0444, chp_type_show, NULL);static ssize_t chp_cmg_show(struct device *dev, struct device_attribute *attr,			    char *buf){	struct channel_path *chp = to_channelpath(dev);	if (!chp)		return 0;

⌨️ 快捷键说明

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