diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/message/i2o/i2o_config.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/message/i2o/i2o_config.c')
-rw-r--r-- | drivers/message/i2o/i2o_config.c | 1160 |
1 files changed, 1160 insertions, 0 deletions
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c new file mode 100644 index 000000000000..5fc5004ea07a --- /dev/null +++ b/drivers/message/i2o/i2o_config.c | |||
@@ -0,0 +1,1160 @@ | |||
1 | /* | ||
2 | * I2O Configuration Interface Driver | ||
3 | * | ||
4 | * (C) Copyright 1999-2002 Red Hat | ||
5 | * | ||
6 | * Written by Alan Cox, Building Number Three Ltd | ||
7 | * | ||
8 | * Fixes/additions: | ||
9 | * Deepak Saxena (04/20/1999): | ||
10 | * Added basic ioctl() support | ||
11 | * Deepak Saxena (06/07/1999): | ||
12 | * Added software download ioctl (still testing) | ||
13 | * Auvo Häkkinen (09/10/1999): | ||
14 | * Changes to i2o_cfg_reply(), ioctl_parms() | ||
15 | * Added ioct_validate() | ||
16 | * Taneli Vähäkangas (09/30/1999): | ||
17 | * Fixed ioctl_swdl() | ||
18 | * Taneli Vähäkangas (10/04/1999): | ||
19 | * Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel() | ||
20 | * Deepak Saxena (11/18/1999): | ||
21 | * Added event managmenet support | ||
22 | * Alan Cox <alan@redhat.com>: | ||
23 | * 2.4 rewrite ported to 2.5 | ||
24 | * Markus Lidel <Markus.Lidel@shadowconnect.com>: | ||
25 | * Added pass-thru support for Adaptec's raidutils | ||
26 | * | ||
27 | * This program is free software; you can redistribute it and/or | ||
28 | * modify it under the terms of the GNU General Public License | ||
29 | * as published by the Free Software Foundation; either version | ||
30 | * 2 of the License, or (at your option) any later version. | ||
31 | */ | ||
32 | |||
33 | #include <linux/module.h> | ||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/pci.h> | ||
36 | #include <linux/i2o.h> | ||
37 | #include <linux/errno.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/miscdevice.h> | ||
41 | #include <linux/mm.h> | ||
42 | #include <linux/spinlock.h> | ||
43 | #include <linux/smp_lock.h> | ||
44 | #include <linux/ioctl32.h> | ||
45 | #include <linux/compat.h> | ||
46 | #include <linux/syscalls.h> | ||
47 | |||
48 | #include <asm/uaccess.h> | ||
49 | #include <asm/io.h> | ||
50 | |||
51 | #define OSM_NAME "config-osm" | ||
52 | #define OSM_VERSION "$Rev$" | ||
53 | #define OSM_DESCRIPTION "I2O Configuration OSM" | ||
54 | |||
55 | extern int i2o_parm_issue(struct i2o_device *, int, void *, int, void *, int); | ||
56 | |||
57 | static spinlock_t i2o_config_lock; | ||
58 | |||
59 | #define MODINC(x,y) ((x) = ((x) + 1) % (y)) | ||
60 | |||
61 | struct sg_simple_element { | ||
62 | u32 flag_count; | ||
63 | u32 addr_bus; | ||
64 | }; | ||
65 | |||
66 | struct i2o_cfg_info { | ||
67 | struct file *fp; | ||
68 | struct fasync_struct *fasync; | ||
69 | struct i2o_evt_info event_q[I2O_EVT_Q_LEN]; | ||
70 | u16 q_in; // Queue head index | ||
71 | u16 q_out; // Queue tail index | ||
72 | u16 q_len; // Queue length | ||
73 | u16 q_lost; // Number of lost events | ||
74 | ulong q_id; // Event queue ID...used as tx_context | ||
75 | struct i2o_cfg_info *next; | ||
76 | }; | ||
77 | static struct i2o_cfg_info *open_files = NULL; | ||
78 | static ulong i2o_cfg_info_id = 0; | ||
79 | |||
80 | /* | ||
81 | * Each of these describes an i2o message handler. They are | ||
82 | * multiplexed by the i2o_core code | ||
83 | */ | ||
84 | |||
85 | static struct i2o_driver i2o_config_driver = { | ||
86 | .name = OSM_NAME | ||
87 | }; | ||
88 | |||
89 | static int i2o_cfg_getiops(unsigned long arg) | ||
90 | { | ||
91 | struct i2o_controller *c; | ||
92 | u8 __user *user_iop_table = (void __user *)arg; | ||
93 | u8 tmp[MAX_I2O_CONTROLLERS]; | ||
94 | int ret = 0; | ||
95 | |||
96 | memset(tmp, 0, MAX_I2O_CONTROLLERS); | ||
97 | |||
98 | list_for_each_entry(c, &i2o_controllers, list) | ||
99 | tmp[c->unit] = 1; | ||
100 | |||
101 | if (copy_to_user(user_iop_table, tmp, MAX_I2O_CONTROLLERS)) | ||
102 | ret = -EFAULT; | ||
103 | |||
104 | return ret; | ||
105 | }; | ||
106 | |||
107 | static int i2o_cfg_gethrt(unsigned long arg) | ||
108 | { | ||
109 | struct i2o_controller *c; | ||
110 | struct i2o_cmd_hrtlct __user *cmd = (struct i2o_cmd_hrtlct __user *)arg; | ||
111 | struct i2o_cmd_hrtlct kcmd; | ||
112 | i2o_hrt *hrt; | ||
113 | int len; | ||
114 | u32 reslen; | ||
115 | int ret = 0; | ||
116 | |||
117 | if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) | ||
118 | return -EFAULT; | ||
119 | |||
120 | if (get_user(reslen, kcmd.reslen) < 0) | ||
121 | return -EFAULT; | ||
122 | |||
123 | if (kcmd.resbuf == NULL) | ||
124 | return -EFAULT; | ||
125 | |||
126 | c = i2o_find_iop(kcmd.iop); | ||
127 | if (!c) | ||
128 | return -ENXIO; | ||
129 | |||
130 | hrt = (i2o_hrt *) c->hrt.virt; | ||
131 | |||
132 | len = 8 + ((hrt->entry_len * hrt->num_entries) << 2); | ||
133 | |||
134 | /* We did a get user...so assuming mem is ok...is this bad? */ | ||
135 | put_user(len, kcmd.reslen); | ||
136 | if (len > reslen) | ||
137 | ret = -ENOBUFS; | ||
138 | if (copy_to_user(kcmd.resbuf, (void *)hrt, len)) | ||
139 | ret = -EFAULT; | ||
140 | |||
141 | return ret; | ||
142 | }; | ||
143 | |||
144 | static int i2o_cfg_getlct(unsigned long arg) | ||
145 | { | ||
146 | struct i2o_controller *c; | ||
147 | struct i2o_cmd_hrtlct __user *cmd = (struct i2o_cmd_hrtlct __user *)arg; | ||
148 | struct i2o_cmd_hrtlct kcmd; | ||
149 | i2o_lct *lct; | ||
150 | int len; | ||
151 | int ret = 0; | ||
152 | u32 reslen; | ||
153 | |||
154 | if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) | ||
155 | return -EFAULT; | ||
156 | |||
157 | if (get_user(reslen, kcmd.reslen) < 0) | ||
158 | return -EFAULT; | ||
159 | |||
160 | if (kcmd.resbuf == NULL) | ||
161 | return -EFAULT; | ||
162 | |||
163 | c = i2o_find_iop(kcmd.iop); | ||
164 | if (!c) | ||
165 | return -ENXIO; | ||
166 | |||
167 | lct = (i2o_lct *) c->lct; | ||
168 | |||
169 | len = (unsigned int)lct->table_size << 2; | ||
170 | put_user(len, kcmd.reslen); | ||
171 | if (len > reslen) | ||
172 | ret = -ENOBUFS; | ||
173 | else if (copy_to_user(kcmd.resbuf, lct, len)) | ||
174 | ret = -EFAULT; | ||
175 | |||
176 | return ret; | ||
177 | }; | ||
178 | |||
179 | static int i2o_cfg_parms(unsigned long arg, unsigned int type) | ||
180 | { | ||
181 | int ret = 0; | ||
182 | struct i2o_controller *c; | ||
183 | struct i2o_device *dev; | ||
184 | struct i2o_cmd_psetget __user *cmd = | ||
185 | (struct i2o_cmd_psetget __user *)arg; | ||
186 | struct i2o_cmd_psetget kcmd; | ||
187 | u32 reslen; | ||
188 | u8 *ops; | ||
189 | u8 *res; | ||
190 | int len = 0; | ||
191 | |||
192 | u32 i2o_cmd = (type == I2OPARMGET ? | ||
193 | I2O_CMD_UTIL_PARAMS_GET : I2O_CMD_UTIL_PARAMS_SET); | ||
194 | |||
195 | if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_psetget))) | ||
196 | return -EFAULT; | ||
197 | |||
198 | if (get_user(reslen, kcmd.reslen)) | ||
199 | return -EFAULT; | ||
200 | |||
201 | c = i2o_find_iop(kcmd.iop); | ||
202 | if (!c) | ||
203 | return -ENXIO; | ||
204 | |||
205 | dev = i2o_iop_find_device(c, kcmd.tid); | ||
206 | if (!dev) | ||
207 | return -ENXIO; | ||
208 | |||
209 | ops = (u8 *) kmalloc(kcmd.oplen, GFP_KERNEL); | ||
210 | if (!ops) | ||
211 | return -ENOMEM; | ||
212 | |||
213 | if (copy_from_user(ops, kcmd.opbuf, kcmd.oplen)) { | ||
214 | kfree(ops); | ||
215 | return -EFAULT; | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * It's possible to have a _very_ large table | ||
220 | * and that the user asks for all of it at once... | ||
221 | */ | ||
222 | res = (u8 *) kmalloc(65536, GFP_KERNEL); | ||
223 | if (!res) { | ||
224 | kfree(ops); | ||
225 | return -ENOMEM; | ||
226 | } | ||
227 | |||
228 | len = i2o_parm_issue(dev, i2o_cmd, ops, kcmd.oplen, res, 65536); | ||
229 | kfree(ops); | ||
230 | |||
231 | if (len < 0) { | ||
232 | kfree(res); | ||
233 | return -EAGAIN; | ||
234 | } | ||
235 | |||
236 | put_user(len, kcmd.reslen); | ||
237 | if (len > reslen) | ||
238 | ret = -ENOBUFS; | ||
239 | else if (copy_to_user(kcmd.resbuf, res, len)) | ||
240 | ret = -EFAULT; | ||
241 | |||
242 | kfree(res); | ||
243 | |||
244 | return ret; | ||
245 | }; | ||
246 | |||
247 | static int i2o_cfg_swdl(unsigned long arg) | ||
248 | { | ||
249 | struct i2o_sw_xfer kxfer; | ||
250 | struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg; | ||
251 | unsigned char maxfrag = 0, curfrag = 1; | ||
252 | struct i2o_dma buffer; | ||
253 | struct i2o_message __iomem *msg; | ||
254 | u32 m; | ||
255 | unsigned int status = 0, swlen = 0, fragsize = 8192; | ||
256 | struct i2o_controller *c; | ||
257 | |||
258 | if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) | ||
259 | return -EFAULT; | ||
260 | |||
261 | if (get_user(swlen, kxfer.swlen) < 0) | ||
262 | return -EFAULT; | ||
263 | |||
264 | if (get_user(maxfrag, kxfer.maxfrag) < 0) | ||
265 | return -EFAULT; | ||
266 | |||
267 | if (get_user(curfrag, kxfer.curfrag) < 0) | ||
268 | return -EFAULT; | ||
269 | |||
270 | if (curfrag == maxfrag) | ||
271 | fragsize = swlen - (maxfrag - 1) * 8192; | ||
272 | |||
273 | if (!kxfer.buf || !access_ok(VERIFY_READ, kxfer.buf, fragsize)) | ||
274 | return -EFAULT; | ||
275 | |||
276 | c = i2o_find_iop(kxfer.iop); | ||
277 | if (!c) | ||
278 | return -ENXIO; | ||
279 | |||
280 | m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); | ||
281 | if (m == I2O_QUEUE_EMPTY) | ||
282 | return -EBUSY; | ||
283 | |||
284 | if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) { | ||
285 | i2o_msg_nop(c, m); | ||
286 | return -ENOMEM; | ||
287 | } | ||
288 | |||
289 | __copy_from_user(buffer.virt, kxfer.buf, fragsize); | ||
290 | |||
291 | writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]); | ||
292 | writel(I2O_CMD_SW_DOWNLOAD << 24 | HOST_TID << 12 | ADAPTER_TID, | ||
293 | &msg->u.head[1]); | ||
294 | writel(i2o_config_driver.context, &msg->u.head[2]); | ||
295 | writel(0, &msg->u.head[3]); | ||
296 | writel((((u32) kxfer.flags) << 24) | (((u32) kxfer.sw_type) << 16) | | ||
297 | (((u32) maxfrag) << 8) | (((u32) curfrag)), &msg->body[0]); | ||
298 | writel(swlen, &msg->body[1]); | ||
299 | writel(kxfer.sw_id, &msg->body[2]); | ||
300 | writel(0xD0000000 | fragsize, &msg->body[3]); | ||
301 | writel(buffer.phys, &msg->body[4]); | ||
302 | |||
303 | osm_debug("swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); | ||
304 | status = i2o_msg_post_wait_mem(c, m, 60, &buffer); | ||
305 | |||
306 | if (status != -ETIMEDOUT) | ||
307 | i2o_dma_free(&c->pdev->dev, &buffer); | ||
308 | |||
309 | if (status != I2O_POST_WAIT_OK) { | ||
310 | // it fails if you try and send frags out of order | ||
311 | // and for some yet unknown reasons too | ||
312 | osm_info("swdl failed, DetailedStatus = %d\n", status); | ||
313 | return status; | ||
314 | } | ||
315 | |||
316 | return 0; | ||
317 | }; | ||
318 | |||
319 | static int i2o_cfg_swul(unsigned long arg) | ||
320 | { | ||
321 | struct i2o_sw_xfer kxfer; | ||
322 | struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg; | ||
323 | unsigned char maxfrag = 0, curfrag = 1; | ||
324 | struct i2o_dma buffer; | ||
325 | struct i2o_message __iomem *msg; | ||
326 | u32 m; | ||
327 | unsigned int status = 0, swlen = 0, fragsize = 8192; | ||
328 | struct i2o_controller *c; | ||
329 | int ret = 0; | ||
330 | |||
331 | if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) | ||
332 | goto return_fault; | ||
333 | |||
334 | if (get_user(swlen, kxfer.swlen) < 0) | ||
335 | goto return_fault; | ||
336 | |||
337 | if (get_user(maxfrag, kxfer.maxfrag) < 0) | ||
338 | goto return_fault; | ||
339 | |||
340 | if (get_user(curfrag, kxfer.curfrag) < 0) | ||
341 | goto return_fault; | ||
342 | |||
343 | if (curfrag == maxfrag) | ||
344 | fragsize = swlen - (maxfrag - 1) * 8192; | ||
345 | |||
346 | if (!kxfer.buf) | ||
347 | goto return_fault; | ||
348 | |||
349 | c = i2o_find_iop(kxfer.iop); | ||
350 | if (!c) | ||
351 | return -ENXIO; | ||
352 | |||
353 | m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); | ||
354 | if (m == I2O_QUEUE_EMPTY) | ||
355 | return -EBUSY; | ||
356 | |||
357 | if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) { | ||
358 | i2o_msg_nop(c, m); | ||
359 | return -ENOMEM; | ||
360 | } | ||
361 | |||
362 | writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]); | ||
363 | writel(I2O_CMD_SW_UPLOAD << 24 | HOST_TID << 12 | ADAPTER_TID, | ||
364 | &msg->u.head[1]); | ||
365 | writel(i2o_config_driver.context, &msg->u.head[2]); | ||
366 | writel(0, &msg->u.head[3]); | ||
367 | writel((u32) kxfer.flags << 24 | (u32) kxfer. | ||
368 | sw_type << 16 | (u32) maxfrag << 8 | (u32) curfrag, | ||
369 | &msg->body[0]); | ||
370 | writel(swlen, &msg->body[1]); | ||
371 | writel(kxfer.sw_id, &msg->body[2]); | ||
372 | writel(0xD0000000 | fragsize, &msg->body[3]); | ||
373 | writel(buffer.phys, &msg->body[4]); | ||
374 | |||
375 | osm_debug("swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); | ||
376 | status = i2o_msg_post_wait_mem(c, m, 60, &buffer); | ||
377 | |||
378 | if (status != I2O_POST_WAIT_OK) { | ||
379 | if (status != -ETIMEDOUT) | ||
380 | i2o_dma_free(&c->pdev->dev, &buffer); | ||
381 | |||
382 | osm_info("swul failed, DetailedStatus = %d\n", status); | ||
383 | return status; | ||
384 | } | ||
385 | |||
386 | if (copy_to_user(kxfer.buf, buffer.virt, fragsize)) | ||
387 | ret = -EFAULT; | ||
388 | |||
389 | i2o_dma_free(&c->pdev->dev, &buffer); | ||
390 | |||
391 | return_ret: | ||
392 | return ret; | ||
393 | return_fault: | ||
394 | ret = -EFAULT; | ||
395 | goto return_ret; | ||
396 | }; | ||
397 | |||
398 | static int i2o_cfg_swdel(unsigned long arg) | ||
399 | { | ||
400 | struct i2o_controller *c; | ||
401 | struct i2o_sw_xfer kxfer; | ||
402 | struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg; | ||
403 | struct i2o_message __iomem *msg; | ||
404 | u32 m; | ||
405 | unsigned int swlen; | ||
406 | int token; | ||
407 | |||
408 | if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) | ||
409 | return -EFAULT; | ||
410 | |||
411 | if (get_user(swlen, kxfer.swlen) < 0) | ||
412 | return -EFAULT; | ||
413 | |||
414 | c = i2o_find_iop(kxfer.iop); | ||
415 | if (!c) | ||
416 | return -ENXIO; | ||
417 | |||
418 | m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); | ||
419 | if (m == I2O_QUEUE_EMPTY) | ||
420 | return -EBUSY; | ||
421 | |||
422 | writel(SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); | ||
423 | writel(I2O_CMD_SW_REMOVE << 24 | HOST_TID << 12 | ADAPTER_TID, | ||
424 | &msg->u.head[1]); | ||
425 | writel(i2o_config_driver.context, &msg->u.head[2]); | ||
426 | writel(0, &msg->u.head[3]); | ||
427 | writel((u32) kxfer.flags << 24 | (u32) kxfer.sw_type << 16, | ||
428 | &msg->body[0]); | ||
429 | writel(swlen, &msg->body[1]); | ||
430 | writel(kxfer.sw_id, &msg->body[2]); | ||
431 | |||
432 | token = i2o_msg_post_wait(c, m, 10); | ||
433 | |||
434 | if (token != I2O_POST_WAIT_OK) { | ||
435 | osm_info("swdel failed, DetailedStatus = %d\n", token); | ||
436 | return -ETIMEDOUT; | ||
437 | } | ||
438 | |||
439 | return 0; | ||
440 | }; | ||
441 | |||
442 | static int i2o_cfg_validate(unsigned long arg) | ||
443 | { | ||
444 | int token; | ||
445 | int iop = (int)arg; | ||
446 | struct i2o_message __iomem *msg; | ||
447 | u32 m; | ||
448 | struct i2o_controller *c; | ||
449 | |||
450 | c = i2o_find_iop(iop); | ||
451 | if (!c) | ||
452 | return -ENXIO; | ||
453 | |||
454 | m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); | ||
455 | if (m == I2O_QUEUE_EMPTY) | ||
456 | return -EBUSY; | ||
457 | |||
458 | writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); | ||
459 | writel(I2O_CMD_CONFIG_VALIDATE << 24 | HOST_TID << 12 | iop, | ||
460 | &msg->u.head[1]); | ||
461 | writel(i2o_config_driver.context, &msg->u.head[2]); | ||
462 | writel(0, &msg->u.head[3]); | ||
463 | |||
464 | token = i2o_msg_post_wait(c, m, 10); | ||
465 | |||
466 | if (token != I2O_POST_WAIT_OK) { | ||
467 | osm_info("Can't validate configuration, ErrorStatus = %d\n", | ||
468 | token); | ||
469 | return -ETIMEDOUT; | ||
470 | } | ||
471 | |||
472 | return 0; | ||
473 | }; | ||
474 | |||
475 | static int i2o_cfg_evt_reg(unsigned long arg, struct file *fp) | ||
476 | { | ||
477 | struct i2o_message __iomem *msg; | ||
478 | u32 m; | ||
479 | struct i2o_evt_id __user *pdesc = (struct i2o_evt_id __user *)arg; | ||
480 | struct i2o_evt_id kdesc; | ||
481 | struct i2o_controller *c; | ||
482 | struct i2o_device *d; | ||
483 | |||
484 | if (copy_from_user(&kdesc, pdesc, sizeof(struct i2o_evt_id))) | ||
485 | return -EFAULT; | ||
486 | |||
487 | /* IOP exists? */ | ||
488 | c = i2o_find_iop(kdesc.iop); | ||
489 | if (!c) | ||
490 | return -ENXIO; | ||
491 | |||
492 | /* Device exists? */ | ||
493 | d = i2o_iop_find_device(c, kdesc.tid); | ||
494 | if (!d) | ||
495 | return -ENODEV; | ||
496 | |||
497 | m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); | ||
498 | if (m == I2O_QUEUE_EMPTY) | ||
499 | return -EBUSY; | ||
500 | |||
501 | writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); | ||
502 | writel(I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | kdesc.tid, | ||
503 | &msg->u.head[1]); | ||
504 | writel(i2o_config_driver.context, &msg->u.head[2]); | ||
505 | writel(i2o_cntxt_list_add(c, fp->private_data), &msg->u.head[3]); | ||
506 | writel(kdesc.evt_mask, &msg->body[0]); | ||
507 | |||
508 | i2o_msg_post(c, m); | ||
509 | |||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | static int i2o_cfg_evt_get(unsigned long arg, struct file *fp) | ||
514 | { | ||
515 | struct i2o_cfg_info *p = NULL; | ||
516 | struct i2o_evt_get __user *uget = (struct i2o_evt_get __user *)arg; | ||
517 | struct i2o_evt_get kget; | ||
518 | unsigned long flags; | ||
519 | |||
520 | for (p = open_files; p; p = p->next) | ||
521 | if (p->q_id == (ulong) fp->private_data) | ||
522 | break; | ||
523 | |||
524 | if (!p->q_len) | ||
525 | return -ENOENT; | ||
526 | |||
527 | memcpy(&kget.info, &p->event_q[p->q_out], sizeof(struct i2o_evt_info)); | ||
528 | MODINC(p->q_out, I2O_EVT_Q_LEN); | ||
529 | spin_lock_irqsave(&i2o_config_lock, flags); | ||
530 | p->q_len--; | ||
531 | kget.pending = p->q_len; | ||
532 | kget.lost = p->q_lost; | ||
533 | spin_unlock_irqrestore(&i2o_config_lock, flags); | ||
534 | |||
535 | if (copy_to_user(uget, &kget, sizeof(struct i2o_evt_get))) | ||
536 | return -EFAULT; | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | #ifdef CONFIG_COMPAT | ||
541 | static int i2o_cfg_passthru32(unsigned fd, unsigned cmnd, unsigned long arg, | ||
542 | struct file *file) | ||
543 | { | ||
544 | struct i2o_cmd_passthru32 __user *cmd; | ||
545 | struct i2o_controller *c; | ||
546 | u32 __user *user_msg; | ||
547 | u32 *reply = NULL; | ||
548 | u32 __user *user_reply = NULL; | ||
549 | u32 size = 0; | ||
550 | u32 reply_size = 0; | ||
551 | u32 rcode = 0; | ||
552 | struct i2o_dma sg_list[SG_TABLESIZE]; | ||
553 | u32 sg_offset = 0; | ||
554 | u32 sg_count = 0; | ||
555 | u32 i = 0; | ||
556 | i2o_status_block *sb; | ||
557 | struct i2o_message *msg; | ||
558 | u32 m; | ||
559 | unsigned int iop; | ||
560 | |||
561 | cmd = (struct i2o_cmd_passthru32 __user *)arg; | ||
562 | |||
563 | if (get_user(iop, &cmd->iop) || get_user(i, &cmd->msg)) | ||
564 | return -EFAULT; | ||
565 | |||
566 | user_msg = compat_ptr(i); | ||
567 | |||
568 | c = i2o_find_iop(iop); | ||
569 | if (!c) { | ||
570 | osm_debug("controller %d not found\n", iop); | ||
571 | return -ENXIO; | ||
572 | } | ||
573 | |||
574 | m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); | ||
575 | |||
576 | sb = c->status_block.virt; | ||
577 | |||
578 | if (get_user(size, &user_msg[0])) { | ||
579 | osm_warn("unable to get size!\n"); | ||
580 | return -EFAULT; | ||
581 | } | ||
582 | size = size >> 16; | ||
583 | |||
584 | if (size > sb->inbound_frame_size) { | ||
585 | osm_warn("size of message > inbound_frame_size"); | ||
586 | return -EFAULT; | ||
587 | } | ||
588 | |||
589 | user_reply = &user_msg[size]; | ||
590 | |||
591 | size <<= 2; // Convert to bytes | ||
592 | |||
593 | /* Copy in the user's I2O command */ | ||
594 | if (copy_from_user(msg, user_msg, size)) { | ||
595 | osm_warn("unable to copy user message\n"); | ||
596 | return -EFAULT; | ||
597 | } | ||
598 | i2o_dump_message(msg); | ||
599 | |||
600 | if (get_user(reply_size, &user_reply[0]) < 0) | ||
601 | return -EFAULT; | ||
602 | |||
603 | reply_size >>= 16; | ||
604 | reply_size <<= 2; | ||
605 | |||
606 | reply = kmalloc(reply_size, GFP_KERNEL); | ||
607 | if (!reply) { | ||
608 | printk(KERN_WARNING "%s: Could not allocate reply buffer\n", | ||
609 | c->name); | ||
610 | return -ENOMEM; | ||
611 | } | ||
612 | memset(reply, 0, reply_size); | ||
613 | |||
614 | sg_offset = (msg->u.head[0] >> 4) & 0x0f; | ||
615 | |||
616 | writel(i2o_config_driver.context, &msg->u.s.icntxt); | ||
617 | writel(i2o_cntxt_list_add(c, reply), &msg->u.s.tcntxt); | ||
618 | |||
619 | memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE); | ||
620 | if (sg_offset) { | ||
621 | struct sg_simple_element *sg; | ||
622 | |||
623 | if (sg_offset * 4 >= size) { | ||
624 | rcode = -EFAULT; | ||
625 | goto cleanup; | ||
626 | } | ||
627 | // TODO 64bit fix | ||
628 | sg = (struct sg_simple_element *)((&msg->u.head[0]) + | ||
629 | sg_offset); | ||
630 | sg_count = | ||
631 | (size - sg_offset * 4) / sizeof(struct sg_simple_element); | ||
632 | if (sg_count > SG_TABLESIZE) { | ||
633 | printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n", | ||
634 | c->name, sg_count); | ||
635 | kfree(reply); | ||
636 | return -EINVAL; | ||
637 | } | ||
638 | |||
639 | for (i = 0; i < sg_count; i++) { | ||
640 | int sg_size; | ||
641 | struct i2o_dma *p; | ||
642 | |||
643 | if (!(sg[i].flag_count & 0x10000000 | ||
644 | /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT */ )) { | ||
645 | printk(KERN_DEBUG | ||
646 | "%s:Bad SG element %d - not simple (%x)\n", | ||
647 | c->name, i, sg[i].flag_count); | ||
648 | rcode = -EINVAL; | ||
649 | goto cleanup; | ||
650 | } | ||
651 | sg_size = sg[i].flag_count & 0xffffff; | ||
652 | p = &(sg_list[i]); | ||
653 | /* Allocate memory for the transfer */ | ||
654 | if (i2o_dma_alloc | ||
655 | (&c->pdev->dev, p, sg_size, | ||
656 | PCI_DMA_BIDIRECTIONAL)) { | ||
657 | printk(KERN_DEBUG | ||
658 | "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n", | ||
659 | c->name, sg_size, i, sg_count); | ||
660 | rcode = -ENOMEM; | ||
661 | goto cleanup; | ||
662 | } | ||
663 | /* Copy in the user's SG buffer if necessary */ | ||
664 | if (sg[i]. | ||
665 | flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR */ ) { | ||
666 | // TODO 64bit fix | ||
667 | if (copy_from_user | ||
668 | (p->virt, (void __user *)(unsigned long)sg[i].addr_bus, | ||
669 | sg_size)) { | ||
670 | printk(KERN_DEBUG | ||
671 | "%s: Could not copy SG buf %d FROM user\n", | ||
672 | c->name, i); | ||
673 | rcode = -EFAULT; | ||
674 | goto cleanup; | ||
675 | } | ||
676 | } | ||
677 | //TODO 64bit fix | ||
678 | sg[i].addr_bus = (u32) p->phys; | ||
679 | } | ||
680 | } | ||
681 | |||
682 | rcode = i2o_msg_post_wait(c, m, 60); | ||
683 | if (rcode) | ||
684 | goto cleanup; | ||
685 | |||
686 | if (sg_offset) { | ||
687 | u32 msg[128]; | ||
688 | /* Copy back the Scatter Gather buffers back to user space */ | ||
689 | u32 j; | ||
690 | // TODO 64bit fix | ||
691 | struct sg_simple_element *sg; | ||
692 | int sg_size; | ||
693 | |||
694 | // re-acquire the original message to handle correctly the sg copy operation | ||
695 | memset(&msg, 0, MSG_FRAME_SIZE * 4); | ||
696 | // get user msg size in u32s | ||
697 | if (get_user(size, &user_msg[0])) { | ||
698 | rcode = -EFAULT; | ||
699 | goto cleanup; | ||
700 | } | ||
701 | size = size >> 16; | ||
702 | size *= 4; | ||
703 | /* Copy in the user's I2O command */ | ||
704 | if (copy_from_user(msg, user_msg, size)) { | ||
705 | rcode = -EFAULT; | ||
706 | goto cleanup; | ||
707 | } | ||
708 | sg_count = | ||
709 | (size - sg_offset * 4) / sizeof(struct sg_simple_element); | ||
710 | |||
711 | // TODO 64bit fix | ||
712 | sg = (struct sg_simple_element *)(msg + sg_offset); | ||
713 | for (j = 0; j < sg_count; j++) { | ||
714 | /* Copy out the SG list to user's buffer if necessary */ | ||
715 | if (! | ||
716 | (sg[j]. | ||
717 | flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR */ )) { | ||
718 | sg_size = sg[j].flag_count & 0xffffff; | ||
719 | // TODO 64bit fix | ||
720 | if (copy_to_user | ||
721 | ((void __user *)(u64) sg[j].addr_bus, | ||
722 | sg_list[j].virt, sg_size)) { | ||
723 | printk(KERN_WARNING | ||
724 | "%s: Could not copy %p TO user %x\n", | ||
725 | c->name, sg_list[j].virt, | ||
726 | sg[j].addr_bus); | ||
727 | rcode = -EFAULT; | ||
728 | goto cleanup; | ||
729 | } | ||
730 | } | ||
731 | } | ||
732 | } | ||
733 | |||
734 | /* Copy back the reply to user space */ | ||
735 | if (reply_size) { | ||
736 | // we wrote our own values for context - now restore the user supplied ones | ||
737 | if (copy_from_user(reply + 2, user_msg + 2, sizeof(u32) * 2)) { | ||
738 | printk(KERN_WARNING | ||
739 | "%s: Could not copy message context FROM user\n", | ||
740 | c->name); | ||
741 | rcode = -EFAULT; | ||
742 | } | ||
743 | if (copy_to_user(user_reply, reply, reply_size)) { | ||
744 | printk(KERN_WARNING | ||
745 | "%s: Could not copy reply TO user\n", c->name); | ||
746 | rcode = -EFAULT; | ||
747 | } | ||
748 | } | ||
749 | |||
750 | cleanup: | ||
751 | kfree(reply); | ||
752 | return rcode; | ||
753 | } | ||
754 | |||
755 | #else | ||
756 | |||
757 | static int i2o_cfg_passthru(unsigned long arg) | ||
758 | { | ||
759 | struct i2o_cmd_passthru __user *cmd = | ||
760 | (struct i2o_cmd_passthru __user *)arg; | ||
761 | struct i2o_controller *c; | ||
762 | u32 __user *user_msg; | ||
763 | u32 *reply = NULL; | ||
764 | u32 __user *user_reply = NULL; | ||
765 | u32 size = 0; | ||
766 | u32 reply_size = 0; | ||
767 | u32 rcode = 0; | ||
768 | void *sg_list[SG_TABLESIZE]; | ||
769 | u32 sg_offset = 0; | ||
770 | u32 sg_count = 0; | ||
771 | int sg_index = 0; | ||
772 | u32 i = 0; | ||
773 | void *p = NULL; | ||
774 | i2o_status_block *sb; | ||
775 | struct i2o_message __iomem *msg; | ||
776 | u32 m; | ||
777 | unsigned int iop; | ||
778 | |||
779 | if (get_user(iop, &cmd->iop) || get_user(user_msg, &cmd->msg)) | ||
780 | return -EFAULT; | ||
781 | |||
782 | c = i2o_find_iop(iop); | ||
783 | if (!c) { | ||
784 | osm_warn("controller %d not found\n", iop); | ||
785 | return -ENXIO; | ||
786 | } | ||
787 | |||
788 | m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); | ||
789 | |||
790 | sb = c->status_block.virt; | ||
791 | |||
792 | if (get_user(size, &user_msg[0])) | ||
793 | return -EFAULT; | ||
794 | size = size >> 16; | ||
795 | |||
796 | if (size > sb->inbound_frame_size) { | ||
797 | osm_warn("size of message > inbound_frame_size"); | ||
798 | return -EFAULT; | ||
799 | } | ||
800 | |||
801 | user_reply = &user_msg[size]; | ||
802 | |||
803 | size <<= 2; // Convert to bytes | ||
804 | |||
805 | /* Copy in the user's I2O command */ | ||
806 | if (copy_from_user(msg, user_msg, size)) | ||
807 | return -EFAULT; | ||
808 | |||
809 | if (get_user(reply_size, &user_reply[0]) < 0) | ||
810 | return -EFAULT; | ||
811 | |||
812 | reply_size >>= 16; | ||
813 | reply_size <<= 2; | ||
814 | |||
815 | reply = kmalloc(reply_size, GFP_KERNEL); | ||
816 | if (!reply) { | ||
817 | printk(KERN_WARNING "%s: Could not allocate reply buffer\n", | ||
818 | c->name); | ||
819 | return -ENOMEM; | ||
820 | } | ||
821 | memset(reply, 0, reply_size); | ||
822 | |||
823 | sg_offset = (msg->u.head[0] >> 4) & 0x0f; | ||
824 | |||
825 | writel(i2o_config_driver.context, &msg->u.s.icntxt); | ||
826 | writel(i2o_cntxt_list_add(c, reply), &msg->u.s.tcntxt); | ||
827 | |||
828 | memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE); | ||
829 | if (sg_offset) { | ||
830 | struct sg_simple_element *sg; | ||
831 | |||
832 | if (sg_offset * 4 >= size) { | ||
833 | rcode = -EFAULT; | ||
834 | goto cleanup; | ||
835 | } | ||
836 | // TODO 64bit fix | ||
837 | sg = (struct sg_simple_element *)((&msg->u.head[0]) + | ||
838 | sg_offset); | ||
839 | sg_count = | ||
840 | (size - sg_offset * 4) / sizeof(struct sg_simple_element); | ||
841 | if (sg_count > SG_TABLESIZE) { | ||
842 | printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n", | ||
843 | c->name, sg_count); | ||
844 | kfree(reply); | ||
845 | return -EINVAL; | ||
846 | } | ||
847 | |||
848 | for (i = 0; i < sg_count; i++) { | ||
849 | int sg_size; | ||
850 | |||
851 | if (!(sg[i].flag_count & 0x10000000 | ||
852 | /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT */ )) { | ||
853 | printk(KERN_DEBUG | ||
854 | "%s:Bad SG element %d - not simple (%x)\n", | ||
855 | c->name, i, sg[i].flag_count); | ||
856 | rcode = -EINVAL; | ||
857 | goto cleanup; | ||
858 | } | ||
859 | sg_size = sg[i].flag_count & 0xffffff; | ||
860 | /* Allocate memory for the transfer */ | ||
861 | p = kmalloc(sg_size, GFP_KERNEL); | ||
862 | if (!p) { | ||
863 | printk(KERN_DEBUG | ||
864 | "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n", | ||
865 | c->name, sg_size, i, sg_count); | ||
866 | rcode = -ENOMEM; | ||
867 | goto cleanup; | ||
868 | } | ||
869 | sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame. | ||
870 | /* Copy in the user's SG buffer if necessary */ | ||
871 | if (sg[i]. | ||
872 | flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR */ ) { | ||
873 | // TODO 64bit fix | ||
874 | if (copy_from_user | ||
875 | (p, (void __user *)sg[i].addr_bus, | ||
876 | sg_size)) { | ||
877 | printk(KERN_DEBUG | ||
878 | "%s: Could not copy SG buf %d FROM user\n", | ||
879 | c->name, i); | ||
880 | rcode = -EFAULT; | ||
881 | goto cleanup; | ||
882 | } | ||
883 | } | ||
884 | //TODO 64bit fix | ||
885 | sg[i].addr_bus = virt_to_bus(p); | ||
886 | } | ||
887 | } | ||
888 | |||
889 | rcode = i2o_msg_post_wait(c, m, 60); | ||
890 | if (rcode) | ||
891 | goto cleanup; | ||
892 | |||
893 | if (sg_offset) { | ||
894 | u32 msg[128]; | ||
895 | /* Copy back the Scatter Gather buffers back to user space */ | ||
896 | u32 j; | ||
897 | // TODO 64bit fix | ||
898 | struct sg_simple_element *sg; | ||
899 | int sg_size; | ||
900 | |||
901 | // re-acquire the original message to handle correctly the sg copy operation | ||
902 | memset(&msg, 0, MSG_FRAME_SIZE * 4); | ||
903 | // get user msg size in u32s | ||
904 | if (get_user(size, &user_msg[0])) { | ||
905 | rcode = -EFAULT; | ||
906 | goto cleanup; | ||
907 | } | ||
908 | size = size >> 16; | ||
909 | size *= 4; | ||
910 | /* Copy in the user's I2O command */ | ||
911 | if (copy_from_user(msg, user_msg, size)) { | ||
912 | rcode = -EFAULT; | ||
913 | goto cleanup; | ||
914 | } | ||
915 | sg_count = | ||
916 | (size - sg_offset * 4) / sizeof(struct sg_simple_element); | ||
917 | |||
918 | // TODO 64bit fix | ||
919 | sg = (struct sg_simple_element *)(msg + sg_offset); | ||
920 | for (j = 0; j < sg_count; j++) { | ||
921 | /* Copy out the SG list to user's buffer if necessary */ | ||
922 | if (! | ||
923 | (sg[j]. | ||
924 | flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR */ )) { | ||
925 | sg_size = sg[j].flag_count & 0xffffff; | ||
926 | // TODO 64bit fix | ||
927 | if (copy_to_user | ||
928 | ((void __user *)sg[j].addr_bus, sg_list[j], | ||
929 | sg_size)) { | ||
930 | printk(KERN_WARNING | ||
931 | "%s: Could not copy %p TO user %x\n", | ||
932 | c->name, sg_list[j], | ||
933 | sg[j].addr_bus); | ||
934 | rcode = -EFAULT; | ||
935 | goto cleanup; | ||
936 | } | ||
937 | } | ||
938 | } | ||
939 | } | ||
940 | |||
941 | /* Copy back the reply to user space */ | ||
942 | if (reply_size) { | ||
943 | // we wrote our own values for context - now restore the user supplied ones | ||
944 | if (copy_from_user(reply + 2, user_msg + 2, sizeof(u32) * 2)) { | ||
945 | printk(KERN_WARNING | ||
946 | "%s: Could not copy message context FROM user\n", | ||
947 | c->name); | ||
948 | rcode = -EFAULT; | ||
949 | } | ||
950 | if (copy_to_user(user_reply, reply, reply_size)) { | ||
951 | printk(KERN_WARNING | ||
952 | "%s: Could not copy reply TO user\n", c->name); | ||
953 | rcode = -EFAULT; | ||
954 | } | ||
955 | } | ||
956 | |||
957 | cleanup: | ||
958 | kfree(reply); | ||
959 | return rcode; | ||
960 | } | ||
961 | #endif | ||
962 | |||
963 | /* | ||
964 | * IOCTL Handler | ||
965 | */ | ||
966 | static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, | ||
967 | unsigned long arg) | ||
968 | { | ||
969 | int ret; | ||
970 | |||
971 | switch (cmd) { | ||
972 | case I2OGETIOPS: | ||
973 | ret = i2o_cfg_getiops(arg); | ||
974 | break; | ||
975 | |||
976 | case I2OHRTGET: | ||
977 | ret = i2o_cfg_gethrt(arg); | ||
978 | break; | ||
979 | |||
980 | case I2OLCTGET: | ||
981 | ret = i2o_cfg_getlct(arg); | ||
982 | break; | ||
983 | |||
984 | case I2OPARMSET: | ||
985 | ret = i2o_cfg_parms(arg, I2OPARMSET); | ||
986 | break; | ||
987 | |||
988 | case I2OPARMGET: | ||
989 | ret = i2o_cfg_parms(arg, I2OPARMGET); | ||
990 | break; | ||
991 | |||
992 | case I2OSWDL: | ||
993 | ret = i2o_cfg_swdl(arg); | ||
994 | break; | ||
995 | |||
996 | case I2OSWUL: | ||
997 | ret = i2o_cfg_swul(arg); | ||
998 | break; | ||
999 | |||
1000 | case I2OSWDEL: | ||
1001 | ret = i2o_cfg_swdel(arg); | ||
1002 | break; | ||
1003 | |||
1004 | case I2OVALIDATE: | ||
1005 | ret = i2o_cfg_validate(arg); | ||
1006 | break; | ||
1007 | |||
1008 | case I2OEVTREG: | ||
1009 | ret = i2o_cfg_evt_reg(arg, fp); | ||
1010 | break; | ||
1011 | |||
1012 | case I2OEVTGET: | ||
1013 | ret = i2o_cfg_evt_get(arg, fp); | ||
1014 | break; | ||
1015 | |||
1016 | #ifndef CONFIG_COMPAT | ||
1017 | case I2OPASSTHRU: | ||
1018 | ret = i2o_cfg_passthru(arg); | ||
1019 | break; | ||
1020 | #endif | ||
1021 | |||
1022 | default: | ||
1023 | osm_debug("unknown ioctl called!\n"); | ||
1024 | ret = -EINVAL; | ||
1025 | } | ||
1026 | |||
1027 | return ret; | ||
1028 | } | ||
1029 | |||
1030 | static int cfg_open(struct inode *inode, struct file *file) | ||
1031 | { | ||
1032 | struct i2o_cfg_info *tmp = | ||
1033 | (struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info), | ||
1034 | GFP_KERNEL); | ||
1035 | unsigned long flags; | ||
1036 | |||
1037 | if (!tmp) | ||
1038 | return -ENOMEM; | ||
1039 | |||
1040 | file->private_data = (void *)(i2o_cfg_info_id++); | ||
1041 | tmp->fp = file; | ||
1042 | tmp->fasync = NULL; | ||
1043 | tmp->q_id = (ulong) file->private_data; | ||
1044 | tmp->q_len = 0; | ||
1045 | tmp->q_in = 0; | ||
1046 | tmp->q_out = 0; | ||
1047 | tmp->q_lost = 0; | ||
1048 | tmp->next = open_files; | ||
1049 | |||
1050 | spin_lock_irqsave(&i2o_config_lock, flags); | ||
1051 | open_files = tmp; | ||
1052 | spin_unlock_irqrestore(&i2o_config_lock, flags); | ||
1053 | |||
1054 | return 0; | ||
1055 | } | ||
1056 | |||
1057 | static int cfg_fasync(int fd, struct file *fp, int on) | ||
1058 | { | ||
1059 | ulong id = (ulong) fp->private_data; | ||
1060 | struct i2o_cfg_info *p; | ||
1061 | |||
1062 | for (p = open_files; p; p = p->next) | ||
1063 | if (p->q_id == id) | ||
1064 | break; | ||
1065 | |||
1066 | if (!p) | ||
1067 | return -EBADF; | ||
1068 | |||
1069 | return fasync_helper(fd, fp, on, &p->fasync); | ||
1070 | } | ||
1071 | |||
1072 | static int cfg_release(struct inode *inode, struct file *file) | ||
1073 | { | ||
1074 | ulong id = (ulong) file->private_data; | ||
1075 | struct i2o_cfg_info *p1, *p2; | ||
1076 | unsigned long flags; | ||
1077 | |||
1078 | lock_kernel(); | ||
1079 | p1 = p2 = NULL; | ||
1080 | |||
1081 | spin_lock_irqsave(&i2o_config_lock, flags); | ||
1082 | for (p1 = open_files; p1;) { | ||
1083 | if (p1->q_id == id) { | ||
1084 | |||
1085 | if (p1->fasync) | ||
1086 | cfg_fasync(-1, file, 0); | ||
1087 | if (p2) | ||
1088 | p2->next = p1->next; | ||
1089 | else | ||
1090 | open_files = p1->next; | ||
1091 | |||
1092 | kfree(p1); | ||
1093 | break; | ||
1094 | } | ||
1095 | p2 = p1; | ||
1096 | p1 = p1->next; | ||
1097 | } | ||
1098 | spin_unlock_irqrestore(&i2o_config_lock, flags); | ||
1099 | unlock_kernel(); | ||
1100 | |||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | static struct file_operations config_fops = { | ||
1105 | .owner = THIS_MODULE, | ||
1106 | .llseek = no_llseek, | ||
1107 | .ioctl = i2o_cfg_ioctl, | ||
1108 | .open = cfg_open, | ||
1109 | .release = cfg_release, | ||
1110 | .fasync = cfg_fasync, | ||
1111 | }; | ||
1112 | |||
1113 | static struct miscdevice i2o_miscdev = { | ||
1114 | I2O_MINOR, | ||
1115 | "i2octl", | ||
1116 | &config_fops | ||
1117 | }; | ||
1118 | |||
1119 | static int __init i2o_config_init(void) | ||
1120 | { | ||
1121 | printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n"); | ||
1122 | |||
1123 | spin_lock_init(&i2o_config_lock); | ||
1124 | |||
1125 | if (misc_register(&i2o_miscdev) < 0) { | ||
1126 | osm_err("can't register device.\n"); | ||
1127 | return -EBUSY; | ||
1128 | } | ||
1129 | /* | ||
1130 | * Install our handler | ||
1131 | */ | ||
1132 | if (i2o_driver_register(&i2o_config_driver)) { | ||
1133 | osm_err("handler register failed.\n"); | ||
1134 | misc_deregister(&i2o_miscdev); | ||
1135 | return -EBUSY; | ||
1136 | } | ||
1137 | #ifdef CONFIG_COMPAT | ||
1138 | register_ioctl32_conversion(I2OPASSTHRU32, i2o_cfg_passthru32); | ||
1139 | register_ioctl32_conversion(I2OGETIOPS, (void *)sys_ioctl); | ||
1140 | #endif | ||
1141 | return 0; | ||
1142 | } | ||
1143 | |||
1144 | static void i2o_config_exit(void) | ||
1145 | { | ||
1146 | #ifdef CONFIG_COMPAT | ||
1147 | unregister_ioctl32_conversion(I2OPASSTHRU32); | ||
1148 | unregister_ioctl32_conversion(I2OGETIOPS); | ||
1149 | #endif | ||
1150 | misc_deregister(&i2o_miscdev); | ||
1151 | i2o_driver_unregister(&i2o_config_driver); | ||
1152 | } | ||
1153 | |||
1154 | MODULE_AUTHOR("Red Hat Software"); | ||
1155 | MODULE_LICENSE("GPL"); | ||
1156 | MODULE_DESCRIPTION(OSM_DESCRIPTION); | ||
1157 | MODULE_VERSION(OSM_VERSION); | ||
1158 | |||
1159 | module_init(i2o_config_init); | ||
1160 | module_exit(i2o_config_exit); | ||