ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ia64 / sn / io / hwgfs / labelcl.c
1 /*  labelcl - SGI's Hwgraph Compatibility Layer.
2  *
3  * This file is subject to the terms and conditions of the GNU General Public
4  * License.  See the file "COPYING" in the main directory of this archive
5  * for more details.
6  *
7  * Copyright (c) 2001-2003 Silicon Graphics, Inc.  All rights reserved.
8 */
9
10 #include <linux/types.h>
11 #include <linux/slab.h>
12 #include <linux/kernel.h>
13 #include <linux/fs.h>
14 #include <linux/string.h>
15 #include <linux/sched.h>                /* needed for smp_lock.h :( */
16 #include <linux/smp_lock.h>
17 #include <asm/sn/sgi.h>
18 #include <asm/sn/hwgfs.h>
19 #include <asm/sn/hcl.h>
20 #include <asm/sn/labelcl.h>
21
22 /*
23 ** Very simple and dumb string table that supports only find/insert.
24 ** In practice, if this table gets too large, we may need a more
25 ** efficient data structure.   Also note that currently there is no 
26 ** way to delete an item once it's added.  Therefore, name collision 
27 ** will return an error.
28 */
29
30 struct string_table label_string_table;
31
32
33
34 /*
35  * string_table_init - Initialize the given string table.
36  */
37 void
38 string_table_init(struct string_table *string_table)
39 {
40         string_table->string_table_head = NULL;
41         string_table->string_table_generation = 0;
42
43         /*
44          * We nedd to initialize locks here!
45          */
46
47         return;
48 }
49
50
51 /*
52  * string_table_destroy - Destroy the given string table.
53  */
54 void
55 string_table_destroy(struct string_table *string_table)
56 {
57         struct string_table_item *item, *next_item;
58
59         item = string_table->string_table_head;
60         while (item) {
61                 next_item = item->next;
62
63                 STRTBL_FREE(item);
64                 item = next_item;
65         }
66
67         /*
68          * We need to destroy whatever lock we have here
69          */
70
71         return;
72 }
73
74
75
76 /*
77  * string_table_insert - Insert an entry in the string table .. duplicate 
78  *      names are not allowed.
79  */
80 char *
81 string_table_insert(struct string_table *string_table, char *name)
82 {
83         struct string_table_item *item, *new_item = NULL, *last_item = NULL;
84
85 again:
86         /*
87          * Need to lock the table ..
88          */
89         item = string_table->string_table_head;
90         last_item = NULL;
91
92         while (item) {
93                 if (!strcmp(item->string, name)) {
94                         /*
95                          * If we allocated space for the string and the found that
96                          * someone else already entered it into the string table,
97                          * free the space we just allocated.
98                          */
99                         if (new_item)
100                                 STRTBL_FREE(new_item);
101
102
103                         /*
104                          * Search optimization: move the found item to the head
105                          * of the list.
106                          */
107                         if (last_item != NULL) {
108                                 last_item->next = item->next;
109                                 item->next = string_table->string_table_head;
110                                 string_table->string_table_head = item;
111                         }
112                         goto out;
113                 }
114                 last_item = item;
115                 item=item->next;
116         }
117
118         /*
119          * name was not found, so add it to the string table.
120          */
121         if (new_item == NULL) {
122                 long old_generation = string_table->string_table_generation;
123
124                 new_item = STRTBL_ALLOC(strlen(name));
125
126                 strcpy(new_item->string, name);
127
128                 /*
129                  * While we allocated memory for the new string, someone else 
130                  * changed the string table.
131                  */
132                 if (old_generation != string_table->string_table_generation) {
133                         goto again;
134                 }
135         } else {
136                 /* At this we only have the string table lock in access mode.
137                  * Promote the access lock to an update lock for the string
138                  * table insertion below.
139                  */
140                         long old_generation = 
141                                 string_table->string_table_generation;
142
143                         /*
144                          * After we did the unlock and wer waiting for update
145                          * lock someone could have potentially updated
146                          * the string table. Check the generation number
147                          * for this case. If it is the case we have to
148                          * try all over again.
149                          */
150                         if (old_generation != 
151                             string_table->string_table_generation) {
152                                 goto again;
153                         }
154                 }
155
156         /*
157          * At this point, we're committed to adding new_item to the string table.
158          */
159         new_item->next = string_table->string_table_head;
160         item = string_table->string_table_head = new_item;
161         string_table->string_table_generation++;
162
163 out:
164         /*
165          * Need to unlock here.
166          */
167         return(item->string);
168 }
169
170 /*
171  * labelcl_info_create - Creates the data structure that will hold the
172  *      device private information asscoiated with a entry.
173  *      The pointer to this structure is what gets stored in the 
174  *      (void * info).
175  */
176 labelcl_info_t *
177 labelcl_info_create()
178 {
179
180         labelcl_info_t *new = NULL;
181
182         /* Initial allocation does not include any area for labels */
183         if ( ( new = (labelcl_info_t *)kmalloc (sizeof(labelcl_info_t), GFP_KERNEL) ) == NULL )
184                 return NULL;
185
186         memset (new, 0, sizeof(labelcl_info_t));
187         new->hwcl_magic = LABELCL_MAGIC;
188         return( new);
189
190 }
191
192 /*
193  * labelcl_info_destroy - Frees the data structure that holds the
194  *      device private information asscoiated with a entry.  This 
195  *      data structure was created by device_info_create().
196  *
197  *      The caller is responsible for nulling the (void *info) in the 
198  *      corresponding entry.
199  */
200 int
201 labelcl_info_destroy(labelcl_info_t *labelcl_info)
202 {
203
204         if (labelcl_info == NULL)
205                 return(0);
206
207         /* Free the label list */
208         if (labelcl_info->label_list)
209                 kfree(labelcl_info->label_list);
210
211         /* Now free the label info area */
212         labelcl_info->hwcl_magic = 0;
213         kfree(labelcl_info);
214
215         return(0);
216 }
217
218 /*
219  * labelcl_info_add_LBL - Adds a new label entry in the labelcl info 
220  *      structure.
221  *
222  *      Error is returned if we find another label with the same name.
223  */
224 int
225 labelcl_info_add_LBL(vertex_hdl_t de,
226                         char *info_name,
227                         arb_info_desc_t info_desc,
228                         arbitrary_info_t info)
229 {
230         labelcl_info_t  *labelcl_info = NULL;
231         int num_labels;
232         int new_label_list_size;
233         label_info_t *old_label_list, *new_label_list = NULL;
234         char *name;
235         int i;
236
237         if (de == NULL)
238                 return(-1);
239
240         labelcl_info = hwgfs_get_info(de);
241         if (labelcl_info == NULL)
242                 return(-1);
243
244         if (labelcl_info->hwcl_magic != LABELCL_MAGIC)
245                 return(-1);
246
247         if (info_name == NULL)
248                 return(-1);
249
250         if (strlen(info_name) >= LABEL_LENGTH_MAX)
251                 return(-1);
252
253         name = string_table_insert(&label_string_table, info_name);
254
255         num_labels = labelcl_info->num_labels;
256         new_label_list_size = sizeof(label_info_t) * (num_labels+1);
257
258         /*
259          * Create a new label info area.
260          */
261         if (new_label_list_size != 0) {
262                 new_label_list = (label_info_t *) kmalloc(new_label_list_size, GFP_KERNEL);
263
264                 if (new_label_list == NULL)
265                         return(-1);
266         }
267
268         /*
269          * At this point, we are committed to adding the labelled info, 
270          * if there isn't already information there with the same name.
271          */
272         old_label_list = labelcl_info->label_list;
273
274         /* 
275          * Look for matching info name.
276          */
277         for (i=0; i<num_labels; i++) {
278                 if (!strcmp(info_name, old_label_list[i].name)) {
279                         /* Not allowed to add duplicate labelled info names. */
280                         kfree(new_label_list);
281                         return(-1);
282                 }
283                 new_label_list[i] = old_label_list[i]; /* structure copy */
284         }
285
286         new_label_list[num_labels].name = name;
287         new_label_list[num_labels].desc = info_desc;
288         new_label_list[num_labels].info = info;
289
290         labelcl_info->num_labels = num_labels+1;
291         labelcl_info->label_list = new_label_list;
292
293         if (old_label_list != NULL)
294                 kfree(old_label_list);
295
296         return(0);
297 }
298
299 /*
300  * labelcl_info_remove_LBL - Remove a label entry.
301  */
302 int
303 labelcl_info_remove_LBL(vertex_hdl_t de,
304                          char *info_name,
305                          arb_info_desc_t *info_desc,
306                          arbitrary_info_t *info)
307 {
308         labelcl_info_t  *labelcl_info = NULL;
309         int num_labels;
310         int new_label_list_size;
311         label_info_t *old_label_list, *new_label_list = NULL;
312         arb_info_desc_t label_desc_found;
313         arbitrary_info_t label_info_found;
314         int i;
315
316         if (de == NULL)
317                 return(-1);
318
319         labelcl_info = hwgfs_get_info(de);
320         if (labelcl_info == NULL)
321                 return(-1);
322
323         if (labelcl_info->hwcl_magic != LABELCL_MAGIC)
324                 return(-1);
325
326         num_labels = labelcl_info->num_labels;
327         if (num_labels == 0) {
328                 return(-1);
329         }
330
331         /*
332          * Create a new info area.
333          */
334         new_label_list_size = sizeof(label_info_t) * (num_labels-1);
335         if (new_label_list_size) {
336                 new_label_list = (label_info_t *) kmalloc(new_label_list_size, GFP_KERNEL);
337                 if (new_label_list == NULL)
338                         return(-1);
339         }
340
341         /*
342          * At this point, we are committed to removing the labelled info, 
343          * if it still exists.
344          */
345         old_label_list = labelcl_info->label_list;
346
347         /* 
348          * Find matching info name.
349          */
350         for (i=0; i<num_labels; i++) {
351                 if (!strcmp(info_name, old_label_list[i].name)) {
352                         label_desc_found = old_label_list[i].desc;
353                         label_info_found = old_label_list[i].info;
354                         goto found;
355                 }
356                 if (i < num_labels-1) /* avoid walking off the end of the new vertex */
357                         new_label_list[i] = old_label_list[i]; /* structure copy */
358         }
359
360         /* The named info doesn't exist. */
361         if (new_label_list)
362                 kfree(new_label_list);
363
364         return(-1);
365
366 found:
367         /* Finish up rest of labelled info */
368         for (i=i+1; i<num_labels; i++)
369                 new_label_list[i-1] = old_label_list[i]; /* structure copy */
370
371         labelcl_info->num_labels = num_labels+1;
372         labelcl_info->label_list = new_label_list;
373
374         kfree(old_label_list);
375
376         if (info != NULL)
377                 *info = label_info_found;
378
379         if (info_desc != NULL)
380                 *info_desc = label_desc_found;
381
382         return(0);
383 }
384
385
386 /*
387  * labelcl_info_replace_LBL - Replace an existing label entry with the 
388  *      given new information.
389  *
390  *      Label entry must exist.
391  */
392 int
393 labelcl_info_replace_LBL(vertex_hdl_t de,
394                         char *info_name,
395                         arb_info_desc_t info_desc,
396                         arbitrary_info_t info,
397                         arb_info_desc_t *old_info_desc,
398                         arbitrary_info_t *old_info)
399 {
400         labelcl_info_t  *labelcl_info = NULL;
401         int num_labels;
402         label_info_t *label_list;
403         int i;
404
405         if (de == NULL)
406                 return(-1);
407
408         labelcl_info = hwgfs_get_info(de);
409         if (labelcl_info == NULL)
410                 return(-1);
411
412         if (labelcl_info->hwcl_magic != LABELCL_MAGIC)
413                 return(-1);
414
415         num_labels = labelcl_info->num_labels;
416         if (num_labels == 0) {
417                 return(-1);
418         }
419
420         if (info_name == NULL)
421                 return(-1);
422
423         label_list = labelcl_info->label_list;
424
425         /* 
426          * Verify that information under info_name already exists.
427          */
428         for (i=0; i<num_labels; i++)
429                 if (!strcmp(info_name, label_list[i].name)) {
430                         if (old_info != NULL)
431                                 *old_info = label_list[i].info;
432
433                         if (old_info_desc != NULL)
434                                 *old_info_desc = label_list[i].desc;
435
436                         label_list[i].info = info;
437                         label_list[i].desc = info_desc;
438
439                         return(0);
440                 }
441
442
443         return(-1);
444 }
445
446 /*
447  * labelcl_info_get_LBL - Retrieve and return the information for the 
448  *      given label entry.
449  */
450 int
451 labelcl_info_get_LBL(vertex_hdl_t de,
452                       char *info_name,
453                       arb_info_desc_t *info_desc,
454                       arbitrary_info_t *info)
455 {
456         labelcl_info_t  *labelcl_info = NULL;
457         int num_labels;
458         label_info_t *label_list;
459         int i;
460
461         if (de == NULL)
462                 return(-1);
463
464         labelcl_info = hwgfs_get_info(de);
465         if (labelcl_info == NULL)
466                 return(-1);
467
468         if (labelcl_info->hwcl_magic != LABELCL_MAGIC)
469                 return(-1);
470
471         num_labels = labelcl_info->num_labels;
472         if (num_labels == 0) {
473                 return(-1);
474         }
475
476         label_list = labelcl_info->label_list;
477
478         /* 
479          * Find information under info_name.
480          */
481         for (i=0; i<num_labels; i++)
482                 if (!strcmp(info_name, label_list[i].name)) {
483                         if (info != NULL)
484                                 *info = label_list[i].info;
485                         if (info_desc != NULL)
486                                 *info_desc = label_list[i].desc;
487
488                         return(0);
489                 }
490
491         return(-1);
492 }
493
494 /*
495  * labelcl_info_get_next_LBL - returns the next label entry on the list.
496  */
497 int
498 labelcl_info_get_next_LBL(vertex_hdl_t de,
499                            char *buffer,
500                            arb_info_desc_t *info_descp,
501                            arbitrary_info_t *infop,
502                            labelcl_info_place_t *placeptr)
503 {
504         labelcl_info_t  *labelcl_info = NULL;
505         uint which_info;
506         label_info_t *label_list;
507
508         if ((buffer == NULL) && (infop == NULL))
509                 return(-1);
510
511         if (placeptr == NULL)
512                 return(-1);
513
514         if (de == NULL)
515                 return(-1);
516
517         labelcl_info = hwgfs_get_info(de);
518         if (labelcl_info == NULL)
519                 return(-1);
520
521         if (labelcl_info->hwcl_magic != LABELCL_MAGIC)
522                 return(-1);
523
524         which_info = *placeptr;
525
526         if (which_info >= labelcl_info->num_labels) {
527                 return(-1);
528         }
529
530         label_list = (label_info_t *) labelcl_info->label_list;
531
532         if (buffer != NULL)
533                 strcpy(buffer, label_list[which_info].name);
534
535         if (infop)
536                 *infop = label_list[which_info].info;
537
538         if (info_descp)
539                 *info_descp = label_list[which_info].desc;
540
541         *placeptr = which_info + 1;
542
543         return(0);
544 }
545
546
547 int
548 labelcl_info_replace_IDX(vertex_hdl_t de,
549                         int index,
550                         arbitrary_info_t info,
551                         arbitrary_info_t *old_info)
552 {
553         arbitrary_info_t *info_list_IDX;
554         labelcl_info_t  *labelcl_info = NULL;
555
556         if (de == NULL) {
557                 printk(KERN_ALERT "labelcl: NULL handle given.\n");
558                 return(-1);
559         }
560
561         labelcl_info = hwgfs_get_info(de);
562         if (labelcl_info == NULL) {
563                 printk(KERN_ALERT "labelcl: Entry %p does not have info pointer.\n", (void *)de);
564                 return(-1);
565         }
566
567         if (labelcl_info->hwcl_magic != LABELCL_MAGIC)
568                 return(-1);
569
570         if ( (index < 0) || (index >= HWGRAPH_NUM_INDEX_INFO) )
571                 return(-1);
572
573         /*
574          * Replace information at the appropriate index in this vertex with 
575          * the new info.
576          */
577         info_list_IDX = labelcl_info->IDX_list;
578         if (old_info != NULL)
579                 *old_info = info_list_IDX[index];
580         info_list_IDX[index] = info;
581
582         return(0);
583
584 }
585
586 /*
587  * labelcl_info_connectpt_set - Sets the connectpt.
588  */
589 int
590 labelcl_info_connectpt_set(hwgfs_handle_t de,
591                           hwgfs_handle_t connect_de)
592 {
593         arbitrary_info_t old_info;
594         int     rv;
595
596         rv = labelcl_info_replace_IDX(de, HWGRAPH_CONNECTPT, 
597                 (arbitrary_info_t) connect_de, &old_info);
598
599         if (rv) {
600                 return(rv);
601         }
602
603         return(0);
604 }
605
606
607 /*
608  * labelcl_info_get_IDX - Returns the information pointed at by index.
609  *
610  */
611 int
612 labelcl_info_get_IDX(vertex_hdl_t de,
613                         int index,
614                         arbitrary_info_t *info)
615 {
616         arbitrary_info_t *info_list_IDX;
617         labelcl_info_t  *labelcl_info = NULL;
618
619         if (de == NULL)
620                 return(-1);
621
622         labelcl_info = hwgfs_get_info(de);
623         if (labelcl_info == NULL)
624                 return(-1);
625
626         if (labelcl_info->hwcl_magic != LABELCL_MAGIC)
627                 return(-1);
628
629         if ( (index < 0) || (index >= HWGRAPH_NUM_INDEX_INFO) )
630                 return(-1);
631
632         /*
633          * Return information at the appropriate index in this vertex.
634          */
635         info_list_IDX = labelcl_info->IDX_list;
636         if (info != NULL)
637                 *info = info_list_IDX[index];
638
639         return(0);
640 }
641
642 /*
643  * labelcl_info_connectpt_get - Retrieve the connect point for a device entry.
644  */
645 hwgfs_handle_t
646 labelcl_info_connectpt_get(hwgfs_handle_t de)
647 {
648         int rv;
649         arbitrary_info_t info;
650
651         rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info);
652         if (rv)
653                 return(NULL);
654
655         return((hwgfs_handle_t) info);
656 }