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/device.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/device.c')
-rw-r--r-- | drivers/message/i2o/device.c | 634 |
1 files changed, 634 insertions, 0 deletions
diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c new file mode 100644 index 000000000000..eb907e87bc7b --- /dev/null +++ b/drivers/message/i2o/device.c | |||
@@ -0,0 +1,634 @@ | |||
1 | /* | ||
2 | * Functions to handle I2O devices | ||
3 | * | ||
4 | * Copyright (C) 2004 Markus Lidel <Markus.Lidel@shadowconnect.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | * Fixes/additions: | ||
12 | * Markus Lidel <Markus.Lidel@shadowconnect.com> | ||
13 | * initial version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/i2o.h> | ||
18 | #include <linux/delay.h> | ||
19 | |||
20 | /* Exec OSM functions */ | ||
21 | extern struct bus_type i2o_bus_type; | ||
22 | |||
23 | /** | ||
24 | * i2o_device_issue_claim - claim or release a device | ||
25 | * @dev: I2O device to claim or release | ||
26 | * @cmd: claim or release command | ||
27 | * @type: type of claim | ||
28 | * | ||
29 | * Issue I2O UTIL_CLAIM or UTIL_RELEASE messages. The message to be sent | ||
30 | * is set by cmd. dev is the I2O device which should be claim or | ||
31 | * released and the type is the claim type (see the I2O spec). | ||
32 | * | ||
33 | * Returs 0 on success or negative error code on failure. | ||
34 | */ | ||
35 | static inline int i2o_device_issue_claim(struct i2o_device *dev, u32 cmd, | ||
36 | u32 type) | ||
37 | { | ||
38 | struct i2o_message __iomem *msg; | ||
39 | u32 m; | ||
40 | |||
41 | m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); | ||
42 | if (m == I2O_QUEUE_EMPTY) | ||
43 | return -ETIMEDOUT; | ||
44 | |||
45 | writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); | ||
46 | writel(cmd << 24 | HOST_TID << 12 | dev->lct_data.tid, &msg->u.head[1]); | ||
47 | writel(type, &msg->body[0]); | ||
48 | |||
49 | return i2o_msg_post_wait(dev->iop, m, 60); | ||
50 | }; | ||
51 | |||
52 | /** | ||
53 | * i2o_device_claim - claim a device for use by an OSM | ||
54 | * @dev: I2O device to claim | ||
55 | * @drv: I2O driver which wants to claim the device | ||
56 | * | ||
57 | * Do the leg work to assign a device to a given OSM. If the claim succeed | ||
58 | * the owner of the rimary. If the attempt fails a negative errno code | ||
59 | * is returned. On success zero is returned. | ||
60 | */ | ||
61 | int i2o_device_claim(struct i2o_device *dev) | ||
62 | { | ||
63 | int rc = 0; | ||
64 | |||
65 | down(&dev->lock); | ||
66 | |||
67 | rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_CLAIM, I2O_CLAIM_PRIMARY); | ||
68 | if (!rc) | ||
69 | pr_debug("i2o: claim of device %d succeded\n", | ||
70 | dev->lct_data.tid); | ||
71 | else | ||
72 | pr_debug("i2o: claim of device %d failed %d\n", | ||
73 | dev->lct_data.tid, rc); | ||
74 | |||
75 | up(&dev->lock); | ||
76 | |||
77 | return rc; | ||
78 | }; | ||
79 | |||
80 | /** | ||
81 | * i2o_device_claim_release - release a device that the OSM is using | ||
82 | * @dev: device to release | ||
83 | * @drv: driver which claimed the device | ||
84 | * | ||
85 | * Drop a claim by an OSM on a given I2O device. | ||
86 | * | ||
87 | * AC - some devices seem to want to refuse an unclaim until they have | ||
88 | * finished internal processing. It makes sense since you don't want a | ||
89 | * new device to go reconfiguring the entire system until you are done. | ||
90 | * Thus we are prepared to wait briefly. | ||
91 | * | ||
92 | * Returns 0 on success or negative error code on failure. | ||
93 | */ | ||
94 | int i2o_device_claim_release(struct i2o_device *dev) | ||
95 | { | ||
96 | int tries; | ||
97 | int rc = 0; | ||
98 | |||
99 | down(&dev->lock); | ||
100 | |||
101 | /* | ||
102 | * If the controller takes a nonblocking approach to | ||
103 | * releases we have to sleep/poll for a few times. | ||
104 | */ | ||
105 | for (tries = 0; tries < 10; tries++) { | ||
106 | rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_RELEASE, | ||
107 | I2O_CLAIM_PRIMARY); | ||
108 | if (!rc) | ||
109 | break; | ||
110 | |||
111 | ssleep(1); | ||
112 | } | ||
113 | |||
114 | if (!rc) | ||
115 | pr_debug("i2o: claim release of device %d succeded\n", | ||
116 | dev->lct_data.tid); | ||
117 | else | ||
118 | pr_debug("i2o: claim release of device %d failed %d\n", | ||
119 | dev->lct_data.tid, rc); | ||
120 | |||
121 | up(&dev->lock); | ||
122 | |||
123 | return rc; | ||
124 | }; | ||
125 | |||
126 | /** | ||
127 | * i2o_device_release - release the memory for a I2O device | ||
128 | * @dev: I2O device which should be released | ||
129 | * | ||
130 | * Release the allocated memory. This function is called if refcount of | ||
131 | * device reaches 0 automatically. | ||
132 | */ | ||
133 | static void i2o_device_release(struct device *dev) | ||
134 | { | ||
135 | struct i2o_device *i2o_dev = to_i2o_device(dev); | ||
136 | |||
137 | pr_debug("i2o: device %s released\n", dev->bus_id); | ||
138 | |||
139 | kfree(i2o_dev); | ||
140 | }; | ||
141 | |||
142 | /** | ||
143 | * i2o_device_class_release - Remove I2O device attributes | ||
144 | * @cd: I2O class device which is added to the I2O device class | ||
145 | * | ||
146 | * Removes attributes from the I2O device again. Also search each device | ||
147 | * on the controller for I2O devices which refert to this device as parent | ||
148 | * or user and remove this links also. | ||
149 | */ | ||
150 | static void i2o_device_class_release(struct class_device *cd) | ||
151 | { | ||
152 | struct i2o_device *i2o_dev, *tmp; | ||
153 | struct i2o_controller *c; | ||
154 | |||
155 | i2o_dev = to_i2o_device(cd->dev); | ||
156 | c = i2o_dev->iop; | ||
157 | |||
158 | sysfs_remove_link(&i2o_dev->device.kobj, "parent"); | ||
159 | sysfs_remove_link(&i2o_dev->device.kobj, "user"); | ||
160 | |||
161 | list_for_each_entry(tmp, &c->devices, list) { | ||
162 | if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid) | ||
163 | sysfs_remove_link(&tmp->device.kobj, "parent"); | ||
164 | if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid) | ||
165 | sysfs_remove_link(&tmp->device.kobj, "user"); | ||
166 | } | ||
167 | }; | ||
168 | |||
169 | /* I2O device class */ | ||
170 | static struct class i2o_device_class = { | ||
171 | .name = "i2o_device", | ||
172 | .release = i2o_device_class_release | ||
173 | }; | ||
174 | |||
175 | /** | ||
176 | * i2o_device_alloc - Allocate a I2O device and initialize it | ||
177 | * | ||
178 | * Allocate the memory for a I2O device and initialize locks and lists | ||
179 | * | ||
180 | * Returns the allocated I2O device or a negative error code if the device | ||
181 | * could not be allocated. | ||
182 | */ | ||
183 | static struct i2o_device *i2o_device_alloc(void) | ||
184 | { | ||
185 | struct i2o_device *dev; | ||
186 | |||
187 | dev = kmalloc(sizeof(*dev), GFP_KERNEL); | ||
188 | if (!dev) | ||
189 | return ERR_PTR(-ENOMEM); | ||
190 | |||
191 | memset(dev, 0, sizeof(*dev)); | ||
192 | |||
193 | INIT_LIST_HEAD(&dev->list); | ||
194 | init_MUTEX(&dev->lock); | ||
195 | |||
196 | dev->device.bus = &i2o_bus_type; | ||
197 | dev->device.release = &i2o_device_release; | ||
198 | dev->classdev.class = &i2o_device_class; | ||
199 | dev->classdev.dev = &dev->device; | ||
200 | |||
201 | return dev; | ||
202 | }; | ||
203 | |||
204 | /** | ||
205 | * i2o_device_add - allocate a new I2O device and add it to the IOP | ||
206 | * @iop: I2O controller where the device is on | ||
207 | * @entry: LCT entry of the I2O device | ||
208 | * | ||
209 | * Allocate a new I2O device and initialize it with the LCT entry. The | ||
210 | * device is appended to the device list of the controller. | ||
211 | * | ||
212 | * Returns a pointer to the I2O device on success or negative error code | ||
213 | * on failure. | ||
214 | */ | ||
215 | static struct i2o_device *i2o_device_add(struct i2o_controller *c, | ||
216 | i2o_lct_entry * entry) | ||
217 | { | ||
218 | struct i2o_device *dev; | ||
219 | |||
220 | dev = i2o_device_alloc(); | ||
221 | if (IS_ERR(dev)) { | ||
222 | printk(KERN_ERR "i2o: unable to allocate i2o device\n"); | ||
223 | return dev; | ||
224 | } | ||
225 | |||
226 | dev->lct_data = *entry; | ||
227 | |||
228 | snprintf(dev->device.bus_id, BUS_ID_SIZE, "%d:%03x", c->unit, | ||
229 | dev->lct_data.tid); | ||
230 | |||
231 | snprintf(dev->classdev.class_id, BUS_ID_SIZE, "%d:%03x", c->unit, | ||
232 | dev->lct_data.tid); | ||
233 | |||
234 | dev->iop = c; | ||
235 | dev->device.parent = &c->device; | ||
236 | |||
237 | device_register(&dev->device); | ||
238 | |||
239 | list_add_tail(&dev->list, &c->devices); | ||
240 | |||
241 | class_device_register(&dev->classdev); | ||
242 | |||
243 | i2o_driver_notify_device_add_all(dev); | ||
244 | |||
245 | pr_debug("i2o: device %s added\n", dev->device.bus_id); | ||
246 | |||
247 | return dev; | ||
248 | }; | ||
249 | |||
250 | /** | ||
251 | * i2o_device_remove - remove an I2O device from the I2O core | ||
252 | * @dev: I2O device which should be released | ||
253 | * | ||
254 | * Is used on I2O controller removal or LCT modification, when the device | ||
255 | * is removed from the system. Note that the device could still hang | ||
256 | * around until the refcount reaches 0. | ||
257 | */ | ||
258 | void i2o_device_remove(struct i2o_device *i2o_dev) | ||
259 | { | ||
260 | i2o_driver_notify_device_remove_all(i2o_dev); | ||
261 | class_device_unregister(&i2o_dev->classdev); | ||
262 | list_del(&i2o_dev->list); | ||
263 | device_unregister(&i2o_dev->device); | ||
264 | }; | ||
265 | |||
266 | /** | ||
267 | * i2o_device_parse_lct - Parse a previously fetched LCT and create devices | ||
268 | * @c: I2O controller from which the LCT should be parsed. | ||
269 | * | ||
270 | * The Logical Configuration Table tells us what we can talk to on the | ||
271 | * board. For every entry we create an I2O device, which is registered in | ||
272 | * the I2O core. | ||
273 | * | ||
274 | * Returns 0 on success or negative error code on failure. | ||
275 | */ | ||
276 | int i2o_device_parse_lct(struct i2o_controller *c) | ||
277 | { | ||
278 | struct i2o_device *dev, *tmp; | ||
279 | i2o_lct *lct; | ||
280 | int i; | ||
281 | int max; | ||
282 | |||
283 | down(&c->lct_lock); | ||
284 | |||
285 | if (c->lct) | ||
286 | kfree(c->lct); | ||
287 | |||
288 | lct = c->dlct.virt; | ||
289 | |||
290 | c->lct = kmalloc(lct->table_size * 4, GFP_KERNEL); | ||
291 | if (!c->lct) { | ||
292 | up(&c->lct_lock); | ||
293 | return -ENOMEM; | ||
294 | } | ||
295 | |||
296 | if (lct->table_size * 4 > c->dlct.len) { | ||
297 | memcpy_fromio(c->lct, c->dlct.virt, c->dlct.len); | ||
298 | up(&c->lct_lock); | ||
299 | return -EAGAIN; | ||
300 | } | ||
301 | |||
302 | memcpy_fromio(c->lct, c->dlct.virt, lct->table_size * 4); | ||
303 | |||
304 | lct = c->lct; | ||
305 | |||
306 | max = (lct->table_size - 3) / 9; | ||
307 | |||
308 | pr_debug("%s: LCT has %d entries (LCT size: %d)\n", c->name, max, | ||
309 | lct->table_size); | ||
310 | |||
311 | /* remove devices, which are not in the LCT anymore */ | ||
312 | list_for_each_entry_safe(dev, tmp, &c->devices, list) { | ||
313 | int found = 0; | ||
314 | |||
315 | for (i = 0; i < max; i++) { | ||
316 | if (lct->lct_entry[i].tid == dev->lct_data.tid) { | ||
317 | found = 1; | ||
318 | break; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | if (!found) | ||
323 | i2o_device_remove(dev); | ||
324 | } | ||
325 | |||
326 | /* add new devices, which are new in the LCT */ | ||
327 | for (i = 0; i < max; i++) { | ||
328 | int found = 0; | ||
329 | |||
330 | list_for_each_entry_safe(dev, tmp, &c->devices, list) { | ||
331 | if (lct->lct_entry[i].tid == dev->lct_data.tid) { | ||
332 | found = 1; | ||
333 | break; | ||
334 | } | ||
335 | } | ||
336 | |||
337 | if (!found) | ||
338 | i2o_device_add(c, &lct->lct_entry[i]); | ||
339 | } | ||
340 | up(&c->lct_lock); | ||
341 | |||
342 | return 0; | ||
343 | }; | ||
344 | |||
345 | /** | ||
346 | * i2o_device_class_show_class_id - Displays class id of I2O device | ||
347 | * @cd: class device of which the class id should be displayed | ||
348 | * @buf: buffer into which the class id should be printed | ||
349 | * | ||
350 | * Returns the number of bytes which are printed into the buffer. | ||
351 | */ | ||
352 | static ssize_t i2o_device_class_show_class_id(struct class_device *cd, | ||
353 | char *buf) | ||
354 | { | ||
355 | struct i2o_device *dev = to_i2o_device(cd->dev); | ||
356 | |||
357 | sprintf(buf, "%03x\n", dev->lct_data.class_id); | ||
358 | return strlen(buf) + 1; | ||
359 | }; | ||
360 | |||
361 | /** | ||
362 | * i2o_device_class_show_tid - Displays TID of I2O device | ||
363 | * @cd: class device of which the TID should be displayed | ||
364 | * @buf: buffer into which the class id should be printed | ||
365 | * | ||
366 | * Returns the number of bytes which are printed into the buffer. | ||
367 | */ | ||
368 | static ssize_t i2o_device_class_show_tid(struct class_device *cd, char *buf) | ||
369 | { | ||
370 | struct i2o_device *dev = to_i2o_device(cd->dev); | ||
371 | |||
372 | sprintf(buf, "%03x\n", dev->lct_data.tid); | ||
373 | return strlen(buf) + 1; | ||
374 | }; | ||
375 | |||
376 | /* I2O device class attributes */ | ||
377 | static CLASS_DEVICE_ATTR(class_id, S_IRUGO, i2o_device_class_show_class_id, | ||
378 | NULL); | ||
379 | static CLASS_DEVICE_ATTR(tid, S_IRUGO, i2o_device_class_show_tid, NULL); | ||
380 | |||
381 | /** | ||
382 | * i2o_device_class_add - Adds attributes to the I2O device | ||
383 | * @cd: I2O class device which is added to the I2O device class | ||
384 | * | ||
385 | * This function get called when a I2O device is added to the class. It | ||
386 | * creates the attributes for each device and creates user/parent symlink | ||
387 | * if necessary. | ||
388 | * | ||
389 | * Returns 0 on success or negative error code on failure. | ||
390 | */ | ||
391 | static int i2o_device_class_add(struct class_device *cd) | ||
392 | { | ||
393 | struct i2o_device *i2o_dev, *tmp; | ||
394 | struct i2o_controller *c; | ||
395 | |||
396 | i2o_dev = to_i2o_device(cd->dev); | ||
397 | c = i2o_dev->iop; | ||
398 | |||
399 | class_device_create_file(cd, &class_device_attr_class_id); | ||
400 | class_device_create_file(cd, &class_device_attr_tid); | ||
401 | |||
402 | /* create user entries for this device */ | ||
403 | tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid); | ||
404 | if (tmp) | ||
405 | sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj, | ||
406 | "user"); | ||
407 | |||
408 | /* create user entries refering to this device */ | ||
409 | list_for_each_entry(tmp, &c->devices, list) | ||
410 | if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid) | ||
411 | sysfs_create_link(&tmp->device.kobj, | ||
412 | &i2o_dev->device.kobj, "user"); | ||
413 | |||
414 | /* create parent entries for this device */ | ||
415 | tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.parent_tid); | ||
416 | if (tmp) | ||
417 | sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj, | ||
418 | "parent"); | ||
419 | |||
420 | /* create parent entries refering to this device */ | ||
421 | list_for_each_entry(tmp, &c->devices, list) | ||
422 | if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid) | ||
423 | sysfs_create_link(&tmp->device.kobj, | ||
424 | &i2o_dev->device.kobj, "parent"); | ||
425 | |||
426 | return 0; | ||
427 | }; | ||
428 | |||
429 | /* I2O device class interface */ | ||
430 | static struct class_interface i2o_device_class_interface = { | ||
431 | .class = &i2o_device_class, | ||
432 | .add = i2o_device_class_add | ||
433 | }; | ||
434 | |||
435 | /* | ||
436 | * Run time support routines | ||
437 | */ | ||
438 | |||
439 | /* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET | ||
440 | * | ||
441 | * This function can be used for all UtilParamsGet/Set operations. | ||
442 | * The OperationList is given in oplist-buffer, | ||
443 | * and results are returned in reslist-buffer. | ||
444 | * Note that the minimum sized reslist is 8 bytes and contains | ||
445 | * ResultCount, ErrorInfoSize, BlockStatus and BlockSize. | ||
446 | */ | ||
447 | |||
448 | int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist, | ||
449 | int oplen, void *reslist, int reslen) | ||
450 | { | ||
451 | struct i2o_message __iomem *msg; | ||
452 | u32 m; | ||
453 | u32 *res32 = (u32 *) reslist; | ||
454 | u32 *restmp = (u32 *) reslist; | ||
455 | int len = 0; | ||
456 | int i = 0; | ||
457 | int rc; | ||
458 | struct i2o_dma res; | ||
459 | struct i2o_controller *c = i2o_dev->iop; | ||
460 | struct device *dev = &c->pdev->dev; | ||
461 | |||
462 | res.virt = NULL; | ||
463 | |||
464 | if (i2o_dma_alloc(dev, &res, reslen, GFP_KERNEL)) | ||
465 | return -ENOMEM; | ||
466 | |||
467 | m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); | ||
468 | if (m == I2O_QUEUE_EMPTY) { | ||
469 | i2o_dma_free(dev, &res); | ||
470 | return -ETIMEDOUT; | ||
471 | } | ||
472 | |||
473 | i = 0; | ||
474 | writel(cmd << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid, | ||
475 | &msg->u.head[1]); | ||
476 | writel(0, &msg->body[i++]); | ||
477 | writel(0x4C000000 | oplen, &msg->body[i++]); /* OperationList */ | ||
478 | memcpy_toio(&msg->body[i], oplist, oplen); | ||
479 | i += (oplen / 4 + (oplen % 4 ? 1 : 0)); | ||
480 | writel(0xD0000000 | res.len, &msg->body[i++]); /* ResultList */ | ||
481 | writel(res.phys, &msg->body[i++]); | ||
482 | |||
483 | writel(I2O_MESSAGE_SIZE(i + sizeof(struct i2o_message) / 4) | | ||
484 | SGL_OFFSET_5, &msg->u.head[0]); | ||
485 | |||
486 | rc = i2o_msg_post_wait_mem(c, m, 10, &res); | ||
487 | |||
488 | /* This only looks like a memory leak - don't "fix" it. */ | ||
489 | if (rc == -ETIMEDOUT) | ||
490 | return rc; | ||
491 | |||
492 | memcpy_fromio(reslist, res.virt, res.len); | ||
493 | i2o_dma_free(dev, &res); | ||
494 | |||
495 | /* Query failed */ | ||
496 | if (rc) | ||
497 | return rc; | ||
498 | /* | ||
499 | * Calculate number of bytes of Result LIST | ||
500 | * We need to loop through each Result BLOCK and grab the length | ||
501 | */ | ||
502 | restmp = res32 + 1; | ||
503 | len = 1; | ||
504 | for (i = 0; i < (res32[0] & 0X0000FFFF); i++) { | ||
505 | if (restmp[0] & 0x00FF0000) { /* BlockStatus != SUCCESS */ | ||
506 | printk(KERN_WARNING | ||
507 | "%s - Error:\n ErrorInfoSize = 0x%02x, " | ||
508 | "BlockStatus = 0x%02x, BlockSize = 0x%04x\n", | ||
509 | (cmd == | ||
510 | I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET" : | ||
511 | "PARAMS_GET", res32[1] >> 24, | ||
512 | (res32[1] >> 16) & 0xFF, res32[1] & 0xFFFF); | ||
513 | |||
514 | /* | ||
515 | * If this is the only request,than we return an error | ||
516 | */ | ||
517 | if ((res32[0] & 0x0000FFFF) == 1) { | ||
518 | return -((res32[1] >> 16) & 0xFF); /* -BlockStatus */ | ||
519 | } | ||
520 | } | ||
521 | len += restmp[0] & 0x0000FFFF; /* Length of res BLOCK */ | ||
522 | restmp += restmp[0] & 0x0000FFFF; /* Skip to next BLOCK */ | ||
523 | } | ||
524 | return (len << 2); /* bytes used by result list */ | ||
525 | } | ||
526 | |||
527 | /* | ||
528 | * Query one field group value or a whole scalar group. | ||
529 | */ | ||
530 | int i2o_parm_field_get(struct i2o_device *i2o_dev, int group, int field, | ||
531 | void *buf, int buflen) | ||
532 | { | ||
533 | u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field }; | ||
534 | u8 resblk[8 + buflen]; /* 8 bytes for header */ | ||
535 | int size; | ||
536 | |||
537 | if (field == -1) /* whole group */ | ||
538 | opblk[4] = -1; | ||
539 | |||
540 | size = i2o_parm_issue(i2o_dev, I2O_CMD_UTIL_PARAMS_GET, opblk, | ||
541 | sizeof(opblk), resblk, sizeof(resblk)); | ||
542 | |||
543 | memcpy(buf, resblk + 8, buflen); /* cut off header */ | ||
544 | |||
545 | if (size > buflen) | ||
546 | return buflen; | ||
547 | |||
548 | return size; | ||
549 | } | ||
550 | |||
551 | /* | ||
552 | * if oper == I2O_PARAMS_TABLE_GET, get from all rows | ||
553 | * if fieldcount == -1 return all fields | ||
554 | * ibuf and ibuflen are unused (use NULL, 0) | ||
555 | * else return specific fields | ||
556 | * ibuf contains fieldindexes | ||
557 | * | ||
558 | * if oper == I2O_PARAMS_LIST_GET, get from specific rows | ||
559 | * if fieldcount == -1 return all fields | ||
560 | * ibuf contains rowcount, keyvalues | ||
561 | * else return specific fields | ||
562 | * fieldcount is # of fieldindexes | ||
563 | * ibuf contains fieldindexes, rowcount, keyvalues | ||
564 | * | ||
565 | * You could also use directly function i2o_issue_params(). | ||
566 | */ | ||
567 | int i2o_parm_table_get(struct i2o_device *dev, int oper, int group, | ||
568 | int fieldcount, void *ibuf, int ibuflen, void *resblk, | ||
569 | int reslen) | ||
570 | { | ||
571 | u16 *opblk; | ||
572 | int size; | ||
573 | |||
574 | size = 10 + ibuflen; | ||
575 | if (size % 4) | ||
576 | size += 4 - size % 4; | ||
577 | |||
578 | opblk = kmalloc(size, GFP_KERNEL); | ||
579 | if (opblk == NULL) { | ||
580 | printk(KERN_ERR "i2o: no memory for query buffer.\n"); | ||
581 | return -ENOMEM; | ||
582 | } | ||
583 | |||
584 | opblk[0] = 1; /* operation count */ | ||
585 | opblk[1] = 0; /* pad */ | ||
586 | opblk[2] = oper; | ||
587 | opblk[3] = group; | ||
588 | opblk[4] = fieldcount; | ||
589 | memcpy(opblk + 5, ibuf, ibuflen); /* other params */ | ||
590 | |||
591 | size = i2o_parm_issue(dev, I2O_CMD_UTIL_PARAMS_GET, opblk, | ||
592 | size, resblk, reslen); | ||
593 | |||
594 | kfree(opblk); | ||
595 | if (size > reslen) | ||
596 | return reslen; | ||
597 | |||
598 | return size; | ||
599 | } | ||
600 | |||
601 | /** | ||
602 | * i2o_device_init - Initialize I2O devices | ||
603 | * | ||
604 | * Registers the I2O device class. | ||
605 | * | ||
606 | * Returns 0 on success or negative error code on failure. | ||
607 | */ | ||
608 | int i2o_device_init(void) | ||
609 | { | ||
610 | int rc; | ||
611 | |||
612 | rc = class_register(&i2o_device_class); | ||
613 | if (rc) | ||
614 | return rc; | ||
615 | |||
616 | return class_interface_register(&i2o_device_class_interface); | ||
617 | }; | ||
618 | |||
619 | /** | ||
620 | * i2o_device_exit - I2O devices exit function | ||
621 | * | ||
622 | * Unregisters the I2O device class. | ||
623 | */ | ||
624 | void i2o_device_exit(void) | ||
625 | { | ||
626 | class_interface_register(&i2o_device_class_interface); | ||
627 | class_unregister(&i2o_device_class); | ||
628 | }; | ||
629 | |||
630 | EXPORT_SYMBOL(i2o_device_claim); | ||
631 | EXPORT_SYMBOL(i2o_device_claim_release); | ||
632 | EXPORT_SYMBOL(i2o_parm_field_get); | ||
633 | EXPORT_SYMBOL(i2o_parm_table_get); | ||
634 | EXPORT_SYMBOL(i2o_parm_issue); | ||