chandev.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:88k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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