📄 chandev.c
字号:
curr_chandev=chandev_get_by_irq(curr_irqinfo->sch.irq); if(curr_chandev) { auto_msck_recovery=curr_chandev->model_info-> auto_msck_recovery; } else goto remove; for_each(curr_msck_range,chandev_msck_range_head) { if(curr_msck_range->lo_devno<= curr_irqinfo->sch.devno&& curr_msck_range->hi_devno>= curr_irqinfo->sch.devno) { auto_msck_recovery= curr_msck_range-> auto_msck_recovery; break; } } if((1<<(curr_irqinfo->msck_status-1))&auto_msck_recovery) { if(curr_irqinfo->msck_status==chandev_status_revalidate) { if((get_dev_info_by_irq(curr_irqinfo->sch.irq,&curr_devinfo)==0)) { curr_irqinfo->sch.devno=curr_devinfo.devno; curr_irqinfo->msck_status=chandev_status_good; } } else { if(curr_chandev) { /* Has the device reappeared */ if(chandev_compare_subchannel_info( &curr_chandev->sch, &curr_device->read_irqinfo->sch)|| chandev_compare_subchannel_info( &curr_chandev->sch, &curr_device->write_irqinfo->sch)|| (curr_device->data_irqinfo&& chandev_compare_subchannel_info( &curr_chandev->sch, &curr_device->data_irqinfo->sch))) { if((err=chandev_request_irq_from_irqinfo(curr_irqinfo,curr_chandev))==0) curr_irqinfo->msck_status=chandev_status_good; else chandev_irqallocerr(curr_irqinfo,err); } } } } } chandev_call_notification_func(curr_device,curr_irqinfo,prevstatus); } /* This is required because the device can go & come back */ /* even before we realize it is gone owing to the waits in our kernel threads */ /* & the device will be marked as not owned but its status will be good */ /* & an attempt to accidently reprobe it may be done. */ remove: chandev_remove(chandev_get_by_irq(curr_irqinfo->sch.irq)); } /* extra sanity */ for_each_allow_delete(curr_chandev,next_chandev,(chandev *)chandev_head.head) if(curr_chandev->owned) chandev_remove(curr_chandev); for_each(curr_force,chandev_force_head) { if(curr_force->devif_num==-2) { for_each_allow_delete2(curr_chandev,next_chandev,(chandev *)chandev_head.head) { if(chandev_find_eligible_channels(curr_chandev,&read_chandev, &write_chandev,&data_chandev, &next_chandev, curr_force->chan_type)); { if((curr_force->read_lo_devno>=read_chandev->sch.devno)&& (curr_force->write_hi_devno<=read_chandev->sch.devno)&& (curr_force->read_lo_devno>=write_chandev->sch.devno)&& (curr_force->write_hi_devno<=write_chandev->sch.devno)&& (!data_chandev||(data_chandev&& (curr_force->read_lo_devno>=data_chandev->sch.devno)&& (curr_force->write_hi_devno<=data_chandev->sch.devno)))) chandev_doprobe(curr_force,read_chandev,write_chandev, data_chandev); } } } else { read_chandev=chandev_get_free_chandev_by_devno(curr_force->read_lo_devno); if(read_chandev) { write_chandev=chandev_get_free_chandev_by_devno(curr_force->write_hi_devno); if(write_chandev) { if(curr_force->chan_type==chandev_type_qeth) { data_chandev=chandev_get_free_chandev_by_devno(curr_force->data_devno); if(data_chandev==NULL) printk("chandev_probe unable to force gigabit_ethernet driver invalid device no 0x%04x given\n",curr_force->data_devno); } else data_chandev=NULL; chandev_doprobe(curr_force,read_chandev,write_chandev, data_chandev); } } } } for_each_allow_delete(curr_chandev,next_chandev,(chandev *)chandev_head.head) { for_each(curr_noauto,chandev_noauto_head) { if(curr_chandev->sch.devno>=curr_noauto->lo_devno&& curr_chandev->sch.devno<=curr_noauto->hi_devno) { chandev_remove(curr_chandev); break; } } } for_each_allow_delete2(curr_chandev,next_chandev,(chandev *)chandev_head.head) { if(chandev_find_eligible_channels(curr_chandev,&read_chandev, &write_chandev,&data_chandev, &next_chandev, chandev_type_none)) chandev_doprobe(NULL,read_chandev,write_chandev, data_chandev); } chandev_remove_all(); chandev_unlock();}static void chandev_not_oper_func(int irq,int status){ chandev_irqinfo *curr_irqinfo; chandev_activelist *curr_device; chandev_lock(); for_each(curr_irqinfo,chandev_irqinfo_head) if(curr_irqinfo->sch.irq==irq) { chandev_msck_status prevstatus=curr_irqinfo->msck_status; switch(status) { /* Currently defined but not used in kernel */ /* Despite being in specs */ case DEVSTAT_NOT_OPER: curr_irqinfo->msck_status=chandev_status_not_oper; break;#ifdef DEVSTAT_NO_PATH /* Kernel hasn't this defined currently. */ /* Despite being in specs */ case DEVSTAT_NO_PATH: curr_irqinfo->msck_status=chandev_status_no_path; break;#endif case DEVSTAT_REVALIDATE: curr_irqinfo->msck_status=chandev_status_revalidate; break; case DEVSTAT_DEVICE_GONE: curr_irqinfo->msck_status=chandev_status_gone; break; } if((curr_device=chandev_get_activelist_by_irq(irq))) chandev_call_notification_func(curr_device,curr_irqinfo,prevstatus); else printk("chandev_not_oper_func received channel check for unowned irq %d",irq); } chandev_unlock();}static int chandev_msck_thread(void *unused){ int loopcnt,not_oper_probe_required=FALSE; wait_queue_head_t wait; chandev_not_oper_struct *new_not_oper; /* This loop exists because machine checks tend to come in groups & we have to wait for the other devnos to appear also */ init_waitqueue_head(&wait); for(loopcnt=0;loopcnt<10||(jiffies-chandev_last_machine_check)<HZ;loopcnt++) { sleep_on_timeout(&wait,HZ); } atomic_set(&chandev_msck_thread_lock,1); while(!atomic_compare_and_swap(TRUE,FALSE,&chandev_new_msck)); { chandev_probe(); } while(TRUE) { unsigned long flags; spin_lock_irqsave(&chandev_not_oper_spinlock,flags); new_not_oper=(chandev_not_oper_struct *)dequeue_head(&chandev_not_oper_head); spin_unlock_irqrestore(&chandev_not_oper_spinlock,flags); if(new_not_oper) { chandev_not_oper_func(new_not_oper->irq,new_not_oper->status); not_oper_probe_required=TRUE; kfree(new_not_oper); } else break; } if(not_oper_probe_required) chandev_probe(); return(0);}static void chandev_msck_task(void *unused){ if(kernel_thread(chandev_msck_thread,NULL,SIGCHLD)<0) { atomic_set(&chandev_msck_thread_lock,1); printk("error making chandev_msck_thread kernel thread\n"); }}static char *argstrs[]={ "noauto", "del_noauto", "ctc", "escon", "lcs", "osad", "qeth", "claw", "add_parms", "del_parms", "del_force",#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0) "use_devno_names", "dont_use_devno_names",#endif "cautious_auto_detect", "non_cautious_auto_detect", "add_model", "del_model", "auto_msck", "del_auto_msck", "del_all_models", "reset_conf_clean", "reset_conf", "shutdown", "reprobe", "unregister_probe", "unregister_probe_by_chan_type", "read_conf", "dont_read_conf", "persist"};typedef enum{ stridx_mult=256, first_stridx=0, noauto_stridx=first_stridx, del_noauto_stridx, ctc_stridx, escon_stridx, lcs_stridx, osad_stridx, qeth_stridx, claw_stridx, add_parms_stridx, del_parms_stridx, del_force_stridx,#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0) use_devno_names_stridx, dont_use_devno_names_stridx,#endif cautious_auto_detect_stridx, non_cautious_auto_detect_stridx, add_model_stridx, del_model_stridx, auto_msck_stridx, del_auto_msck_stridx, del_all_models_stridx, reset_conf_clean_stridx, reset_conf_stridx, shutdown_stridx, reprobe_stridx, unregister_probe_stridx, unregister_probe_by_chan_type_stridx, read_conf_stridx, dont_read_conf_stridx, persist_stridx, last_stridx,} chandev_str_enum;void chandev_add_noauto(u16 lo_devno,u16 hi_devno){ chandev_noauto_range *new_range; if((new_range=chandev_alloc(sizeof(chandev_noauto_range)))) { new_range->lo_devno=lo_devno; new_range->hi_devno=hi_devno; chandev_add_to_list((list **)&chandev_noauto_head,new_range); }}void chandev_add_msck_range(u16 lo_devno,u16 hi_devno,int auto_msck_recovery){ chandev_msck_range *new_range; if((new_range=chandev_alloc(sizeof(chandev_msck_range)))) { new_range->lo_devno=lo_devno; new_range->hi_devno=hi_devno; new_range->auto_msck_recovery=auto_msck_recovery; chandev_add_to_list((list **)&chandev_msck_range_head,new_range); }}static char chandev_keydescript[]="\nchan_type key bitfield ctc=0x1,escon=0x2,lcs=0x4,osad=0x8,qeth=0x10,claw=0x20\n";#if CONFIG_ARCH_S390X/* We need this as we sometimes use this to evaluate pointers */typedef long chandev_int; #elsetypedef int chandev_int;#endif#if (LINUX_VERSION_CODE<KERNEL_VERSION(2,3,0)) || (CONFIG_ARCH_S390X)/* * Read an int from an option string; if available accept a subsequent * comma as well. * * Return values: * 0 : no int in string * 1 : int found, no subsequent comma * 2 : int found including a subsequent comma */static chandev_int chandev_get_option(char **str,chandev_int *pint){ char *cur = *str; if (!cur || !(*cur)) return 0; *pint = simple_strtol(cur,str,0); if (cur==*str) return 0; if (**str==',') { (*str)++; return 2; } return 1;}static char *chandev_get_options(char *str, int nints, chandev_int *ints){ int res,i=1; while (i<nints) { res = chandev_get_option(&str, ints+i); if (res==0) break; i++; if (res==1) break; } ints[0] = i-1; return(str);}#else#define chandev_get_option get_option#define chandev_get_options get_options#endif/* * Read an string from an option string; if available accept a subsequent * comma as well & set this comma to a null character when returning the string. * * Return values: * 0 : no string found * 1 : string found, no subsequent comma * 2 : string found including a subsequent comma */static int chandev_get_string(char **instr,char **outstr){ char *cur = *instr; if (!cur ||*cur==0) { *outstr=NULL; return 0; } *outstr=*instr; for(;;) { if(*(++cur)==',') { *cur=0; *instr=cur+1; return 2; } else if(*cur==0) { *instr=cur+1; return 1; } }}static int chandev_setup(int in_read_conf,char *instr,char *errstr,int lineno){ chandev_strval val=isnull; chandev_str_enum stridx; long endlong; chandev_type chan_type; char *str,*currstr,*interpretstr=NULL; int cnt,strcnt; int retval=0;#define CHANDEV_MAX_EXTRA_INTS 12 chandev_int ints[CHANDEV_MAX_EXTRA_INTS+1]; currstr=alloca(strlen(instr)+1); strcpy(currstr,instr); strcnt=chandev_pack_args(currstr); for(cnt=1;cnt<=strcnt;cnt++) { interpretstr=currstr; memset(ints,0,sizeof(ints)); for(stridx=first_stridx;stridx<last_stridx;stridx++) { str=currstr; if((val=chandev_strcmp(argstrs[stridx],&str,&endlong))) break; } currstr=str; if(val) { val=(((chandev_strval)stridx)*stridx_mult)+(val&~isstr); switch(val) { case (add_parms_stridx*stridx_mult)|iscomma: currstr=chandev_get_options(currstr,4,ints); if(*currstr&&ints[0]>=1) { if(ints[0]==1) { ints[2]=0; ints[3]=0xffff; } else if(ints[0]==2) ints[3]=ints[2]; chandev_add_parms(ints[1],ints[2],ints[3],currstr); goto NextOption; } else goto BadArgs; break; case (claw_stridx*stridx_mult)|isnum|iscomma: case (claw_stridx*stridx_mult)|iscomma: currstr=chandev_get_options(str,6,ints); break; default: if(val&iscomma) currstr=chandev_get_options(str,CHANDEV_MAX_EXTRA_INTS,ints); break; } switch(val) { case noauto_stridx*stridx_mult: case (noauto_stridx*stridx_mult)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -