1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/module.h>
24#include <linux/types.h>
25#include <linux/errno.h>
26#include <linux/proc_fs.h>
27#include <linux/init.h>
28#include <linux/delay.h>
29#include <asm/uaccess.h>
30#include <asm/rtas.h>
31#include <asm/prom.h>
32
33#define MODULE_VERS "1.0"
34#define MODULE_NAME "scanlog"
35
36
37#define SCANLOG_COMPLETE 0
38#define SCANLOG_HWERROR -1
39#define SCANLOG_CONTINUE 1
40
41
42static unsigned int ibm_scan_log_dump;
43static struct proc_dir_entry *proc_ppc64_scan_log_dump;
44
45static ssize_t scanlog_read(struct file *file, char __user *buf,
46 size_t count, loff_t *ppos)
47{
48 struct inode * inode = file->f_path.dentry->d_inode;
49 struct proc_dir_entry *dp;
50 unsigned int *data;
51 int status;
52 unsigned long len, off;
53 unsigned int wait_time;
54
55 dp = PDE(inode);
56 data = (unsigned int *)dp->data;
57
58 if (count > RTAS_DATA_BUF_SIZE)
59 count = RTAS_DATA_BUF_SIZE;
60
61 if (count < 1024) {
62
63
64
65
66 printk(KERN_ERR "scanlog: cannot perform a small read (%ld)\n", count);
67 return -EINVAL;
68 }
69
70 if (!access_ok(VERIFY_WRITE, buf, count))
71 return -EFAULT;
72
73 for (;;) {
74 wait_time = 500;
75 spin_lock(&rtas_data_buf_lock);
76 memcpy(rtas_data_buf, data, RTAS_DATA_BUF_SIZE);
77 status = rtas_call(ibm_scan_log_dump, 2, 1, NULL,
78 (u32) __pa(rtas_data_buf), (u32) count);
79 memcpy(data, rtas_data_buf, RTAS_DATA_BUF_SIZE);
80 spin_unlock(&rtas_data_buf_lock);
81
82 pr_debug("scanlog: status=%d, data[0]=%x, data[1]=%x, " \
83 "data[2]=%x\n", status, data[0], data[1], data[2]);
84 switch (status) {
85 case SCANLOG_COMPLETE:
86 pr_debug("scanlog: hit eof\n");
87 return 0;
88 case SCANLOG_HWERROR:
89 pr_debug("scanlog: hardware error reading data\n");
90 return -EIO;
91 case SCANLOG_CONTINUE:
92
93 len = data[1];
94 off = data[2];
95 if (len > 0) {
96 if (copy_to_user(buf, ((char *)data)+off, len))
97 return -EFAULT;
98 return len;
99 }
100
101 break;
102 default:
103
104 wait_time = rtas_busy_delay_time(status);
105 if (!wait_time) {
106 printk(KERN_ERR "scanlog: unknown error " \
107 "from rtas: %d\n", status);
108 return -EIO;
109 }
110 }
111
112 msleep_interruptible(wait_time);
113 }
114
115}
116
117static ssize_t scanlog_write(struct file * file, const char __user * buf,
118 size_t count, loff_t *ppos)
119{
120 char stkbuf[20];
121 int status;
122
123 if (count > 19) count = 19;
124 if (copy_from_user (stkbuf, buf, count)) {
125 return -EFAULT;
126 }
127 stkbuf[count] = 0;
128
129 if (buf) {
130 if (strncmp(stkbuf, "reset", 5) == 0) {
131 pr_debug("scanlog: reset scanlog\n");
132 status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, 0, 0);
133 pr_debug("scanlog: rtas returns %d\n", status);
134 }
135 }
136 return count;
137}
138
139static int scanlog_open(struct inode * inode, struct file * file)
140{
141 struct proc_dir_entry *dp = PDE(inode);
142 unsigned int *data = (unsigned int *)dp->data;
143
144 if (data[0] != 0) {
145
146
147
148 return -EBUSY;
149 }
150
151 data[0] = 0;
152
153 return 0;
154}
155
156static int scanlog_release(struct inode * inode, struct file * file)
157{
158 struct proc_dir_entry *dp = PDE(inode);
159 unsigned int *data = (unsigned int *)dp->data;
160
161 data[0] = 0;
162
163 return 0;
164}
165
166const struct file_operations scanlog_fops = {
167 .owner = THIS_MODULE,
168 .read = scanlog_read,
169 .write = scanlog_write,
170 .open = scanlog_open,
171 .release = scanlog_release,
172};
173
174static int __init scanlog_init(void)
175{
176 struct proc_dir_entry *ent;
177 void *data;
178 int err = -ENOMEM;
179
180 ibm_scan_log_dump = rtas_token("ibm,scan-log-dump");
181 if (ibm_scan_log_dump == RTAS_UNKNOWN_SERVICE)
182 return -ENODEV;
183
184
185 data = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
186 if (!data)
187 goto err;
188
189 ent = proc_create_data("ppc64/rtas/scan-log-dump", S_IRUSR, NULL,
190 &scanlog_fops, data);
191 if (!ent)
192 goto err;
193
194 proc_ppc64_scan_log_dump = ent;
195
196 return 0;
197err:
198 kfree(data);
199 return err;
200}
201
202static void __exit scanlog_cleanup(void)
203{
204 if (proc_ppc64_scan_log_dump) {
205 kfree(proc_ppc64_scan_log_dump->data);
206 remove_proc_entry("scan-log-dump", proc_ppc64_scan_log_dump->parent);
207 }
208}
209
210module_init(scanlog_init);
211module_exit(scanlog_cleanup);
212MODULE_LICENSE("GPL");
213