1 /* CONFIG.C     (c) Copyright Jan Jaeger, 2000-2009                  */
2 /*              Device configuration functions                       */
3 
4 /*-------------------------------------------------------------------*/
5 /* The original configuration builder is now called bldcfg.c         */
6 /*-------------------------------------------------------------------*/
7 
8 #include "hstdinc.h"
9 
10 #define _CONFIG_C_
11 #define _HENGINE_DLL_
12 
13 #include "hercules.h"
14 #include "opcode.h"
15 
16 #if !defined(_GEN_ARCH)
17 
18 #if defined(_ARCHMODE3)
19  #define  _GEN_ARCH _ARCHMODE3
20  #include "config.c"
21  #undef   _GEN_ARCH
22 #endif
23 
24 #if defined(_ARCHMODE2)
25  #define  _GEN_ARCH _ARCHMODE2
26  #include "config.c"
27  #undef   _GEN_ARCH
28 #endif
29 
30 #if defined(OPTION_FISHIO)
31 #include "w32chan.h"
32 #endif // defined(OPTION_FISHIO)
33 
34 
35 /*-------------------------------------------------------------------*/
36 /* Function to terminate all CPUs and devices                        */
37 /*-------------------------------------------------------------------*/
release_config()38 void release_config()
39 {
40 DEVBLK *dev;
41 int     cpu;
42 
43     /* Deconfigure all CPU's */
44     OBTAIN_INTLOCK(NULL);
45     for (cpu = 0; cpu < MAX_CPU_ENGINES; cpu++)
46         if(IS_CPU_ONLINE(cpu))
47             deconfigure_cpu(cpu);
48     RELEASE_INTLOCK(NULL);
49 
50 #if defined(OPTION_SHARED_DEVICES)
51     /* Terminate the shared device listener thread */
52     if (sysblk.shrdtid)
53         signal_thread (sysblk.shrdtid, SIGUSR2);
54 #endif
55 
56     /* Detach all devices */
57     for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev)
58        if (dev->allocated)
59            detach_subchan(SSID_TO_LCSS(dev->ssid), dev->subchan);
60 
61 #if !defined(OPTION_FISHIO)
62     /* Terminate device threads */
63     obtain_lock (&sysblk.ioqlock);
64     sysblk.devtwait=0;
65     broadcast_condition (&sysblk.ioqcond);
66     release_lock (&sysblk.ioqlock);
67 #endif
68 
69 } /* end function release_config */
70 
71 
72 /*-------------------------------------------------------------------*/
73 /* Function to start a new CPU thread                                */
74 /* Caller MUST own the intlock                                       */
75 /*-------------------------------------------------------------------*/
configure_cpu(int cpu)76 int configure_cpu(int cpu)
77 {
78 int   i;
79 char  thread_name[16];
80 
81     if(IS_CPU_ONLINE(cpu))
82         return -1;
83 
84     snprintf(thread_name,sizeof(thread_name),"cpu%d thread",cpu);
85     thread_name[sizeof(thread_name)-1]=0;
86 
87     if ( create_thread (&sysblk.cputid[cpu], DETACHED, cpu_thread,
88                         &cpu, thread_name)
89        )
90     {
91         logmsg(_("HHCCF040E Cannot create CPU%4.4X thread: %s\n"),
92                cpu, strerror(errno));
93         return -1;
94     }
95 
96     /* Find out if we are a cpu thread */
97     for (i = 0; i < MAX_CPU_ENGINES; i++)
98         if (sysblk.cputid[i] == thread_id())
99             break;
100 
101     if (i < MAX_CPU_ENGINES)
102         sysblk.regs[i]->intwait = 1;
103 
104     /* Wait for CPU thread to initialize */
105     wait_condition (&sysblk.cpucond, &sysblk.intlock);
106 
107     if (i < MAX_CPU_ENGINES)
108         sysblk.regs[i]->intwait = 0;
109 
110     return 0;
111 } /* end function configure_cpu */
112 
113 
114 /*-------------------------------------------------------------------*/
115 /* Function to remove a CPU from the configuration                   */
116 /* This routine MUST be called with the intlock held                 */
117 /*-------------------------------------------------------------------*/
deconfigure_cpu(int cpu)118 int deconfigure_cpu(int cpu)
119 {
120 int   i;
121 
122     /* Find out if we are a cpu thread */
123     for (i = 0; i < MAX_CPU_ENGINES; i++)
124         if (sysblk.cputid[i] == thread_id())
125             break;
126 
127     /* If we're NOT trying to deconfigure ourselves */
128     if (cpu != i)
129     {
130         if (!IS_CPU_ONLINE(cpu))
131             return -1;
132 
133         /* Deconfigure CPU */
134         sysblk.regs[cpu]->configured = 0;
135         sysblk.regs[cpu]->cpustate = CPUSTATE_STOPPING;
136         ON_IC_INTERRUPT(sysblk.regs[cpu]);
137 
138         /* Wake up CPU as it may be waiting */
139         WAKEUP_CPU (sysblk.regs[cpu]);
140 
141         /* (if we're a cpu thread) */
142         if (i < MAX_CPU_ENGINES)
143             sysblk.regs[i]->intwait = 1;
144 
145         /* Wait for CPU thread to terminate */
146         wait_condition (&sysblk.cpucond, &sysblk.intlock);
147 
148         /* (if we're a cpu thread) */
149         if (i < MAX_CPU_ENGINES)
150             sysblk.regs[i]->intwait = 0;
151 
152         join_thread (sysblk.cputid[cpu], NULL);
153         detach_thread( sysblk.cputid[cpu] );
154     }
155     else
156     {
157         /* Else we ARE trying to deconfigure ourselves */
158         sysblk.regs[cpu]->configured = 0;
159         sysblk.regs[cpu]->cpustate = CPUSTATE_STOPPING;
160         ON_IC_INTERRUPT(sysblk.regs[cpu]);
161     }
162 
163     sysblk.cputid[cpu] = 0;
164 
165     return 0;
166 
167 } /* end function deconfigure_cpu */
168 
169 
170 /* 4 next functions used for fast device lookup cache management */
171 #if defined(OPTION_FAST_DEVLOOKUP)
AddDevnumFastLookup(DEVBLK * dev,U16 lcss,U16 devnum)172 static void AddDevnumFastLookup(DEVBLK *dev,U16 lcss,U16 devnum)
173 {
174     unsigned int Channel;
175     if(sysblk.devnum_fl==NULL)
176     {
177         sysblk.devnum_fl=(DEVBLK ***)malloc(sizeof(DEVBLK **)*256*FEATURE_LCSS_MAX);
178         memset(sysblk.devnum_fl,0,sizeof(DEVBLK **)*256*FEATURE_LCSS_MAX);
179     }
180     Channel=(devnum & 0xff00)>>8 | ((lcss & (FEATURE_LCSS_MAX-1))<<8);
181     if(sysblk.devnum_fl[Channel]==NULL)
182     {
183         sysblk.devnum_fl[Channel]=(DEVBLK **)malloc(sizeof(DEVBLK *)*256);
184         memset(sysblk.devnum_fl[Channel],0,sizeof(DEVBLK *)*256);
185     }
186     sysblk.devnum_fl[Channel][devnum & 0xff]=dev;
187 }
188 
189 
AddSubchanFastLookup(DEVBLK * dev,U16 ssid,U16 subchan)190 static void AddSubchanFastLookup(DEVBLK *dev,U16 ssid, U16 subchan)
191 {
192     unsigned int schw;
193 #if 0
194     logmsg(D_("DEBUG : ASFL Adding %d\n"),subchan);
195 #endif
196     if(sysblk.subchan_fl==NULL)
197     {
198         sysblk.subchan_fl=(DEVBLK ***)malloc(sizeof(DEVBLK **)*256*FEATURE_LCSS_MAX);
199         memset(sysblk.subchan_fl,0,sizeof(DEVBLK **)*256*FEATURE_LCSS_MAX);
200     }
201     schw=((subchan & 0xff00)>>8)|(SSID_TO_LCSS(ssid)<<8);
202     if(sysblk.subchan_fl[schw]==NULL)
203     {
204         sysblk.subchan_fl[schw]=(DEVBLK **)malloc(sizeof(DEVBLK *)*256);
205         memset(sysblk.subchan_fl[schw],0,sizeof(DEVBLK *)*256);
206     }
207     sysblk.subchan_fl[schw][subchan & 0xff]=dev;
208 }
209 
210 
DelDevnumFastLookup(U16 lcss,U16 devnum)211 static void DelDevnumFastLookup(U16 lcss,U16 devnum)
212 {
213     unsigned int Channel;
214     if(sysblk.devnum_fl==NULL)
215     {
216         return;
217     }
218     Channel=(devnum & 0xff00)>>8 | ((lcss & (FEATURE_LCSS_MAX-1))<<8);
219     if(sysblk.devnum_fl[Channel]==NULL)
220     {
221         return;
222     }
223     sysblk.devnum_fl[Channel][devnum & 0xff]=NULL;
224 }
225 
226 
DelSubchanFastLookup(U16 ssid,U16 subchan)227 static void DelSubchanFastLookup(U16 ssid, U16 subchan)
228 {
229     unsigned int schw;
230 #if 0
231     logmsg(D_("DEBUG : DSFL Removing %d\n"),subchan);
232 #endif
233     if(sysblk.subchan_fl==NULL)
234     {
235         return;
236     }
237     schw=((subchan & 0xff00)>>8)|(SSID_TO_LCSS(ssid) << 8);
238     if(sysblk.subchan_fl[schw]==NULL)
239     {
240         return;
241     }
242     sysblk.subchan_fl[schw][subchan & 0xff]=NULL;
243 }
244 #endif
245 
246 
get_devblk(U16 lcss,U16 devnum)247 DEVBLK *get_devblk(U16 lcss, U16 devnum)
248 {
249 DEVBLK *dev;
250 DEVBLK**dvpp;
251 
252     if(lcss >= FEATURE_LCSS_MAX)
253         lcss = 0;
254 
255     for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev)
256         if (!(dev->allocated) && dev->ssid == LCSS_TO_SSID(lcss)) break;
257 
258     if(!dev)
259     {
260         if (!(dev = (DEVBLK*)malloc(sizeof(DEVBLK))))
261         {
262             logmsg (_("HHCCF043E Cannot obtain device block\n"),
263                     strerror(errno));
264             return NULL;
265         }
266         memset (dev, 0, sizeof(DEVBLK));
267 
268         /* Initialize the device lock and conditions */
269         initialize_lock (&dev->lock);
270         initialize_condition (&dev->resumecond);
271         initialize_condition (&dev->iocond);
272 #if defined(OPTION_SCSI_TAPE)
273         initialize_condition (&dev->stape_sstat_cond);
274         InitializeListLink (&dev->stape_statrq.link);
275         InitializeListLink (&dev->stape_mntdrq.link);
276         dev->stape_statrq.dev = dev;
277         dev->stape_mntdrq.dev = dev;
278         dev->sstat = GMT_DR_OPEN(-1);
279 #endif
280 
281         /* Search for the last device block on the chain */
282         for (dvpp = &(sysblk.firstdev); *dvpp != NULL;
283             dvpp = &((*dvpp)->nextdev));
284 
285         /* Add the new device block to the end of the chain */
286         *dvpp = dev;
287 
288         dev->ssid = LCSS_TO_SSID(lcss);
289         dev->subchan = sysblk.highsubchan[lcss]++;
290     }
291 
292     /* Initialize the device block */
293     obtain_lock (&dev->lock);
294 
295     dev->group = NULL;
296     dev->member = 0;
297 
298     dev->cpuprio = sysblk.cpuprio;
299     dev->devprio = sysblk.devprio;
300     dev->hnd = NULL;
301     dev->devnum = devnum;
302     dev->chanset = lcss;
303     dev->fd = -1;
304     dev->syncio = 0;
305     dev->ioint.dev = dev;
306     dev->ioint.pending = 1;
307     dev->pciioint.dev = dev;
308     dev->pciioint.pcipending = 1;
309     dev->attnioint.dev = dev;
310     dev->attnioint.attnpending = 1;
311     dev->oslinux = sysblk.pgminttr == OS_LINUX;
312 
313     /* Initialize storage view */
314     dev->mainstor = sysblk.mainstor;
315     dev->storkeys = sysblk.storkeys;
316     dev->mainlim = sysblk.mainsize - 1;
317 
318     /* Initialize the path management control word */
319     memset (&dev->pmcw, 0, sizeof(PMCW));
320     dev->pmcw.devnum[0] = dev->devnum >> 8;
321     dev->pmcw.devnum[1] = dev->devnum & 0xFF;
322     dev->pmcw.lpm = 0x80;
323     dev->pmcw.pim = 0x80;
324     dev->pmcw.pom = 0xFF;
325     dev->pmcw.pam = 0x80;
326     dev->pmcw.chpid[0] = dev->devnum >> 8;
327 
328 #if defined(OPTION_SHARED_DEVICES)
329     dev->shrdwait = -1;
330 #endif /*defined(OPTION_SHARED_DEVICES)*/
331 
332 #ifdef _FEATURE_CHANNEL_SUBSYSTEM
333     /* Indicate a CRW is pending for this device */
334 #if defined(_370)
335     if (sysblk.arch_mode != ARCH_370)
336 #endif /*defined(_370)*/
337         dev->crwpending = 1;
338 #endif /*_FEATURE_CHANNEL_SUBSYSTEM*/
339 
340 #ifdef EXTERNALGUI
341     if ( !dev->pGUIStat )
342     {
343          dev->pGUIStat = malloc( sizeof(GUISTAT) );
344          dev->pGUIStat->pszOldStatStr = dev->pGUIStat->szStatStrBuff1;
345          dev->pGUIStat->pszNewStatStr = dev->pGUIStat->szStatStrBuff2;
346         *dev->pGUIStat->pszOldStatStr = 0;
347         *dev->pGUIStat->pszNewStatStr = 0;
348     }
349 #endif /*EXTERNALGUI*/
350 
351     /* Mark device valid */
352     dev->pmcw.flag5 |= PMCW5_V;
353     dev->allocated = 1;
354 
355     return dev;
356 }
357 
358 
ret_devblk(DEVBLK * dev)359 void ret_devblk(DEVBLK *dev)
360 {
361     /* Mark device invalid */
362     dev->allocated = 0;
363     dev->pmcw.flag5 &= ~PMCW5_V; // compat ZZ deprecated
364     release_lock(&dev->lock);
365 }
366 
367 
368 /*-------------------------------------------------------------------*/
369 /* Function to build a device configuration block                    */
370 /*-------------------------------------------------------------------*/
attach_device(U16 lcss,U16 devnum,const char * type,int addargc,char * addargv[])371 int attach_device (U16 lcss, U16 devnum, const char *type,
372                    int addargc, char *addargv[])
373 {
374 DEVBLK *dev;                            /* -> Device block           */
375 int     rc;                             /* Return code               */
376 int     i;                              /* Loop index                */
377 
378     /* Check whether device number has already been defined */
379     if (find_device_by_devnum(lcss,devnum) != NULL)
380     {
381         logmsg (_("HHCCF041E Device %d:%4.4X already exists\n"), lcss,devnum);
382         return 1;
383     }
384 
385     /* obtain device block */
386     dev = get_devblk(lcss,devnum);
387 
388     if(!(dev->hnd = hdl_ghnd(type)))
389     {
390         logmsg (_("HHCCF042E Device type %s not recognized\n"), type);
391 
392         ret_devblk(dev);
393 
394         return 1;
395     }
396 
397     dev->typname = strdup(type);
398 
399     /* Copy the arguments */
400     dev->argc = addargc;
401     if (addargc)
402     {
403         dev->argv = malloc ( addargc * sizeof(BYTE *) );
404         for (i = 0; i < addargc; i++)
405             if (addargv[i])
406                 dev->argv[i] = strdup(addargv[i]);
407             else
408                 dev->argv[i] = NULL;
409     }
410     else
411         dev->argv = NULL;
412 
413     /* Call the device handler initialization function */
414     rc = (dev->hnd->init)(dev, addargc, addargv);
415 
416     if (rc < 0)
417     {
418         logmsg (_("HHCCF044E Initialization failed for device %4.4X\n"),
419                 devnum);
420 
421         for (i = 0; i < dev->argc; i++)
422             if (dev->argv[i])
423                 free(dev->argv[i]);
424         if (dev->argv)
425             free(dev->argv);
426 
427         free(dev->typname);
428 
429         ret_devblk(dev);
430 
431         return 1;
432     }
433 
434     /* Obtain device data buffer */
435     if (dev->bufsize != 0)
436     {
437         dev->buf = malloc (dev->bufsize);
438         if (dev->buf == NULL)
439         {
440             logmsg (_("HHCCF045E Cannot obtain buffer "
441                     "for device %4.4X: %s\n"),
442                     dev->devnum, strerror(errno));
443 
444             for (i = 0; i < dev->argc; i++)
445                 if (dev->argv[i])
446                     free(dev->argv[i]);
447             if (dev->argv)
448                 free(dev->argv);
449 
450             free(dev->typname);
451 
452             ret_devblk(dev);
453 
454             return 1;
455         }
456     }
457 
458     /* Release device lock */
459     release_lock(&dev->lock);
460 
461 #ifdef _FEATURE_CHANNEL_SUBSYSTEM
462     /* Signal machine check */
463 #if defined(_370)
464     if (sysblk.arch_mode != ARCH_370)
465 #endif
466         machine_check_crwpend();
467 #endif /*_FEATURE_CHANNEL_SUBSYSTEM*/
468 
469     /*
470     if(lcss!=0 && sysblk.arch_mode==ARCH_370)
471     {
472         logmsg(_("HHCCF078W %d:%4.4X : Only devices on CSS 0 are usable in S/370 mode\n"),lcss,devnum);
473     }
474     */
475 
476     return 0;
477 } /* end function attach_device */
478 
479 
480 /*-------------------------------------------------------------------*/
481 /* Function to delete a device configuration block                   */
482 /*-------------------------------------------------------------------*/
detach_devblk(DEVBLK * dev)483 static int detach_devblk (DEVBLK *dev)
484 {
485 int     i;                              /* Loop index                */
486 
487     /* Obtain the device lock */
488     obtain_lock(&dev->lock);
489 
490 #if defined(OPTION_FAST_DEVLOOKUP)
491     DelSubchanFastLookup(dev->ssid, dev->subchan);
492     if(dev->pmcw.flag5 & PMCW5_V)
493         DelDevnumFastLookup(SSID_TO_LCSS(dev->ssid),dev->devnum);
494 #endif
495 
496     /* Close file or socket */
497     if ((dev->fd > 2) || dev->console)
498         /* Call the device close handler */
499         (dev->hnd->close)(dev);
500 
501     for (i = 0; i < dev->argc; i++)
502         if (dev->argv[i])
503             free(dev->argv[i]);
504     if (dev->argv)
505         free(dev->argv);
506 
507     free(dev->typname);
508 
509 #ifdef _FEATURE_CHANNEL_SUBSYSTEM
510     /* Indicate a CRW is pending for this device */
511 #if defined(_370)
512     if (sysblk.arch_mode != ARCH_370)
513 #endif /*defined(_370)*/
514         dev->crwpending = 1;
515 #endif /*_FEATURE_CHANNEL_SUBSYSTEM*/
516 
517     // detach all devices in group
518     if(dev->group)
519     {
520     int i;
521 
522         dev->group->memdev[dev->member] = NULL;
523 
524         if(dev->group->members)
525         {
526             dev->group->members = 0;
527 
528             for(i = 0; i < dev->group->acount; i++)
529             {
530                 if(dev->group->memdev[i] && dev->group->memdev[i]->allocated)
531                 {
532                     detach_devblk(dev->group->memdev[i]);
533                 }
534             }
535 
536             free(dev->group);
537         }
538 
539         dev->group = NULL;
540     }
541 
542     ret_devblk(dev);
543 
544     /* Zeroize the PMCW */
545     memset (&dev->pmcw, 0, sizeof(PMCW));
546 
547 #ifdef _FEATURE_CHANNEL_SUBSYSTEM
548     /* Signal machine check */
549 #if defined(_370)
550     if (sysblk.arch_mode != ARCH_370)
551 #endif
552         machine_check_crwpend();
553 #endif /*_FEATURE_CHANNEL_SUBSYSTEM*/
554 
555     return 0;
556 } /* end function detach_devblk */
557 
558 
559 /*-------------------------------------------------------------------*/
560 /* Function to delete a device configuration block by subchannel     */
561 /*-------------------------------------------------------------------*/
detach_subchan(U16 lcss,U16 subchan)562 int detach_subchan (U16 lcss, U16 subchan)
563 {
564 DEVBLK *dev;                            /* -> Device block           */
565 int    rc;
566 
567     /* Find the device block */
568     dev = find_device_by_subchan ((LCSS_TO_SSID(lcss)<<16)|subchan);
569 
570     if (dev == NULL)
571     {
572         logmsg (_("HHCCF046E Subchannel %d:%4.4X does not exist\n"), lcss, subchan);
573         return 1;
574     }
575 
576     rc = detach_devblk( dev );
577 
578     if(!rc)
579         logmsg (_("HHCCF047I Subchannel %d:%4.4X detached\n"), lcss, subchan);
580 
581     return rc;
582 }
583 
584 
585 /*-------------------------------------------------------------------*/
586 /* Function to delete a device configuration block by device number  */
587 /*-------------------------------------------------------------------*/
detach_device(U16 lcss,U16 devnum)588 int detach_device (U16 lcss,U16 devnum)
589 {
590 DEVBLK *dev;                            /* -> Device block           */
591 int    rc;
592 
593     /* Find the device block */
594     dev = find_device_by_devnum (lcss,devnum);
595 
596     if (dev == NULL)
597     {
598         logmsg (_("HHCCF046E Device %d:%4.4X does not exist\n"), lcss, devnum);
599         return 1;
600     }
601 
602     rc = detach_devblk( dev );
603 
604     if(!rc)
605         logmsg (_("HHCCF047I Device %4.4X detached\n"), devnum);
606 
607     return rc;
608 }
609 
610 
611 /*-------------------------------------------------------------------*/
612 /* Function to rename a device configuration block                   */
613 /*-------------------------------------------------------------------*/
define_device(U16 lcss,U16 olddevn,U16 newdevn)614 int define_device (U16 lcss, U16 olddevn,U16 newdevn)
615 {
616 DEVBLK *dev;                            /* -> Device block           */
617 
618     /* Find the device block */
619     dev = find_device_by_devnum (lcss, olddevn);
620 
621     if (dev == NULL)
622     {
623         logmsg (_("HHCCF048E Device %d:%4.4X does not exist\n"), lcss, olddevn);
624         return 1;
625     }
626 
627     /* Check that new device number does not already exist */
628     if (find_device_by_devnum(lcss, newdevn) != NULL)
629     {
630         logmsg (_("HHCCF049E Device %d:%4.4X already exists\n"), lcss, newdevn);
631         return 1;
632     }
633 
634     /* Obtain the device lock */
635     obtain_lock(&dev->lock);
636 
637     /* Update the device number in the DEVBLK */
638     dev->devnum = newdevn;
639 
640     /* Update the device number in the PMCW */
641     dev->pmcw.devnum[0] = newdevn >> 8;
642     dev->pmcw.devnum[1] = newdevn & 0xFF;
643 
644     /* Disable the device */
645     dev->pmcw.flag5 &= ~PMCW5_E;
646 #if defined(OPTION_FAST_DEVLOOKUP)
647     DelDevnumFastLookup(lcss,olddevn);
648     DelDevnumFastLookup(lcss,newdevn);
649 #endif
650 
651 #ifdef _FEATURE_CHANNEL_SUBSYSTEM
652     /* Indicate a CRW is pending for this device */
653 #if defined(_370)
654     if (sysblk.arch_mode != ARCH_370)
655 #endif /*defined(_370)*/
656         dev->crwpending = 1;
657 #endif /*_FEATURE_CHANNEL_SUBSYSTEM*/
658 
659     /* Release device lock */
660     release_lock(&dev->lock);
661 
662 #ifdef _FEATURE_CHANNEL_SUBSYSTEM
663     /* Signal machine check */
664 #if defined(_370)
665     if (sysblk.arch_mode != ARCH_370)
666 #endif
667         machine_check_crwpend();
668 #endif /*_FEATURE_CHANNEL_SUBSYSTEM*/
669 
670 //  logmsg (_("HHCCF050I Device %4.4X defined as %4.4X\n"),
671 //          olddevn, newdevn);
672 
673     return 0;
674 } /* end function define_device */
675 
676 
677 /*-------------------------------------------------------------------*/
678 /* Function to group devblk's belonging to one device (eg OSA, LCS)  */
679 /*                                                                   */
680 /* group_device is intended to be called from within a device        */
681 /* initialisation routine to group 1 or more devices to a logical    */
682 /* device group.                                                     */
683 /*                                                                   */
684 /* group_device will return true for the device that completes       */
685 /* the device group. (ie the last device to join the group)          */
686 /*                                                                   */
687 /* when no group exists, and device group is called with a device    */
688 /* count of zero, then no group will be created.  Otherwise          */
689 /* a new group will be created and the currently attaching device    */
690 /* will be the first in the group.                                   */
691 /*                                                                   */
692 /* when a device in a group is detached, all devices in the group    */
693 /* will be detached. The first device to be detached will enter      */
694 /* its close routine with the group intact.  Subsequent devices      */
695 /* being detached will no longer have access to previously detached  */
696 /* devices.                                                          */
697 /*                                                                   */
698 /* Example of a fixed count device group:                            */
699 /*                                                                   */
700 /* device_init(dev)                                                  */
701 /* {                                                                 */
702 /*    if( !device_group(dev, 2) )                                    */
703 /*       return 0;                                                   */
704 /*                                                                   */
705 /*    ... all devices in the group have been attached,               */
706 /*    ... group initialisation may proceed.                          */
707 /*                                                                   */
708 /* }                                                                 */
709 /*                                                                   */
710 /*                                                                   */
711 /* Variable device group example:                                    */
712 /*                                                                   */
713 /* device_init(dev)                                                  */
714 /* {                                                                 */
715 /*    if( !group_device(dev, 0) && dev->group )                      */
716 /*        return 0;                                                  */
717 /*                                                                   */
718 /*    if( !device->group )                                           */
719 /*    {                                                              */
720 /*        ... process parameters to determine number of devices      */
721 /*                                                                   */
722 /*        // Create group                                            */
723 /*        if( !group_device(dev, variable_count) )                   */
724 /*            return 0;                                              */
725 /*    }                                                              */
726 /*                                                                   */
727 /*    ... all devices in the group have been attached,               */
728 /*    ... group initialisation may proceed.                          */
729 /* }                                                                 */
730 /*                                                                   */
731 /*                                                                   */
732 /* dev->group      : pointer to DEVGRP structure or NULL             */
733 /* dev->member     : index into memdev array in DEVGRP structure for */
734 /*                 : current DEVBLK                                  */
735 /* group->members  : number of members in group                      */
736 /* group->acount   : number active members in group                  */
737 /* group->memdev[] : array of DEVBLK pointers of member devices      */
738 /*                                                                   */
739 /*                                                                   */
740 /* members will be equal to acount for a complete group              */
741 /*                                                                   */
742 /*                                                                   */
743 /* Always: (for grouped devices)                                     */
744 /*   dev->group->memdev[dev->member] == dev                          */
745 /*                                                                   */
746 /*                                                                   */
747 /*                                           Jan Jaeger, 23 Apr 2004 */
748 /*-------------------------------------------------------------------*/
group_device(DEVBLK * dev,int members)749 DLL_EXPORT int group_device(DEVBLK *dev, int members)
750 {
751 DEVBLK *tmp;
752 
753     // Find a compatible group that is incomplete
754     for (tmp = sysblk.firstdev;
755          tmp != NULL
756            && (!tmp->allocated      // not allocated
757              || !tmp->group          // not a group device
758              || strcmp(tmp->typname,dev->typname)  // unequal type
759              || (tmp->group->members == tmp->group->acount) ); // complete
760          tmp = tmp->nextdev) ;
761 
762     if(tmp)
763     {
764         // Join Group
765         dev->group = tmp->group;
766         dev->member = dev->group->acount++;
767         dev->group->memdev[dev->member] = dev;
768     }
769     else if(members)
770     {
771         // Allocate a new Group when requested
772         dev->group = malloc(sizeof(DEVGRP) + members * sizeof(DEVBLK *));
773         dev->group->members = members;
774         dev->group->acount = 1;
775         dev->group->memdev[0] = dev;
776         dev->member = 0;
777     }
778 
779     return (dev->group && (dev->group->members == dev->group->acount));
780 }
781 
782 
783 /*-------------------------------------------------------------------*/
784 /* Function to find a device block given the device number           */
785 /*-------------------------------------------------------------------*/
find_device_by_devnum(U16 lcss,U16 devnum)786 DLL_EXPORT DEVBLK *find_device_by_devnum (U16 lcss,U16 devnum)
787 {
788 DEVBLK *dev;
789 #if defined(OPTION_FAST_DEVLOOKUP)
790 DEVBLK **devtab;
791 int Chan;
792 
793     Chan=(devnum & 0xff00)>>8 | ((lcss & (FEATURE_LCSS_MAX-1))<<8);
794     if(sysblk.devnum_fl!=NULL)
795     {
796         devtab=sysblk.devnum_fl[Chan];
797         if(devtab!=NULL)
798         {
799             dev=devtab[devnum & 0xff];
800             if(dev && dev->allocated && dev->pmcw.flag5 & PMCW5_V && dev->devnum==devnum)
801             {
802                 return dev;
803             }
804             else
805             {
806                 DelDevnumFastLookup(lcss,devnum);
807             }
808         }
809     }
810 
811 #endif
812     for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev)
813         if (dev->allocated && dev->devnum == devnum && lcss==SSID_TO_LCSS(dev->ssid) && dev->pmcw.flag5 & PMCW5_V) break;
814 #if defined(OPTION_FAST_DEVLOOKUP)
815     if(dev)
816     {
817         AddDevnumFastLookup(dev,lcss,devnum);
818     }
819 #endif
820     return dev;
821 } /* end function find_device_by_devnum */
822 
823 
824 /*-------------------------------------------------------------------*/
825 /* Function to find a device block given the subchannel number       */
826 /*-------------------------------------------------------------------*/
find_device_by_subchan(U32 ioid)827 DEVBLK *find_device_by_subchan (U32 ioid)
828 {
829     U16 subchan = ioid & 0xFFFF;
830     DEVBLK *dev;
831 #if defined(OPTION_FAST_DEVLOOKUP)
832     unsigned int schw = ((subchan & 0xff00)>>8)|(IOID_TO_LCSS(ioid)<<8);
833 #if 0
834     logmsg(D_("DEBUG : FDBS FL Looking for %d\n"),subchan);
835 #endif
836     if(sysblk.subchan_fl && sysblk.subchan_fl[schw] && sysblk.subchan_fl[schw][subchan & 0xff])
837         return sysblk.subchan_fl[schw][subchan & 0xff];
838 #endif
839 #if 0
840     logmsg(D_("DEBUG : FDBS SL Looking for %8.8x\n"),ioid);
841 #endif
842     for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev)
843         if (dev->ssid == IOID_TO_SSID(ioid) && dev->subchan == subchan) break;
844 
845 #if defined(OPTION_FAST_DEVLOOKUP)
846     if(dev)
847     {
848         AddSubchanFastLookup(dev, IOID_TO_SSID(ioid), subchan);
849     }
850     else
851     {
852         DelSubchanFastLookup(IOID_TO_SSID(ioid), subchan);
853     }
854 #endif
855 
856     return dev;
857 } /* end function find_device_by_subchan */
858 
859 
860 /*-------------------------------------------------------------------*/
861 /* Returns a CPU register context for the device, or else NULL       */
862 /*-------------------------------------------------------------------*/
devregs(DEVBLK * dev)863 REGS *devregs(DEVBLK *dev)
864 {
865     /* If a register context already exists then use it */
866     if (dev->regs)
867         return dev->regs;
868 
869     /* Otherwise attempt to determine what it should be */
870     {
871         int i;
872         TID tid = thread_id();              /* Our own thread id     */
873         for (i=0; i < MAX_CPU; i++)
874             if (tid == sysblk.cputid[i])    /* Are we a cpu thread?  */
875                 return sysblk.regs[i];      /* yes, use its context  */
876     }
877     return NULL;    /* Not CPU thread. Return NULL register context  */
878 }
879 
880 
881 /*-------------------------------------------------------------------*/
882 /* Internal device parsing structures                                */
883 /*-------------------------------------------------------------------*/
884 typedef struct _DEVARRAY
885 {
886     U16 cuu1;
887     U16 cuu2;
888 } DEVARRAY;
889 
890 typedef struct _DEVNUMSDESC
891 {
892     BYTE lcss;
893     DEVARRAY *da;
894 } DEVNUMSDESC;
895 
896 
897 /*-------------------------------------------------------------------*/
898 /* Function to Parse a LCSS specification in a device number spec    */
899 /* Syntax : [lcss:]Anything...                                       */
900 /* Function args :                                                   */
901 /*               const char * spec : Parsed string                   */
902 /*               char **rest : Rest of string (or original str)      */
903 /* Returns :                                                         */
904 /*               int : 0 if not specified, 0<=n<FEATURE_LCSS_MAX     */
905 /*                     -1 Spec error                                 */
906 /*                                                                   */
907 /* If the function returns a positive value, then *rest should       */
908 /* be freed by the caller.                                           */
909 /*-------------------------------------------------------------------*/
910 
911 static int
parse_lcss(const char * spec,char ** rest,int verbose)912 parse_lcss(const char *spec,
913            char **rest,int verbose)
914 {
915     int     lcssid;
916     char    *wrk;
917     char    *lcss;
918     char    *r;
919     char    *strptr;
920     char    *garbage;
921 
922     wrk=malloc(strlen(spec)+1);
923     strcpy(wrk,spec);
924     lcss=strtok(wrk,":");
925     if(lcss==NULL)
926     {
927         if(verbose)
928         {
929             logmsg(_("HHCCF074E Unspecified error occured while parsing Logical Channel Subsystem Identification\n"));
930         }
931         free(wrk);
932         return(-1);
933     }
934     r=strtok(NULL,":");
935     if(r==NULL)
936     {
937         *rest=wrk;
938         return 0;
939     }
940     garbage=strtok(NULL,":");
941     if(garbage!=NULL)
942     {
943         if(verbose)
944         {
945             logmsg(_("HHCCF075E No more than 1 Logical Channel Subsystem Identification may be specified\n"));
946         }
947         free(wrk);
948         return(-1);
949     }
950     lcssid=strtoul(lcss,&strptr,10);
951     if(*strptr!=0)
952     {
953         if(verbose)
954         {
955             logmsg(_("HHCCF076E Non numeric Logical Channel Subsystem Identification %s\n"),lcss);
956         }
957         free(wrk);
958         return -1;
959     }
960     if(lcssid>FEATURE_LCSS_MAX)
961     {
962         if(verbose)
963         {
964             logmsg(_("HHCCF077E Logical Channel Subsystem Identification %d exceeds maximum of %d\n"),lcssid,FEATURE_LCSS_MAX-1);
965         }
966         free(wrk);
967         return -1;
968     }
969     *rest=malloc(strlen(r)+1);
970     strcpy(*rest,r);
971     free(wrk);
972     return lcssid;
973 }
974 
975 static int
parse_single_devnum__INTERNAL(const char * spec,U16 * p_lcss,U16 * p_devnum,int verbose)976 parse_single_devnum__INTERNAL(const char *spec,
977                     U16 *p_lcss,
978                     U16 *p_devnum,
979                     int verbose)
980 {
981     int rc;
982     U16     lcss;
983     char    *r;
984     char    *strptr;
985     rc=parse_lcss(spec,&r,verbose);
986     if(rc<0)
987     {
988         return -1;
989     }
990     lcss=rc;
991     rc=strtoul(r,&strptr,16);
992     if(rc<0 || rc>0xffff || *strptr!=0)
993     {
994         if(verbose)
995         {
996             logmsg(_("HHCCF055E Incorrect device address specification near character %c\n"),*strptr);
997         }
998         free(r);
999         return -1;
1000     }
1001     *p_devnum=rc;
1002     *p_lcss=lcss;
1003     return 0;
1004 }
1005 
1006 DLL_EXPORT
1007 int
parse_single_devnum(const char * spec,U16 * lcss,U16 * devnum)1008 parse_single_devnum(const char *spec,
1009                     U16 *lcss,
1010                     U16 *devnum)
1011 {
1012     return parse_single_devnum__INTERNAL(spec,lcss,devnum,1);
1013 }
1014 int
parse_single_devnum_silent(const char * spec,U16 * lcss,U16 * devnum)1015 parse_single_devnum_silent(const char *spec,
1016                     U16 *lcss,
1017                     U16 *devnum)
1018 {
1019     return parse_single_devnum__INTERNAL(spec,lcss,devnum,0);
1020 }
1021 
1022 /*-------------------------------------------------------------------*/
1023 /* Function to Parse compound device numbers                         */
1024 /* Syntax : [lcss:]CCUU[-CUU][,CUU..][.nn][...]                      */
1025 /* Examples : 200-23F                                                */
1026 /*            200,201                                                */
1027 /*            200.16                                                 */
1028 /*            200-23F,280.8                                          */
1029 /*            etc...                                                 */
1030 /* : is the LCSS id separator (only 0 or 1 allowed and it must be 1st*/
1031 /* - is the range specification (from CUU to CUU)                    */
1032 /* , is the separator                                                */
1033 /* . is the count indicator (nn is decimal)                          */
1034 /* 1st parm is the specification string as specified above           */
1035 /* 2nd parm is the address of an array of DEVARRAY                   */
1036 /* Return value : 0 - Parsing error, etc..                           */
1037 /*                >0 - Size of da                                    */
1038 /*                                                                   */
1039 /* NOTE : A basic validity check is made for the following :         */
1040 /*        All CUUs must belong on the same channel                   */
1041 /*        (this check is to eventually pave the way to a formal      */
1042 /*         channel/cu/device architecture)                           */
1043 /*        no 2 identical CCUUs                                       */
1044 /*   ex : 200,300 : WRONG                                            */
1045 /*        200.12,200.32 : WRONG                                      */
1046 /*        2FF.2 : WRONG                                              */
1047 /* NOTE : caller should free the array returned in da if the return  */
1048 /*        value is not 0                                             */
1049 /*-------------------------------------------------------------------*/
parse_devnums(const char * spec,DEVNUMSDESC * dd)1050 static size_t parse_devnums(const char *spec,DEVNUMSDESC *dd)
1051 {
1052     size_t gcount;      /* Group count                     */
1053     size_t i;           /* Index runner                    */
1054     char *grps;         /* Pointer to current devnum group */
1055     char *sc;           /* Specification string copy       */
1056     DEVARRAY *dgrs;   /* Device groups                   */
1057     U16  cuu1,cuu2;     /* CUUs                            */
1058     char *strptr;       /* strtoul ptr-ptr                 */
1059     int  basechan=0;    /* Channel for all CUUs            */
1060     int  duplicate;     /* duplicated CUU indicator        */
1061     int badcuu;         /* offending CUU                   */
1062     int rc;             /* Return code work var            */
1063 
1064     rc=parse_lcss(spec,&sc,1);
1065     if(rc<0)
1066     {
1067         return 0;
1068     }
1069     dd->lcss=rc;
1070 
1071     /* Split by ',' groups */
1072     gcount=0;
1073     grps=strtok(sc,",");
1074     dgrs=NULL;
1075     while(grps!=NULL)
1076     {
1077         if(dgrs==NULL)
1078         {
1079             dgrs=malloc(sizeof(DEVARRAY));
1080         }
1081         else
1082         {
1083             dgrs=realloc(dgrs,(sizeof(DEVARRAY))*(gcount+1));
1084         }
1085         cuu1=strtoul(grps,&strptr,16);
1086         switch(*strptr)
1087         {
1088         case 0:     /* Single CUU */
1089             cuu2=cuu1;
1090             break;
1091         case '-':   /* CUU Range */
1092             cuu2=strtoul(&strptr[1],&strptr,16);
1093             if(*strptr!=0)
1094             {
1095                 logmsg(_("HHCCF053E Incorrect second device number in device range near character %c\n"),*strptr);
1096                 free(dgrs);
1097                 free(sc);
1098                 return(0);
1099             }
1100             break;
1101         case '.':   /* CUU Count */
1102             cuu2=cuu1+strtoul(&strptr[1],&strptr,10);
1103             cuu2--;
1104             if(*strptr!=0)
1105             {
1106                 logmsg(_("HHCCF054E Incorrect Device count near character %c\n"),*strptr);
1107                 free(dgrs);
1108                 free(sc);
1109                 return(0);
1110             }
1111             break;
1112         default:
1113             logmsg(_("HHCCF055E Incorrect device address specification near character %c\n"),*strptr);
1114             free(dgrs);
1115             free(sc);
1116             return(0);
1117         }
1118         /* Check cuu1 <= cuu2 */
1119         if(cuu1>cuu2)
1120         {
1121             logmsg(_("HHCCF056E Incorrect device address range. %4.4X < %4.4X\n"),cuu2,cuu1);
1122             free(dgrs);
1123             free(sc);
1124             return(0);
1125         }
1126         if(gcount==0)
1127         {
1128             basechan=(cuu1 >> 8) & 0xff;
1129         }
1130         badcuu=-1;
1131         if(((cuu1 >> 8) & 0xff) != basechan)
1132         {
1133             badcuu=cuu1;
1134         }
1135         else
1136         {
1137             if(((cuu2 >> 8) & 0xff) != basechan)
1138             {
1139                 badcuu=cuu2;
1140             }
1141         }
1142         if(badcuu>=0)
1143         {
1144             logmsg(_("HHCCF057E %4.4X is on wrong channel (1st device defined on channel %2.2X)\n"),badcuu,basechan);
1145             free(dgrs);
1146             free(sc);
1147             return(0);
1148         }
1149         /* Check for duplicates */
1150         duplicate=0;
1151         for(i=0;i<gcount;i++)
1152         {
1153             /* check 1st cuu not within existing range */
1154             if(cuu1>=dgrs[i].cuu1 && cuu1<=dgrs[i].cuu2)
1155             {
1156                 duplicate=1;
1157                 break;
1158             }
1159             /* check 2nd cuu not within existing range */
1160             if(cuu2>=dgrs[i].cuu1 && cuu1<=dgrs[i].cuu2)
1161             {
1162                 duplicate=1;
1163                 break;
1164             }
1165             /* check current range doesn't completelly overlap existing range */
1166             if(cuu1<dgrs[i].cuu1 && cuu2>dgrs[i].cuu2)
1167             {
1168                 duplicate=1;
1169                 break;
1170             }
1171         }
1172         if(duplicate)
1173         {
1174             logmsg(_("HHCCF058E Some or all devices in %4.4X-%4.4X duplicate devices already defined\n"),cuu1,cuu2);
1175             free(dgrs);
1176             free(sc);
1177             return(0);
1178         }
1179         dgrs[gcount].cuu1=cuu1;
1180         dgrs[gcount].cuu2=cuu2;
1181         gcount++;
1182         grps=strtok(NULL,",");
1183     }
1184     free(sc);
1185     dd->da=dgrs;
1186     return(gcount);
1187 }
1188 
1189 int
parse_and_attach_devices(const char * sdevnum,const char * sdevtype,int addargc,char ** addargv)1190 parse_and_attach_devices(const char *sdevnum,
1191                         const char *sdevtype,
1192                         int  addargc,
1193                         char **addargv)
1194 {
1195         DEVNUMSDESC dnd;
1196         int         baddev;
1197         size_t      devncount;
1198         DEVARRAY    *da;
1199         int         i;
1200         U16         devnum;
1201         int         rc;
1202 
1203 #if defined(OPTION_CONFIG_SYMBOLS)
1204         int         j;
1205         char        **newargv;
1206         char        **orig_newargv;
1207 #endif
1208 
1209         devncount=parse_devnums(sdevnum,&dnd);
1210 
1211         if(devncount==0)
1212         {
1213             return -2;
1214         }
1215 
1216 #if defined(OPTION_CONFIG_SYMBOLS)
1217         newargv=malloc(MAX_ARGS*sizeof(char *));
1218         orig_newargv=malloc(MAX_ARGS*sizeof(char *));
1219 #endif /* #if defined(OPTION_CONFIG_SYMBOLS) */
1220         for(baddev=0,i=0;i<(int)devncount;i++)
1221         {
1222             da=dnd.da;
1223             for(devnum=da[i].cuu1;devnum<=da[i].cuu2;devnum++)
1224             {
1225 #if defined(OPTION_CONFIG_SYMBOLS)
1226                char wrkbfr[16];
1227                snprintf(wrkbfr,sizeof(wrkbfr),"%3.3x",devnum);
1228                set_symbol("cuu",wrkbfr);
1229                snprintf(wrkbfr,sizeof(wrkbfr),"%4.4x",devnum);
1230                set_symbol("ccuu",wrkbfr);
1231                snprintf(wrkbfr,sizeof(wrkbfr),"%3.3X",devnum);
1232                set_symbol("CUU",wrkbfr);
1233                snprintf(wrkbfr,sizeof(wrkbfr),"%4.4X",devnum);
1234                set_symbol("CCUU",wrkbfr);
1235                snprintf(wrkbfr,sizeof(wrkbfr),"%d",dnd.lcss);
1236                set_symbol("CSS",wrkbfr);
1237                for(j=0;j<addargc;j++)
1238                {
1239                    orig_newargv[j]=newargv[j]=resolve_symbol_string(addargv[j]);
1240                }
1241                 /* Build the device configuration block */
1242                rc=attach_device(dnd.lcss, devnum, sdevtype, addargc, newargv);
1243                for(j=0;j<addargc;j++)
1244                {
1245                    free(orig_newargv[j]);
1246                }
1247 #else /* #if defined(OPTION_CONFIG_SYMBOLS) */
1248                 /* Build the device configuration block (no syms) */
1249                rc=attach_device(dnd.lcss, devnum, sdevtype, addargc, addargv);
1250 #endif /* #if defined(OPTION_CONFIG_SYMBOLS) */
1251                if(rc!=0)
1252                {
1253                    baddev=1;
1254                    break;
1255                }
1256             }
1257             if(baddev)
1258             {
1259                 break;
1260             }
1261         }
1262 #if defined(OPTION_CONFIG_SYMBOLS)
1263         free(newargv);
1264         free(orig_newargv);
1265 #endif /* #if defined(OPTION_CONFIG_SYMBOLS) */
1266         free(dnd.da);
1267         return baddev?0:-1;
1268 }
1269 
1270 #define MAX_LOGO_LINES 256
1271 void
clearlogo()1272 clearlogo()
1273 {
1274     size_t i;
1275     if(sysblk.herclogo!=NULL)
1276     {
1277         for(i=0;i<sysblk.logolines;i++)
1278         {
1279             free(sysblk.herclogo[i]);
1280         }
1281         free(sysblk.herclogo);
1282         sysblk.herclogo=NULL;
1283     }
1284 }
1285 int
readlogo(char * fn)1286 readlogo(char *fn)
1287 {
1288     char    **data;
1289     char    bfr[256];
1290     char    *rec;
1291     FILE *lf;
1292 
1293     clearlogo();
1294 
1295     lf=fopen(fn,"r");
1296     if(lf==NULL)
1297     {
1298         return -1;
1299     }
1300     data=malloc(sizeof(char *)*MAX_LOGO_LINES);
1301     sysblk.logolines=0;
1302     while((rec=fgets(bfr,sizeof(bfr),lf))!=NULL)
1303     {
1304         rec[strlen(rec)-1]=0;
1305         data[sysblk.logolines]=malloc(strlen(rec)+1);
1306         strcpy(data[sysblk.logolines],rec);
1307         sysblk.logolines++;
1308         if(sysblk.logolines>MAX_LOGO_LINES)
1309         {
1310             break;
1311         }
1312     }
1313     fclose(lf);
1314     sysblk.herclogo=data;
1315     return 0;
1316 }
1317 
parse_conkpalv(char * s,int * idle,int * intv,int * cnt)1318 DLL_EXPORT int parse_conkpalv(char* s, int* idle, int* intv, int* cnt )
1319 {
1320     size_t n; char *p1, *p2, *p3, c;
1321     ASSERT(s && *s && idle && intv && cnt);
1322     if (!s || !*s || !idle || !intv || !cnt) return -1;
1323     // Format: "(idle,intv,cnt)". All numbers. No spaces.
1324     if (0
1325         || (n = strlen(s)) < 7
1326         || s[0]   != '('
1327         || s[n-1] != ')'
1328     )
1329         return -1;
1330     // 1st sub-operand
1331     if (!(p1 = strchr(s+1, ','))) return -1;
1332     c = *p1; *p1 = 0;
1333     if ( strspn( s+1, "0123456789" ) != strlen(s+1) )
1334     {
1335         *p1 = c;
1336         return -1;
1337     }
1338     *p1 = c;
1339     // 2nd sub-operand
1340     if (!(p2 = strchr(p1+1, ','))) return -1;
1341     c = *p2; *p2 = 0;
1342     if ( strspn( p1+1, "0123456789" ) != strlen(p1+1) )
1343     {
1344         *p2 = c;
1345         return -1;
1346     }
1347     *p2 = c;
1348     // 3rd sub-operand
1349     if (!(p3 = strchr(p2+1, ')'))) return -1;
1350     c = *p3; *p3 = 0;
1351     if ( strspn( p2+1, "0123456789" ) != strlen(p2+1) )
1352     {
1353         *p3 = c;
1354         return -1;
1355     }
1356     *p3 = c;
1357     // convert each to number
1358     c = *p1; *p1 = 0; *idle = atoi(s+1);  *p1 = c;
1359     c = *p2; *p2 = 0; *intv = atoi(p1+1); *p2 = c;
1360     c = *p3; *p3 = 0; *cnt  = atoi(p2+1); *p3 = c;
1361     // check results
1362     if (*idle <= 0 || INT_MAX == *idle) return -1;
1363     if (*intv <= 0 || INT_MAX == *intv) return -1;
1364     if (*cnt  <= 0 || INT_MAX == *cnt ) return -1;
1365     return 0;
1366 }
1367 
1368 #endif /*!defined(_GEN_ARCH)*/
1369