patch-2.4.22 linux-2.4.22/arch/ppc64/kernel/rtas-proc.c

Next file: linux-2.4.22/arch/ppc64/kernel/rtas.c
Previous file: linux-2.4.22/arch/ppc64/kernel/prom.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/arch/ppc64/kernel/rtas-proc.c linux-2.4.22/arch/ppc64/kernel/rtas-proc.c
@@ -115,14 +115,18 @@
 
 
 /* Globals */
-static struct proc_dir_entry *proc_rtas;
 static struct rtas_sensors sensors;
-static struct device_node *rtas_node;
+static struct device_node *rtas_node = NULL;
 static unsigned long power_on_time = 0; /* Save the time the user set */
 static char progress_led[MAX_LINELENGTH];
 
 static unsigned long rtas_tone_frequency = 1000;
 static unsigned long rtas_tone_volume = 0;
+static unsigned int open_token = 0;
+
+extern struct proc_dir_entry *proc_ppc64_root;
+extern struct proc_dir_entry *rtas_proc_dir;
+extern spinlock_t proc_ppc64_lock;
 
 /* ****************STRUCTS******************************************* */
 struct individual_sensor {
@@ -160,6 +164,12 @@
 		size_t count, loff_t *ppos);
 static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
 		size_t count, loff_t *ppos);
+static int ppc_rtas_errinjct_open(struct inode *inode, struct file *file);
+static int ppc_rtas_errinjct_release(struct inode *inode, struct file *file);
+static ssize_t ppc_rtas_errinjct_write(struct file * file, const char * buf,
+				   size_t count, loff_t *ppos);
+static ssize_t ppc_rtas_errinjct_read(struct file *file, char *buf,
+				      size_t count, loff_t *ppos);
 
 struct file_operations ppc_rtas_poweron_operations = {
 	.read =		ppc_rtas_poweron_read,
@@ -184,6 +194,13 @@
 	.write =	ppc_rtas_tone_volume_write
 };
 
+struct file_operations ppc_rtas_errinjct_operations = {
+    .open =		ppc_rtas_errinjct_open,
+    .read = 		ppc_rtas_errinjct_read,
+    .write = 		ppc_rtas_errinjct_write,
+    .release = 		ppc_rtas_errinjct_release
+};
+
 int ppc_rtas_find_all_sensors (void);
 int ppc_rtas_process_sensor(struct individual_sensor s, int state, 
 		int error, char * buf);
@@ -200,33 +217,54 @@
 	struct proc_dir_entry *entry;
 
 	rtas_node = find_devices("rtas");
-	if ((rtas_node == 0) || (systemcfg->platform == PLATFORM_ISERIES_LPAR)) {
+	if ((rtas_node == NULL) || (systemcfg->platform == PLATFORM_ISERIES_LPAR)) {
 		return;
 	}
 	
-	proc_rtas = proc_mkdir("rtas", 0);
-	if (proc_rtas == 0)
+	spin_lock(&proc_ppc64_lock);
+	if (proc_ppc64_root == NULL) {
+		proc_ppc64_root = proc_mkdir("ppc64", 0);
+		if (!proc_ppc64_root) {
+			spin_unlock(&proc_ppc64_lock);
+			return;
+		}		
+	}
+	spin_unlock(&proc_ppc64_lock);
+	
+	if (rtas_proc_dir == NULL) {
+		rtas_proc_dir = proc_mkdir("rtas", proc_ppc64_root);
+	}
+
+	if (rtas_proc_dir == NULL) {
+		printk(KERN_ERR "Failed to create /proc/ppc64/rtas in rtas_init\n");
 		return;
+	}
 
 	/* /proc/rtas entries */
 
-	entry = create_proc_entry("progress", S_IRUGO|S_IWUSR, proc_rtas);
+	entry = create_proc_entry("progress", S_IRUGO|S_IWUSR, rtas_proc_dir);
 	if (entry) entry->proc_fops = &ppc_rtas_progress_operations;
 
-	entry = create_proc_entry("clock", S_IRUGO|S_IWUSR, proc_rtas); 
+	entry = create_proc_entry("clock", S_IRUGO|S_IWUSR, rtas_proc_dir); 
 	if (entry) entry->proc_fops = &ppc_rtas_clock_operations;
 
-	entry = create_proc_entry("poweron", S_IWUSR|S_IRUGO, proc_rtas); 
+	entry = create_proc_entry("poweron", S_IWUSR|S_IRUGO, rtas_proc_dir); 
 	if (entry) entry->proc_fops = &ppc_rtas_poweron_operations;
 
-	create_proc_read_entry("sensors", S_IRUGO, proc_rtas, 
+	create_proc_read_entry("sensors", S_IRUGO, rtas_proc_dir, 
 			ppc_rtas_sensor_read, NULL);
 	
-	entry = create_proc_entry("frequency", S_IWUSR|S_IRUGO, proc_rtas); 
+	entry = create_proc_entry("frequency", S_IWUSR|S_IRUGO, rtas_proc_dir); 
 	if (entry) entry->proc_fops = &ppc_rtas_tone_freq_operations;
 
-	entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_rtas); 
+	entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, rtas_proc_dir); 
 	if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations;
