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
init_waitqueue_head(wait_queue_head_t * q)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)
netif_stop_queue(net_device * dev)243 static __inline__ void netif_stop_queue(net_device *dev)
244 {
245 dev->tbusy=1;
246 }
247
netif_start_queue(net_device * dev)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
chandev_lock(void)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
chandev_full_unlock(void)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
chandev_unlock(void)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
chandev_alloc(size_t size)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
chandev_add_to_list(list ** listhead,void * member)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
chandev_queuemember(qheader * qhead,void * member)415 static void chandev_queuemember(qheader *qhead,void *member)
416 {
417 chandev_lock();
418 enqueue_tail(qhead,(queue *)member);
419 chandev_unlock();
420 }
421
chandev_remove_from_list(list ** listhead,list * member)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
chandev_remove_from_queue(qheader * qhead,queue * member)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
chandev_free_listmember(list ** listhead,list * member)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
chandev_free_queuemember(qheader * qhead,queue * member)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
chandev_free_all_list(list ** listhead)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
chandev_free_all_queue(qheader * qhead)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
chandev_wait_for_root_fs(void)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 */
chandev_exec_start_script(void * unused)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
chandev_allocstr(const char * str,size_t offset)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
chandev_add_to_userland_notify_list(chandev_userland_notify_tag tag,char * devname,chandev_msck_status prev_status,chandev_msck_status curr_status)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
chandev_oper_func(int irq,devreg_t * dreg)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
chandev_not_oper_handler(int irq,int status)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
chandev_get_irqinfo_by_irq(int irq)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
chandev_get_by_irq(int irq)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
chandev_get_activelist_by_irq(int irq)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
chandev_remove_irqinfo_by_irq(unsigned int irq)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
chandev_add_schib_info(int irq,chandev_subchannel_info * sch)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
chandev_request_irq(unsigned int irq,void (* handler)(int,void *,struct pt_regs *),unsigned long irqflags,const char * devname,void * dev_id)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. */
chandev_free_irq(unsigned int irq,void * dev_id)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 */
chandev_free_irq_by_irqinfo(chandev_irqinfo * irqinfo)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
chandev_sprint_type_model(char * buff,s32 type,s16 model)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
chandev_sprint_devinfo(char * buff,s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model)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
chandev_remove_parms(chandev_type chan_type,int exact_match,int lo_devno)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
chandev_add_parms(chandev_type chan_type,u16 lo_devno,u16 hi_devno,char * parmstr)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
chandev_add_model(chandev_type chan_type,s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model,u8 max_port_no,int auto_msck_recovery,u8 default_checksum_received_ip_pkts,u8 default_use_hw_stats)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
chandev_remove(chandev * member)972 void chandev_remove(chandev *member)
973 {
974 chandev_free_queuemember(&chandev_head,(queue *)member);
975 }
976
977
chandev_remove_all(void)978 void chandev_remove_all(void)
979 {
980 chandev_free_all_queue(&chandev_head);
981 }
982
chandev_remove_model(chandev_model_info * model)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
chandev_remove_all_models(void)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
chandev_del_model(s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model)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
chandev_init_default_models(void)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
chandev_del_noauto(u16 devno)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
chandev_del_msck(u16 devno)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
chandev_add(s390_dev_info_t * newdevinfo,chandev_model_info * newmodelinfo)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
chandev_unregister_probe(chandev_probefunc probefunc)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
chandev_unregister_probe_by_chan_type(chandev_type chan_type)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
chandev_reset(void)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
chandev_is_chandev(int irq,s390_dev_info_t * devinfo,chandev_force ** forceinfo,chandev_model_info ** ret_model)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
chandev_collect_devices(void)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
chandev_add_force(chandev_type chan_type,s32 devif_num,u16 read_lo_devno,u16 write_hi_devno,u16 data_devno,s32 memory_usage_in_k,s16 port_protocol_no,u8 checksum_received_ip_pkts,u8 use_hw_stats,char * host_name,char * adapter_name,char * api_type)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
chandev_del_force(int read_lo_devno)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
chandev_shutdown(chandev_activelist * curr_device)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
chandev_shutdown_all(void)1306 void chandev_shutdown_all(void)
1307 {
1308 while(chandev_activelist_head)
1309 chandev_shutdown(chandev_activelist_head);
1310 }
chandev_shutdown_by_name(char * devname)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
chandev_active(u16 devno)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
chandev_shutdown_by_devno(u16 devno)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
chandev_pack_args(char * str)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
chandev_strcmp(char * teststr,char ** str,long * endlong)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
chandev_initdevice(chandev_probeinfo * probeinfo,void * dev_ptr,u8 port_no,char * devname,chandev_category category,chandev_unregfunc unreg_dev)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
chandev_build_device_name(chandev_probeinfo * probeinfo,char * destnamebuff,char * basename,int buildfullname)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)
chandev_init_netdev(chandev_probeinfo * probeinfo,char * basename,struct net_device * dev,int sizeof_priv,struct net_device * (* init_netdevfunc)(struct net_device * dev,int sizeof_priv))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)
chandev_initnetdevice(chandev_probeinfo * probeinfo,u8 port_no,struct net_device * dev,int sizeof_priv,char * basename,struct net_device * (* init_netdevfunc)(struct net_device * dev,int sizeof_priv),void (* unreg_netdevfunc)(struct net_device * dev))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
chandev_compare_chpid_info(chandev_subchannel_info * chan1,chandev_subchannel_info * chan2)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
chandev_compare_cu_dev_info(chandev_subchannel_info * chan1,chandev_subchannel_info * chan2)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
chandev_compare_subchannel_info(chandev_subchannel_info * chan1,chandev_subchannel_info * chan2)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
chandev_doprobe(chandev_force * force,chandev * read,chandev * write,chandev * data)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
chandev_request_irq_from_irqinfo(chandev_irqinfo * irqinfo,chandev * this_chandev)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
chandev_irqallocerr(chandev_irqinfo * irqinfo,int err)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
chandev_call_notification_func(chandev_activelist * curr_device,chandev_irqinfo * curr_irqinfo,chandev_msck_status prevstatus)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
chandev_find_eligible_channels(chandev * first_chandev_to_check,chandev ** read,chandev ** write,chandev ** data,chandev ** next,chandev_type chan_type)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
chandev_get_free_chandev_by_devno(int devno)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
chandev_probe(void)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
chandev_not_oper_func(int irq,int status)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
chandev_msck_thread(void * unused)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
chandev_msck_task(void * unused)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
chandev_add_noauto(u16 lo_devno,u16 hi_devno)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
chandev_add_msck_range(u16 lo_devno,u16 hi_devno,int auto_msck_recovery)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 */
chandev_get_option(char ** str,chandev_int * pint)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
chandev_get_options(char * str,int nints,chandev_int * ints)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 */
chandev_get_string(char ** instr,char ** outstr)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
chandev_setup(int in_read_conf,char * instr,char * errstr,int lineno)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="
chandev_setup_bootargs(char * str,int paramno)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 */
chandev_parse_args(void)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
chandev_do_setup(int in_read_conf,char * buff,int size)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
chandev_read_conf(void)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
chandev_read_conf_if_necessary(void)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
sprintf_msck(char * buff,int auto_msck_recovery)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
chandev_read_proc(char * page,char ** start,off_t offset,int length,int * eof,void * data)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
chandev_write_proc(struct file * file,const char * buffer,unsigned long count,void * data)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
chandev_create_proc(void)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
chandev_init(void)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
chandev_register_and_probe(chandev_probefunc probefunc,chandev_shutdownfunc shutdownfunc,chandev_msck_notification_func msck_notfunc,chandev_type chan_type)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
chandev_unregister(chandev_probefunc probefunc,int call_shutdown)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
chandev_persist(chandev_type chan_type)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
3290