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