+
+#ifdef CONFIG_RTAS_ERRINJCT
+	entry = create_proc_entry("errinjct", S_IWUSR|S_IRUGO, rtas_proc_dir);
+	if (entry) entry->proc_fops = &ppc_rtas_errinjct_operations;
+#endif
+
 }
 
 /* ****************************************************************** */
@@ -405,10 +443,14 @@
 		j = sensors.sensor[i].quant;
 		/* A sensor may have multiple instances */
 		while (j >= 0) {
+
 			error =	rtas_call(get_sensor_state, 2, 2, &ret, 
-				  sensors.sensor[i].token, sensors.sensor[i].quant-j);
+				  	  sensors.sensor[i].token, 
+				  	  sensors.sensor[i].quant - j);
+
 			state = (int) ret;
-			n += ppc_rtas_process_sensor(sensors.sensor[i], state, error, buffer+n );
+			n += ppc_rtas_process_sensor(sensors.sensor[i], state, 
+					     	     error, buffer+n );
 			n += sprintf (buffer+n, "\n");
 			j--;
 		} /* while */
@@ -426,6 +468,7 @@
 		n = count;
 	else
 		*eof = 1;
+
 	memcpy(buf, buffer + off, n);
 	*start = buf;
 	kfree(buffer);
@@ -436,10 +479,10 @@
 
 int ppc_rtas_find_all_sensors (void)
 {
-	unsigned long *utmp;
-	int len, i, j;
+	unsigned int *utmp;
+	int len, i;
 
-	utmp = (unsigned long *) get_property(rtas_node, "rtas-sensors", &len);
+	utmp = (unsigned int *) get_property(rtas_node, "rtas-sensors", &len);
 	if (utmp == NULL) {
 		printk (KERN_ERR "error: could not get rtas-sensors\n");
 		return 1;
@@ -447,9 +490,9 @@
 
 	sensors.quant = len / 8;      /* int + int */
 
-	for (i=0, j=0; j<sensors.quant; i+=2, j++) {
-		sensors.sensor[j].token = utmp[i];
-		sensors.sensor[j].quant = utmp[i+1];
+	for (i=0; i<sensors.quant; i++) {
+		sensors.sensor[i].token = *utmp++;
+		sensors.sensor[i].quant = *utmp++;
 	}
 	return 0;
 }
@@ -515,6 +558,7 @@
 	int n = 0;
 
 	/* What kind of sensor do we have here? */
+	
 	switch (s.token) {
 		case KEY_SWITCH:
 			n += sprintf(buf+n, "Key switch:\t");
@@ -698,9 +742,9 @@
 	ret = (char *) get_property(rtas_node, rstr, &llen);
 
 	n=0;
-	if (ret[0] == '\0')
+	if (ret == NULL || ret[0] == '\0') {
 		n += sprintf ( buffer+n, "--- ");/* does not have a location */
-	else {
+	} else {
 		char t[50];
 		ret += pos;
 
@@ -794,3 +838,137 @@
 	*ppos += n;
 	return n;
 }
+
+/* ****************************************************************** */
+/* ERRINJCT			                                      */
+/* ****************************************************************** */
+static int ppc_rtas_errinjct_open(struct inode *inode, struct file *file)
+{
+	int rc;
+
+	/* We will only allow one process to use error inject at a
+	   time.  Since errinjct is usually only used for testing,
+	   this shouldn't be an issue */
+	if (open_token) {
+		return -EAGAIN;
+	}
+	rc = rtas_errinjct_open();
+	if (rc < 0) {
+		return -EIO;
+	}
+	open_token = rc;
+
+	return 0;
+}
+
+static ssize_t ppc_rtas_errinjct_write(struct file * file, const char * buf,
+				       size_t count, loff_t *ppos)
+{
+ 
+	char * ei_token;
+	char * workspace = NULL;
+	size_t max_len;
+	int token_len;
+	int rc;
+
+	/* Verify the errinjct token length */
+	if (count < ERRINJCT_TOKEN_LEN) {
+		max_len = count;
+	} else {
+		max_len = ERRINJCT_TOKEN_LEN;
+	}
+
+	token_len = strnlen(buf, max_len);
+	token_len++; /* Add one for the null termination */
+    
+	ei_token = (char *)kmalloc(token_len, GFP_KERNEL);
+	if (!ei_token) {
+		printk(KERN_WARNING "error: kmalloc failed\n");
+		return -ENOMEM;
+	}
+
+	strncpy(ei_token, buf, token_len);
+    
+	if (count > token_len + WORKSPACE_SIZE) {
+		count = token_len + WORKSPACE_SIZE;
+	}
+    
+	buf += token_len;
+
+	/* check if there is a workspace */
+	if (count > token_len) {
+		/* Verify the workspace size */
+		if ((count - token_len) > WORKSPACE_SIZE) {
+			max_len = WORKSPACE_SIZE;
+		} else {
+			max_len = count - token_len;
+		}
+
+		workspace = (char *)kmalloc(max_len, GFP_KERNEL);
+		if (!workspace) {
+			printk(KERN_WARNING "error: failed kmalloc\n");
+			kfree(ei_token);
+			return -ENOMEM;
+		}
+	
+		memcpy(workspace, buf, max_len);
+	}
+
+	rc = rtas_errinjct(open_token, ei_token, workspace);
+
+	if (count > token_len) {
+		kfree(workspace);
+	}
+	kfree(ei_token);
+
+	return rc < 0 ? rc : count;
+}
+
+static int ppc_rtas_errinjct_release(struct inode *inode, struct file *file)
+{
+	int rc;
+    
+	rc = rtas_errinjct_close(open_token);
+	if (rc) {
+		return rc;
+	}
+	open_token = 0;
+	return 0;
+}
+
+static ssize_t ppc_rtas_errinjct_read(struct file *file, char *buf,
+				      size_t count, loff_t *ppos) 
+{
+	char * buffer;
+	int i;
+	int n = 0;
+
+	buffer = (char *)kmalloc(MAX_ERRINJCT_TOKENS * (ERRINJCT_TOKEN_LEN+1),
+				 GFP_KERNEL);
+	if (!buffer) {
+		printk(KERN_ERR "error: kmalloc failed\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < MAX_ERRINJCT_TOKENS && ei_token_list[i].value; i++) {
+		n += sprintf(buffer+n, ei_token_list[i].name);
+		n += sprintf(buffer+n, "\n");
+	}
+
+	if (*ppos >= strlen(buffer)) {
+		kfree(buffer);
+		return 0;
+	}
+	if (n > strlen(buffer) - *ppos)
+		n = strlen(buffer) - *ppos;
+
+	if (n > count)
+		n = count;
+
+	memcpy(buf, buffer + *ppos, n);
+
+	*ppos += n;
+
+	kfree(buffer);
+	return n;
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)