brute-forced more changes from MontaVista's tree. SCSI partition table read still...
[linux-2.4.git] / drivers / s390 / misc / chandev.c
1 /*
2  *  drivers/s390/misc/chandev.c
3  *
4  *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
5  *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
6  * 
7  *  Generic channel device initialisation support. 
8  */
9 #define TRUE 1
10 #define FALSE 0
11 #define __KERNEL_SYSCALLS__
12 #include <linux/module.h>
13 #include <linux/config.h>
14 #include <linux/types.h>
15 #include <linux/ctype.h>
16 #include <asm/uaccess.h>
17 #include <linux/slab.h>
18 #include <asm/irq.h>
19 #include <linux/init.h>
20 #include <linux/unistd.h>
21 #include <asm/chandev.h>
22 #include <linux/proc_fs.h>
23 #include <linux/vmalloc.h>
24 #include <asm/s390dyn.h>
25 #include <asm/queue.h>
26 #include <linux/kmod.h>
27 #ifndef MIN
28 #define MIN(a,b) ((a<b)?a:b)
29 #endif
30 #ifndef MAX
31 #define MAX(a,b) ((a>b)?a:b)
32 #endif
33
34
35
36 typedef struct chandev_model_info chandev_model_info;
37 struct chandev_model_info
38 {
39         struct chandev_model_info *next;
40         chandev_type chan_type;
41         s32 cu_type;      /* control unit type  -1 = don't care */
42         s16 cu_model;     /* control unit model -1 = don't care */
43         s32 dev_type;     /* device type -1 = don't care */
44         s16 dev_model;    /* device model -1 = don't care */
45         u8  max_port_no;
46         int auto_msck_recovery;
47         u8  default_checksum_received_ip_pkts;
48         u8  default_use_hw_stats; /* where available e.g. lcs */
49         devreg_t drinfo;
50 };
51
52 typedef struct chandev chandev;
53 struct chandev
54 {
55         struct chandev *next;
56         chandev_model_info *model_info;
57         chandev_subchannel_info sch;
58         int owned;
59 };
60
61 typedef struct chandev_noauto_range chandev_noauto_range;
62 struct chandev_noauto_range
63 {
64         struct chandev_noauto_range *next;
65         u16     lo_devno;
66         u16     hi_devno;
67 };
68
69 typedef struct chandev_force chandev_force;
70 struct chandev_force
71 {
72         struct chandev_force *next;
73         chandev_type chan_type;
74         s32     devif_num; /* -1 don't care, -2 we are forcing a range e.g. tr0 implies 0 */
75         u16     read_lo_devno;
76         u16     write_hi_devno;
77         u16     data_devno; /* only used by gigabit ethernet */
78         s32     memory_usage_in_k;
79         s16     port_protocol_no; /* where available e.g. lcs,-1 don't care */
80         u8      checksum_received_ip_pkts;
81         u8      use_hw_stats; /* where available e.g. lcs */
82         /* claw specific stuff */
83         chandev_claw_info  claw;
84 };
85
86 typedef struct chandev_probelist chandev_probelist;
87 struct chandev_probelist
88 {
89         struct chandev_probelist            *next;
90         chandev_probefunc                   probefunc;
91         chandev_shutdownfunc                shutdownfunc;
92         chandev_msck_notification_func      msck_notfunc;
93         chandev_type                        chan_type;
94         int                                 devices_found;
95 };
96
97
98
99 #define default_msck_bits ((1<<(chandev_status_not_oper-1))|(1<<(chandev_status_no_path-1))|(1<<(chandev_status_revalidate-1))|(1<<(chandev_status_gone-1)))
100
101
102 static char *msck_status_strs[]=
103 {
104         "good",
105         "not_operational",
106         "no_path",
107         "revalidate",
108         "device_gone"
109 };
110
111 typedef struct chandev_msck_range chandev_msck_range;
112 struct chandev_msck_range
113 {
114         struct chandev_msck_range *next;
115         u16     lo_devno;
116         u16     hi_devno;
117         int      auto_msck_recovery;
118 };
119
120 static chandev_msck_range *chandev_msck_range_head=NULL;
121
122 typedef struct chandev_irqinfo chandev_irqinfo;
123 struct chandev_irqinfo
124 {
125         chandev_irqinfo         *next;
126         chandev_subchannel_info sch;
127         chandev_msck_status     msck_status;
128         void                    (*handler)(int, void *, struct pt_regs *);
129         unsigned long           irqflags;
130         void                    *dev_id;
131         char                    devname[0];
132 };
133
134
135 chandev_irqinfo *chandev_irqinfo_head=NULL;
136
137 typedef struct chandev_parms chandev_parms;
138 struct chandev_parms
139 {
140         chandev_parms      *next;
141         chandev_type       chan_type;
142         u16                lo_devno;
143         u16                hi_devno;
144         char               parmstr[0];
145 };
146
147 static chandev_type chandev_persistent=0; 
148
149 chandev_parms *chandev_parms_head=NULL;
150
151
152 typedef struct chandev_activelist chandev_activelist;
153 struct chandev_activelist
154 {
155         struct chandev_activelist        *next;
156         chandev_irqinfo                  *read_irqinfo;
157         chandev_irqinfo                  *write_irqinfo;
158         chandev_irqinfo                  *data_irqinfo;
159         chandev_probefunc                probefunc;
160         chandev_shutdownfunc             shutdownfunc;
161         chandev_msck_notification_func   msck_notfunc;
162         chandev_unregfunc                unreg_dev;
163         chandev_type                     chan_type;
164         u8                               port_no;
165         chandev_category                 category;
166         s32                              memory_usage_in_k;
167         void                             *dev_ptr;
168         char                             devname[0];
169 };
170
171
172
173 static chandev_model_info *chandev_models_head=NULL;
174 /* The only reason chandev_head is a queue is so that net devices */
175 /* will be by default named in the order of their irqs */
176 static qheader chandev_head={NULL,NULL};
177 static chandev_noauto_range *chandev_noauto_head=NULL;
178 static chandev_force *chandev_force_head=NULL;
179 static chandev_probelist *chandev_probelist_head=NULL;
180 static chandev_activelist *chandev_activelist_head=NULL;
181 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
182 int chandev_use_devno_names=FALSE;
183 #endif
184 static int chandev_cautious_auto_detect=TRUE;
185 static atomic_t chandev_conf_read=ATOMIC_INIT(FALSE);
186 static atomic_t chandev_initialised=ATOMIC_INIT(FALSE);
187
188
189 static unsigned long chandev_last_machine_check;
190
191
192 static struct tq_struct chandev_msck_task_tq;
193 static atomic_t chandev_msck_thread_lock;
194 static atomic_t chandev_new_msck;
195 static unsigned long chandev_last_startmsck_list_update;
196
197
198 typedef enum
199 {
200         chandev_start,
201         chandev_first_tag=chandev_start,
202         chandev_msck,
203         chandev_num_notify_tags
204 } chandev_userland_notify_tag;
205
206 static char *userland_notify_strs[]=
207 {
208         "start",
209         "machine_check"
210 };
211
212 typedef struct chandev_userland_notify_list chandev_userland_notify_list;
213 struct chandev_userland_notify_list
214 {
215         chandev_userland_notify_list    *next;
216         chandev_userland_notify_tag      tag;
217         chandev_msck_status              prev_status;
218         chandev_msck_status              curr_status;
219         char                      devname[0];
220 };
221
222
223 static chandev_userland_notify_list *chandev_userland_notify_head=NULL;
224
225
226
227
228 static void chandev_read_conf_if_necessary(void);
229 static void chandev_read_conf(void);
230
231 #if LINUX_VERSION_CODE >=KERNEL_VERSION(2,3,0)
232 typedef struct net_device  net_device;
233 #else
234 typedef struct device  net_device;
235
236 static inline void init_waitqueue_head(wait_queue_head_t *q)
237 {
238         *q=NULL;
239 }
240 #endif
241
242 #if LINUX_VERSION_CODE<KERNEL_VERSION(2,3,45)
243 static __inline__ void netif_stop_queue(net_device *dev)
244 {
245         dev->tbusy=1;
246 }
247
248 static __inline__ void netif_start_queue(net_device *dev)
249 {
250         dev->tbusy=0;
251 }
252 #endif
253
254
255
256 #define CHANDEV_INVALID_LOCK_OWNER            -1
257 static long                 chandev_lock_owner;
258 static int                  chandev_lock_cnt; 
259 static spinlock_t           chandev_spinlock;
260 #define CHANDEV_LOCK_DEBUG 0
261 #if CHANDEV_LOCK_DEBUG && !defined(CONFIG_ARCH_S390X)
262 #define CHANDEV_BACKTRACE_LOOPCNT 10
263 void                        *chandev_first_lock_addr[CHANDEV_BACKTRACE_LOOPCNT],
264                             *chandev_last_lock_addr[CHANDEV_BACKTRACE_LOOPCNT],
265                             *chandev_last_unlock_addr[CHANDEV_BACKTRACE_LOOPCNT];
266 #define CHANDEV_BACKTRACE(variable) \
267 memset((variable),0,sizeof(void *)*CHANDEV_BACKTRACE_LOOPCNT); \
268 (variable)[0]=__builtin_return_address(0); \
269 if(((long)variable[0])&0x80000000)         \
270 {                                          \
271 (variable)[1]=__builtin_return_address(1); \
272 if(((long)variable[1])&0x80000000)         \
273 {                                          \
274 (variable)[2]=__builtin_return_address(2); \
275 if(((long)variable[2])&0x80000000)         \
276 {                                          \
277 (variable)[3]=__builtin_return_address(3); \
278 if(((long)variable[3])&0x80000000)         \
279 {                                          \
280 (variable)[4]=__builtin_return_address(4); \
281 if(((long)variable[4])&0x80000000)         \
282 {                                          \
283 (variable)[5]=__builtin_return_address(5); \
284 if(((long)variable[5])&0x80000000)         \
285 {                                          \
286 (variable)[6]=__builtin_return_address(6); \
287 if(((long)variable[6])&0x80000000)         \
288 {                                          \
289 (variable)[7]=__builtin_return_address(7); \
290 if(((long)variable[7])&0x80000000)         \
291 {                                          \
292 (variable)[8]=__builtin_return_address(8); \
293 if(((long)variable[8])&0x80000000)         \
294 {                                          \
295 (variable)[9]=__builtin_return_address(9); \
296 } \
297 } \
298 } \
299 } \
300 } \
301 } \
302 } \
303 } \
304 }
305 #else
306 #define CHANDEV_BACKTRACE(variable)
307 #endif
308
309
310
311 typedef struct chandev_not_oper_struct chandev_not_oper_struct;
312
313 struct  chandev_not_oper_struct
314 {
315         chandev_not_oper_struct *next;
316         int irq;
317         int status;
318 };
319
320
321 /* May as well try to keep machine checks in the order they happen so
322  * we use qheader for chandev_not_oper_head instead of list.
323  */
324 static qheader chandev_not_oper_head={NULL,NULL};
325 static spinlock_t           chandev_not_oper_spinlock;
326
327 #define chandev_interrupt_check() \
328 if(in_interrupt())                \
329      printk(KERN_WARNING __FUNCTION__ " called under interrupt this shouldn't happen\n")
330
331
332 #define for_each(variable,head) \
333 for((variable)=(head);(variable)!=NULL;(variable)=(variable)->next)
334
335 #define for_each_allow_delete(variable,nextmember,head) \
336 for((variable)=(head),(nextmember)=((head) ? (head)->next:NULL); \
337 (variable)!=NULL; (variable)=(nextmember),(nextmember)=((nextmember) ? (nextmember->next) : NULL))
338
339 #define for_each_allow_delete2(variable,nextmember,head) \
340 for((variable)=(head);(variable)!=NULL;(variable)=(nextmember))
341
342
343 static void chandev_lock(void)
344 {
345         eieio();
346         chandev_interrupt_check();
347         if(chandev_lock_owner!=(long)current)
348         {
349                 while(!spin_trylock(&chandev_spinlock))
350                         schedule();
351                 chandev_lock_cnt=1;
352                 chandev_lock_owner=(long)current;
353                 CHANDEV_BACKTRACE(chandev_first_lock_addr)
354         }
355         else
356         {
357                 chandev_lock_cnt++;
358                 CHANDEV_BACKTRACE(chandev_last_lock_addr)
359         }
360         if(chandev_lock_cnt<0||chandev_lock_cnt>100)
361         {
362                 printk("odd lock_cnt %d lcs_chan_lock",chandev_lock_cnt);
363                 chandev_lock_cnt=1;
364         }
365 }
366
367 static int chandev_full_unlock(void)
368 {
369         int ret_lock_cnt=chandev_lock_cnt;
370         chandev_lock_cnt=0;
371         chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;
372         spin_unlock(&chandev_spinlock);
373         return(ret_lock_cnt);
374 }
375
376 static void chandev_unlock(void)
377 {
378         if(chandev_lock_owner!=(long)current)
379                 printk("chandev_unlock: current=%lx"
380                       " chandev_lock_owner=%lx chandev_lock_cnt=%d\n",
381                       (long)current,
382                       chandev_lock_owner,
383                       chandev_lock_cnt);
384         CHANDEV_BACKTRACE(chandev_last_unlock_addr)
385         if(--chandev_lock_cnt==0)
386         {
387                 chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;
388                 spin_unlock(&chandev_spinlock);
389         }
390         if(chandev_lock_cnt<0)
391         {
392                 printk("odd lock_cnt=%d in chan_unlock",chandev_lock_cnt);
393                 chandev_full_unlock();
394         }
395
396 }
397
398
399
400 void *chandev_alloc(size_t size)
401 {
402         void *mem=kmalloc(size,GFP_ATOMIC);
403         if(mem)
404                 memset(mem,0,size);
405         return(mem);
406 }
407
408 static void chandev_add_to_list(list **listhead,void *member)
409 {
410         chandev_lock();
411         add_to_list(listhead,member);
412         chandev_unlock();
413 }
414
415 static void chandev_queuemember(qheader *qhead,void *member)
416 {
417         chandev_lock();
418         enqueue_tail(qhead,(queue *)member);
419         chandev_unlock();
420 }
421
422 static int chandev_remove_from_list(list **listhead,list *member)
423 {
424         int retval;
425
426         chandev_lock();
427         retval=remove_from_list(listhead,member);
428         chandev_unlock();
429         return(retval);
430 }
431
432 static int chandev_remove_from_queue(qheader *qhead,queue *member)
433 {
434         int retval;
435         
436         chandev_lock();
437         retval=remove_from_queue(qhead,member);
438         chandev_unlock();
439         return(retval);
440 }
441
442
443
444 void chandev_free_listmember(list **listhead,list *member)
445 {
446         chandev_lock();
447         if(member)
448         {
449                 if(chandev_remove_from_list(listhead,member))
450                         kfree(member);
451                 else
452                         printk(KERN_CRIT"chandev_free_listmember detected nonexistant"
453                                "listmember listhead=%p member %p\n",listhead,member);
454         }
455         chandev_unlock();
456 }
457
458 void chandev_free_queuemember(qheader *qhead,queue *member)
459 {
460         chandev_lock();
461         if(member)
462         {
463                 if(chandev_remove_from_queue(qhead,member))
464                         kfree(member);
465                 else
466                         printk(KERN_CRIT"chandev_free_queuemember detected nonexistant"
467                                "queuemember qhead=%p member %p\n",qhead,member);
468         }
469         chandev_unlock();
470 }
471
472
473
474 void chandev_free_all_list(list **listhead)
475 {
476         list *head;
477
478         chandev_lock();
479         while((head=remove_listhead(listhead)))
480                 kfree(head);
481         chandev_unlock();
482 }
483
484 void chandev_free_all_queue(qheader *qhead)
485 {
486         chandev_lock();
487         while(qhead->head)
488                 chandev_free_queuemember(qhead,qhead->head);
489         chandev_unlock();
490 }
491
492 static void chandev_wait_for_root_fs(void)
493 {
494         wait_queue_head_t      wait;
495
496         init_waitqueue_head(&wait);
497         /* We need to wait till there is a root filesystem */
498         while(init_task.fs->root==NULL)
499         {
500                 sleep_on_timeout(&wait,HZ);
501         }
502 }
503
504 /* We are now hotplug compliant i.e. */
505 /* we typically get called in /sbin/hotplug chandev our parameters */
506 static int chandev_exec_start_script(void *unused)
507 {
508         
509         char **argv,*tempname;
510         int retval=-ENOMEM;
511         int argc,loopcnt;
512         size_t allocsize;
513         chandev_userland_notify_list *member;
514         wait_queue_head_t      wait;
515         int                    have_tag[chandev_num_notify_tags]={FALSE,};
516         chandev_userland_notify_tag tagidx;
517         static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
518         
519         init_waitqueue_head(&wait);
520         strcpy(current->comm,"chandev_script");
521
522         for(loopcnt=0;loopcnt<10&&(jiffies-chandev_last_startmsck_list_update)<HZ;loopcnt++)
523         {
524                 sleep_on_timeout(&wait,HZ);
525         }
526         if(!chandev_userland_notify_head)
527                 return(0);
528         chandev_lock();
529         argc=2;
530         for(tagidx=chandev_first_tag;tagidx<chandev_num_notify_tags;tagidx++)
531         {
532                 for_each(member,chandev_userland_notify_head)
533                 {
534                         if(member->tag==tagidx)
535                         {
536                                 switch(tagidx)
537                                 {
538                                 case chandev_start:
539                                         argc++;
540                                         break;
541                                 case chandev_msck:
542                                         argc+=3;
543                                         break;
544                                 default:
545                                 }
546                                 if(have_tag[tagidx]==FALSE)
547                                         argc++;
548                                 have_tag[tagidx]=TRUE;
549
550                         }
551                 }
552         }
553         allocsize=(argc+1)*sizeof(char *);
554         /* Warning possible stack overflow */
555         /* We can't kmalloc the parameters here as execve will */
556         /* not return if successful */
557         argv=alloca(allocsize);
558         if(argv)
559         {
560                 memset(argv,0,allocsize);
561                 argv[0]=hotplug_path;
562                 argv[1]="chandev";
563                 argc=2;
564                 for(tagidx=chandev_first_tag;tagidx<chandev_num_notify_tags;tagidx++)
565                 {
566                         if(have_tag[tagidx])
567                         {
568                                 argv[argc++]=userland_notify_strs[tagidx];
569                                 for_each(member,chandev_userland_notify_head)
570                                 {
571                                         if(member->tag==tagidx)
572                                         {
573                                                 tempname=alloca(strlen(member->devname)+1);
574                                                 if(tempname)
575                                                 {
576                                                         strcpy(tempname,member->devname);
577                                                         argv[argc++]=tempname;
578                                                 }
579                                                 else
580                                                         goto Fail;
581                                                 if(member->tag==chandev_msck)
582                                                 {
583                                                         argv[argc++]=msck_status_strs[member->prev_status];
584                                                         argv[argc++]=msck_status_strs[member->curr_status];
585                                                 }
586                                         }
587                                 }
588                         }
589                 }
590                 chandev_free_all_list((list **)&chandev_userland_notify_head);
591                 chandev_unlock();
592                 chandev_wait_for_root_fs();
593                 /* We are basically execve'ing here there normally is no */
594                 /* return */
595                 retval=exec_usermodehelper(hotplug_path, argv, envp);
596                 goto Fail2;
597         }
598  Fail:
599         
600         chandev_unlock();
601  Fail2:
602         return(retval);
603 }
604
605
606 void *chandev_allocstr(const char *str,size_t offset)
607 {
608         char *member;
609
610         if((member=chandev_alloc(offset+strlen(str)+1)))
611         {
612                 strcpy(&member[offset],str);
613         }
614         return((void *)member);
615 }
616
617
618 static int chandev_add_to_userland_notify_list(chandev_userland_notify_tag tag,
619 char *devname, chandev_msck_status prev_status,chandev_msck_status curr_status)
620 {
621         chandev_userland_notify_list *member,*nextmember;
622         int pid;
623         
624         chandev_lock();
625         /* remove operations still outstanding for this device */
626         for_each_allow_delete(member,nextmember,chandev_userland_notify_head)
627                 if(strcmp(member->devname,devname)==0)
628                         chandev_free_listmember((list **)&chandev_userland_notify_head,(list *)member);
629         
630
631         if((member=chandev_allocstr(devname,offsetof(chandev_userland_notify_list,devname))))
632         {
633                 member->tag=tag;
634                 member->prev_status=prev_status;
635                 member->curr_status=curr_status;
636                 add_to_list((list **)&chandev_userland_notify_head,(list *)member);
637                 chandev_last_startmsck_list_update=jiffies;
638                 chandev_unlock();
639                 pid = kernel_thread(chandev_exec_start_script,NULL,SIGCHLD);
640                 if(pid<0)
641                 {
642                         printk("error making kernel thread for chandev_exec_start_script\n");
643                         return(pid);
644                 }
645                 else
646                         return(0);
647
648         }
649         else
650         {
651                 chandev_unlock();
652                 printk("chandev_add_to_startmscklist memory allocation failed devname=%s\n",devname);
653                 return(-ENOMEM);
654         }
655 }
656
657
658
659
660
661 int chandev_oper_func(int irq,devreg_t *dreg)
662 {
663         chandev_last_machine_check=jiffies;
664         if(atomic_dec_and_test(&chandev_msck_thread_lock))
665         {
666                 schedule_task(&chandev_msck_task_tq);
667         }
668         atomic_set(&chandev_new_msck,TRUE);
669         return(0);
670 }
671
672 static void chandev_not_oper_handler(int irq,int status )
673 {
674         chandev_not_oper_struct *new_not_oper;
675
676         chandev_last_machine_check=jiffies;
677         if((new_not_oper=kmalloc(sizeof(chandev_not_oper_struct),GFP_ATOMIC)))
678         {
679                 new_not_oper->irq=irq;
680                 new_not_oper->status=status;
681                 spin_lock(&chandev_not_oper_spinlock);
682                 enqueue_tail(&chandev_not_oper_head,(queue *)new_not_oper);
683                 spin_unlock(&chandev_not_oper_spinlock);
684                 if(atomic_dec_and_test(&chandev_msck_thread_lock))
685                 {
686                         schedule_task(&chandev_msck_task_tq);
687                 }
688         }
689         else
690                 printk("chandev_not_oper_handler failed to allocate memory & "
691                        "lost a not operational interrupt %d %x",
692                        irq,status);
693 }
694
695 chandev_irqinfo *chandev_get_irqinfo_by_irq(int irq)
696 {
697         chandev_irqinfo *curr_irqinfo;
698         for_each(curr_irqinfo,chandev_irqinfo_head)
699                 if(irq==curr_irqinfo->sch.irq)
700                         return(curr_irqinfo);
701         return(NULL);
702 }
703
704 chandev *chandev_get_by_irq(int irq)
705 {
706         chandev *curr_chandev;
707
708         for_each(curr_chandev,(chandev *)chandev_head.head)
709                 if(curr_chandev->sch.irq==irq)
710                 {
711                         return(curr_chandev);
712                 }
713         return(NULL);
714 }
715
716 chandev_activelist *chandev_get_activelist_by_irq(int irq)
717 {
718         chandev_activelist *curr_device;
719
720         for_each(curr_device,chandev_activelist_head)
721         {
722                         if(curr_device->read_irqinfo->sch.irq==irq||
723                            curr_device->write_irqinfo->sch.irq==irq||
724                            (curr_device->data_irqinfo&&curr_device->data_irqinfo->sch.irq==irq))
725                                 return(curr_device);
726         }
727         return(NULL);
728 }
729
730
731 void chandev_remove_irqinfo_by_irq(unsigned int irq)
732 {
733         chandev_irqinfo *remove_irqinfo;
734         chandev_activelist *curr_device;
735
736         chandev_lock();
737         /* remove any orphan irqinfo left lying around. */
738         if((remove_irqinfo=chandev_get_irqinfo_by_irq(irq)))
739         {
740                 for_each(curr_device,chandev_activelist_head)
741                 {
742                         if(curr_device->read_irqinfo==remove_irqinfo)
743                         {
744                                 curr_device->read_irqinfo=NULL;
745                                 break;
746                         }
747                         if(curr_device->write_irqinfo==remove_irqinfo)
748                         {
749                                 curr_device->write_irqinfo=NULL;
750                                 break;
751                         }
752                         if(curr_device->data_irqinfo&&curr_device->data_irqinfo==remove_irqinfo)
753                         {
754                                 curr_device->data_irqinfo=NULL;
755                                 break;
756                         }
757                 }
758                 chandev_free_listmember((list **)&chandev_irqinfo_head,
759                                          (list *)remove_irqinfo);
760         }
761         chandev_unlock();
762         
763 }
764
765 int chandev_add_schib_info(int irq,chandev_subchannel_info *sch)
766 {
767         schib_t *new_schib;
768         
769         if((new_schib=s390_get_schib(irq)))
770         {
771                 sch->pim=new_schib->pmcw.pim;
772                 memcpy(&sch->chpid,&new_schib->pmcw.chpid,sizeof(sch->chpid));
773                 return(0);
774         }
775         return(-ENODEV);
776 }
777
778 int chandev_request_irq(unsigned int   irq,
779                       void           (*handler)(int, void *, struct pt_regs *),
780                       unsigned long  irqflags,
781                       const char    *devname,
782                       void          *dev_id)
783 {
784         chandev_irqinfo *new_irqinfo;
785         chandev_activelist *curr_device;
786         s390_dev_info_t         devinfo;
787         int          retval;
788         
789
790         chandev_lock();
791         if((curr_device=chandev_get_activelist_by_irq(irq)))
792         {
793                 printk("chandev_request_irq failed devname=%s irq=%d "
794                        "it already belongs to %s shutdown this device first.\n",
795                        devname,irq,curr_device->devname);
796                 chandev_unlock();
797                 return(-EPERM);
798         }
799         /* remove any orphan irqinfo left lying around. */
800         chandev_remove_irqinfo_by_irq(irq);
801         chandev_unlock();
802         if((new_irqinfo=chandev_allocstr(devname,offsetof(chandev_irqinfo,devname))))
803         {
804                 
805                 if((retval=get_dev_info_by_irq(irq,&devinfo))||
806                    (retval=s390_request_irq_special(irq,handler,
807                                                 chandev_not_oper_handler,
808                                                 irqflags,devname,dev_id)))
809                         kfree(new_irqinfo);
810                 else
811                 {
812                         new_irqinfo->msck_status=chandev_status_good;
813                         new_irqinfo->sch.devno=devinfo.devno;
814                         new_irqinfo->sch.irq=irq;
815                         new_irqinfo->sch.cu_type=devinfo.sid_data.cu_type; /* control unit type */
816                         new_irqinfo->sch.cu_model=devinfo.sid_data.cu_model; /* control unit model */
817                         new_irqinfo->sch.dev_type=devinfo.sid_data.dev_type; /* device type */
818                         new_irqinfo->sch.dev_model=devinfo.sid_data.dev_model; /* device model */
819                         chandev_add_schib_info(irq,&new_irqinfo->sch);
820                         new_irqinfo->handler=handler;
821                         new_irqinfo->dev_id=dev_id;
822                         chandev_add_to_list((list **)&chandev_irqinfo_head,new_irqinfo);
823                 }
824         }
825         else
826         {
827                 printk("chandev_request_irq memory allocation failed devname=%s irq=%d\n",devname,irq);
828                 retval=-ENOMEM;
829         }
830         return(retval);
831 }
832
833 /* This should be safe to call even multiple times. */
834 void chandev_free_irq(unsigned int irq, void *dev_id)
835 {
836         s390_dev_info_t devinfo;
837         int err;
838         
839         /* remove any orphan irqinfo left lying around. */
840         chandev_remove_irqinfo_by_irq(irq);
841         if((err=get_dev_info_by_irq(irq,&devinfo)))
842         {
843                 printk("chandev_free_irq get_dev_info_by_irq reported err=%X on irq %d\n"
844                        "should not happen\n",err,irq);
845                 return;
846          }
847         if(devinfo.status&DEVSTAT_DEVICE_OWNED)
848            free_irq(irq,dev_id);
849 }
850
851 /* This should be safe even if chandev_free_irq is already called by the device */
852 void chandev_free_irq_by_irqinfo(chandev_irqinfo *irqinfo)
853 {
854         if(irqinfo)
855                 chandev_free_irq(irqinfo->sch.irq,irqinfo->dev_id);
856 }
857
858
859
860 void chandev_sprint_type_model(char *buff,s32 type,s16 model)
861 {
862         if(type==-1)
863                 strcpy(buff,"    *    ");
864         else
865                 sprintf(buff," 0x%04x  ",(int)type);
866         buff+=strlen(buff);
867         if(model==-1)
868                 strcpy(buff,"    *   ");
869         else
870                 sprintf(buff," 0x%02x  ",(int)model);
871 }
872
873 void chandev_sprint_devinfo(char *buff,s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model)
874 {
875         chandev_sprint_type_model(buff,cu_type,cu_model);
876         chandev_sprint_type_model(&buff[strlen(buff)],dev_type,dev_model);
877 }
878
879 void chandev_remove_parms(chandev_type chan_type,int exact_match,int lo_devno)
880 {
881         chandev_parms      *curr_parms,*next_parms;
882
883         chandev_lock();
884         for_each_allow_delete(curr_parms,next_parms,chandev_parms_head)
885         {
886                 if(((chan_type&(curr_parms->chan_type)&&!exact_match)||
887                    (chan_type==(curr_parms->chan_type)&&exact_match))&&
888                    (lo_devno==-1||lo_devno==curr_parms->lo_devno))
889                         chandev_free_listmember((list **)&chandev_parms_head,(list *)curr_parms);
890         }
891         chandev_unlock();
892 }
893
894
895 void chandev_add_parms(chandev_type chan_type,u16 lo_devno,u16 hi_devno,char *parmstr)
896 {
897         chandev_parms      *parms;
898
899         if(lo_devno>hi_devno)
900         {
901                 printk("chandev_add_parms detected bad device range lo_devno=0x%04x  hi_devno=0x%04x\n,",
902                        (int)lo_devno,(int)hi_devno);
903                 return;
904         }
905         if((parms=chandev_allocstr(parmstr,offsetof(chandev_parms,parmstr))))
906         {
907                 parms->chan_type=chan_type;
908                 parms->lo_devno=lo_devno;
909                 parms->hi_devno=hi_devno;
910                 chandev_add_to_list((list **)&chandev_parms_head,(void *)parms);
911         }
912         else
913                 printk("chandev_add_parms memory request failed\n");
914 }
915
916
917 void chandev_add_model(chandev_type chan_type,s32 cu_type,s16 cu_model,
918                        s32 dev_type,s16 dev_model,u8 max_port_no,int auto_msck_recovery,
919                        u8 default_checksum_received_ip_pkts,u8 default_use_hw_stats)
920 {
921         chandev_model_info *newmodel;
922         int                err;
923         char buff[40];
924
925         if((newmodel=chandev_alloc(sizeof(chandev_model_info))))
926         {
927                 devreg_t *drinfo=&newmodel->drinfo;
928                 newmodel->chan_type=chan_type;
929                 newmodel->cu_type=cu_type;
930                 newmodel->cu_model=cu_model;
931                 newmodel->dev_type=dev_type;
932                 newmodel->dev_model=dev_model;
933                 newmodel->max_port_no=max_port_no;
934                 newmodel->auto_msck_recovery=auto_msck_recovery;
935                 newmodel->default_checksum_received_ip_pkts=default_checksum_received_ip_pkts;
936                 newmodel->default_use_hw_stats=default_use_hw_stats; /* where available e.g. lcs */
937                 if(cu_type==-1&&dev_type==-1)
938                 {
939                         chandev_sprint_devinfo(buff,newmodel->cu_type,newmodel->cu_model,
940                                                newmodel->dev_type,newmodel->dev_model);
941                         printk(KERN_INFO"can't call s390_device_register for this device chan_type/chan_model/dev_type/dev_model %s\n",buff);
942                         kfree(newmodel);
943                         return;
944                 }
945                 drinfo->flag=DEVREG_TYPE_DEVCHARS;
946                 if(cu_type!=-1)
947                         drinfo->flag|=DEVREG_MATCH_CU_TYPE;
948                 if(cu_model!=-1)
949                         drinfo->flag|=DEVREG_MATCH_CU_MODEL;
950                 if(dev_type!=-1)
951                         drinfo->flag|=DEVREG_MATCH_DEV_TYPE;
952                 if(dev_model!=-1)
953                         drinfo->flag|=DEVREG_MATCH_DEV_MODEL;
954                 drinfo->ci.hc.ctype=cu_type;
955                 drinfo->ci.hc.cmode=cu_model;
956                 drinfo->ci.hc.dtype=dev_type;
957                 drinfo->ci.hc.dmode=dev_model;
958                 drinfo->oper_func=chandev_oper_func;
959                 if((err=s390_device_register(&newmodel->drinfo)))
960                 {
961                         chandev_sprint_devinfo(buff,newmodel->cu_type,newmodel->cu_model,
962                                                newmodel->dev_type,newmodel->dev_model);
963                         printk("s390_device_register failed in chandev_add_model"
964                                " this is nothing to worry about chan_type/chan_model/dev_type/dev_model %s\n",buff);
965                         drinfo->oper_func=NULL;
966                 }
967                 chandev_add_to_list((list **)&chandev_models_head,newmodel);
968         }
969 }
970
971
972 void chandev_remove(chandev *member)
973 {
974         chandev_free_queuemember(&chandev_head,(queue *)member);
975 }
976
977
978 void chandev_remove_all(void)
979 {
980         chandev_free_all_queue(&chandev_head);
981 }
982
983 void chandev_remove_model(chandev_model_info *model)
984 {
985         chandev *curr_chandev,*next_chandev;
986
987         chandev_lock();
988         for_each_allow_delete(curr_chandev,next_chandev,(chandev *)chandev_head.head)
989                 if(curr_chandev->model_info==model)
990                         chandev_remove(curr_chandev);
991         if(model->drinfo.oper_func)
992                 s390_device_unregister(&model->drinfo);
993         chandev_free_listmember((list **)&chandev_models_head,(list *)model);
994         chandev_unlock();
995 }
996
997 void chandev_remove_all_models(void)
998 {
999         chandev_lock();
1000         while(chandev_models_head)
1001                 chandev_remove_model(chandev_models_head);
1002         chandev_unlock();
1003 }
1004
1005 void chandev_del_model(s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model)
1006 {
1007         chandev_model_info *curr_model,*next_model;
1008         
1009         chandev_lock();
1010         for_each_allow_delete(curr_model,next_model,chandev_models_head)
1011                 if((curr_model->cu_type==cu_type||cu_type==-1)&&
1012                    (curr_model->cu_model==cu_model||cu_model==-1)&&
1013                    (curr_model->dev_type==dev_type||dev_type==-1)&&
1014                    (curr_model->dev_model==dev_model||dev_model==-1))
1015                         chandev_remove_model(curr_model);                       
1016         chandev_unlock();
1017 }
1018
1019 static void chandev_init_default_models(void)
1020 {
1021         /* Usually P390/Planter 3172 emulation assume maximum 16 to be safe. */
1022         chandev_add_model(chandev_type_lcs,0x3088,0x1,-1,-1,15,default_msck_bits,FALSE,FALSE);  
1023
1024         /* 3172/2216 Paralell the 2216 allows 16 ports per card the */
1025         /* the original 3172 only allows 4 we will assume the max of 16 */
1026         chandev_add_model(chandev_type_lcs|chandev_type_ctc,0x3088,0x8,-1,-1,15,default_msck_bits,FALSE,FALSE);
1027
1028         /* 3172/2216 Escon serial the 2216 allows 16 ports per card the */
1029         /* the original 3172 only allows 4 we will assume the max of 16 */
1030         chandev_add_model(chandev_type_lcs|chandev_type_escon,0x3088,0x1F,-1,-1,15,default_msck_bits,FALSE,FALSE);
1031
1032         /* Only 2 ports allowed on OSA2 cards model 0x60 */
1033         chandev_add_model(chandev_type_lcs,0x3088,0x60,-1,-1,1,default_msck_bits,FALSE,FALSE);
1034         /* qeth gigabit ethernet */
1035         chandev_add_model(chandev_type_qeth,0x1731,0x1,0x1732,0x1,0,default_msck_bits,FALSE,FALSE);
1036         chandev_add_model(chandev_type_qeth,0x1731,0x5,0x1732,0x5,0,default_msck_bits,FALSE,FALSE);
1037         /* Osa-D we currently aren't too emotionally involved with this */
1038         chandev_add_model(chandev_type_osad,0x3088,0x62,-1,-1,0,default_msck_bits,FALSE,FALSE);
1039         /* claw */
1040         chandev_add_model(chandev_type_claw,0x3088,0x61,-1,-1,0,default_msck_bits,FALSE,FALSE);
1041
1042         /* ficon attached ctc */
1043         chandev_add_model(chandev_type_escon,0x3088,0x1E,-1,-1,0,default_msck_bits,FALSE,FALSE);
1044 }
1045
1046
1047 void chandev_del_noauto(u16 devno)
1048 {
1049         chandev_noauto_range *curr_noauto,*next_noauto;
1050         chandev_lock();
1051         for_each_allow_delete(curr_noauto,next_noauto,chandev_noauto_head)
1052                 if(curr_noauto->lo_devno<=devno&&curr_noauto->hi_devno>=devno)
1053                         chandev_free_listmember((list **)&chandev_noauto_head,(list *)curr_noauto); 
1054         chandev_unlock();
1055 }
1056
1057 void chandev_del_msck(u16 devno)
1058 {
1059         chandev_msck_range *curr_msck_range,*next_msck_range;
1060         chandev_lock();
1061         for_each_allow_delete(curr_msck_range,next_msck_range,chandev_msck_range_head)
1062                 if(curr_msck_range->lo_devno<=devno&&curr_msck_range->hi_devno>=devno)
1063                         chandev_free_listmember((list **)&chandev_msck_range_head,(list *)curr_msck_range); 
1064         chandev_unlock();
1065 }
1066
1067
1068 void chandev_add(s390_dev_info_t  *newdevinfo,chandev_model_info *newmodelinfo)
1069 {
1070         chandev *new_chandev=NULL;
1071
1072         if((new_chandev=chandev_alloc(sizeof(chandev))))
1073         {
1074                 new_chandev->model_info=newmodelinfo;
1075                 new_chandev->sch.devno=newdevinfo->devno;
1076                 new_chandev->sch.irq=newdevinfo->irq;
1077                 new_chandev->sch.cu_type=newdevinfo->sid_data.cu_type; /* control unit type */
1078                 new_chandev->sch.cu_model=newdevinfo->sid_data.cu_model; /* control unit model */
1079                 new_chandev->sch.dev_type=newdevinfo->sid_data.dev_type; /* device type */
1080                 new_chandev->sch.dev_model=newdevinfo->sid_data.dev_model; /* device model */
1081                 chandev_add_schib_info(newdevinfo->irq,&new_chandev->sch);
1082                 new_chandev->owned=(newdevinfo->status&DEVSTAT_DEVICE_OWNED ? TRUE:FALSE);
1083                 chandev_queuemember(&chandev_head,new_chandev);
1084         }
1085 }
1086
1087 void chandev_unregister_probe(chandev_probefunc probefunc)
1088 {
1089         chandev_probelist *curr_probe,*next_probe;
1090
1091         chandev_lock();
1092         for_each_allow_delete(curr_probe,next_probe,chandev_probelist_head)
1093                 if(curr_probe->probefunc==probefunc)
1094                         chandev_free_listmember((list **)&chandev_probelist_head,
1095                                                 (list *)curr_probe);
1096         chandev_unlock();
1097 }
1098
1099 void chandev_unregister_probe_by_chan_type(chandev_type chan_type)
1100 {
1101         chandev_probelist *curr_probe,*next_probe;
1102
1103         chandev_lock();
1104         for_each_allow_delete(curr_probe,next_probe,chandev_probelist_head)
1105                 if(curr_probe->chan_type==chan_type)
1106                         chandev_free_listmember((list **)&chandev_probelist_head,
1107                                                 (list *)curr_probe);
1108         chandev_unlock();
1109 }
1110
1111
1112
1113 void chandev_reset(void)
1114 {
1115         chandev_lock();
1116         chandev_remove_all_models();
1117         chandev_free_all_list((list **)&chandev_noauto_head);
1118         chandev_free_all_list((list **)&chandev_msck_range_head);
1119         chandev_free_all_list((list **)&chandev_force_head);
1120         chandev_remove_parms(-1,FALSE,-1);
1121 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
1122         chandev_use_devno_names=FALSE;
1123 #endif
1124         chandev_persistent=0;
1125         chandev_unlock();
1126 }
1127
1128
1129 int chandev_is_chandev(int irq,s390_dev_info_t *devinfo,chandev_force **forceinfo,chandev_model_info **ret_model)
1130 {
1131         chandev_force *curr_force;
1132         chandev_model_info *curr_model=NULL;
1133         int err;
1134         int retval=FALSE;
1135
1136         if(forceinfo)
1137                 *forceinfo=NULL;
1138         if(ret_model)
1139                 *ret_model=NULL;
1140         if((err=get_dev_info_by_irq(irq,devinfo)))
1141         {
1142                 printk("chandev_is_chandev get_dev_info_by_irq reported err=%X on irq %d\n"
1143                        "should not happen\n",err,irq);
1144                         return FALSE;
1145         }
1146         chandev_lock();
1147         
1148         for_each(curr_model,chandev_models_head)
1149         {
1150                 if(((curr_model->cu_type==devinfo->sid_data.cu_type)||(curr_model->cu_type==-1))&&
1151                    ((curr_model->cu_model==devinfo->sid_data.cu_model)||(curr_model->cu_model==-1))&&
1152                    ((curr_model->dev_type==devinfo->sid_data.dev_type)||(curr_model->dev_type==-1))&&
1153                    ((curr_model->dev_model==devinfo->sid_data.dev_model)||(curr_model->dev_model==-1)))
1154                 {
1155                         retval=TRUE;
1156                         if(ret_model)
1157                                 *ret_model=curr_model;
1158                         break;
1159                 }
1160         }
1161         for_each(curr_force,chandev_force_head)
1162         {
1163                 if(((curr_force->read_lo_devno==devinfo->devno)&&
1164                    (curr_force->write_hi_devno==devinfo->devno)&&
1165                     (curr_force->devif_num!=-2))||
1166                    ((curr_force->read_lo_devno>=devinfo->devno)&&
1167                     (curr_force->write_hi_devno<=devinfo->devno)&&
1168                     (curr_force->devif_num==-2)))
1169                 {
1170                         if(forceinfo)
1171                                 *forceinfo=curr_force;
1172                         break;
1173                 }
1174         }
1175         chandev_unlock();
1176         return(retval);
1177 }
1178
1179 void chandev_collect_devices(void)
1180 {
1181         int curr_irq,loopcnt=0;
1182         s390_dev_info_t   curr_devinfo;
1183         chandev_model_info *curr_model;
1184      
1185
1186         for(curr_irq=get_irq_first();curr_irq>=0; curr_irq=get_irq_next(curr_irq))
1187         {
1188                 /* check read chandev
1189                  * we had to do the cu_model check also because ctc devices
1190                  * have the same cutype & after asking some people
1191                  * the model numbers are given out pseudo randomly so
1192                  * we can't just take a range of them also the dev_type & models are 0
1193                  */
1194                 loopcnt++;
1195                 if(loopcnt>0x10000)
1196                 {
1197                         printk(KERN_ERR"chandev_collect_devices detected infinite loop bug in get_irq_next\n");
1198                         break;
1199                 }
1200                 chandev_lock();
1201                 if(chandev_is_chandev(curr_irq,&curr_devinfo,NULL,&curr_model))
1202                         chandev_add(&curr_devinfo,curr_model);
1203                 chandev_unlock();
1204         }
1205 }
1206
1207 int chandev_add_force(chandev_type chan_type,s32 devif_num,u16 read_lo_devno,
1208 u16 write_hi_devno,u16 data_devno,s32 memory_usage_in_k,s16 port_protocol_no,u8 checksum_received_ip_pkts,
1209 u8 use_hw_stats,char *host_name,char *adapter_name,char *api_type)
1210 {
1211         chandev_force *new_chandev_force;
1212         
1213         if(devif_num==-2&&read_lo_devno>write_hi_devno)
1214         {
1215                 printk("chandev_add_force detected bad device range lo_devno=0x%04x  hi_devno=0x%04x\n,",
1216                        (int)read_lo_devno,(int)write_hi_devno);
1217                 return(-1);
1218         }
1219         if(memory_usage_in_k<0)
1220         {
1221                 printk("chandev_add_force memory_usage_in_k is bad\n");
1222                 return(-1);
1223         }
1224         if(chan_type==chandev_type_claw)
1225         {
1226                 int host_name_len=strlen(host_name),
1227                         adapter_name_len=strlen(adapter_name),
1228                         api_type_len=strlen(api_type);
1229                 if(host_name_len>=CLAW_NAMELEN||host_name_len==0||
1230                    adapter_name_len>=CLAW_NAMELEN||adapter_name_len==0||
1231                    api_type_len>=CLAW_NAMELEN||api_type_len==0)
1232                         return(-1);
1233         }
1234         if((new_chandev_force=chandev_alloc(sizeof(chandev_force))))
1235         {
1236                 new_chandev_force->chan_type=chan_type;
1237                 new_chandev_force->devif_num=devif_num;
1238                 new_chandev_force->read_lo_devno=read_lo_devno;
1239                 new_chandev_force->write_hi_devno=write_hi_devno;
1240                 new_chandev_force->data_devno=data_devno;
1241                 new_chandev_force->memory_usage_in_k=memory_usage_in_k;
1242                 new_chandev_force->port_protocol_no=port_protocol_no;
1243                 new_chandev_force->checksum_received_ip_pkts=checksum_received_ip_pkts;
1244                 new_chandev_force->use_hw_stats=use_hw_stats;
1245                 
1246                 if(chan_type==chandev_type_claw)
1247                 {
1248                         strcpy(new_chandev_force->claw.host_name,host_name);
1249                         strcpy(new_chandev_force->claw.adapter_name,adapter_name);
1250                         strcpy(new_chandev_force->claw.api_type,api_type);
1251                 }
1252                 chandev_add_to_list((list **)&chandev_force_head,new_chandev_force);
1253         }
1254         return(0);
1255 }
1256
1257 void chandev_del_force(int read_lo_devno)
1258 {
1259         chandev_force *curr_force,*next_force;
1260         
1261         chandev_lock();
1262         for_each_allow_delete(curr_force,next_force,chandev_force_head)
1263         {
1264                 if(curr_force->read_lo_devno==read_lo_devno||read_lo_devno==-1)
1265                         chandev_free_listmember((list **)&chandev_force_head,
1266                                                 (list *)curr_force);
1267         }
1268         chandev_unlock();
1269 }
1270
1271
1272 void chandev_shutdown(chandev_activelist *curr_device)
1273 {
1274         int err=0;
1275         chandev_lock();
1276
1277
1278         /* unregister_netdev calls the dev->close so we shouldn't do this */
1279         /* this otherwise we crash */
1280         if(curr_device->unreg_dev)
1281         {
1282                 curr_device->unreg_dev(curr_device->dev_ptr);
1283                 curr_device->unreg_dev=NULL;
1284         }
1285         if(curr_device->shutdownfunc)
1286         {
1287                 err=curr_device->shutdownfunc(curr_device->dev_ptr);
1288         }
1289         if(err)
1290                 printk("chandev_shutdown unable to fully shutdown & unload %s err=%d\n"
1291                        "probably some upper layer still requires the device to exist\n",
1292                        curr_device->devname,err);
1293         else
1294         {
1295                 
1296                 chandev_free_irq_by_irqinfo(curr_device->read_irqinfo);
1297                 chandev_free_irq_by_irqinfo(curr_device->write_irqinfo);
1298                 if(curr_device->data_irqinfo)
1299                         chandev_free_irq_by_irqinfo(curr_device->data_irqinfo);
1300                 chandev_free_listmember((list **)&chandev_activelist_head,
1301                                 (list *)curr_device);
1302         }
1303         chandev_unlock();
1304 }
1305
1306 void chandev_shutdown_all(void)
1307 {
1308         while(chandev_activelist_head)
1309                 chandev_shutdown(chandev_activelist_head);
1310 }
1311 void chandev_shutdown_by_name(char *devname)
1312 {
1313         chandev_activelist *curr_device;
1314
1315         chandev_lock();
1316         for_each(curr_device,chandev_activelist_head)
1317                 if(strcmp(devname,curr_device->devname)==0)
1318                 {
1319                         chandev_shutdown(curr_device);
1320                         break;
1321                 }
1322         chandev_unlock();
1323 }
1324
1325 static chandev_activelist *chandev_active(u16 devno)
1326 {
1327         chandev_activelist *curr_device;
1328
1329         for_each(curr_device,chandev_activelist_head)
1330                 if(curr_device->read_irqinfo->sch.devno==devno||
1331                    curr_device->write_irqinfo->sch.devno==devno||
1332                    (curr_device->data_irqinfo&&curr_device->data_irqinfo->sch.devno==devno))
1333                 {
1334                         return(curr_device);
1335                 }
1336         return(NULL);
1337 }
1338
1339 void chandev_shutdown_by_devno(u16 devno)
1340 {
1341         chandev_activelist *curr_device;
1342
1343         chandev_lock();
1344         curr_device=chandev_active(devno);
1345         if(curr_device)
1346                 chandev_shutdown(curr_device);
1347         chandev_unlock();
1348 }
1349
1350
1351 int chandev_pack_args(char *str)
1352 {
1353         char *newstr=str,*next;
1354         int strcnt=1;
1355
1356         while(*str)
1357         {
1358                 next=str+1;
1359                 /*remove dead spaces */
1360                 if(isspace(*str)&&isspace(*next))
1361                 {
1362                         str++;
1363                         continue;
1364                 }
1365                 if(isspace(*str))
1366                 {
1367                         *str=',';
1368                         goto pack_dn;
1369                 }
1370                 if(((*str)==';')&&(*next))
1371                 {
1372                         strcnt++;
1373                         *str=0;
1374                 }
1375         pack_dn:
1376                 *newstr++=*str++;
1377                 
1378         }
1379         *newstr=0;
1380         return(strcnt);
1381 }
1382
1383 typedef enum
1384
1385         isnull=0,
1386         isstr=1,
1387         isnum=2,
1388         iscomma=4,
1389 } chandev_strval;
1390
1391 chandev_strval chandev_strcmp(char *teststr,char **str,long *endlong)
1392 {
1393         char *cur;
1394         chandev_strval  retval=isnull;
1395
1396         int len=strlen(teststr);
1397         if(strncmp(teststr,*str,len)==0)
1398         {
1399                 *str+=len;
1400                 retval=isstr;
1401                 cur=*str;
1402                 *endlong=simple_strtol(cur,str,0);
1403                 if(cur!=*str)
1404                         retval|=isnum;
1405                 if(**str==',')
1406                 {
1407                         retval|=iscomma;
1408                         *str+=1;
1409                 }
1410                 else if(**str!=0)
1411                         retval=isnull;
1412         }
1413         return(retval);
1414 }
1415
1416
1417 int chandev_initdevice(chandev_probeinfo *probeinfo,void *dev_ptr,u8 port_no,char *devname,chandev_category category,chandev_unregfunc unreg_dev)
1418 {
1419         chandev_activelist *newdevice,*curr_device;
1420
1421         chandev_interrupt_check();
1422         if(probeinfo->newdevice!=NULL)
1423         {
1424                 printk("probeinfo->newdevice!=NULL in chandev_initdevice for %s",devname);
1425                 return(-EPERM);
1426         }
1427
1428
1429         chandev_lock();
1430         for_each(curr_device,chandev_activelist_head)
1431         {
1432                 if(strcmp(curr_device->devname,devname)==0)
1433                 {
1434                         printk("chandev_initdevice detected duplicate devicename %s\n",devname);
1435                         chandev_unlock();
1436                         return(-EPERM);
1437                 }
1438         }
1439         if((newdevice=chandev_allocstr(devname,offsetof(chandev_activelist,devname))))
1440         {
1441                 newdevice->read_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->read.irq);
1442                 newdevice->write_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->write.irq);
1443                 if(probeinfo->data_exists)
1444                         newdevice->data_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->data.irq);
1445                 chandev_unlock();
1446                 if(newdevice->read_irqinfo==NULL||newdevice->write_irqinfo==NULL||
1447                    (probeinfo->data_exists&&newdevice->data_irqinfo==NULL))
1448                 {
1449                         printk("chandev_initdevice, it appears that chandev_request_irq was not "
1450                                "called for devname=%s read_irq=%d write_irq=%d data_irq=%d\n",
1451                                devname,probeinfo->read.irq,probeinfo->write.irq,probeinfo->data.irq);
1452                         kfree(newdevice);
1453                         return(-EPERM);
1454                 }
1455                 newdevice->chan_type=probeinfo->chan_type;              
1456                 newdevice->dev_ptr=dev_ptr;
1457                 newdevice->port_no=port_no;
1458                 newdevice->memory_usage_in_k=probeinfo->memory_usage_in_k;
1459                 newdevice->category=category;
1460                 newdevice->unreg_dev=unreg_dev;
1461                 probeinfo->newdevice=newdevice;
1462                 return(0);
1463         }
1464         chandev_unlock();
1465         return(-ENOMEM);
1466 }
1467
1468
1469 char *chandev_build_device_name(chandev_probeinfo *probeinfo,char *destnamebuff,char *basename,int buildfullname)
1470 {
1471         if (chandev_use_devno_names&&(!probeinfo->device_forced||probeinfo->devif_num==-1)) 
1472                 sprintf(destnamebuff,"%s%04x",basename,(int)probeinfo->read.devno);
1473         else
1474         {
1475                 if(probeinfo->devif_num==-1)
1476                 {
1477                         if(buildfullname)
1478                         {
1479                                 int idx,len=strlen(basename);
1480                                 
1481                                 chandev_activelist *curr_device;
1482                                 for(idx=0;idx<0xffff;idx++)
1483                                 {
1484                                         for_each(curr_device,chandev_activelist_head)
1485                                         {
1486                                                 if(strncmp(curr_device->devname,basename,len)==0)
1487                                                 {
1488                                                         char numbuff[10];
1489                                                         sprintf(numbuff,"%d",idx);
1490                                                         if(strcmp(&curr_device->devname[len],numbuff)==0)
1491                                                                 goto next_idx;
1492                                                 }
1493                                         }
1494                                         sprintf(destnamebuff,"%s%d",basename,idx);
1495                                         return(destnamebuff);
1496                                 next_idx:
1497                                 }
1498                                 printk("chandev_build_device_name was usable to build a unique name for %s\n",basename);
1499                                 return(NULL);
1500                         }
1501                         else
1502                                 sprintf(destnamebuff,"%s%%d",basename);
1503                 }
1504                 else
1505                 {
1506                         sprintf(destnamebuff,"%s%d",basename,(int)probeinfo->devif_num);
1507                 }
1508         }
1509         return(destnamebuff);
1510 }
1511
1512 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
1513 struct net_device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
1514 struct net_device *dev, int sizeof_priv,
1515 struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv))
1516 #else
1517 struct device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
1518 struct device *dev, int sizeof_priv,
1519 struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv))
1520 #endif
1521 {
1522 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
1523         struct net_device *retdevice=NULL;
1524         int new_device = FALSE;
1525 #else
1526         struct device *retdevice=NULL;
1527 #endif
1528         
1529
1530         chandev_interrupt_check();
1531         if (!init_netdevfunc) 
1532         {
1533                 printk("init_netdevfunc=NULL in chandev_init_netdev, it should not be valid.\n");
1534                 return NULL;
1535         }
1536 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
1537         /* Allocate a device if one is not provided. */
1538         if (dev == NULL) 
1539         {
1540                 /* ensure 32-byte alignment of the private area */
1541                 int alloc_size = sizeof (*dev) + sizeof_priv + 31;
1542
1543                 dev = (struct net_device *) kmalloc (alloc_size, GFP_KERNEL);
1544                 if (dev == NULL) 
1545                 {
1546                         printk(KERN_ERR "chandev_initnetdevice: Unable to allocate device memory.\n");
1547                         return NULL;
1548                 }
1549
1550                 memset(dev, 0, alloc_size);
1551
1552                 if (sizeof_priv)
1553                         dev->priv = (void *) (((long)(dev + 1) + 31) & ~31);
1554                 new_device=TRUE;
1555         }
1556         chandev_build_device_name(probeinfo,dev->name,basename,FALSE);
1557 #endif
1558         retdevice=init_netdevfunc(dev,sizeof_priv);
1559 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
1560         /* Register device if necessary */
1561         /* we need to do this as init_netdev doesn't call register_netdevice */
1562         /* for already allocated devices */
1563         if (retdevice && new_device)
1564                 register_netdev(retdevice);
1565 #endif
1566 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
1567         /* We allocated it, so we should free it on error */
1568         if (!retdevice && new_device) 
1569                 kfree(dev);
1570 #endif
1571         return retdevice;
1572 }
1573
1574
1575
1576
1577 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
1578 struct net_device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
1579 struct net_device *dev, int sizeof_priv, char *basename, 
1580 struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv),
1581 void (*unreg_netdevfunc)(struct net_device *dev))
1582 #else
1583 struct device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
1584 struct device *dev, int sizeof_priv, char *basename,
1585 struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv),
1586 void (*unreg_netdevfunc)(struct device *dev))
1587 #endif
1588 {
1589 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
1590         struct net_device *retdevice=NULL;
1591         int new_device=(dev==NULL);
1592 #else
1593         struct device *retdevice=NULL;
1594 #endif
1595
1596         if (!unreg_netdevfunc) 
1597         {
1598                 printk("unreg_netdevfunc=NULL in chandev_initnetdevice, it should not be valid.\n");
1599                 return NULL;
1600         }
1601         chandev_interrupt_check();
1602         retdevice=chandev_init_netdev(probeinfo,basename,dev,sizeof_priv,init_netdevfunc);
1603         if (retdevice) 
1604         {
1605                 if (chandev_initdevice(probeinfo,retdevice,port_no,retdevice->name,
1606                                       chandev_category_network_device,(chandev_unregfunc)unreg_netdevfunc)) 
1607                 {
1608                         unreg_netdevfunc(retdevice);
1609 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
1610                         /* We allocated it, so we should free it on error */
1611                         if(new_device)
1612                                 kfree(dev);
1613 #endif
1614
1615                         retdevice = NULL;
1616                 }
1617         }
1618         return retdevice;
1619 }
1620
1621
1622 int chandev_compare_chpid_info(chandev_subchannel_info *chan1,chandev_subchannel_info *chan2)
1623 {
1624         return (chan1->pim!=chan2->pim || *chan1->chpid!=*chan2->chpid);
1625 }
1626
1627 int chandev_compare_cu_dev_info(chandev_subchannel_info *chan1,chandev_subchannel_info *chan2)
1628 {
1629         return ((chan1->cu_type != chan2->cu_type)||
1630                 (chan1->cu_model != chan2->cu_model)||
1631                 (chan1->dev_type != chan2->dev_type)||
1632                 (chan1->dev_model != chan2->dev_model));
1633 }
1634
1635 int chandev_compare_subchannel_info(chandev_subchannel_info *chan1,chandev_subchannel_info *chan2)
1636 {
1637         return((chan1->devno == chan2->devno) &&
1638                (chan1->cu_type == chan2->cu_type) &&
1639                (chan1->cu_model == chan2->cu_model) &&
1640                (chan1->dev_type == chan2->dev_type) &&
1641                (chan1->dev_model == chan2->dev_model) &&
1642                (chan1->pim == chan2->pim) &&
1643                (*chan1->chpid == *chan2->chpid));
1644 }
1645
1646
1647 int chandev_doprobe(chandev_force *force,chandev *read,
1648 chandev *write,chandev *data)
1649 {
1650         chandev_probelist *probe;
1651         chandev_model_info *model_info;
1652         chandev_probeinfo probeinfo;
1653         int               rc=-1,hint=-1;
1654         chandev_activelist *newdevice;
1655         chandev_probefunc  probefunc;
1656         chandev_parms      *curr_parms;
1657         chandev_model_info dummy_model_info;
1658
1659         memset(&probeinfo,0,sizeof(probeinfo));
1660         memset(&dummy_model_info,0,sizeof(dummy_model_info));
1661         probeinfo.device_forced=(force!=NULL);
1662         probeinfo.chpid_info_inconsistent=chandev_compare_chpid_info(&read->sch,&write->sch)||
1663                  (data&&chandev_compare_chpid_info(&read->sch,&data->sch));
1664         probeinfo.cu_dev_info_inconsistent=chandev_compare_cu_dev_info(&read->sch,&write->sch)||
1665                  (data&&chandev_compare_cu_dev_info(&read->sch,&data->sch));
1666         if(read->model_info)
1667                 model_info=read->model_info;
1668         else
1669         {
1670                 dummy_model_info.chan_type=chandev_type_none;
1671                 dummy_model_info.max_port_no=16;
1672                 model_info=&dummy_model_info;
1673         }
1674         for_each(probe,chandev_probelist_head)
1675         {
1676                 if(force)
1677                         probeinfo.chan_type = ( probe->chan_type & force->chan_type );
1678                 else
1679                 {
1680                         if(chandev_cautious_auto_detect)
1681                                 probeinfo.chan_type = ( probe->chan_type == model_info->chan_type ? 
1682                                                        probe->chan_type : chandev_type_none );
1683                         else
1684                                 probeinfo.chan_type = ( probe->chan_type & model_info->chan_type );
1685                 }
1686                 if(probeinfo.chan_type && (force || ( !probeinfo.cu_dev_info_inconsistent &&
1687                   ((probe->chan_type&(chandev_type_ctc|chandev_type_escon)) ||
1688                    !probeinfo.chpid_info_inconsistent))))
1689                 {
1690 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
1691                         if(chandev_use_devno_names)
1692                                 probeinfo.devif_num=read->sch.devno;
1693                         else
1694 #endif
1695                                 probeinfo.devif_num=-1;
1696                         probeinfo.read=read->sch;
1697                         probeinfo.write=write->sch;
1698                         if(data)
1699                         {
1700                                 probeinfo.data=data->sch;
1701                                 probeinfo.data_exists=TRUE;
1702                         }
1703                         probeinfo.max_port_no=(force&&(force->port_protocol_no!=-1) ? 
1704                               force->port_protocol_no : model_info->max_port_no);
1705                         for_each(curr_parms,chandev_parms_head)
1706                         {
1707                                 if(probe->chan_type==curr_parms->chan_type&&
1708                                    read->sch.devno>=curr_parms->lo_devno&&
1709                                         read->sch.devno<=curr_parms->hi_devno)
1710                                 {
1711                                         if (!probeinfo.parmstr) {
1712                                                 probeinfo.parmstr = vmalloc(sizeof(curr_parms->parmstr)+1);
1713                                                 strcpy(probeinfo.parmstr, curr_parms->parmstr);
1714                                         } else {
1715                                                 char *buf;
1716
1717                                                 buf = vmalloc(strlen(probeinfo.parmstr)+strlen(curr_parms->parmstr)+2);
1718                                                 sprintf(buf, "%s,%s",probeinfo.parmstr, curr_parms->parmstr);
1719                                                 probeinfo.parmstr=buf;
1720                                         }
1721                                 }
1722                         }
1723                         if(force)
1724                         {
1725                                 if(force->chan_type==chandev_type_claw)
1726                                         memcpy(&probeinfo.claw,&force->claw,sizeof(chandev_claw_info));
1727                                 probeinfo.port_protocol_no=force->port_protocol_no;
1728                                 if(force->devif_num==-1&&force->devif_num==-2)
1729                                         probeinfo.devif_num=-1;
1730                                 else
1731                                         probeinfo.devif_num=force->devif_num;
1732                                 probeinfo.memory_usage_in_k=force->memory_usage_in_k;
1733                                 probeinfo.checksum_received_ip_pkts=force->checksum_received_ip_pkts;
1734                                 probeinfo.use_hw_stats=force->use_hw_stats;
1735                         }
1736                         else
1737                         {
1738                                 probeinfo.port_protocol_no=0;
1739                                 probeinfo.checksum_received_ip_pkts=model_info->default_checksum_received_ip_pkts;
1740                                 probeinfo.use_hw_stats=model_info->default_use_hw_stats;
1741                                 probeinfo.memory_usage_in_k=0;
1742                                 if(probe->chan_type&chandev_type_lcs)
1743                                 {
1744                                         hint=(read->sch.devno&0xFF)>>1;
1745                                         if(hint>model_info->max_port_no)
1746                                         {
1747                                 /* The card is possibly emulated e.g P/390 */
1748                                 /* or possibly configured to use a shared */
1749                                 /* port configured by osa-sf. */
1750                                                 hint=0;
1751                                         }
1752                                 }
1753                         }
1754                         probeinfo.hint_port_no=hint;
1755                         probefunc=probe->probefunc;
1756                         rc=probefunc(&probeinfo);
1757                         if(rc==0)
1758                         {
1759                                 newdevice=probeinfo.newdevice;
1760                                 if(newdevice)
1761                                 {
1762                                         newdevice->probefunc=probe->probefunc;
1763                                         newdevice->shutdownfunc=probe->shutdownfunc;
1764                                         newdevice->msck_notfunc=probe->msck_notfunc;
1765                                         probe->devices_found++;
1766                                         chandev_add_to_list((list **)&chandev_activelist_head,
1767                                                             newdevice);
1768                                         chandev_add_to_userland_notify_list(chandev_start,
1769                                                                       newdevice->devname,chandev_status_good,chandev_status_good);
1770                                 }
1771                                 else
1772                                 {
1773                                         printk("chandev_initdevice either failed or wasn't called for device read_irq=0x%04x\n",probeinfo.read.irq);
1774                                 }
1775                                 break;
1776                                 
1777                         }
1778                 }
1779         }
1780         chandev_remove(read);
1781         chandev_remove(write);
1782         if(data)
1783                 chandev_remove(data);
1784         return(rc);
1785 }
1786
1787
1788 int chandev_request_irq_from_irqinfo(chandev_irqinfo *irqinfo,chandev *this_chandev)
1789 {
1790         int retval=s390_request_irq_special(irqinfo->sch.irq,
1791                                    irqinfo->handler,
1792                                    chandev_not_oper_handler,
1793                                    irqinfo->irqflags,
1794                                    irqinfo->devname,
1795                                    irqinfo->dev_id);
1796         if(retval==0)
1797         {
1798                 irqinfo->msck_status=chandev_status_good;
1799                 this_chandev->owned=TRUE;
1800         }
1801         return(retval);
1802 }
1803
1804 void chandev_irqallocerr(chandev_irqinfo *irqinfo,int err)
1805 {
1806         printk("chandev_probe failed to realloc irq=%d for %s err=%d\n",irqinfo->sch.irq,irqinfo->devname,err);
1807 }
1808
1809
1810 void chandev_call_notification_func(chandev_activelist *curr_device,chandev_irqinfo *curr_irqinfo,
1811 chandev_msck_status prevstatus)
1812 {
1813         if(curr_irqinfo->msck_status!=prevstatus)
1814         {
1815                 chandev_msck_status new_msck_status=curr_irqinfo->msck_status;
1816                 if(curr_irqinfo->msck_status==chandev_status_good)
1817                 {
1818                         if(curr_device->read_irqinfo->msck_status==chandev_status_good&&
1819                            curr_device->write_irqinfo->msck_status==chandev_status_good)
1820                         {
1821                                 if(curr_device->data_irqinfo)
1822                                 {
1823                                         if(curr_device->data_irqinfo->msck_status==chandev_status_good)
1824                                                 new_msck_status=chandev_status_all_chans_good;
1825                                 }
1826                                 else
1827                                         new_msck_status=chandev_status_all_chans_good;
1828                         }
1829                 }
1830                 if(curr_device->msck_notfunc)
1831                 {
1832                         curr_device->msck_notfunc(curr_device->dev_ptr,
1833                                               curr_irqinfo->sch.irq,
1834                                               prevstatus,new_msck_status);
1835                 }
1836                 if(new_msck_status!=chandev_status_good)
1837                 {
1838                         /* No point in sending a machine check if only one channel is good */
1839                         chandev_add_to_userland_notify_list(chandev_msck,curr_device->devname,
1840                                                       prevstatus,curr_irqinfo->msck_status);
1841                 }
1842         }
1843 }
1844
1845 int chandev_find_eligible_channels(chandev *first_chandev_to_check,
1846                                chandev **read,chandev **write,chandev **data,chandev **next,
1847                                    chandev_type chan_type)
1848 {
1849         chandev *curr_chandev;
1850         int eligible_found=FALSE,changed;
1851         
1852         *next=first_chandev_to_check->next;
1853         *read=*write=*data=NULL;
1854         for_each(curr_chandev,first_chandev_to_check)
1855                 if((curr_chandev->sch.devno&1)==0&&curr_chandev->model_info->chan_type!=chandev_type_claw)
1856                 {
1857                         *read=curr_chandev;
1858                         if(chan_type==chandev_type_none)
1859                                 chan_type=(*read)->model_info->chan_type;
1860                         break;
1861                 }
1862         if(*read)
1863         {
1864                 for_each(curr_chandev,(chandev *)chandev_head.head)
1865                         if((((*read)->sch.devno|1)==curr_chandev->sch.devno)&&
1866                            (chandev_compare_cu_dev_info(&(*read)->sch,&curr_chandev->sch)==0)&&
1867                            ((chan_type&(chandev_type_ctc|chandev_type_escon))||
1868                             chandev_compare_chpid_info(&(*read)->sch,&curr_chandev->sch)==0))
1869                         {
1870                                 *write=curr_chandev;
1871                                 break;
1872                         }
1873         }
1874         if((chan_type&chandev_type_qeth))
1875         {
1876                 if(*write)
1877                 {
1878                         for_each(curr_chandev,(chandev *)chandev_head.head)
1879                                 if((curr_chandev!=*read&&curr_chandev!=*write)&&
1880                                    (chandev_compare_cu_dev_info(&(*read)->sch,&curr_chandev->sch)==0)&&
1881                                    (chandev_compare_chpid_info(&(*read)->sch,&curr_chandev->sch)==0))
1882                                 {
1883                                         *data=curr_chandev;
1884                                         break;
1885                                 }
1886                         if(*data)
1887                                 eligible_found=TRUE;
1888                 }
1889                 
1890         }
1891         else
1892                 if(*write)
1893                         eligible_found=TRUE;
1894         if(eligible_found)
1895         {
1896                 do
1897                 {
1898                         changed=FALSE;
1899                         if(*next&&
1900                            ((*read&&(*read==*next))||
1901                            (*write&&(*write==*next))||
1902                            (*data&&(*data==*next))))
1903                         {
1904                                 *next=(*next)->next;
1905                                 changed=TRUE;
1906                         }
1907                 }while(changed==TRUE);
1908         }
1909         return(eligible_found);
1910 }
1911
1912 chandev *chandev_get_free_chandev_by_devno(int devno)
1913 {
1914         chandev *curr_chandev;
1915         if(devno==-1)
1916                 return(NULL);
1917         for_each(curr_chandev,(chandev *)chandev_head.head)
1918                 if(curr_chandev->sch.devno==devno)
1919                 {
1920                         if(chandev_active(devno))
1921                                 return(NULL);
1922                         else
1923                                 return(curr_chandev);
1924                 }
1925         return(NULL);
1926
1927 }
1928
1929 void chandev_probe(void)
1930 {
1931         chandev *read_chandev,*write_chandev,*data_chandev,*curr_chandev,*next_chandev;
1932         chandev_force *curr_force;
1933         chandev_noauto_range *curr_noauto;
1934         chandev_activelist *curr_device;
1935         chandev_irqinfo *curr_irqinfo;
1936         s390_dev_info_t curr_devinfo;
1937         int  err;
1938         int auto_msck_recovery;
1939         chandev_msck_status prevstatus;
1940         chandev_msck_range *curr_msck_range;
1941
1942
1943         chandev_interrupt_check();
1944         chandev_read_conf_if_necessary();
1945         chandev_collect_devices();
1946         chandev_lock();
1947         for_each(curr_irqinfo,chandev_irqinfo_head)
1948         {
1949                 if((curr_device=chandev_get_activelist_by_irq(curr_irqinfo->sch.irq)))
1950                 {
1951                         prevstatus=curr_irqinfo->msck_status;
1952                         if(curr_irqinfo->msck_status!=chandev_status_good)
1953                         {
1954                                 curr_chandev=chandev_get_by_irq(curr_irqinfo->sch.irq);
1955                                 if(curr_chandev)
1956                                 {
1957                                         auto_msck_recovery=curr_chandev->model_info->
1958                                                 auto_msck_recovery;
1959                                 }
1960                                 else
1961                                         goto remove;
1962                                 for_each(curr_msck_range,chandev_msck_range_head)
1963                                 {
1964                                         if(curr_msck_range->lo_devno<=
1965                                            curr_irqinfo->sch.devno&&
1966                                            curr_msck_range->hi_devno>=
1967                                            curr_irqinfo->sch.devno)
1968                                         {
1969                                                 auto_msck_recovery=
1970                                                         curr_msck_range->
1971                                                         auto_msck_recovery;
1972                                                 break;
1973                                         }
1974                                 }
1975                                 if((1<<(curr_irqinfo->msck_status-1))&auto_msck_recovery)
1976                                 {
1977                                         if(curr_irqinfo->msck_status==chandev_status_revalidate)
1978                                         {
1979                                                 if((get_dev_info_by_irq(curr_irqinfo->sch.irq,&curr_devinfo)==0))
1980                                                 {
1981                                                         curr_irqinfo->sch.devno=curr_devinfo.devno;
1982                                                         curr_irqinfo->msck_status=chandev_status_good;
1983                                                 }
1984                                         }
1985                                         else
1986                                         {
1987                                                 if(curr_chandev)
1988                                                 {
1989                                                         /* Has the device reappeared */
1990                                                         if(chandev_compare_subchannel_info(
1991                                                                 &curr_chandev->sch,
1992                                                                 &curr_device->read_irqinfo->sch)||
1993                                                            chandev_compare_subchannel_info(
1994                                                                 &curr_chandev->sch,
1995                                                                 &curr_device->write_irqinfo->sch)||
1996                                                            (curr_device->data_irqinfo&&
1997                                                             chandev_compare_subchannel_info(
1998                                                                     &curr_chandev->sch,
1999                                                                     &curr_device->data_irqinfo->sch)))
2000                                                         {
2001                                                                 if((err=chandev_request_irq_from_irqinfo(curr_irqinfo,curr_chandev))==0)
2002                                                                         curr_irqinfo->msck_status=chandev_status_good;
2003                                                                 else
2004                                                                         chandev_irqallocerr(curr_irqinfo,err);
2005                                                         }
2006                                         
2007                                                 }
2008                                         }
2009                                 }
2010                         }
2011                         chandev_call_notification_func(curr_device,curr_irqinfo,prevstatus);
2012                 }
2013                 /* This is required because the device can go & come back */
2014                 /* even before we realize it is gone owing to the waits in our kernel threads */
2015                 /* & the device will be marked as not owned but its status will be good */
2016                 /* & an attempt to accidently reprobe it may be done. */ 
2017                 remove:
2018                 chandev_remove(chandev_get_by_irq(curr_irqinfo->sch.irq));
2019                 
2020         }
2021         /* extra sanity */
2022         for_each_allow_delete(curr_chandev,next_chandev,(chandev *)chandev_head.head)
2023                 if(curr_chandev->owned)
2024                         chandev_remove(curr_chandev);
2025         for_each(curr_force,chandev_force_head)
2026         {
2027                 if(curr_force->devif_num==-2)
2028                 {
2029                         for_each_allow_delete2(curr_chandev,next_chandev,(chandev *)chandev_head.head)
2030                         {
2031                                 if(chandev_find_eligible_channels(curr_chandev,&read_chandev,
2032                                                                   &write_chandev,&data_chandev,
2033                                                                   &next_chandev,
2034                                                                   curr_force->chan_type));
2035                                 {
2036                                         if((curr_force->read_lo_devno>=read_chandev->sch.devno)&&
2037                                            (curr_force->write_hi_devno<=read_chandev->sch.devno)&&
2038                                            (curr_force->read_lo_devno>=write_chandev->sch.devno)&&
2039                                            (curr_force->write_hi_devno<=write_chandev->sch.devno)&&
2040                                            (!data_chandev||(data_chandev&&
2041                                            (curr_force->read_lo_devno>=data_chandev->sch.devno)&&
2042                                            (curr_force->write_hi_devno<=data_chandev->sch.devno))))
2043                                                 chandev_doprobe(curr_force,read_chandev,write_chandev,
2044                                                                 data_chandev);
2045                                 }
2046                         }
2047                 }
2048                 else
2049                 {
2050                         read_chandev=chandev_get_free_chandev_by_devno(curr_force->read_lo_devno);
2051                         if(read_chandev)
2052                         {
2053                                 write_chandev=chandev_get_free_chandev_by_devno(curr_force->write_hi_devno);
2054                                 if(write_chandev)
2055                                 {
2056                                         if(curr_force->chan_type==chandev_type_qeth)
2057                                         {
2058
2059                                                 data_chandev=chandev_get_free_chandev_by_devno(curr_force->data_devno);
2060                                                 if(data_chandev==NULL)
2061                                                         printk("chandev_probe unable to force gigabit_ethernet driver invalid device  no 0x%04x given\n",curr_force->data_devno);
2062                                         }
2063                                         else
2064                                                 data_chandev=NULL;
2065                                         chandev_doprobe(curr_force,read_chandev,write_chandev,
2066                                                         data_chandev);
2067                                 }
2068                         }
2069                 }
2070         }
2071         for_each_allow_delete(curr_chandev,next_chandev,(chandev *)chandev_head.head)
2072         {
2073                 for_each(curr_noauto,chandev_noauto_head)
2074                 {
2075                         if(curr_chandev->sch.devno>=curr_noauto->lo_devno&&
2076                            curr_chandev->sch.devno<=curr_noauto->hi_devno)
2077                         {
2078                                 chandev_remove(curr_chandev);
2079                                 break;
2080                         }
2081                 }
2082         }
2083         for_each_allow_delete2(curr_chandev,next_chandev,(chandev *)chandev_head.head)
2084         {
2085                 if(chandev_find_eligible_channels(curr_chandev,&read_chandev,
2086                                                   &write_chandev,&data_chandev,
2087                                                   &next_chandev,
2088                                                   chandev_type_none))
2089                         chandev_doprobe(NULL,read_chandev,write_chandev,
2090                                         data_chandev);
2091         }
2092         chandev_remove_all();
2093         chandev_unlock();
2094 }
2095
2096 static void chandev_not_oper_func(int irq,int status)
2097 {
2098         chandev_irqinfo *curr_irqinfo;
2099         chandev_activelist *curr_device;
2100         
2101         chandev_lock();
2102         for_each(curr_irqinfo,chandev_irqinfo_head)
2103                 if(curr_irqinfo->sch.irq==irq)
2104                 {
2105                         chandev_msck_status prevstatus=curr_irqinfo->msck_status;
2106                         switch(status)
2107                         {
2108                                 /* Currently defined but not used in kernel */
2109                                 /* Despite being in specs */
2110                         case DEVSTAT_NOT_OPER:
2111                                 curr_irqinfo->msck_status=chandev_status_not_oper;
2112                                 break;
2113 #ifdef DEVSTAT_NO_PATH
2114                                 /* Kernel hasn't this defined currently. */
2115                                 /* Despite being in specs */
2116                         case DEVSTAT_NO_PATH:
2117                                 curr_irqinfo->msck_status=chandev_status_no_path;
2118                                 break;
2119 #endif
2120                         case DEVSTAT_REVALIDATE:
2121                                 curr_irqinfo->msck_status=chandev_status_revalidate;
2122                                 break;
2123                         case DEVSTAT_DEVICE_GONE:
2124                                 curr_irqinfo->msck_status=chandev_status_gone;
2125                                 break;
2126                         }
2127                         if((curr_device=chandev_get_activelist_by_irq(irq)))
2128                                         chandev_call_notification_func(curr_device,curr_irqinfo,prevstatus);
2129                         else
2130                                 printk("chandev_not_oper_func received channel check for unowned irq %d",irq);
2131                 }
2132         chandev_unlock();
2133 }
2134
2135
2136 static int chandev_msck_thread(void *unused)
2137 {
2138         int loopcnt,not_oper_probe_required=FALSE;
2139         wait_queue_head_t    wait;
2140         chandev_not_oper_struct *new_not_oper;
2141
2142         /* This loop exists because machine checks tend to come in groups & we have
2143            to wait for the other devnos to appear also */
2144         init_waitqueue_head(&wait);
2145         for(loopcnt=0;loopcnt<10||(jiffies-chandev_last_machine_check)<HZ;loopcnt++)
2146         {
2147                 sleep_on_timeout(&wait,HZ);
2148         }
2149         atomic_set(&chandev_msck_thread_lock,1);
2150         while(!atomic_compare_and_swap(TRUE,FALSE,&chandev_new_msck));
2151         {
2152                 chandev_probe();
2153         }
2154         while(TRUE)
2155         {
2156                 
2157                 unsigned long        flags; 
2158                 spin_lock_irqsave(&chandev_not_oper_spinlock,flags);
2159                 new_not_oper=(chandev_not_oper_struct *)dequeue_head(&chandev_not_oper_head);
2160                 spin_unlock_irqrestore(&chandev_not_oper_spinlock,flags);
2161                 if(new_not_oper)
2162                 {
2163                         chandev_not_oper_func(new_not_oper->irq,new_not_oper->status);
2164                         not_oper_probe_required=TRUE;
2165                         kfree(new_not_oper);
2166                 }
2167                 else
2168                         break;
2169         }
2170         if(not_oper_probe_required)
2171                 chandev_probe();
2172         return(0);
2173 }
2174
2175 static void chandev_msck_task(void *unused)
2176 {
2177         if(kernel_thread(chandev_msck_thread,NULL,SIGCHLD)<0)
2178         {
2179                 atomic_set(&chandev_msck_thread_lock,1);
2180                 printk("error making chandev_msck_thread kernel thread\n");
2181         }
2182 }
2183
2184
2185
2186 static char *argstrs[]=
2187 {
2188         "noauto",
2189         "del_noauto",
2190         "ctc",
2191         "escon",
2192         "lcs",
2193         "osad",
2194         "qeth",
2195         "claw",
2196         "add_parms",
2197         "del_parms",
2198         "del_force",
2199 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
2200         "use_devno_names",
2201         "dont_use_devno_names",
2202 #endif
2203         "cautious_auto_detect",
2204         "non_cautious_auto_detect",
2205         "add_model",
2206         "del_model",
2207         "auto_msck",
2208         "del_auto_msck",
2209         "del_all_models",
2210         "reset_conf_clean",
2211         "reset_conf",
2212         "shutdown",
2213         "reprobe",
2214         "unregister_probe",
2215         "unregister_probe_by_chan_type",
2216         "read_conf",
2217         "dont_read_conf",
2218         "persist"
2219 };
2220
2221 typedef enum
2222 {
2223         stridx_mult=256,
2224         first_stridx=0,
2225         noauto_stridx=first_stridx,
2226         del_noauto_stridx,
2227         ctc_stridx,
2228         escon_stridx,
2229         lcs_stridx,
2230         osad_stridx,
2231         qeth_stridx,
2232         claw_stridx,
2233         add_parms_stridx,
2234         del_parms_stridx,
2235         del_force_stridx,
2236 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
2237         use_devno_names_stridx,
2238         dont_use_devno_names_stridx,
2239 #endif
2240         cautious_auto_detect_stridx,
2241         non_cautious_auto_detect_stridx,
2242         add_model_stridx,
2243         del_model_stridx,
2244         auto_msck_stridx,
2245         del_auto_msck_stridx,
2246         del_all_models_stridx,
2247         reset_conf_clean_stridx,
2248         reset_conf_stridx,
2249         shutdown_stridx,
2250         reprobe_stridx,
2251         unregister_probe_stridx,
2252         unregister_probe_by_chan_type_stridx,
2253         read_conf_stridx,
2254         dont_read_conf_stridx,
2255         persist_stridx,
2256         last_stridx,
2257 } chandev_str_enum;
2258
2259 void chandev_add_noauto(u16 lo_devno,u16 hi_devno)
2260 {
2261         chandev_noauto_range *new_range;
2262
2263         if((new_range=chandev_alloc(sizeof(chandev_noauto_range))))
2264         {
2265                 new_range->lo_devno=lo_devno;
2266                 new_range->hi_devno=hi_devno;
2267                 chandev_add_to_list((list **)&chandev_noauto_head,new_range);
2268         }
2269 }
2270
2271
2272 void chandev_add_msck_range(u16 lo_devno,u16 hi_devno,int auto_msck_recovery)
2273 {
2274         chandev_msck_range *new_range;
2275
2276         if((new_range=chandev_alloc(sizeof(chandev_msck_range))))
2277         {
2278                 new_range->lo_devno=lo_devno;
2279                 new_range->hi_devno=hi_devno;
2280                 new_range->auto_msck_recovery=auto_msck_recovery;
2281                 chandev_add_to_list((list **)&chandev_msck_range_head,new_range);
2282         }
2283 }
2284
2285
2286
2287 static char chandev_keydescript[]=
2288 "\nchan_type key bitfield ctc=0x1,escon=0x2,lcs=0x4,osad=0x8,qeth=0x10,claw=0x20\n";
2289
2290
2291 #if  CONFIG_ARCH_S390X
2292 /* We need this as we sometimes use this to evaluate pointers */
2293 typedef long chandev_int; 
2294 #else
2295 typedef int chandev_int;
2296 #endif
2297
2298
2299 #if (LINUX_VERSION_CODE<KERNEL_VERSION(2,3,0)) || (CONFIG_ARCH_S390X)
2300 /*
2301  * Read an int from an option string; if available accept a subsequent
2302  * comma as well.
2303  *
2304  * Return values:
2305  * 0 : no int in string
2306  * 1 : int found, no subsequent comma
2307  * 2 : int found including a subsequent comma
2308  */
2309 static chandev_int chandev_get_option(char **str,chandev_int *pint)
2310 {
2311     char *cur = *str;
2312
2313     if (!cur || !(*cur)) return 0;
2314     *pint = simple_strtol(cur,str,0);
2315     if (cur==*str) return 0;
2316     if (**str==',') {
2317         (*str)++;
2318         return 2;
2319     }
2320
2321     return 1;
2322 }
2323
2324
2325 static char *chandev_get_options(char *str, int nints, chandev_int *ints)
2326 {
2327         int res,i=1;
2328
2329         while (i<nints) 
2330         {
2331                 res = chandev_get_option(&str, ints+i);
2332                 if (res==0) break;
2333                 i++;
2334                 if (res==1) break;
2335         }
2336         ints[0] = i-1;
2337         return(str);
2338 }
2339 #else
2340 #define chandev_get_option get_option
2341 #define chandev_get_options get_options
2342 #endif
2343 /*
2344  * Read an string from an option string; if available accept a subsequent
2345  * comma as well & set this comma to a null character when returning the string.
2346  *
2347  * Return values:
2348  * 0 : no string found
2349  * 1 : string found, no subsequent comma
2350  * 2 : string found including a subsequent comma
2351  */
2352 static int chandev_get_string(char **instr,char **outstr)
2353 {
2354         char *cur = *instr;
2355
2356         if (!cur ||*cur==0)
2357         {
2358                 *outstr=NULL;
2359                 return 0;
2360         }
2361         *outstr=*instr;
2362         for(;;)
2363         {
2364                 if(*(++cur)==',')
2365                 {
2366                         *cur=0;
2367                         *instr=cur+1;
2368                         return 2;
2369                 }
2370                 else if(*cur==0)
2371                 {
2372                         *instr=cur+1;
2373                         return 1;
2374                 }
2375         }
2376 }
2377
2378
2379
2380
2381 static int chandev_setup(int in_read_conf,char *instr,char *errstr,int lineno)
2382 {
2383         chandev_strval   val=isnull;
2384         chandev_str_enum stridx;
2385         long             endlong;
2386         chandev_type     chan_type;
2387         char             *str,*currstr,*interpretstr=NULL;
2388         int              cnt,strcnt;
2389         int              retval=0;
2390 #define CHANDEV_MAX_EXTRA_INTS 12
2391         chandev_int ints[CHANDEV_MAX_EXTRA_INTS+1];
2392         currstr=alloca(strlen(instr)+1);
2393         strcpy(currstr,instr);
2394         strcnt=chandev_pack_args(currstr);
2395         for(cnt=1;cnt<=strcnt;cnt++)
2396         {
2397                 interpretstr=currstr;
2398                 memset(ints,0,sizeof(ints));
2399                 for(stridx=first_stridx;stridx<last_stridx;stridx++)
2400                 {
2401                         str=currstr;
2402                         if((val=chandev_strcmp(argstrs[stridx],&str,&endlong)))
2403                                 break;
2404                 }
2405                 currstr=str;
2406                 if(val)
2407                 {
2408                         val=(((chandev_strval)stridx)*stridx_mult)+(val&~isstr);
2409                         switch(val)
2410                         {
2411                         case (add_parms_stridx*stridx_mult)|iscomma:
2412                                 currstr=chandev_get_options(currstr,4,ints);
2413                                 if(*currstr&&ints[0]>=1)
2414                                 {
2415                                         if(ints[0]==1)
2416                                         {
2417                                                 ints[2]=0;
2418                                                 ints[3]=0xffff;
2419                                         }
2420                                         else if(ints[0]==2)
2421                                                 ints[3]=ints[2];
2422                                         chandev_add_parms(ints[1],ints[2],ints[3],currstr);
2423                                         goto NextOption;
2424                                 }
2425                                 else
2426                                         goto BadArgs;
2427                                 break;
2428                         case (claw_stridx*stridx_mult)|isnum|iscomma:
2429                         case (claw_stridx*stridx_mult)|iscomma:
2430                                 currstr=chandev_get_options(str,6,ints);
2431                                 break;
2432                         default:
2433                                 if(val&iscomma)
2434                                         currstr=chandev_get_options(str,CHANDEV_MAX_EXTRA_INTS,ints);
2435                                 break;
2436                         }
2437                         switch(val)
2438                         {
2439                         case noauto_stridx*stridx_mult:
2440                         case (noauto_stridx*stridx_mult)|iscomma:
2441                                 switch(ints[0])
2442                                 {
2443                                 case 0: 
2444                                         chandev_free_all_list((list **)&chandev_noauto_head);
2445                                         chandev_add_noauto(0,0xffff);
2446                                         break;
2447                                 case 1:
2448                                         ints[2]=ints[1];
2449                                 case 2:
2450                                         chandev_add_noauto(ints[1],ints[2]);
2451                                         break;
2452                                 default:
2453                                         goto BadArgs;
2454                                 }
2455                                 break;
2456                         case (auto_msck_stridx*stridx_mult)|iscomma:
2457                                 switch(ints[0])
2458                                 {
2459                                 case 1:
2460                                         chandev_free_all_list((list **)&chandev_msck_range_head);
2461                                         chandev_add_msck_range(0,0xffff,ints[1]);
2462                                         break;
2463                                 case 2:
2464                                         chandev_add_msck_range(ints[1],ints[1],ints[2]);
2465                                         break;
2466                                 case 3:
2467                                         chandev_add_msck_range(ints[1],ints[2],ints[3]);
2468                                         break;
2469                                 default:
2470                                         goto BadArgs;
2471                                         
2472                                 }
2473                                 break;
2474                         case del_auto_msck_stridx*stridx_mult:
2475                         case (del_auto_msck_stridx*stridx_mult)|iscomma:
2476                                 switch(ints[0])
2477                                 {
2478                                 case 0:
2479                                         chandev_free_all_list((list **)&chandev_msck_range_head);
2480                                         break;
2481                                 case 1:
2482                                         chandev_del_msck(ints[1]);
2483                                 default:
2484                                         goto BadArgs;
2485                                 }
2486                                 break;
2487                         case del_noauto_stridx*stridx_mult:
2488                                 chandev_free_all_list((list **)&chandev_noauto_head);
2489                                 break;
2490                         case (del_noauto_stridx*stridx_mult)|iscomma:
2491                                 if(ints[0]==1)
2492                                         chandev_del_noauto(ints[1]);
2493                                 else
2494                                         goto BadArgs;
2495                                 break;
2496                         case (qeth_stridx*stridx_mult)|isnum|iscomma:
2497                                 if(ints[0]<3||ints[0]>7)
2498                                         goto BadArgs;
2499                                 chandev_add_force(chandev_type_qeth,endlong,ints[1],ints[2],
2500                                                   ints[3],ints[4],ints[5],ints[6],ints[7],
2501                                                   NULL,NULL,NULL);
2502                                 break;
2503                         case (ctc_stridx*stridx_mult)|isnum|iscomma:
2504                         case (escon_stridx*stridx_mult)|isnum|iscomma:
2505                         case (lcs_stridx*stridx_mult)|isnum|iscomma:
2506                         case (osad_stridx*stridx_mult)|isnum|iscomma:
2507                         case (ctc_stridx*stridx_mult)|iscomma:
2508                         case (escon_stridx*stridx_mult)|iscomma:
2509                         case (lcs_stridx*stridx_mult)|iscomma:
2510                         case (osad_stridx*stridx_mult)|iscomma:
2511                                 switch(val&~(isnum|iscomma))
2512                                 {
2513                                 case (ctc_stridx*stridx_mult):
2514                                         chan_type=chandev_type_ctc;
2515                                         break;
2516                                 case (escon_stridx*stridx_mult):
2517                                         chan_type=chandev_type_escon;
2518                                         break;
2519                                 case (lcs_stridx*stridx_mult):
2520                                         chan_type=chandev_type_lcs;
2521                                         break;
2522                                 case (osad_stridx*stridx_mult):
2523                                         chan_type=chandev_type_osad;
2524                                         break;
2525                                 case (qeth_stridx*stridx_mult):
2526                                         chan_type=chandev_type_qeth;
2527                                         break;
2528                                 default:
2529                                         goto BadArgs;
2530                                 }
2531                                 if((val&isnum)==0)
2532                                         endlong=-2;
2533                                 if(ints[0]<2||ints[0]>6)
2534                                         goto BadArgs;
2535                                 chandev_add_force(chan_type,endlong,ints[1],ints[2],
2536                                                   0,ints[3],ints[4],ints[5],ints[6],
2537                                                   NULL,NULL,NULL);
2538                                 break;
2539                         case (claw_stridx*stridx_mult)|isnum|iscomma:
2540                         case (claw_stridx*stridx_mult)|iscomma:
2541                                 if(ints[0]>=2&&ints[0]<=5)
2542                                 {
2543                                         char    *host_name,*adapter_name,*api_type;
2544                                         char    *clawstr=alloca(strlen(currstr)+1);
2545                                         
2546                                         strcpy(clawstr,currstr);
2547                                         if(!(chandev_get_string(&clawstr,&host_name)==2&&
2548                                              chandev_get_string(&clawstr,&adapter_name)==2&&
2549                                              chandev_get_string(&clawstr,&api_type)==1&&
2550                                              chandev_add_force(chandev_type_claw,
2551                                                                endlong,ints[1],ints[2],0,
2552                                                                ints[3],0,ints[4],ints[5],
2553                                                                host_name,adapter_name,api_type)==0))
2554                                                 goto BadArgs;
2555                                                 
2556                                 }
2557                                 else
2558                                         goto BadArgs;
2559                                 break;
2560                         case (del_parms_stridx*stridx_mult):
2561                                 ints[1]=-1;
2562                         case (del_parms_stridx*stridx_mult)|iscomma:
2563                                 if(ints[0]==0)
2564                                         ints[1]=-1;
2565                                 if(ints[0]<=1)
2566                                         ints[2]=FALSE;
2567                                 if(ints[0]<=2)
2568                                         ints[3]=-1;
2569                                 if(ints[0]>3)
2570                                         goto BadArgs;
2571                                 chandev_remove_parms(ints[1],ints[2],ints[3]);
2572                                 break;
2573                         case (del_force_stridx*stridx_mult)|iscomma:
2574                                 if(ints[0]!=1)
2575                                         goto BadArgs;
2576                                 chandev_del_force(ints[1]);
2577                                 break;
2578                         case (del_force_stridx*stridx_mult):
2579                                 chandev_del_force(-1);
2580                                 break;
2581 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
2582                         case (use_devno_names_stridx*stridx_mult):
2583                                 chandev_use_devno_names=TRUE;
2584                                 break;
2585                         case (dont_use_devno_names_stridx*stridx_mult):
2586                                 chandev_use_devno_names=FALSE;
2587                                 break;
2588 #endif
2589                         case (cautious_auto_detect_stridx*stridx_mult):
2590                                 chandev_cautious_auto_detect=TRUE;
2591                                 break;
2592                         case (non_cautious_auto_detect_stridx*stridx_mult):
2593                                 chandev_cautious_auto_detect=FALSE;
2594                                 break;
2595                         case (add_model_stridx*stridx_mult)|iscomma:
2596                                 if(ints[0]<3)
2597                                         goto BadArgs;
2598                                 if(ints[0]==3)
2599                                         ints[4]=-1;
2600                                 if(ints[0]<=4)
2601                                         ints[5]=-1;
2602                                 if(ints[0]<=5)
2603                                         ints[6]=-1;
2604                                 if(ints[0]<=6)
2605                                         ints[7]=default_msck_bits;
2606                                 if(ints[0]<=7)
2607                                         ints[8]=FALSE;
2608                                 if(ints[0]<=8)
2609                                         ints[9]=FALSE;
2610                                 ints[0]=7;
2611                                 chandev_add_model(ints[1],ints[2],ints[3],
2612                                                   ints[4],ints[5],ints[6],ints[7],ints[8],ints[9]);
2613                                 break;
2614                         case (del_model_stridx*stridx_mult)|iscomma:
2615                                 if(ints[0]<2||ints[0]>4)
2616                                         goto BadArgs;
2617                                 if(ints[0]<3)
2618                                         ints[3]=-2;
2619                                 if(ints[0]<4)
2620                                         ints[4]=-2;
2621                                 ints[0]=4;
2622                                 chandev_del_model(ints[1],ints[2],ints[3],ints[4]);
2623                                 break;
2624                         case del_all_models_stridx*stridx_mult:
2625                                 chandev_remove_all_models();
2626                                 break;
2627                         case reset_conf_stridx*stridx_mult:
2628                                 chandev_reset();
2629                                 chandev_init_default_models();
2630                                 break;
2631                         case reset_conf_clean_stridx*stridx_mult:
2632                                 chandev_reset();
2633                                 break;
2634                         case shutdown_stridx*stridx_mult:
2635                                 chandev_shutdown_all();
2636                                 break;
2637                         case (shutdown_stridx*stridx_mult)|iscomma:
2638                                 switch(ints[0])
2639                                 {
2640                                 case 0:
2641                                         if(strlen(str))
2642                                                 chandev_shutdown_by_name(str);
2643                                         else
2644                                                 goto BadArgs;
2645                                         break;
2646                                 case 1:
2647                                         chandev_shutdown_by_devno(ints[1]);
2648                                         break;
2649                                 default:
2650                                         goto BadArgs;
2651                                 }
2652                                 break;
2653                         case reprobe_stridx*stridx_mult:
2654                                 chandev_probe();
2655                                 break;
2656                         case unregister_probe_stridx*stridx_mult:
2657                                 chandev_free_all_list((list **)&chandev_probelist_head);
2658                                 break;
2659                         case (unregister_probe_stridx*stridx_mult)|iscomma:
2660                                 if(ints[0]!=1)
2661                                         goto BadArgs;
2662                                 chandev_unregister_probe((chandev_probefunc)ints[1]);
2663                                 break;
2664                         case (unregister_probe_by_chan_type_stridx*stridx_mult)|iscomma:
2665                                 if(ints[0]!=1)
2666                                         goto BadArgs;
2667                                 chandev_unregister_probe_by_chan_type((chandev_type)ints[1]);
2668                                 break;
2669                         case read_conf_stridx*stridx_mult:
2670                                 if(in_read_conf)
2671                                 {
2672                                         printk("attempt to recursively call read_conf\n");
2673                                         goto BadArgs;
2674                                 }
2675                                 chandev_read_conf();
2676                                 break;
2677                         case dont_read_conf_stridx*stridx_mult:
2678                                 atomic_set(&chandev_conf_read,TRUE);
2679                                 break;
2680                         case (persist_stridx*stridx_mult)|iscomma:
2681                                 if(ints[0]==1)
2682                                         chandev_persistent=ints[1];
2683                                 else
2684                                         goto BadArgs;
2685                                 break;
2686                         default:
2687                                 goto BadArgs;
2688                         }
2689                 }
2690                 else
2691                         goto BadArgs;
2692         NextOption:
2693                 if(cnt<strcnt)
2694                 {
2695                         /* eat up stuff till next string */
2696                         while(*(currstr++));
2697                 }
2698         }
2699         retval=1;
2700  BadArgs:
2701         if(!retval)
2702         {
2703                 printk("chandev_setup %s %s",(val==0 ? "unknown verb":"bad argument"),instr);
2704                 if(errstr)
2705                 {
2706                         printk("%s %d interpreted as %s",errstr,lineno,interpretstr);
2707                         if(strcnt>1)
2708                         {
2709                                 if(cnt==strcnt)
2710                                         printk(" after the last semicolon\n");
2711                                 else
2712                                         printk(" before semicolon no %d",cnt);
2713                         }
2714                 }
2715                 printk(".\n Type man chandev for more info.\n\n");
2716         }
2717         return(retval);
2718 }
2719 #define CHANDEV_KEYWORD "chandev="
2720 static int chandev_setup_bootargs(char *str,int paramno)
2721 {
2722         int len;
2723
2724         char *copystr;
2725         for(len=0;str[len]!=0&&!isspace(str[len]);len++);
2726         copystr=alloca(len+1);
2727         strncpy(copystr,str,len);
2728         copystr[len]=0;
2729         if(chandev_setup(FALSE,copystr,"at "CHANDEV_KEYWORD" bootparam no",paramno)==0)
2730                 return(0);
2731         return(len);
2732
2733 }
2734
2735 /*
2736   We can't parse using a __setup function as kmalloc isn't available
2737   at this time.
2738  */
2739 static void __init chandev_parse_args(void)
2740 {
2741 #define CHANDEV_KEYWORD "chandev="
2742         extern char saved_command_line[];
2743         int cnt,len,paramno=1;
2744
2745         len=strlen(saved_command_line)-sizeof(CHANDEV_KEYWORD);
2746         for(cnt=0;cnt<len;cnt++)
2747         {
2748                 if(strncmp(&saved_command_line[cnt],CHANDEV_KEYWORD,
2749                            sizeof(CHANDEV_KEYWORD)-1)==0)
2750                 {
2751                         cnt+=(sizeof(CHANDEV_KEYWORD)-1);       
2752                         cnt+=chandev_setup_bootargs(&saved_command_line[cnt],paramno);
2753                         paramno++;
2754                 }
2755         }
2756 }
2757
2758 int chandev_do_setup(int in_read_conf,char *buff,int size)
2759 {
2760         int curr,comment=FALSE,newline=FALSE,oldnewline=TRUE;
2761         char *startline=NULL,*endbuff=&buff[size];
2762
2763         int lineno=0;
2764
2765         *endbuff=0;
2766         for(;buff<=endbuff;curr++,buff++)
2767         {
2768                 if(*buff==0xa||*buff==0xc||*buff==0)
2769                 {
2770                         if(*buff==0xa||*buff==0)
2771                                 lineno++;
2772                         *buff=0;
2773                         newline=TRUE;
2774                 }
2775                 else
2776                 { 
2777                         newline=FALSE;
2778                         if(*buff=='#')
2779                                 comment=TRUE;
2780                 }
2781                 if(comment==TRUE)
2782                         *buff=0;
2783                 if(startline==NULL&&isalpha(*buff))
2784                         startline=buff;
2785                 if(startline&&(buff>startline)&&(oldnewline==FALSE)&&(newline==TRUE))
2786                 {
2787                         if((chandev_setup(in_read_conf,startline," on line no",lineno))==0)
2788                                 return(-EINVAL);
2789                         startline=NULL;
2790                 }
2791                 if(newline)
2792                         comment=FALSE;
2793                 oldnewline=newline;
2794         }
2795         return(0);
2796 }
2797
2798
2799 static void chandev_read_conf(void)
2800 {
2801 #define CHANDEV_FILE "/etc/chandev.conf"
2802         struct stat statbuf;
2803         char        *buff;
2804         int         curr,left,len,fd;
2805         mm_segment_t oldfs;
2806
2807         /* if called from chandev_register_and_probe & 
2808            the driver is compiled into the kernel the
2809            parameters will need to be passed in from
2810            the kernel boot parameter line as the root
2811            fs is not mounted yet, we can't wait here.
2812         */
2813         if(in_interrupt()||current->fs->root==NULL)
2814                 return;
2815         atomic_set(&chandev_conf_read,TRUE);
2816         oldfs = get_fs();
2817         set_fs(KERNEL_DS);
2818         if(stat(CHANDEV_FILE,&statbuf)==0)
2819         {
2820                 set_fs(USER_DS);
2821                 buff=vmalloc(statbuf.st_size+1);
2822                 if(buff)
2823                 {
2824                         set_fs(KERNEL_DS);
2825                         if((fd=open(CHANDEV_FILE,O_RDONLY,0))!=-1)
2826                         {
2827                                 curr=0;
2828                                 left=statbuf.st_size;
2829                                 while((len=read(fd,&buff[curr],left))>0)
2830                                 {
2831                                         curr+=len;
2832                                         left-=len;
2833                                 }
2834                                 close(fd);
2835                         }
2836                         set_fs(USER_DS);
2837                         chandev_do_setup(TRUE,buff,statbuf.st_size);
2838                         vfree(buff);
2839                 }
2840         }
2841         set_fs(oldfs);
2842 }
2843
2844 static void chandev_read_conf_if_necessary(void)
2845 {
2846         if(in_interrupt()||current->fs->root==NULL)
2847                 return;
2848         if(!atomic_compare_and_swap(FALSE,TRUE,&chandev_conf_read))
2849                 chandev_read_conf();
2850 }
2851
2852 #ifdef CONFIG_PROC_FS
2853 #define chandev_printf(exitchan,args...)     \
2854 splen=sprintf(spbuff,##args);                \
2855 spoffset+=splen;                             \
2856 if(spoffset>offset) {                        \
2857        spbuff+=splen;                        \
2858        currlen+=splen;                       \
2859 }                                            \
2860 if(currlen>=length)                          \
2861        goto exitchan;
2862
2863 void sprintf_msck(char *buff,int auto_msck_recovery)
2864 {
2865         chandev_msck_status idx;
2866         int first_time=TRUE;
2867         buff[0]=0;
2868         for(idx=chandev_status_first_msck;idx<chandev_status_last_msck;idx++)
2869         {
2870                 if((1<<(idx-1))&auto_msck_recovery)
2871                 {
2872                         buff+=sprintf(buff,"%s%s",(first_time ? "":","),
2873                                       msck_status_strs[idx]);
2874                         first_time=FALSE;
2875                 }
2876         }
2877 }
2878
2879 static int chandev_read_proc(char *page, char **start, off_t offset,
2880                           int length, int *eof, void *data)
2881 {
2882         char *spbuff=*start=page;
2883         int    currlen=0,splen=0;
2884         off_t  spoffset=0;
2885         chandev_model_info *curr_model;
2886         chandev_noauto_range *curr_noauto;
2887         chandev_force *curr_force;
2888         chandev_activelist *curr_device;
2889         chandev_probelist  *curr_probe;
2890         chandev_msck_range *curr_msck_range;
2891         s390_dev_info_t   curr_devinfo;
2892         int pass,chandevs_detected,curr_irq,loopcnt;
2893         chandev_irqinfo *read_irqinfo,*write_irqinfo,*data_irqinfo;
2894         char buff[3][80];    
2895
2896         chandev_lock();
2897         chandev_printf(chan_exit,"\n%s\n"
2898                        "*'s for cu/dev type/models indicate don't cares\n",chandev_keydescript);
2899         chandev_printf(chan_exit,"\ncautious_auto_detect: %s\n",chandev_cautious_auto_detect ? "on":"off");
2900         chandev_printf(chan_exit,"\npersist = 0x%02x\n",chandev_persistent);
2901 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
2902         chandev_printf(chan_exit,"\nuse_devno_names: %s\n\n",chandev_use_devno_names ? "on":"off");
2903 #endif
2904         
2905         if(chandev_models_head)
2906         {
2907                 chandev_printf(chan_exit,"Channels enabled for detection\n");      
2908                 chandev_printf(chan_exit,"  chan     cu      cu     dev   dev    max     checksum  use hw  auto recovery\n");
2909                 chandev_printf(chan_exit,"  type    type    model  type  model  port_no. received   stats      type\n");
2910                 chandev_printf(chan_exit,"==============================================================================\n");
2911                 for_each(curr_model,chandev_models_head)
2912                 {
2913                         
2914                         
2915                         chandev_sprint_devinfo(buff[0],curr_model->cu_type,
2916                                                curr_model->cu_model,
2917                                                curr_model->dev_type,
2918                                                curr_model->dev_model);
2919                         sprintf_msck(buff[1],curr_model->auto_msck_recovery);
2920                         chandev_printf(chan_exit,"  0x%02x  %s%3d %s     %s     %s\n",
2921                                        curr_model->chan_type,buff[0],
2922                                        (int)curr_model->max_port_no,
2923                                        curr_model->default_checksum_received_ip_pkts ? "yes":"no ",
2924                                        curr_model->default_use_hw_stats ? "yes":"no ",
2925                                        buff[1]);         
2926                 }
2927         }
2928         
2929         if(chandev_noauto_head)
2930         {
2931                 chandev_printf(chan_exit,"\nNo auto devno ranges\n");
2932                 chandev_printf(chan_exit,"   From        To   \n");
2933                 chandev_printf(chan_exit,"====================\n");
2934                 for_each(curr_noauto,chandev_noauto_head)
2935                 {
2936                         chandev_printf(chan_exit,"  0x%04x     0x%04x\n",
2937                                        curr_noauto->lo_devno,
2938                                        curr_noauto->hi_devno);
2939                 }
2940         }
2941         if(chandev_msck_range_head)
2942         {
2943                 
2944                 chandev_printf(chan_exit,"\nAutomatic machine check recovery devno ranges\n");
2945                 chandev_printf(chan_exit,"   From        To   automatic recovery type\n");
2946                 chandev_printf(chan_exit,"===========================================\n");
2947                 for_each(curr_msck_range,chandev_msck_range_head)
2948                 {
2949                         sprintf_msck(buff[0],curr_msck_range->auto_msck_recovery);
2950                         chandev_printf(chan_exit,"  0x%04x     0x%04x %s\n",
2951                                        curr_msck_range->lo_devno,
2952                                        curr_msck_range->hi_devno,buff[0])
2953                 }
2954         }
2955         if(chandev_force_head)
2956         {
2957                 chandev_printf(chan_exit,"\nForced devices\n");
2958                 chandev_printf(chan_exit,"  chan defif read   write  data   memory      port         ip    hw   host       adapter   api\n");
2959                 chandev_printf(chan_exit,"  type  num  devno  devno  devno  usage(k) protocol no.  chksum stats name        name     name\n");
2960                 chandev_printf(chan_exit,"===============================================================================================\n");
2961                 for_each(curr_force,chandev_force_head)
2962                 {
2963                         if(curr_force->memory_usage_in_k==0)
2964                                 strcpy(buff[0],"default");
2965                         else
2966                                 sprintf(buff[0],"%6d",curr_force->memory_usage_in_k);
2967                         chandev_printf(chan_exit,"  0x%02x  %3d  0x%04x 0x%04x 0x%04x %7s       %3d       %1d    %1d%s",
2968                                        (int)curr_force->chan_type,(int)curr_force->devif_num,
2969                                        (int)curr_force->read_lo_devno,(int)curr_force->write_hi_devno,
2970                                        (int)curr_force->data_devno,buff[0],
2971                                        (int)curr_force->port_protocol_no,(int)curr_force->checksum_received_ip_pkts,
2972                                        (int)curr_force->use_hw_stats,curr_force->chan_type==chandev_type_claw ? "":"\n");
2973                         if(curr_force->chan_type==chandev_type_claw)
2974                         {
2975                                 chandev_printf(chan_exit," %9s %9s %9s\n",
2976                                                curr_force->claw.host_name,
2977                                                curr_force->claw.adapter_name,
2978                                                curr_force->claw.api_type);
2979                         }
2980
2981                 }
2982         }
2983         if(chandev_probelist_head)
2984         {
2985 #if CONFIG_ARCH_S390X
2986                 chandev_printf(chan_exit,"\nRegistered probe functions\n"
2987                                          "probefunc            shutdownfunc        msck_notfunc        chan  devices devices\n"
2988                                          "                                                             type   found  active\n"
2989                                          "==================================================================================\n");
2990 #else
2991                 chandev_printf(chan_exit,"\nRegistered probe functions\n"
2992                                          "probefunc   shutdownfunc   msck_notfunc   chan  devices devices\n"
2993                                          "                                          type   found  active\n"
2994                                          "===============================================================\n");
2995 #endif
2996                 for_each(curr_probe,chandev_probelist_head)
2997                 {
2998                         int devices_active=0;
2999                         for_each(curr_device,chandev_activelist_head)
3000                         {
3001                                 if(curr_device->probefunc==curr_probe->probefunc)
3002                                         devices_active++;
3003                         }
3004                         chandev_printf(chan_exit,"0x%p   0x%p   0x%p       0x%02x     %d      %d\n",
3005                                        curr_probe->probefunc,
3006                                        curr_probe->shutdownfunc,
3007                                        curr_probe->msck_notfunc,
3008                                        curr_probe->chan_type,
3009                                        curr_probe->devices_found,
3010                                        devices_active);
3011                 }
3012         }
3013         if(chandev_activelist_head)
3014         {
3015                 unsigned long long total_memory_usage_in_k=0;
3016                 chandev_printf(chan_exit,
3017                                "\nInitialised Devices\n"
3018                                " read   write  data  read   write  data  chan port  dev     dev         memory   read msck    write msck    data msck\n"
3019                                " irq     irq    irq  devno  devno  devno type no.   ptr     name        usage(k)  status       status        status\n"
3020                                "=====================================================================================================================\n");
3021                 /* We print this list backwards for cosmetic reasons */
3022                 for(curr_device=chandev_activelist_head;
3023                     curr_device->next!=NULL;curr_device=curr_device->next);
3024                 while(curr_device)
3025                 {
3026                         read_irqinfo=curr_device->read_irqinfo;
3027                         write_irqinfo=curr_device->write_irqinfo;
3028                         data_irqinfo=curr_device->data_irqinfo;
3029                         if(data_irqinfo)
3030                         {
3031                                 sprintf(buff[0],"0x%04x",data_irqinfo->sch.irq);
3032                                 sprintf(buff[1],"0x%04x",(int)data_irqinfo->sch.devno);
3033                         }
3034                         else
3035                         {
3036                                 strcpy(buff[0],"  n/a ");
3037                                 strcpy(buff[1],"  n/a ");
3038                         }
3039                         if(curr_device->memory_usage_in_k<0)
3040                         {
3041                                 sprintf(buff[2],"%d",(int)-curr_device->memory_usage_in_k);
3042                                 total_memory_usage_in_k-=curr_device->memory_usage_in_k;
3043                         }
3044                         else
3045                                 strcpy(buff[2],"  n/a ");
3046                         chandev_printf(chan_exit,
3047                                        "0x%04x 0x%04x %s 0x%04x 0x%04x %s 0x%02x %2d 0x%p %-10s  %6s   %-12s %-12s %-12s\n",
3048                                        read_irqinfo->sch.irq,
3049                                        write_irqinfo->sch.irq,
3050                                        buff[0],
3051                                        (int)read_irqinfo->sch.devno,
3052                                        (int)write_irqinfo->sch.devno,
3053                                        buff[1],
3054                                        curr_device->chan_type,(int)curr_device->port_no,
3055                                        curr_device->dev_ptr,curr_device->devname,
3056                                        buff[2],
3057                                        msck_status_strs[read_irqinfo->msck_status],
3058                                        msck_status_strs[write_irqinfo->msck_status],
3059                                        data_irqinfo ? msck_status_strs[data_irqinfo->msck_status] :
3060                                        "not applicable");
3061                         get_prev((list *)chandev_activelist_head,
3062                                  (list *)curr_device,
3063                                  (list **)&curr_device);
3064                 }
3065                 chandev_printf(chan_exit,"\nTotal device memory usage %Luk.\n",total_memory_usage_in_k);
3066         }
3067         chandevs_detected=FALSE;
3068         for(pass=FALSE;pass<=TRUE;pass++)
3069         {
3070                 if(pass&&chandevs_detected)
3071                 {
3072                         chandev_printf(chan_exit,"\nchannels detected\n");
3073                         chandev_printf(chan_exit,"              chan    cu    cu   dev    dev                          in chandev\n");
3074                         chandev_printf(chan_exit,"  irq  devno  type   type  model type  model pim      chpids         use  reg.\n");
3075                         chandev_printf(chan_exit,"===============================================================================\n");
3076                 }
3077                 for(curr_irq=get_irq_first(),loopcnt=0;curr_irq>=0; curr_irq=get_irq_next(curr_irq),loopcnt++)
3078                 {
3079                         if(loopcnt>0x10000)
3080                         {
3081                                 printk(KERN_ERR"chandev_read_proc detected infinite loop bug in get_irq_next\n");
3082                                 goto chan_error;
3083                         }
3084                         if(chandev_is_chandev(curr_irq,&curr_devinfo,&curr_force,&curr_model))
3085                         {
3086                                 schib_t *curr_schib;
3087                                 curr_schib=s390_get_schib(curr_irq);
3088                                 chandevs_detected=TRUE;
3089                                 if(pass)
3090                                 {
3091                                         chandev_printf(chan_exit,"0x%04x 0x%04x 0x%02x  0x%04x 0x%02x  0x%04x 0x%02x 0x%02x 0x%016Lx  %-5s%-5s\n",
3092                                                        curr_irq,curr_devinfo.devno,
3093                                                        ( curr_force ? curr_force->chan_type : 
3094                                                        ( curr_model ? curr_model->chan_type : 
3095                                                          chandev_type_none )),
3096                                                        (int)curr_devinfo.sid_data.cu_type,
3097                                                        (int)curr_devinfo.sid_data.cu_model,
3098                                                        (int)curr_devinfo.sid_data.dev_type,
3099                                                        (int)curr_devinfo.sid_data.dev_model,
3100                                                        (int)(curr_schib ? curr_schib->pmcw.pim : 0),
3101                                                        *(long long *)(curr_schib ? &curr_schib->pmcw.chpid[0] : 0),
3102                                                        (curr_devinfo.status&DEVSTAT_DEVICE_OWNED) ? "yes":"no ",
3103                                                        (chandev_get_irqinfo_by_irq(curr_irq) ? "yes":"no "));
3104                                                        
3105                                                        
3106                                 }
3107                                         
3108                         }
3109
3110                 }
3111         }
3112         if(chandev_parms_head)
3113         {
3114                 chandev_parms      *curr_parms;
3115
3116                 chandev_printf(chan_exit,"\n driver specific parameters\n");
3117                 chandev_printf(chan_exit,"chan    lo    hi      driver\n");
3118                 chandev_printf(chan_exit,"type  devno  devno  parameters\n");
3119                 chandev_printf(chan_exit,"=============================================================================\n");
3120                 for_each(curr_parms,chandev_parms_head)
3121                 {
3122                         chandev_printf(chan_exit,"0x%02x 0x%04x 0x%04x  %s\n",
3123                                        curr_parms->chan_type,(int)curr_parms->lo_devno,
3124                                        (int)curr_parms->hi_devno,curr_parms->parmstr);
3125                 }
3126         }
3127  chan_error:
3128         *eof=TRUE;
3129  chan_exit:
3130         if(currlen>length) {
3131                 /* rewind to previous printf so that we are correctly
3132                  * aligned if we get called to print another page.
3133                  */
3134                 currlen-=splen;
3135         }
3136         chandev_unlock();
3137         return(currlen);
3138 }
3139
3140
3141 static int chandev_write_proc(struct file *file, const char *buffer,
3142                            unsigned long count, void *data)
3143 {
3144         int         rc;
3145         char        *buff;
3146         
3147         if(count > 65536)
3148                 count = 65536;
3149                 
3150         buff=vmalloc(count+1);
3151         if(buff)
3152         {
3153                 rc = copy_from_user(buff,buffer,count);
3154                 if (rc)
3155                         goto chandev_write_exit;
3156                 chandev_do_setup(FALSE,buff,count);
3157                 rc=count;
3158         chandev_write_exit:
3159                 vfree(buff);
3160                 return rc;
3161         }
3162         else
3163                 return -ENOMEM;
3164         return(0);
3165 }
3166
3167 static void __init chandev_create_proc(void)
3168 {
3169         struct proc_dir_entry *dir_entry=
3170                 create_proc_entry("chandev",0644,
3171                                   &proc_root);
3172         if(dir_entry)
3173         {
3174                 dir_entry->read_proc=&chandev_read_proc;
3175                 dir_entry->write_proc=&chandev_write_proc;
3176         }
3177 }
3178
3179
3180 #endif
3181 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
3182 static  
3183 #endif
3184 int __init chandev_init(void)
3185 {
3186         atomic_set(&chandev_initialised,TRUE);
3187         chandev_parse_args();
3188         chandev_init_default_models();
3189 #if CONFIG_PROC_FS
3190         chandev_create_proc();
3191 #endif
3192         chandev_msck_task_tq.routine=
3193                 chandev_msck_task;
3194 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
3195         INIT_LIST_HEAD(&chandev_msck_task_tq.list);
3196         chandev_msck_task_tq.sync=0;
3197 #endif
3198         chandev_msck_task_tq.data=NULL;
3199         chandev_last_startmsck_list_update=chandev_last_machine_check=jiffies-HZ;
3200         atomic_set(&chandev_msck_thread_lock,1);
3201         chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;
3202         chandev_lock_cnt=0;
3203         spin_lock_init(&chandev_spinlock);
3204         spin_lock_init(&chandev_not_oper_spinlock);
3205         atomic_set(&chandev_new_msck,FALSE);
3206         return(0);
3207 }
3208 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
3209 __initcall(chandev_init);
3210 #endif
3211
3212 int chandev_register_and_probe(chandev_probefunc probefunc,
3213                                chandev_shutdownfunc shutdownfunc,
3214                                chandev_msck_notification_func msck_notfunc,
3215                                chandev_type chan_type)
3216 {
3217         chandev_probelist *new_probe,*curr_probe;
3218         /* Avoid chicked & egg situations where we may be called before we */
3219         /* are initialised. */
3220
3221         chandev_interrupt_check();
3222         if(!atomic_compare_and_swap(FALSE,TRUE,&chandev_initialised))
3223                 chandev_init();
3224         chandev_lock();
3225         for_each(curr_probe,chandev_probelist_head)
3226         {
3227                 if(curr_probe->probefunc==probefunc)
3228                 {
3229                         chandev_unlock();
3230                         printk("chandev_register_and_probe detected duplicate probefunc %p"
3231                                " for chan_type  0x%02x \n",probefunc,chan_type);
3232                         return (-EPERM);
3233                 }
3234         }
3235         chandev_unlock();
3236         if((new_probe=chandev_alloc(sizeof(chandev_probelist))))
3237         {
3238                 new_probe->probefunc=probefunc;
3239                 new_probe->shutdownfunc=shutdownfunc;
3240                 new_probe->msck_notfunc=msck_notfunc;
3241                 new_probe->chan_type=chan_type;
3242                 new_probe->devices_found=0;
3243                 chandev_add_to_list((list **)&chandev_probelist_head,new_probe);
3244                 chandev_probe();
3245         }
3246         return(new_probe ? new_probe->devices_found:-ENOMEM);
3247 }
3248
3249 void chandev_unregister(chandev_probefunc probefunc,int call_shutdown)
3250 {
3251         chandev_probelist *curr_probe;
3252         chandev_activelist *curr_device,*next_device;
3253         
3254         chandev_interrupt_check();
3255         chandev_lock();
3256         for_each(curr_probe,chandev_probelist_head)
3257         {
3258                 if(curr_probe->probefunc==probefunc)
3259                 {
3260                         for_each_allow_delete(curr_device,next_device,chandev_activelist_head)
3261                                 if(curr_device->probefunc==probefunc&&call_shutdown)
3262                                         chandev_shutdown(curr_device);
3263                         chandev_free_listmember((list **)&chandev_probelist_head,
3264                                                 (list *)curr_probe);
3265                         break;
3266                 }
3267         }
3268         chandev_unlock();
3269 }
3270
3271
3272 int chandev_persist(chandev_type chan_type)
3273 {
3274         return((chandev_persistent&chan_type) ? TRUE:FALSE);
3275 }
3276
3277 EXPORT_SYMBOL(chandev_register_and_probe);
3278 EXPORT_SYMBOL(chandev_request_irq);
3279 EXPORT_SYMBOL(chandev_unregister);
3280 EXPORT_SYMBOL(chandev_initdevice);
3281 EXPORT_SYMBOL(chandev_build_device_name);
3282 EXPORT_SYMBOL(chandev_initnetdevice);
3283 EXPORT_SYMBOL(chandev_init_netdev);
3284 EXPORT_SYMBOL(chandev_use_devno_names);
3285 EXPORT_SYMBOL(chandev_free_irq);
3286 EXPORT_SYMBOL(chandev_add_model);
3287 EXPORT_SYMBOL(chandev_del_model);
3288 EXPORT_SYMBOL(chandev_persist);
3289