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/exec-osm.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/exec-osm.c')
-rw-r--r-- | drivers/message/i2o/exec-osm.c | 507 |
1 files changed, 507 insertions, 0 deletions
diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c new file mode 100644 index 000000000000..79c1cbfb8f44 --- /dev/null +++ b/drivers/message/i2o/exec-osm.c | |||
@@ -0,0 +1,507 @@ | |||
1 | /* | ||
2 | * Executive OSM | ||
3 | * | ||
4 | * Copyright (C) 1999-2002 Red Hat Software | ||
5 | * | ||
6 | * Written by Alan Cox, Building Number Three Ltd | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * A lot of the I2O message side code from this is taken from the Red | ||
14 | * Creek RCPCI45 adapter driver by Red Creek Communications | ||
15 | * | ||
16 | * Fixes/additions: | ||
17 | * Philipp Rumpf | ||
18 | * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI> | ||
19 | * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> | ||
20 | * Deepak Saxena <deepak@plexity.net> | ||
21 | * Boji T Kannanthanam <boji.t.kannanthanam@intel.com> | ||
22 | * Alan Cox <alan@redhat.com>: | ||
23 | * Ported to Linux 2.5. | ||
24 | * Markus Lidel <Markus.Lidel@shadowconnect.com>: | ||
25 | * Minor fixes for 2.6. | ||
26 | * Markus Lidel <Markus.Lidel@shadowconnect.com>: | ||
27 | * Support for sysfs included. | ||
28 | */ | ||
29 | |||
30 | #include <linux/module.h> | ||
31 | #include <linux/i2o.h> | ||
32 | #include <linux/delay.h> | ||
33 | |||
34 | #define OSM_NAME "exec-osm" | ||
35 | |||
36 | struct i2o_driver i2o_exec_driver; | ||
37 | |||
38 | static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind); | ||
39 | |||
40 | /* Module internal functions from other sources */ | ||
41 | extern int i2o_device_parse_lct(struct i2o_controller *); | ||
42 | |||
43 | /* global wait list for POST WAIT */ | ||
44 | static LIST_HEAD(i2o_exec_wait_list); | ||
45 | |||
46 | /* Wait struct needed for POST WAIT */ | ||
47 | struct i2o_exec_wait { | ||
48 | wait_queue_head_t *wq; /* Pointer to Wait queue */ | ||
49 | struct i2o_dma dma; /* DMA buffers to free on failure */ | ||
50 | u32 tcntxt; /* transaction context from reply */ | ||
51 | int complete; /* 1 if reply received otherwise 0 */ | ||
52 | u32 m; /* message id */ | ||
53 | struct i2o_message __iomem *msg; /* pointer to the reply message */ | ||
54 | struct list_head list; /* node in global wait list */ | ||
55 | }; | ||
56 | |||
57 | /* Exec OSM class handling definition */ | ||
58 | static struct i2o_class_id i2o_exec_class_id[] = { | ||
59 | {I2O_CLASS_EXECUTIVE}, | ||
60 | {I2O_CLASS_END} | ||
61 | }; | ||
62 | |||
63 | /** | ||
64 | * i2o_exec_wait_alloc - Allocate a i2o_exec_wait struct an initialize it | ||
65 | * | ||
66 | * Allocate the i2o_exec_wait struct and initialize the wait. | ||
67 | * | ||
68 | * Returns i2o_exec_wait pointer on success or negative error code on | ||
69 | * failure. | ||
70 | */ | ||
71 | static struct i2o_exec_wait *i2o_exec_wait_alloc(void) | ||
72 | { | ||
73 | struct i2o_exec_wait *wait; | ||
74 | |||
75 | wait = kmalloc(sizeof(*wait), GFP_KERNEL); | ||
76 | if (!wait) | ||
77 | return ERR_PTR(-ENOMEM); | ||
78 | |||
79 | memset(wait, 0, sizeof(*wait)); | ||
80 | |||
81 | INIT_LIST_HEAD(&wait->list); | ||
82 | |||
83 | return wait; | ||
84 | }; | ||
85 | |||
86 | /** | ||
87 | * i2o_exec_wait_free - Free a i2o_exec_wait struct | ||
88 | * @i2o_exec_wait: I2O wait data which should be cleaned up | ||
89 | */ | ||
90 | static void i2o_exec_wait_free(struct i2o_exec_wait *wait) | ||
91 | { | ||
92 | kfree(wait); | ||
93 | }; | ||
94 | |||
95 | /** | ||
96 | * i2o_msg_post_wait_mem - Post and wait a message with DMA buffers | ||
97 | * @c: controller | ||
98 | * @m: message to post | ||
99 | * @timeout: time in seconds to wait | ||
100 | * @dma: i2o_dma struct of the DMA buffer to free on failure | ||
101 | * | ||
102 | * This API allows an OSM to post a message and then be told whether or | ||
103 | * not the system received a successful reply. If the message times out | ||
104 | * then the value '-ETIMEDOUT' is returned. This is a special case. In | ||
105 | * this situation the message may (should) complete at an indefinite time | ||
106 | * in the future. When it completes it will use the memory buffer | ||
107 | * attached to the request. If -ETIMEDOUT is returned then the memory | ||
108 | * buffer must not be freed. Instead the event completion will free them | ||
109 | * for you. In all other cases the buffer are your problem. | ||
110 | * | ||
111 | * Returns 0 on success or negative error code on failure. | ||
112 | */ | ||
113 | int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long | ||
114 | timeout, struct i2o_dma *dma) | ||
115 | { | ||
116 | DECLARE_WAIT_QUEUE_HEAD(wq); | ||
117 | struct i2o_exec_wait *wait; | ||
118 | static u32 tcntxt = 0x80000000; | ||
119 | struct i2o_message __iomem *msg = c->in_queue.virt + m; | ||
120 | int rc = 0; | ||
121 | |||
122 | wait = i2o_exec_wait_alloc(); | ||
123 | if (!wait) | ||
124 | return -ENOMEM; | ||
125 | |||
126 | if (tcntxt == 0xffffffff) | ||
127 | tcntxt = 0x80000000; | ||
128 | |||
129 | if (dma) | ||
130 | wait->dma = *dma; | ||
131 | |||
132 | /* | ||
133 | * Fill in the message initiator context and transaction context. | ||
134 | * We will only use transaction contexts >= 0x80000000 for POST WAIT, | ||
135 | * so we could find a POST WAIT reply easier in the reply handler. | ||
136 | */ | ||
137 | writel(i2o_exec_driver.context, &msg->u.s.icntxt); | ||
138 | wait->tcntxt = tcntxt++; | ||
139 | writel(wait->tcntxt, &msg->u.s.tcntxt); | ||
140 | |||
141 | /* | ||
142 | * Post the message to the controller. At some point later it will | ||
143 | * return. If we time out before it returns then complete will be zero. | ||
144 | */ | ||
145 | i2o_msg_post(c, m); | ||
146 | |||
147 | if (!wait->complete) { | ||
148 | wait->wq = &wq; | ||
149 | /* | ||
150 | * we add elements add the head, because if a entry in the list | ||
151 | * will never be removed, we have to iterate over it every time | ||
152 | */ | ||
153 | list_add(&wait->list, &i2o_exec_wait_list); | ||
154 | |||
155 | wait_event_interruptible_timeout(wq, wait->complete, | ||
156 | timeout * HZ); | ||
157 | |||
158 | wait->wq = NULL; | ||
159 | } | ||
160 | |||
161 | barrier(); | ||
162 | |||
163 | if (wait->complete) { | ||
164 | if (readl(&wait->msg->body[0]) >> 24) | ||
165 | rc = readl(&wait->msg->body[0]) & 0xff; | ||
166 | i2o_flush_reply(c, wait->m); | ||
167 | i2o_exec_wait_free(wait); | ||
168 | } else { | ||
169 | /* | ||
170 | * We cannot remove it now. This is important. When it does | ||
171 | * terminate (which it must do if the controller has not | ||
172 | * died...) then it will otherwise scribble on stuff. | ||
173 | * | ||
174 | * FIXME: try abort message | ||
175 | */ | ||
176 | if (dma) | ||
177 | dma->virt = NULL; | ||
178 | |||
179 | rc = -ETIMEDOUT; | ||
180 | } | ||
181 | |||
182 | return rc; | ||
183 | }; | ||
184 | |||
185 | /** | ||
186 | * i2o_msg_post_wait_complete - Reply to a i2o_msg_post request from IOP | ||
187 | * @c: I2O controller which answers | ||
188 | * @m: message id | ||
189 | * @msg: pointer to the I2O reply message | ||
190 | * | ||
191 | * This function is called in interrupt context only. If the reply reached | ||
192 | * before the timeout, the i2o_exec_wait struct is filled with the message | ||
193 | * and the task will be waked up. The task is now responsible for returning | ||
194 | * the message m back to the controller! If the message reaches us after | ||
195 | * the timeout clean up the i2o_exec_wait struct (including allocated | ||
196 | * DMA buffer). | ||
197 | * | ||
198 | * Return 0 on success and if the message m should not be given back to the | ||
199 | * I2O controller, or >0 on success and if the message should be given back | ||
200 | * afterwords. Returns negative error code on failure. In this case the | ||
201 | * message must also be given back to the controller. | ||
202 | */ | ||
203 | static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m, | ||
204 | struct i2o_message __iomem *msg) | ||
205 | { | ||
206 | struct i2o_exec_wait *wait, *tmp; | ||
207 | static spinlock_t lock; | ||
208 | int rc = 1; | ||
209 | u32 context; | ||
210 | |||
211 | spin_lock_init(&lock); | ||
212 | |||
213 | context = readl(&msg->u.s.tcntxt); | ||
214 | |||
215 | /* | ||
216 | * We need to search through the i2o_exec_wait_list to see if the given | ||
217 | * message is still outstanding. If not, it means that the IOP took | ||
218 | * longer to respond to the message than we had allowed and timer has | ||
219 | * already expired. Not much we can do about that except log it for | ||
220 | * debug purposes, increase timeout, and recompile. | ||
221 | */ | ||
222 | spin_lock(&lock); | ||
223 | list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) { | ||
224 | if (wait->tcntxt == context) { | ||
225 | list_del(&wait->list); | ||
226 | |||
227 | wait->m = m; | ||
228 | wait->msg = msg; | ||
229 | wait->complete = 1; | ||
230 | |||
231 | barrier(); | ||
232 | |||
233 | if (wait->wq) { | ||
234 | wake_up_interruptible(wait->wq); | ||
235 | rc = 0; | ||
236 | } else { | ||
237 | struct device *dev; | ||
238 | |||
239 | dev = &c->pdev->dev; | ||
240 | |||
241 | pr_debug("%s: timedout reply received!\n", | ||
242 | c->name); | ||
243 | i2o_dma_free(dev, &wait->dma); | ||
244 | i2o_exec_wait_free(wait); | ||
245 | rc = -1; | ||
246 | } | ||
247 | |||
248 | spin_unlock(&lock); | ||
249 | |||
250 | return rc; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | spin_unlock(&lock); | ||
255 | |||
256 | pr_debug("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name, | ||
257 | context); | ||
258 | |||
259 | return -1; | ||
260 | }; | ||
261 | |||
262 | /** | ||
263 | * i2o_exec_probe - Called if a new I2O device (executive class) appears | ||
264 | * @dev: I2O device which should be probed | ||
265 | * | ||
266 | * Registers event notification for every event from Executive device. The | ||
267 | * return is always 0, because we want all devices of class Executive. | ||
268 | * | ||
269 | * Returns 0 on success. | ||
270 | */ | ||
271 | static int i2o_exec_probe(struct device *dev) | ||
272 | { | ||
273 | struct i2o_device *i2o_dev = to_i2o_device(dev); | ||
274 | |||
275 | i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff); | ||
276 | |||
277 | i2o_dev->iop->exec = i2o_dev; | ||
278 | |||
279 | return 0; | ||
280 | }; | ||
281 | |||
282 | /** | ||
283 | * i2o_exec_remove - Called on I2O device removal | ||
284 | * @dev: I2O device which was removed | ||
285 | * | ||
286 | * Unregisters event notification from Executive I2O device. | ||
287 | * | ||
288 | * Returns 0 on success. | ||
289 | */ | ||
290 | static int i2o_exec_remove(struct device *dev) | ||
291 | { | ||
292 | i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0); | ||
293 | |||
294 | return 0; | ||
295 | }; | ||
296 | |||
297 | /** | ||
298 | * i2o_exec_lct_modified - Called on LCT NOTIFY reply | ||
299 | * @c: I2O controller on which the LCT has modified | ||
300 | * | ||
301 | * This function handles asynchronus LCT NOTIFY replies. It parses the | ||
302 | * new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY | ||
303 | * again. | ||
304 | */ | ||
305 | static void i2o_exec_lct_modified(struct i2o_controller *c) | ||
306 | { | ||
307 | if (i2o_device_parse_lct(c) == -EAGAIN) | ||
308 | i2o_exec_lct_notify(c, 0); | ||
309 | }; | ||
310 | |||
311 | /** | ||
312 | * i2o_exec_reply - I2O Executive reply handler | ||
313 | * @c: I2O controller from which the reply comes | ||
314 | * @m: message id | ||
315 | * @msg: pointer to the I2O reply message | ||
316 | * | ||
317 | * This function is always called from interrupt context. If a POST WAIT | ||
318 | * reply was received, pass it to the complete function. If a LCT NOTIFY | ||
319 | * reply was received, a new event is created to handle the update. | ||
320 | * | ||
321 | * Returns 0 on success and if the reply should not be flushed or > 0 | ||
322 | * on success and if the reply should be flushed. Returns negative error | ||
323 | * code on failure and if the reply should be flushed. | ||
324 | */ | ||
325 | static int i2o_exec_reply(struct i2o_controller *c, u32 m, | ||
326 | struct i2o_message *msg) | ||
327 | { | ||
328 | if (le32_to_cpu(msg->u.head[0]) & MSG_FAIL) { // Fail bit is set | ||
329 | struct i2o_message __iomem *pmsg; /* preserved message */ | ||
330 | u32 pm; | ||
331 | |||
332 | pm = le32_to_cpu(msg->body[3]); | ||
333 | |||
334 | pmsg = i2o_msg_in_to_virt(c, pm); | ||
335 | |||
336 | i2o_report_status(KERN_INFO, "i2o_core", msg); | ||
337 | |||
338 | /* Release the preserved msg by resubmitting it as a NOP */ | ||
339 | i2o_msg_nop(c, pm); | ||
340 | |||
341 | /* If reply to i2o_post_wait failed, return causes a timeout */ | ||
342 | return -1; | ||
343 | } | ||
344 | |||
345 | if (le32_to_cpu(msg->u.s.tcntxt) & 0x80000000) | ||
346 | return i2o_msg_post_wait_complete(c, m, msg); | ||
347 | |||
348 | if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) { | ||
349 | struct work_struct *work; | ||
350 | |||
351 | pr_debug("%s: LCT notify received\n", c->name); | ||
352 | |||
353 | work = kmalloc(sizeof(*work), GFP_ATOMIC); | ||
354 | if (!work) | ||
355 | return -ENOMEM; | ||
356 | |||
357 | INIT_WORK(work, (void (*)(void *))i2o_exec_lct_modified, c); | ||
358 | queue_work(i2o_exec_driver.event_queue, work); | ||
359 | return 1; | ||
360 | } | ||
361 | |||
362 | /* | ||
363 | * If this happens, we want to dump the message to the syslog so | ||
364 | * it can be sent back to the card manufacturer by the end user | ||
365 | * to aid in debugging. | ||
366 | * | ||
367 | */ | ||
368 | printk(KERN_WARNING "%s: Unsolicited message reply sent to core!" | ||
369 | "Message dumped to syslog\n", c->name); | ||
370 | i2o_dump_message(msg); | ||
371 | |||
372 | return -EFAULT; | ||
373 | } | ||
374 | |||
375 | /** | ||
376 | * i2o_exec_event - Event handling function | ||
377 | * @evt: Event which occurs | ||
378 | * | ||
379 | * Handles events send by the Executive device. At the moment does not do | ||
380 | * anything useful. | ||
381 | */ | ||
382 | static void i2o_exec_event(struct i2o_event *evt) | ||
383 | { | ||
384 | osm_info("Event received from device: %d\n", | ||
385 | evt->i2o_dev->lct_data.tid); | ||
386 | kfree(evt); | ||
387 | }; | ||
388 | |||
389 | /** | ||
390 | * i2o_exec_lct_get - Get the IOP's Logical Configuration Table | ||
391 | * @c: I2O controller from which the LCT should be fetched | ||
392 | * | ||
393 | * Send a LCT NOTIFY request to the controller, and wait | ||
394 | * I2O_TIMEOUT_LCT_GET seconds until arrival of response. If the LCT is | ||
395 | * to large, retry it. | ||
396 | * | ||
397 | * Returns 0 on success or negative error code on failure. | ||
398 | */ | ||
399 | int i2o_exec_lct_get(struct i2o_controller *c) | ||
400 | { | ||
401 | struct i2o_message __iomem *msg; | ||
402 | u32 m; | ||
403 | int i = 0; | ||
404 | int rc = -EAGAIN; | ||
405 | |||
406 | for (i = 1; i <= I2O_LCT_GET_TRIES; i++) { | ||
407 | m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); | ||
408 | if (m == I2O_QUEUE_EMPTY) | ||
409 | return -ETIMEDOUT; | ||
410 | |||
411 | writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6, &msg->u.head[0]); | ||
412 | writel(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 | ADAPTER_TID, | ||
413 | &msg->u.head[1]); | ||
414 | writel(0xffffffff, &msg->body[0]); | ||
415 | writel(0x00000000, &msg->body[1]); | ||
416 | writel(0xd0000000 | c->dlct.len, &msg->body[2]); | ||
417 | writel(c->dlct.phys, &msg->body[3]); | ||
418 | |||
419 | rc = i2o_msg_post_wait(c, m, I2O_TIMEOUT_LCT_GET); | ||
420 | if (rc < 0) | ||
421 | break; | ||
422 | |||
423 | rc = i2o_device_parse_lct(c); | ||
424 | if (rc != -EAGAIN) | ||
425 | break; | ||
426 | } | ||
427 | |||
428 | return rc; | ||
429 | } | ||
430 | |||
431 | /** | ||
432 | * i2o_exec_lct_notify - Send a asynchronus LCT NOTIFY request | ||
433 | * @c: I2O controller to which the request should be send | ||
434 | * @change_ind: change indicator | ||
435 | * | ||
436 | * This function sends a LCT NOTIFY request to the I2O controller with | ||
437 | * the change indicator change_ind. If the change_ind == 0 the controller | ||
438 | * replies immediately after the request. If change_ind > 0 the reply is | ||
439 | * send after change indicator of the LCT is > change_ind. | ||
440 | */ | ||
441 | static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind) | ||
442 | { | ||
443 | i2o_status_block *sb = c->status_block.virt; | ||
444 | struct device *dev; | ||
445 | struct i2o_message __iomem *msg; | ||
446 | u32 m; | ||
447 | |||
448 | dev = &c->pdev->dev; | ||
449 | |||
450 | if (i2o_dma_realloc(dev, &c->dlct, sb->expected_lct_size, GFP_KERNEL)) | ||
451 | return -ENOMEM; | ||
452 | |||
453 | m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); | ||
454 | if (m == I2O_QUEUE_EMPTY) | ||
455 | return -ETIMEDOUT; | ||
456 | |||
457 | writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6, &msg->u.head[0]); | ||
458 | writel(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 | ADAPTER_TID, | ||
459 | &msg->u.head[1]); | ||
460 | writel(i2o_exec_driver.context, &msg->u.s.icntxt); | ||
461 | writel(0, &msg->u.s.tcntxt); /* FIXME */ | ||
462 | writel(0xffffffff, &msg->body[0]); | ||
463 | writel(change_ind, &msg->body[1]); | ||
464 | writel(0xd0000000 | c->dlct.len, &msg->body[2]); | ||
465 | writel(c->dlct.phys, &msg->body[3]); | ||
466 | |||
467 | i2o_msg_post(c, m); | ||
468 | |||
469 | return 0; | ||
470 | }; | ||
471 | |||
472 | /* Exec OSM driver struct */ | ||
473 | struct i2o_driver i2o_exec_driver = { | ||
474 | .name = OSM_NAME, | ||
475 | .reply = i2o_exec_reply, | ||
476 | .event = i2o_exec_event, | ||
477 | .classes = i2o_exec_class_id, | ||
478 | .driver = { | ||
479 | .probe = i2o_exec_probe, | ||
480 | .remove = i2o_exec_remove, | ||
481 | }, | ||
482 | }; | ||
483 | |||
484 | /** | ||
485 | * i2o_exec_init - Registers the Exec OSM | ||
486 | * | ||
487 | * Registers the Exec OSM in the I2O core. | ||
488 | * | ||
489 | * Returns 0 on success or negative error code on failure. | ||
490 | */ | ||
491 | int __init i2o_exec_init(void) | ||
492 | { | ||
493 | return i2o_driver_register(&i2o_exec_driver); | ||
494 | }; | ||
495 | |||
496 | /** | ||
497 | * i2o_exec_exit - Removes the Exec OSM | ||
498 | * | ||
499 | * Unregisters the Exec OSM from the I2O core. | ||
500 | */ | ||
501 | void __exit i2o_exec_exit(void) | ||
502 | { | ||
503 | i2o_driver_unregister(&i2o_exec_driver); | ||
504 | }; | ||
505 | |||
506 | EXPORT_SYMBOL(i2o_msg_post_wait_mem); | ||
507 | EXPORT_SYMBOL(i2o_exec_lct_get); | ||