source: trunk/third/sysinfo/sunos-obp.c @ 12269

Revision 12269, 40.7 KB checked in by ghudson, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12268, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 1992-1998 Michael A. Cooper.
3 * This software may be freely used and distributed provided it is not
4 * sold for profit or used in part or in whole for commercial gain
5 * without prior written agreement, and the author is credited
6 * appropriately.
7 */
8
9#ifndef lint
10static char *RCSid = "$Revision: 1.1.1.1 $";
11#endif
12
13/*
14 * Open Boot PROM (OBP) routines
15 */
16
17#include "defs.h"
18#include "sunos-kdt.h"
19#include "sunos-obp.h"
20
21#if     defined(HAVE_OPENPROM)
22
23#define OBP_IS_BOOL(tp)         (tp->Key[strlen(tp->Key)-1] == '?' \
24                                 || !tp->Value || tp->Value[0] == CNULL)
25
26/*
27 * Pointer to Tree of all OBP nodes.
28 */
29static OBPnode_t               *OBPnodeTree = NULL;
30
31/*
32 * Various declarations
33 */
34static long                     CpuClockFreq = 0;
35
36/*
37 * Function declarations
38 */
39static int                      OBPgetCPUspeed();
40
41/*
42 * Print debugging info of Prop Info
43 */
44static void OBPprintPropInfo(NodeName, Prop)
45    char                       *NodeName;
46    OBPprop_t                  *Prop;
47{
48    register OBPprop_t         *Ptr;
49
50    for (Ptr = Prop; Ptr; Ptr = Ptr->Next)
51        SImsg(SIM_DBG, "OBPpropInfo:\t<%s> <%s>=<%s>",
52              PRTS(NodeName),
53              (Ptr->Key) ? Ptr->Key : "", (Ptr->Value) ? Ptr->Value : "");
54}
55
56/*
57 * Print debugging info of OBP Node
58 */
59static void OBPprintInfo(Node)
60    OBPnode_t                  *Node;
61{
62    SImsg(SIM_DBG,
63          "OBPnode: Name=<%s> ID=<0x%x> ParentID=<0x%x> ParentName=<%s>",
64          (Node->Name) ? Node->Name : "", Node->NodeID, Node->ParentID,
65          (Node->ParentName) ? Node->ParentName : "");
66
67    if (Node->PropTable)
68        OBPprintPropInfo(Node->Name, Node->PropTable);
69
70    if (Node->Children)
71        OBPprintInfo(Node->Children);
72
73    if (Node->Next)
74        OBPprintInfo(Node->Next);
75}
76
77/*
78 * Get next OBP tree node id using "what" as what to get.
79 */
80static OBPnodeid_t OBPnodeNext(NodeID, obp_fd, What)
81    OBPnodeid_t                 NodeID;
82    int                         obp_fd;
83    int                         What;
84{
85    OBPio_t                     opio;
86    struct openpromio          *op;
87    int                        *idptr;
88
89    op = &(opio.opio_oprom);
90    idptr = (OBPnodeid_t *) (op->oprom_array);
91    memset((void *)opio.opio_buff, 0, sizeof(opio.opio_buff));
92    *idptr = NodeID;
93    op->oprom_size = sizeof(opio.opio_buff);
94
95    if (ioctl(obp_fd, What, op) < 0) {
96        SImsg(SIM_GERR, "OBP ioctl %s failed: %s.",
97              (What == OPROMNEXT) ? "OPROMNEXT" : "OPROMCHILD",
98              SYSERR);
99        return(0);
100    }
101
102    return(*((OBPnodeid_t *)op->oprom_array));
103}
104
105/*
106 * Set the property value of propname from the OBP.
107 */
108static int OBPsetPropVal(Prop, obp_fd)
109     OBPprop_t                 *Prop;
110     int                        obp_fd;
111{
112    static OBPio_t              opio;
113    struct openpromio          *op;
114    register char              *cp;
115
116    op = &(opio.opio_oprom);
117    op->oprom_size = sizeof(opio.opio_buff);
118    (void) strcpy(op->oprom_array, Prop->Key);
119
120    if (ioctl(obp_fd, OPROMGETPROP, op) < 0) {
121        SImsg(SIM_GERR, "OBP ioctl OPROMGETPROP failed for '%s': %s.",
122              Prop->Key, SYSERR);
123        return(-1);
124    }
125
126    if (op->oprom_size == -1) {
127        SImsg(SIM_DBG, "OBP no data available for '%s'.", Prop->Key);
128        return(-1);
129    }
130
131    /*
132     * Copy Raw info
133     */
134    Prop->RawLen = op->oprom_size;
135    Prop->Raw = (void *) xcalloc(1, Prop->RawLen);
136    (void) memcpy(Prop->Raw, op->oprom_array, Prop->RawLen);
137
138    /*
139     * Now create a nice ASCII String for Value.
140     * op->oprom_array points at opio.opio_buff where the results
141     * really live.
142     */
143    if (cp = DecodeVal(Prop->Key, op->oprom_array, op->oprom_size))
144        Prop->Value = strdup(cp);
145
146    return(0);
147}
148
149/*
150 * Create and copy a OBPprop_t
151 */
152static OBPprop_t *OBPcopyProp(old)
153    OBPprop_t          *old;
154{
155    OBPprop_t          *new;
156
157    new = (OBPprop_t *) xmalloc(sizeof(OBPprop_t));
158    memcpy((void *)new, (void *)old, sizeof(OBPprop_t));
159
160    return(new);
161}
162
163/*
164 * Get all OBP properties for the current OBP node and return
165 * a table of the results.
166 */
167static OBPprop_t *OBPgetProps(obp_fd, OBPpropPtr)
168    int                         obp_fd;
169    OBPprop_t                 **OBPpropPtr;
170{
171    static OBPio_t              opio;
172    struct openpromio          *op;
173    static OBPprop_t            NewProp;
174    OBPprop_t                  *PropTable;
175    register OBPprop_t         *PropPtr;
176
177    if (OBPpropPtr)
178        PropTable = *OBPpropPtr;
179    else
180        return((OBPprop_t *) NULL);
181
182    op = &(opio.opio_oprom);
183    memset((void *)opio.opio_buff, 0, sizeof(opio.opio_buff));
184
185    for ( ; ; ) {
186        /*
187         * Get next property
188         */
189        op->oprom_size = sizeof(opio.opio_buff);
190        if (ioctl(obp_fd, OPROMNXTPROP, op) < 0) {
191            SImsg(SIM_GERR, "OBP ioctl OPROMNXTPROP failed: %s.", SYSERR);
192            return((OBPprop_t *) NULL);
193        }
194
195        /*
196         * We're done
197         */
198        if (!op->oprom_size)
199            break;
200
201        (void) memset(&NewProp, 0, sizeof(NewProp));
202        NewProp.Key = strdup(op->oprom_array);
203
204        /*
205         * Set Value, Raw, RawLen
206         */
207        (void) OBPsetPropVal(&NewProp, obp_fd);
208
209        /*
210         * Add this entry to the linked list.
211         */
212        NewProp.Next = NULL;
213        if (PropTable) {
214            for (PropPtr = PropTable; PropPtr && PropPtr->Next;
215                 PropPtr = PropPtr->Next);
216            PropPtr->Next = OBPcopyProp(&NewProp);
217        } else
218            PropTable = OBPcopyProp(&NewProp);
219    }
220
221    *OBPpropPtr = PropTable;
222
223    return(PropTable);
224}
225
226/*
227 * Get info about a CPU.
228 *
229 * CpuType is the type/model to lookup.
230 * OBPprop is the OBP Property table for CpuType.
231 * Results are stored in ModelPtr, VendorPtr, FreqPtr
232 */
233static int OBPgetCPUinfo(CpuType, OBPprop, ModelPtr, VendorPtr, FreqPtr)
234    char                       *CpuType;
235    OBPprop_t                  *OBPprop;
236    char                      **ModelPtr;
237    char                      **VendorPtr;
238    long                       *FreqPtr;
239{
240    long                        ClockFreq = 0;
241    Define_t                   *Def;
242    char                       *Str;
243    char                       *Model = NULL;
244    char                       *cp;
245
246    Str = OBPfindPropVal(OBP_CLOCKFREQ, OBPprop, NULL, NULL);
247    if (Str)
248        ClockFreq = strtol(Str, (char **)NULL, 0);
249
250    /*
251     * No individual clock frequency, so we use the "global"
252     * clock freqency that (hopefully) was set earlier.
253     */
254    if (!ClockFreq)
255        ClockFreq = CpuClockFreq;
256
257    /*
258     * Set the frequency we're using so our caller can use it.
259     */
260    if (ClockFreq && FreqPtr)
261        *FreqPtr = ClockFreq;
262
263    /*
264     * If CpuType is of form 'Foo,Bar' then use 'Foo' as the Vendor
265     * and 'Bar' as the actual Model.
266     */
267    if (cp = strchr(CpuType, ',')) {
268        Model = strdup(cp + 1);
269        Str = (char *) xmalloc(cp - CpuType);
270        (void) strncpy(Str, CpuType, cp - CpuType);
271        Str[cp - CpuType] = CNULL;
272        *VendorPtr = Str;
273    }
274
275    /*
276     * Scan the CPU types table looking for an entry that has
277     * the same type name and the same clock frequency.
278     */
279    for (Def = DefGetList(DL_CPU); Def; Def = Def->Next) {
280        if (EQ(Def->KeyStr, CpuType)) {
281            if ((Def->KeyNum == 0) || (Def->KeyNum == -1) ||
282                ((ClockFreq / MHERTZ) == Def->KeyNum))
283                *ModelPtr = Def->ValStr1;
284        }
285    }
286
287    if (!*ModelPtr) {
288        /* No special CPU Definetion was found, so use the OBP value */
289        if (Model)
290            *ModelPtr = strdup(Model);          /* Without Vendor Str */
291        else
292            *ModelPtr = strdup(CpuType);
293    }
294
295    SImsg(SIM_DBG, "OBPgetCPUinfo(%s) Vendor=<%s> Model=<%s> Freq=%d",
296          PRTS(CpuType), PRTS(*VendorPtr), PRTS(*ModelPtr), *FreqPtr);
297
298    return(0);
299}
300
301/*
302 * Get a nice informative string describing OBPprop information and
303 * set the info into DevInfo.
304 */
305static void OBPsetOBPinfo(OBPprop, DevInfo)
306    OBPprop_t                  *OBPprop;
307    DevInfo_t                  *DevInfo;
308{
309    char                       *ExpName = NULL;
310    char                       *Val = NULL;
311    Define_t                   *Def;
312
313    /*
314     * Try to see if this is one of the types of OBP info
315     * that we want to use a more descriptive text than
316     * the key itself.
317     */
318    Def = DefGet(DL_OBP, OBPprop->Key, -1, 0);
319    if (Def && Def->ValStr1)
320        ExpName = Def->ValStr1;
321
322    if (!ExpName)
323        ExpName = ExpandKey(OBPprop->Key);
324
325    if (!OBP_IS_BOOL(OBPprop) && OBPprop->Value) {
326        if (EQ(OBPprop->Key, OBP_CLOCKFREQ))
327            Val = strdup(FreqStr(strtol(OBPprop->Value,
328                                        (char **)NULL, 0)));
329        else if (EQ(OBPprop->Key, OBP_ECACHESIZE) ||
330                 EQ(OBPprop->Key, OBP_DCACHESIZE))
331            Val = GetSizeStr((Large_t) strtol(OBPprop->Value,
332                                              (char **)NULL, 0), BYTES);
333        else
334            Val = OBPprop->Value;
335    }
336
337    if (OBP_IS_BOOL(OBPprop))
338        AddDevDesc(DevInfo, ExpName, "Has", DA_APPEND);
339    else
340        AddDevDesc(DevInfo, Val, ExpName, DA_APPEND);
341}
342
343/*
344 * Fix an OBP node name to be compatable with the
345 * conventions used in SunOS 5.x.
346 *
347 * i.e. All '/' characters are mapped to '_'.
348 */
349static char *OBPfixNodeName(string)
350    char                       *string;
351{
352    register char              *cp;
353    static char                 Buff[256];
354
355    (void) snprintf(Buff, sizeof(Buff), "%s", string);
356    cp = Buff;
357    while (cp = strchr(cp, '/'))
358        *cp++ = '_';
359
360    return(Buff);
361}
362
363/*
364 * Get (make) name of a CPU
365 */
366extern char *GetCpuName(ncpus, cpuid)
367    int                        *ncpus;
368    int                         cpuid;
369{
370    static char                 Buff[32];
371
372    (void) snprintf(Buff, sizeof(Buff), "cpu%d",
373                    (cpuid >= 0) ? cpuid : (*ncpus)++);
374
375    return(Buff);
376}
377
378/*
379 * Probe a CPU using OBP info.
380 */
381extern DevInfo_t *OBPprobeCPU(ProbeData, Node, TreePtr, SearchNames)
382     ProbeData_t               *ProbeData;
383     OBPnode_t                 *Node;
384     DevInfo_t                **TreePtr;
385     char                     **SearchNames;
386{
387    register OBPprop_t         *PropPtr;
388    DevInfo_t                  *DevInfo;
389    DevInfo_t                  *fdev;
390    static DevFind_t            Find;
391    register char              *cp;
392    register int                i;
393    static char                 Buff[256];
394    static int                  ncpus = 0;
395    int                         cpuid = -1;
396    char                       *CpuModel = NULL;
397    char                       *CpuModelPart = NULL;
398    char                       *CpuVendor = NULL;
399    long                        ClockFreq = 0;
400    char                       *ClockFreqStr = NULL;
401
402    /*
403     * This function may be called accidentally if a PROM/kernel node
404     * called "cpu" is found.  In such a case, we return immediately.
405     * This function should only be called explicitly.
406     */
407    if (ProbeData)
408        return((DevInfo_t *) NULL);
409
410    if (!(DevInfo = NewDevInfo(NULL)))
411        return((DevInfo_t *)NULL);
412
413    if (Debug) {
414        (void) snprintf(Buff, sizeof(Buff),  "Node ID is 0x%x", Node->NodeID);
415        AddDevDesc(DevInfo, Buff, NULL, DA_APPEND);
416    }
417
418    for (PropPtr = Node->PropTable; PropPtr; PropPtr = PropPtr->Next) {
419        /*
420         * See if this is the CPU type
421         */
422        if (EQ(OBP_NAME, PropPtr->Key)) {
423            CpuModelPart = strdup(PropPtr->Value);
424            OBPgetCPUinfo(PropPtr->Value, Node->PropTable,
425                          &CpuModel, &CpuVendor, &ClockFreq);
426            continue;
427        } else if (EQ(PropPtr->Key, OBP_CPUID) && PropPtr->Value) {
428            cpuid = (int) strtol(PropPtr->Value, (char **)NULL, 0);
429        } else if (EQ(PropPtr->Key, OBP_DEVTYPE) ||
430                   EQ(PropPtr->Key, OBP_DEVTYPE2) ||
431                   EQ(PropPtr->Key, OBP_CLOCKFREQ)) {
432            continue;
433        }
434
435        OBPsetOBPinfo(PropPtr, DevInfo);
436    }
437
438    if (cp = GetCpuName(&ncpus, cpuid))
439        DevInfo->Name = strdup(cp);
440
441    if (SearchNames && !SearchCheck(DevInfo->Name, SearchNames))
442        return((DevInfo_t *) NULL);
443
444    if (CpuVendor)
445        if (!(DevInfo->Vendor = GetVendorName(CpuVendor)))
446            DevInfo->Vendor = CpuVendor;
447    if (ClockFreq) {
448        ClockFreqStr = FreqStr(ClockFreq);
449        DevInfo->ModelDesc = strdup(ClockFreqStr);
450        AddDevDesc(DevInfo, ClockFreqStr, "Speed", DA_INSERT);
451    }
452    if (CpuModel)
453        DevInfo->Model = CpuModel;
454    /*
455     * This must be an unknown type of CPU
456     */
457    if (!DevInfo->Model)
458        DevInfo->Model = PrimeDesc(DevInfo);
459
460    DevInfo->Type = DT_CPU;
461    DevInfo->NodeID = Node->NodeID;
462
463    /*
464     * The rest of this function depends on CpuModel being available
465     * so if it's not, return what we have so far.
466     */
467    if (!CpuModel)
468        return(DevInfo);
469
470    /*
471     * If no device by our name exists try to find a device
472     * with a name which matches our CPU Model.  This should
473     * be the root device node.  If so, make our device name
474     * match the root device node name, so AddDevice() will
475     * add our info to the root device node later.
476     */
477    if (TreePtr && *TreePtr) {
478        (void) memset(&Find, 0, sizeof(Find));
479        Find.Tree = *TreePtr;
480        Find.NodeName = DevInfo->Name;
481        if (!DevFind(&Find)) {
482            Find.NodeName = CpuModelPart;
483            fdev = DevFind(&Find);
484            if (!fdev) {
485                SImsg(SIM_DBG, "Cannot find CPU device <%s>",
486                      PRTS(CpuModelPart));
487                cp = OBPfixNodeName(CpuModelPart);
488                if (!EQ(cp, CpuModelPart)) {
489                    Find.NodeName = cp;
490                    fdev = DevFind(&Find);
491                }
492            } else
493                SImsg(SIM_DBG, "Found CPU device <%s>", PRTS(CpuModelPart));
494            if (fdev && !fdev->Master)
495                DevInfo->Name = fdev->Name;
496        }
497    }
498
499    if (CpuModelPart)
500        (void) free(CpuModelPart);
501
502    return(DevInfo);
503}
504
505/*
506 * Get part description information using a model (part) name.
507 */
508static Define_t *OBPGetPart(PartName)
509    char                       *PartName;
510{
511    Define_t                   *PartList;
512    register Define_t          *Ptr;
513    register int                i;
514    register char              *cp;
515
516    PartList = DefGetList(DL_PART);
517    if (!PartList) {
518        SImsg(SIM_DBG, "No Part List found.");
519        return((Define_t *) NULL);
520    }
521
522    for (Ptr = PartList; Ptr; Ptr = Ptr->Next) {
523        if (EQN(Ptr->KeyStr, PartName, strlen(Ptr->KeyStr)))
524            return(Ptr);
525        /* Try it without the manufacturer part of part name */
526        if ((cp = strchr(Ptr->KeyStr, ',')) &&
527            EQN(++cp, PartName, strlen(cp)))
528            return(Ptr);
529    }
530
531    return((Define_t *) NULL);
532}
533
534/*
535 * This is for sun4d and sun4u platforms.
536 *
537 * If this device has a board number, then we make a "fake"
538 * device called OBP_SYSBOARD that we insert in between the
539 * Device and it's logical/current Master.
540 */
541static void OBPsetBoard(DevInfo, OBPprop, BoardNum, TreePtr, SearchNames)
542    DevInfo_t                  *DevInfo;
543    OBPprop_t                  *OBPprop;
544    int                         BoardNum;
545    DevInfo_t                 **TreePtr;
546    char                      **SearchNames;
547{
548    static char                 BoardName[64];
549    static char                 Buff[128];
550    static DevFind_t            Find;
551    char                       *What;
552    char                       *BoardType;
553    register DevInfo_t         *DevPtr;
554    register DevInfo_t         *SaveDev;
555    register DevInfo_t         *LastDev;
556    register DevInfo_t         *OldMaster = NULL;
557    register DevInfo_t         *Master = NULL;
558    DevDefine_t                *DevDefine = NULL;
559
560    if (BoardNum < 0 || !DevInfo)
561        return;
562
563    (void) snprintf(BoardName, sizeof(BoardName), "%s%d",
564                    OBP_SYSBOARD, BoardNum);
565
566    /*
567     * Find the Old Master
568     */
569    if (DevInfo->Master) {
570        (void) memset(&Find, 0, sizeof(Find));
571        Find.Tree = *TreePtr;
572        Find.NodeID = DevInfo->Master->NodeID;
573        Find.NodeName = DevInfo->Master->Name;
574        OldMaster = DevFind(&Find);
575    }
576
577    /*
578     * If the Master (sysboard) device doesn't exit, create one.
579     */
580    (void) memset(&Find, 0, sizeof(Find));
581    Find.Tree = *TreePtr;
582    Find.NodeName = BoardName;
583    if (!(Master = DevFind(&Find))) {
584        Master = NewDevInfo(NULL);
585        Master->Name = strdup(BoardName);
586        Master->Unit = BoardNum;
587        if (DevDefine = DevDefGet(OBP_SYSBOARD, 0, 0)) {
588            Master->Model = DevDefine->Model;
589            Master->ModelDesc = DevDefine->Desc;
590            Master->Type = DevDefine->Type;
591        }
592        if (OldMaster) {
593            Master->MasterName = OldMaster->Name;
594            Master->Master = OldMaster;
595        }
596        AddDevice(Master, TreePtr, SearchNames);
597    }
598
599    /*
600     * Insert sysboard between Device and it's logical Master.
601     */
602    if (OldMaster) {
603        Master->Master = OldMaster;
604
605        /*
606         * Find Device in OldMaster and remove it.
607         */
608        SaveDev = NULL;
609        for (DevPtr = OldMaster->Slaves, LastDev = DevPtr; DevPtr;
610             LastDev = DevPtr, DevPtr = DevPtr->Next) {
611
612            if (!EQ(DevPtr->Name, DevInfo->Name))
613                continue;
614
615            SaveDev = DevPtr;
616            LastDev->Next = DevPtr->Next;
617            break;
618        }
619
620        /*
621         * Add SaveDev back to new Master
622         */
623        SaveDev->Next = NULL;
624        if (Master->Slaves) {
625            for (DevPtr = Master->Slaves; DevPtr && DevPtr->Next;
626                 DevPtr = DevPtr->Next);
627            DevPtr->Next = SaveDev;
628        } else
629            Master->Slaves = SaveDev;
630    }
631
632    /*
633     * Update Device
634     */
635    if (Master) {
636        DevInfo->MasterName = Master->Name;
637        DevInfo->Master = Master;
638    }
639
640    /*
641     * If this is an FHC device (sun4u), then try to figure out more
642     * info about the type of board this is.
643     */
644    if (EQN(DevInfo->Name, OBP_FHC, strlen(OBP_FHC))) {
645        BoardType = OBPfindPropVal(OBP_BOARDTYPE, OBPprop, NULL, NULL);
646        if (BoardType) {
647            /*
648             * There are different board types:
649             *  VALUE           DESCRIPTION
650             *  mem             CPU & Memory
651             *  cpu             CPU & Memory
652             *  dual-sbus       I/O
653             *  ?               Graphics
654             */
655            if (EQ(BoardType, "mem") ||
656                EQ(BoardType, "cpu"))
657                What = "CPU & Memory";
658            else if (EQ(BoardType, "dual-sbus"))
659                What = "Sbus I/O";
660            else
661                What = NULL;
662            if (What) {
663                (void) snprintf(Buff, sizeof(Buff),  "%s Board", What);
664                Master->Model = strdup(Buff);
665            }
666        }   
667    }
668}
669
670/*
671 * Decode memory string into number of MBYTES.
672 */
673static int OBPGetMemSize(MemStr)
674    char                       *MemStr;
675{
676    register char              *cp;
677    char                       *MemBuff;
678    u_long                      Amt = 0;
679
680    if (strchr(MemStr, '.')) {
681        MemBuff = strdup(MemStr);
682        for (cp = strtok(MemBuff, "."); cp; cp = strtok((char *)NULL, "."))
683            Amt += strtol(cp, (char **) NULL, 0);
684        (void) free(MemBuff);
685    } else
686        Amt = strtol(MemStr, (char **) NULL, 0);
687
688    return(Amt / MBYTES);
689}
690
691/*
692 * Decode memory string into memory groups and add as a dev description.
693 */
694static void OBPSetMemGrps(DevInfo, MemStr)
695    DevInfo_t                  *DevInfo;
696    char                       *MemStr;
697{
698    static char                 Buff[512];
699    register char              *bPtr;
700    register char              *End;
701    char                        Str[100];
702    register char              *cp;
703    char                       *MemBuff;
704    int                         GrpNum = 0;
705
706    if (!strchr(MemStr, '.'))
707        return;
708
709    Buff[0] = CNULL;
710    bPtr = Buff;
711    End = &Buff[sizeof(Buff)-1];
712    MemBuff = strdup(MemStr);
713    for (cp = strtok(MemBuff, "."); cp && bPtr < End;
714         cp = strtok((char *)NULL, ".")) {
715        (void) snprintf(bPtr, sizeof(Buff)-(End-bPtr), "#%d=%s",
716                        GrpNum++,
717                        GetSizeStr((Large_t)
718                                   strtol(cp, (char **) NULL, 0), BYTES));
719        if (bPtr != Buff)
720            strcat(bPtr, ", ");
721        bPtr += strlen(bPtr);
722    }
723    (void) free(MemBuff);
724
725    AddDevDesc(DevInfo, Buff, "Memory Groups", DA_APPEND);
726}
727
728/*
729 * Probe an OBP node.
730 */
731extern DevInfo_t *OBPprobe(Node, TreePtr, SearchNames)
732    OBPnode_t                  *Node;
733    DevInfo_t                 **TreePtr;
734    char                      **SearchNames;
735{
736    register OBPprop_t         *PropPtr;
737    DevInfo_t                  *DevInfo = NULL;
738    DevInfo_t                  *ParentDevInfo;
739    static DevFind_t            Find;
740    register char             **cpp;
741    register char              *cp;
742    static char                 Buff[128];
743    int                         BoardNum = -1;
744    char                       *ObpModel = NULL;
745    char                       *ObpModelBase = NULL;
746    char                       *Vendor = NULL;
747    Define_t                   *PartInfo = NULL;
748    int                         MemSize = 0;
749
750    /*
751     * See if we can find the node by it's NodeID or NodeName.
752     * NodeName works for the root "system" node and a few others.
753     */
754    (void) memset(&Find, 0, sizeof(Find));
755    Find.Tree = *TreePtr;
756    Find.NodeID = Node->NodeID;
757    Find.NodeName = Node->Name;
758    DevInfo = DevFind(&Find);
759    if (!DevInfo)
760        return((DevInfo_t *)NULL);
761
762    /*
763     * Get all the info we need
764     */
765    for (PropPtr = Node->PropTable; PropPtr; PropPtr = PropPtr->Next) {
766        /*
767         * Skip these
768         */
769        if (EQ(PropPtr->Key, OBP_NAME))
770            continue;
771        else if (EQ(PropPtr->Key, OBP_MODEL))
772            ObpModel = PropPtr->Value;
773        else if (EQ(PropPtr->Key, OBP_BOARD) && PropPtr->Value)
774            BoardNum = strtol(PropPtr->Value, (char **) NULL, 0);
775        else if (EQ(PropPtr->Key, OBP_SIZE) &&
776                 EQ(Node->Name, OBP_MEMUNIT)) {
777            MemSize = OBPGetMemSize(PropPtr->Value);
778            OBPSetMemGrps(DevInfo, PropPtr->Value);
779            /*
780             * If this node has a key="keyboard" and is _NOT_ the
781             * node called "aliases", then this is the kbd parent
782             */
783        } else if (EQ(PropPtr->Key, OBP_KEYBOARD) &&
784                   !EQ(Node->Name, OBP_ALIASES)) {
785            DevInfo->Slaves = ProbeKbd((DevInfo_t **)NULL);
786        }
787
788        OBPsetOBPinfo(PropPtr, DevInfo);
789    }
790
791    /*
792     * Handle special cases
793     */
794    if (MemSize && DevInfo->Model) {
795        (void) snprintf(Buff, sizeof(Buff), "%d MB %s",
796                        MemSize, DevInfo->Model);
797        DevInfo->Model = strdup(Buff);
798    }
799    if (BoardNum >= 0)
800        OBPsetBoard(DevInfo, Node->PropTable, BoardNum, TreePtr, SearchNames);
801
802    /*
803     * Add information to existing Device.
804     */
805    if (ObpModel) {
806        /*
807         * If ObpModel is of form 'Foo,Bar' then use 'Foo' as the Vendor
808         * and 'Bar' as the actual Model.
809         */
810        if (cp = strchr(ObpModel, ',')) {
811            ObpModelBase = cp + 1;
812            Vendor = (char *) xmalloc(cp - ObpModel);
813            (void) strncpy(Vendor, ObpModel, cp - ObpModel);
814            Vendor[cp - ObpModel] = CNULL;
815            if (cp = GetVendorName(Vendor)) {
816                DevInfo->Vendor = cp;
817                (void) free(Vendor);
818            } else
819                DevInfo->Vendor = Vendor;
820        }
821
822        /*
823         * Now lookup the Part (including the Vendor part if any)
824         */
825        PartInfo = OBPGetPart(ObpModel);
826        if (PartInfo) {
827            DevInfo->Model = PartInfo->ValStr1;
828            AddDevDesc(DevInfo, PartInfo->ValStr2, NULL, DA_INSERT|DA_PRIME);
829        } else if (!DevInfo->Model)
830            DevInfo->Model = (ObpModelBase) ? ObpModelBase : ObpModel;
831    }
832
833    return((DevInfo_t *)NULL);
834}
835
836/*
837 * Check over an OBP device.
838 */
839static void OBPdevCheck(Node, TreePtr, SearchNames)
840    OBPnode_t                  *Node;
841    DevInfo_t                 **TreePtr;
842    char                      **SearchNames;
843{
844    register OBPprop_t         *PropPtr;
845    static int                  first = TRUE;
846    DevDefine_t                *DevDefine = NULL;
847    DevType_t                  *DevType = NULL;
848    ClassType_t                *ClassType = NULL;
849    DevInfo_t                  *DevInfo = NULL;
850    DevInfo_t                  *master = NULL;
851    static DevFind_t            Find;
852
853    /*
854     * Iterate over all the properties looking for interesting properties
855     * or until we find the device type.  If the device type is one which
856     * we found in our probe list, go ahead and probe it.
857     */
858    for (PropPtr = Node->PropTable; PropPtr; PropPtr = PropPtr->Next) {
859        SImsg(SIM_DBG, "OBPdevCheck:     NodeID 0x%x <%s> = <%s> (0x%x)",
860              Node->NodeID, PropPtr->Key,
861              (PropPtr->Value) ? PropPtr->Value : "",
862              (PropPtr->Value) ? atol(PropPtr->Value) : 0);
863
864        /*
865         * If this is the first node and this property is the Clock Frequency
866         * then save it for later use by the individual CPUs.
867         */
868        if (first && !CpuClockFreq && EQ(PropPtr->Key, OBP_CLOCKFREQ) &&
869            PropPtr->Value)
870            CpuClockFreq = strtol(PropPtr->Value, (char **)NULL, 0);
871
872        if (EQ(PropPtr->Key, OBP_DEVTYPE) || EQ(PropPtr->Key, OBP_DEVTYPE2)) {
873            /*
874             * OBP isn't consistant in what OBP_DEVTYPE really is so
875             * we do multiple lookups
876             */
877            DevDefine = DevDefGet(PropPtr->Value, 0, 0);
878            DevType = TypeGetByName(PropPtr->Value);
879            ClassType = ClassTypeGetByName(PropPtr->Value);
880        }
881    }
882
883    SImsg(SIM_DBG,
884          "OBPdevCheck: NodeID 0x%x Name = <%s> DevDefine.Name = <%s>",
885          Node->NodeID, (Node->Name[0]) ? Node->Name : "",
886          (DevDefine && DevDefine->Name) ? DevDefine->Name : "");
887
888    /*
889     * We use DevDefine->Probe for our own internal (obp.c) use so we
890     * need to make sure we only call the right Probe functions
891     */
892    if (DevDefine && DevDefine->Probe == OBPprobeCPU)
893        DevInfo = OBPprobeCPU((ProbeData_t *) NULL,
894                              Node, TreePtr, SearchNames);
895
896    if (!DevInfo)
897        DevInfo = OBPprobe(Node, TreePtr, SearchNames);
898
899    if (DevInfo) {
900        /*
901         * Find or create of Master
902         */
903        if (TreePtr && !DevInfo->Master) {
904            (void) memset(&Find, 0, sizeof(Find));
905            Find.NodeID = Node->ParentID;
906            Find.Tree = *TreePtr;
907            master = DevFind(&Find);
908            if (!master && Node->ParentName) {
909                master = NewDevInfo(NULL);
910                master->Name = strdup(Node->ParentName);
911                master->NodeID = Node->ParentID;
912            }
913            DevInfo->Master = master;
914        }
915        DevInfo->NodeID = Node->NodeID;
916        if (DevType && !DevInfo->Type)
917            DevInfo->Type = DevType->Type;
918        if (ClassType && !DevInfo->ClassType)
919            DevInfo->ClassType = ClassType->Type;
920        AddDevice(DevInfo, TreePtr, SearchNames);
921    }
922
923    first = FALSE;
924}
925
926/*
927 * Traverse OBP device tree and build device info
928 */
929static void OBPdevTraverse(Node, TreePtr, SearchNames)
930    OBPnode_t                  *Node;
931    DevInfo_t                 **TreePtr;
932    char                      **SearchNames;
933{
934    OBPdevCheck(Node, TreePtr, SearchNames);
935
936    if (Node->Next)
937        OBPdevTraverse(Node->Next, TreePtr, SearchNames);
938
939    if (Node->Children)
940        OBPdevTraverse(Node->Children, TreePtr, SearchNames);
941}
942
943/*
944 * Find an OBP node in Node with an ID of NodeID.
945 */
946extern OBPnode_t *OBPfindNodeByID(Node, NodeID)
947    OBPnode_t                  *Node;
948    OBPnodeid_t                 NodeID;
949{
950    OBPnode_t                  *Found = NULL;
951
952    if (!Node)
953        Node = OBPnodeTree;
954
955    if (!Node)
956        return((OBPnode_t *) NULL);
957
958    if (Node->NodeID == NodeID)
959        return(Node);
960
961    if (Node->Children)
962        if (Found = OBPfindNodeByID(Node->Children, NodeID))
963            return(Found);
964
965    if (Node->Next)
966        if (Found = OBPfindNodeByID(Node->Next, NodeID))
967            return(Found);
968
969    return((OBPnode_t *) NULL);
970}
971
972/*
973 * Find an OBP node in Node with a device type of MatchType
974 */
975static OBPnode_t *OBPfindNodeByType(Node, MatchType)
976    OBPnode_t                  *Node;
977    char                       *MatchType;
978{
979    OBPnode_t                  *Found = NULL;
980    char                       *NodeType;
981
982    if (!Node)
983        return((OBPnode_t *) NULL);
984
985    if ((NodeType = OBPfindPropVal(OBP_DEVTYPE, Node->PropTable, NULL, NULL))
986        ||
987        (NodeType = OBPfindPropVal(OBP_DEVTYPE2, Node->PropTable, NULL, NULL)))
988        if (EQ(NodeType, MatchType))
989            return(Node);
990
991    if (Node->Children)
992        if (Found = OBPfindNodeByType(Node->Children, MatchType))
993            return(Found);
994
995    if (Node->Next)
996        if (Found = OBPfindNodeByType(Node->Next, MatchType))
997            return(Found);
998
999    return((OBPnode_t *) NULL);
1000}
1001
1002/*
1003 * Find an OBP node in Node with a name of Name.
1004 */
1005static OBPnode_t *OBPfindNodeByName(Node, Name)
1006    OBPnode_t                  *Node;
1007    char                       *Name;
1008{
1009    OBPnode_t                  *Found = NULL;
1010    char                       *cp1;
1011    char                       *cp2;
1012
1013    if (!Node)
1014        return((OBPnode_t *) NULL);
1015
1016    if (EQ(Name, Node->Name))
1017        return(Node);
1018
1019    /*
1020     * Try a match by stripping out any commas found in the names.
1021     */
1022    if (cp1 = strchr(Name, ','))
1023        ++cp1;
1024    else
1025        cp1 = Name;
1026    if (cp2 = strchr(Node->Name, ','))
1027        ++cp2;
1028    else
1029        cp2 = Node->Name;
1030    if (EQ(cp1, cp2))
1031        return(Node);
1032
1033    if (Node->Children)
1034        if (Found = OBPfindNodeByName(Node->Children, Name))
1035            return(Found);
1036
1037    if (Node->Next)
1038        if (Found = OBPfindNodeByName(Node->Next, Name))
1039            return(Found);
1040
1041    return((OBPnode_t *) NULL);
1042}
1043
1044/*
1045 * Get the OBP property entry which matches "Key"
1046 * Look for Key in Table, by NodeID, or by NodeName (whichever is
1047 * not NULL).
1048 */
1049extern OBPprop_t *OBPfindProp(Key, Table, NodeID, NodeName)
1050    char                       *Key;
1051    OBPprop_t                  *Table;
1052    OBPnodeid_t                 NodeID;
1053    char                       *NodeName;
1054{
1055    register OBPprop_t         *Ptr;
1056    OBPprop_t                  *PropTable = NULL;
1057    OBPnode_t                  *Node;
1058
1059    if (Table)
1060        PropTable = Table;
1061    else if (NodeID) {
1062        if (!OBPnodeTree)
1063            OBPbuildNodeTree(&OBPnodeTree);
1064        Node = OBPfindNodeByID(OBPnodeTree, NodeID);
1065        if (Node)
1066            PropTable = Node->PropTable;
1067    } else if (NodeName) {
1068        if (!OBPnodeTree)
1069            OBPbuildNodeTree(&OBPnodeTree);
1070        Node = OBPfindNodeByName(OBPnodeTree, NodeName);
1071        if (Node)
1072            PropTable = Node->PropTable;
1073    } else
1074        return((OBPprop_t *) NULL);
1075
1076    /*
1077     * See if this node has it's own clock frequency
1078     */
1079    for (Ptr = PropTable; Ptr; Ptr = Ptr->Next)
1080        if (Ptr->Key[0] && EQ(Ptr->Key, Key))
1081            return(Ptr);
1082
1083    return((OBPprop_t *) NULL);
1084}
1085
1086/*
1087 * Front-end to OBPfindProp()
1088 */
1089extern char *OBPfindPropVal(Key, Table, NodeID, NodeName)
1090    char                       *Key;
1091    OBPprop_t                  *Table;
1092    OBPnodeid_t                 NodeID;
1093    char                       *NodeName;
1094{
1095    OBPprop_t                  *Prop;
1096
1097    if (Prop = OBPfindProp(Key, Table, NodeID, NodeName))
1098        return(Prop->Value);
1099    else
1100        return((char *) NULL);
1101}
1102
1103/*
1104 * Traverse tree of OBP I/O nodes
1105 */
1106static int OBPnodeTraverse(NodeTree, ParentID, ParentName, NodeID, obp_fd)
1107    OBPnode_t                 **NodeTree;
1108    OBPnodeid_t                 ParentID;
1109    char                       *ParentName;
1110    OBPnodeid_t                 NodeID;
1111    int                         obp_fd;
1112{
1113    OBPnodeid_t                 NewID;
1114    OBPnode_t                  *NewNode;
1115    register OBPnode_t         *NodePtr;
1116    register OBPnode_t         *Master;
1117
1118    NewNode = (OBPnode_t *) xcalloc(1, sizeof(OBPnode_t));
1119    NewNode->NodeID = NodeID;
1120    NewNode->ParentID = ParentID;
1121    NewNode->ParentName = ParentName;
1122    if (OBPgetProps(obp_fd, &(NewNode->PropTable)))
1123        NewNode->Name = OBPfindPropVal(OBP_NAME, NewNode->PropTable,
1124                                       NULL, NULL);
1125
1126    /*
1127     * Add new node to NodeTree
1128     */
1129    Master = OBPfindNodeByID(*NodeTree, ParentID);
1130    if (Master) {
1131        if (Master->Children) {
1132            for (NodePtr = Master->Children; NodePtr && NodePtr->Next;
1133                 NodePtr = NodePtr->Next);
1134            NodePtr->Next = NewNode;
1135        } else
1136            Master->Children = NewNode;
1137    } else
1138        *NodeTree = NewNode;
1139
1140    /*
1141     * Traverse Children and Peers (Next)
1142     */
1143    if (NewID = OBPnodeNext(NodeID, obp_fd, OPROMCHILD))
1144        OBPnodeTraverse(NodeTree, NewNode->NodeID, NewNode->Name,
1145                        NewID, obp_fd);
1146    if (NewID = OBPnodeNext(NodeID, obp_fd, OPROMNEXT))
1147        OBPnodeTraverse(NodeTree, ParentID, ParentName, NewID, obp_fd);
1148
1149    return(0);
1150}
1151
1152/*
1153 * Build tree of OBP nodes based on what we find using I/O calls
1154 * to the OBP device.
1155 */
1156extern int OBPbuildNodeTree(NodeTree)
1157    OBPnode_t                 **NodeTree;
1158{
1159    int                         obp_fd;
1160    int                         status;
1161
1162    if (!NodeTree) {
1163        SImsg(SIM_DBG, "OBPbuildeNodeTree: NULL NodeTree Ptr.");
1164        return(-1);
1165    }
1166
1167    /*
1168     * Note: Only one process at a time can open _PATH_OPENPROM.
1169     */
1170    if ((obp_fd = open(_PATH_OPENPROM, O_RDONLY)) < 0) {
1171        SImsg(SIM_GERR, "Cannot open \"%s\": %s.", _PATH_OPENPROM, SYSERR);
1172        return(-1);
1173    }
1174
1175    status = OBPnodeTraverse(NodeTree, (OBPnodeid_t) 0, (char *) NULL,
1176                             OBPnodeNext((OBPnodeid_t) 0, obp_fd, OPROMNEXT),
1177                             obp_fd);
1178
1179    (void) close(obp_fd);
1180
1181    if (Debug && NodeTree && *NodeTree)
1182        OBPprintInfo(*NodeTree);
1183
1184    return(status);
1185}
1186
1187/*
1188 * Build device tree from OBP device.
1189 */
1190extern int OBPbuild(TreePtr, SearchNames)
1191    DevInfo_t                 **TreePtr;
1192    char                      **SearchNames;
1193{
1194    int                         status = 0;
1195
1196    /*
1197     * Build the OBP Node Tree if it hasn't been done already.
1198     */
1199    if (!OBPnodeTree) {
1200        status = OBPbuildNodeTree(&OBPnodeTree);
1201        if (status != 0)
1202            return(status);
1203    }
1204
1205    /*
1206     * Build the device tree by walking the OBP Node Tree
1207     */
1208    OBPdevTraverse(*OBPnodeTree, TreePtr, SearchNames);
1209
1210    return(status);
1211}
1212
1213/*
1214 * Get the "ROM Version" by querying the OBP
1215 */
1216extern char *OBPgetRomVersion()
1217{
1218    static char                 Version[OPROMMAXPARAM];
1219#if     defined(OPROMGETVERSION)
1220    int                         obp_fd;
1221    struct openpromio          *op;
1222    static OBPio_t              opio;
1223
1224    /*
1225     * Note: Only one process at a time can open _PATH_OPENPROM.
1226     */
1227    if ((obp_fd = open(_PATH_OPENPROM, O_RDONLY)) < 0) {
1228        SImsg(SIM_GERR, "Cannot open \"%s\": %s.", _PATH_OPENPROM, SYSERR);
1229        return((char *) NULL);
1230    }
1231
1232    op = &(opio.opio_oprom);
1233    op->oprom_size = sizeof(opio.opio_buff);
1234
1235    if (ioctl(obp_fd, OPROMGETVERSION, op) < 0) {
1236        SImsg(SIM_GERR, "OBP ioctl OPROMGETVERSION failed: %s", SYSERR);
1237        return((char *) NULL);
1238    }
1239    (void) close(obp_fd);
1240
1241    strcpy(Version, op->oprom_array);
1242#endif  /* OPROMGETVERSION */
1243
1244    return((Version[0]) ? Version : (char *) NULL);
1245}
1246
1247/*
1248 * Get sub system model variables
1249 */
1250extern char *OBPsubSysGetVar(Variable, Params)
1251    char                       *Variable;
1252    Opaque_t                    Params;
1253{
1254    static char                *Banner;
1255    static int                  CPUspeed = 0;
1256    static int                  ClockFreq = 0;
1257    register char              *cp;
1258    register char              *End;
1259    SubSysVar_t                *SubSysVar;
1260    OBPnode_t                  *OBPtree;
1261
1262    SubSysVar = (SubSysVar_t *) Params;
1263    SubSysVar->IntVal = 0;
1264    SubSysVar->StrVal = NULL;
1265    OBPtree = SubSysVar->OBPtree;
1266
1267    if (EQ(Variable, "BannerName")) {
1268        Banner = OBPfindPropVal(OBP_BANNERNAME,
1269                                OBPtree->PropTable, NULL, NULL);
1270        if (Banner) {
1271            End = &Banner[strlen(Banner)];
1272            if (cp = strchr(Banner, '-')) {
1273                if (strncmp(cp, "-slot ", 6) == 0 && cp < End)
1274                    Banner = cp + 6;
1275                else if (strncmp(cp, "-way ", 5) == 0 && cp < End)
1276                    Banner = cp + 5;
1277            }
1278            SubSysVar->StrVal = Banner;
1279            return(Banner);
1280        }
1281    } else if (EQ(Variable, "ClockFreq")) {
1282        if (!ClockFreq) {
1283            cp = OBPfindPropVal(OBP_CLOCKFREQ, OBPtree->PropTable, NULL, NULL);
1284            if (cp)
1285                ClockFreq = (int) ((long)atoi(cp) / (long)MHERTZ);
1286            else
1287                return((char *) NULL); 
1288        }
1289        SubSysVar->IntVal = ClockFreq;
1290        SubSysVar->StrVal = itoa(ClockFreq);
1291        return(SubSysVar->StrVal);
1292    } else if (EQ(Variable, "NumCPU")) {
1293        if (cp = GetNumCpu()) {
1294            SubSysVar->IntVal = atoi(cp);
1295            SubSysVar->StrVal = cp;
1296        }
1297        return(cp);
1298    } else if (EQ(Variable, "CPUspeed")) {
1299        if (!CPUspeed)
1300            CPUspeed = OBPgetCPUspeed(OBPnodeTree);
1301        SubSysVar->IntVal = CPUspeed;
1302        SubSysVar->StrVal = itoa(CPUspeed);
1303        return(SubSysVar->StrVal);
1304    } else {
1305        SImsg(SIM_UNKN, "OBPsubSysGetVar: Unknown variable `%s'", Variable);
1306    }
1307
1308    return((char *) NULL);
1309}
1310
1311/*
1312 * Get the clock frequency from the OBP property table.
1313 */
1314static int OBPgetCPUclockfreq(PropTable)
1315    OBPprop_t                  *PropTable;
1316{
1317    char                       *ClockStr;
1318    long                        ClockFreq;
1319
1320    ClockStr = OBPfindPropVal(OBP_CLOCKFREQ, PropTable, NULL, NULL);
1321    if (!ClockStr) {
1322        SImsg(SIM_DBG, "OBPgetCPUclockfreq: Could not find CPU clockfreq.");
1323        return(0);
1324    }
1325    ClockFreq = strtol(ClockStr, (char **)NULL, 0);
1326
1327    if (ClockFreq > MHERTZ)
1328        return((int) (ClockFreq / MHERTZ));
1329    else
1330        return((int) ClockFreq);
1331}
1332
1333/*
1334 * Get the speed of any CPU (they should all be the same).
1335 */
1336static int OBPgetCPUspeed(NodeTree)
1337    OBPnode_t                  *NodeTree;
1338{
1339    OBPnode_t                  *Node;
1340    int                         Speed;
1341
1342    /*
1343     * First try to find a CPU node.
1344     */
1345    Node = OBPfindNodeByType(NodeTree, OBP_CPU);
1346    if (Node) {
1347        Speed = OBPgetCPUclockfreq(Node->PropTable);
1348        if (Speed)
1349            return(Speed);
1350    } else {
1351        SImsg(SIM_DBG, "OBPgetCPUspeed: Could not find any CPU nodes.");
1352    }
1353
1354    /*
1355     * Some machines have the clock frequency in the root node.
1356     */
1357    Speed = OBPgetCPUclockfreq(NodeTree->PropTable);
1358    if (Speed)
1359        return(Speed);
1360    else
1361        SImsg(SIM_DBG, "OBPgetCPUspeed: No clockfreq in root Node.");
1362
1363    return(0);
1364}
1365
1366/*
1367 * Set Conditionals.
1368 * Conditions are set in SubSysDef->Conditions.
1369 * If String is of form 'key=val', break apart and set Conditions.
1370 * If String is of form 'string' (no '=') and DefaultKey is set, do
1371 * backwards compatibility.
1372 */
1373Condition_t *SetCondition(SubSysDef, String, DefaultKey)
1374     Define_t                  *SubSysDef;
1375     char                      *String;
1376     char                      *DefaultKey;
1377{
1378    register char              *cp;
1379    register char              *StrKey = NULL;
1380    register char              *StrVal = NULL;
1381    Condition_t                *Cond = NULL;
1382    static Condition_t         *LastCon;
1383    static Define_t            *LastSubSysDef;
1384
1385    /*
1386     * See if this is 'key=val'
1387     */
1388    cp = strchr(String, '=');
1389    if (!cp) {
1390        if (DefaultKey) {
1391            /*
1392             * Do backwards compatibility
1393             */
1394            StrKey = DefaultKey;
1395            StrVal = String;
1396        } else
1397            return((Condition_t *) NULL);
1398    } else
1399        *cp = CNULL;
1400
1401    /*
1402     * If we've changed to a new SubSysDef, invalidate LastCon
1403     */
1404    if (LastSubSysDef && LastSubSysDef != SubSysDef)
1405        LastCon = NULL;
1406    LastSubSysDef = SubSysDef;
1407
1408    Cond = (Condition_t *) xcalloc(1, sizeof(Condition_t));
1409    if (StrKey)
1410        Cond->Key = StrKey;
1411    else
1412        Cond->Key = String;
1413    if (StrVal) {
1414        Cond->StrVal = StrVal;
1415        Cond->IntVal = atoi(StrVal);
1416    } else if (++cp) {
1417        Cond->StrVal = cp;
1418        Cond->IntVal = atoi(cp);
1419    }
1420
1421    /*
1422     * Add to end of linked list.
1423     */
1424    if (!SubSysDef->Conditions)
1425        LastCon = SubSysDef->Conditions = Cond;
1426    else {
1427        if (LastCon) {
1428            LastCon->Next = Cond;
1429            LastCon = Cond;
1430        } else
1431            LastCon = SubSysDef->Conditions = Cond;
1432    }
1433
1434    return(Cond);
1435}
1436
1437/*
1438 * Get the sub system model type.
1439 * i.e. "Ultra-1 140"
1440 */
1441extern char *OBPgetSubSysModel(SubSysDef)
1442    Define_t                   *SubSysDef;
1443{
1444    static char                 ErrBuff[128];
1445    static SubSysVar_t          SubSysVar;
1446    Condition_t                *Conditions;
1447    register Condition_t       *Cond;
1448    int                         AllMatch;
1449    register int                Argc;
1450    char                      **Argv = NULL;
1451    char                       *ExpandStr = NULL;
1452    char                       *SubSysName = NULL;
1453    int                         CPUspeedDelta = CPU_SPEED_DELTA;
1454    char                       *cp;
1455    register int                i;
1456
1457    if (SubSysDef->ValStr1)
1458        ExpandStr = SubSysDef->ValStr1;
1459    else
1460        return((char *) NULL);
1461
1462    /*
1463     * Gather info needed for comparision and use in model name expansion
1464     */
1465    if (!OBPnodeTree)
1466        OBPbuildNodeTree(&OBPnodeTree);
1467    SubSysVar.OBPtree = OBPnodeTree;
1468
1469    if (SubSysDef->Conditions) {
1470        /* Reset */
1471        for (Cond = SubSysDef->Conditions; Cond; Cond = Cond->Next)
1472            Cond->Matches = FALSE;
1473    } else {
1474        /* Initialize */
1475        /*
1476         * The first field (ValStr2) is what should be used normally.
1477         * We default to CPUspeed if there is no 'key=val' for backwards
1478         * compat.  The remaining ValStr[3-5] parse are also for backwards
1479         * compat.
1480         */
1481        if (SubSysDef->ValStr2 && *SubSysDef->ValStr2)
1482            if (Argc = StrToArgv(SubSysDef->ValStr2, " ", &Argv, NULL, 0))
1483                for (i = 0; i < Argc; ++i)
1484                    (void) SetCondition(SubSysDef, Argv[i], "CPUspeed");
1485        if (SubSysDef->ValStr3 && *SubSysDef->ValStr3)
1486            if (Argc = StrToArgv(SubSysDef->ValStr3, " ", &Argv, NULL, 0))
1487                for (i = 0; i < Argc; ++i)
1488                    (void) SetCondition(SubSysDef, Argv[i], "NumCPU");
1489        if (SubSysDef->ValStr4 && *SubSysDef->ValStr4)
1490            if (Argc = StrToArgv(SubSysDef->ValStr4, " ", &Argv, NULL, 0))
1491                for (i = 0; i < Argc; ++i)
1492                    (void) SetCondition(SubSysDef, Argv[i], "HasDev");
1493        if (SubSysDef->ValStr5 && *SubSysDef->ValStr5)
1494            if (Argc = StrToArgv(SubSysDef->ValStr5, " ", &Argv, NULL, 0))
1495                for (i = 0; i < Argc; ++i)
1496                    (void) SetCondition(SubSysDef, Argv[i], "HasType");
1497    }
1498
1499    /*
1500     * Iterate through each condition and set Matches==TRUE if condition
1501     * is met.
1502     */
1503    for (Cond = SubSysDef->Conditions; Cond; Cond = Cond->Next) {
1504        if (EQ("HasDev", Cond->Key) && Cond->StrVal) {
1505            if (OBPfindNodeByName(OBPnodeTree, Cond->StrVal))
1506                Cond->Matches = TRUE;
1507        } else if (EQ("HasType", Cond->Key) && Cond->StrVal) {
1508            if (OBPfindNodeByType(OBPnodeTree, Cond->StrVal))
1509                Cond->Matches = TRUE;
1510        } else if (EQ("CPUspeedDelta", Cond->Key) && Cond->IntVal) {
1511            /*
1512             * Set the CPUspeedDelta
1513             * This variable specifies how much leeway is given when
1514             * comparing CPUspeed (in MHz) below.
1515             */
1516            CPUspeedDelta = Cond->IntVal;
1517            /* Don't use this entry for comparisons */
1518            Cond->Flags |= CONFL_SETONLY;
1519        } else if (cp = OBPsubSysGetVar(Cond->Key, (Opaque_t) &SubSysVar)) {
1520            if (EQ("CPUspeed", Cond->Key)) {
1521                /*
1522                 * SubSysVar.IntVal is system's actual CPUspeed.
1523                 * Cond->IntVal is CPUspeed from the .cf parameter.
1524                 * CPUspeed may vary by +/- CPUspeedDelta.
1525                 */
1526                if (SubSysVar.IntVal >= (Cond->IntVal - CPUspeedDelta) &&
1527                    SubSysVar.IntVal <= (Cond->IntVal + CPUspeedDelta))
1528                    Cond->Matches = TRUE;
1529            } else if (EQ("NumCPU", Cond->Key)) {
1530                if (SubSysVar.IntVal == Cond->IntVal)
1531                    Cond->Matches = TRUE;
1532            } else if (EQ("ClockFreq", Cond->Key)) {
1533                if (Cond->IntVal == atoi(cp))
1534                    Cond->Matches = TRUE;
1535            }
1536        } else {
1537            SImsg(SIM_DBG, "%s: Bad keyword in SubSysModel rule.",
1538                  Cond->Key);
1539        }
1540    }
1541
1542    /*
1543     * If all conditions Match (are TRUE), then everything is GO.  If any ONE
1544     * item is not a Match (FALSE), then it's no GO.
1545     */
1546    for (AllMatch = TRUE, Cond = SubSysDef->Conditions; Cond;
1547         Cond = Cond->Next) {
1548        if (FLAGS_ON(Cond->Flags, CONFL_SETONLY))
1549            continue;
1550        if (!Cond->Matches) {
1551            AllMatch = FALSE;
1552            break;
1553        }
1554    }
1555
1556    /*
1557     * Expand name if needed.
1558     */
1559    if (AllMatch) {
1560        SubSysName = VarSub(ExpandStr, ErrBuff, sizeof(ErrBuff),
1561                            OBPsubSysGetVar, (Opaque_t) &SubSysVar);
1562        if (SubSysName)
1563            return(SubSysName);
1564        else
1565            SImsg(SIM_GERR, "Variable error in `%s': %s", ExpandStr, ErrBuff);
1566    }
1567
1568    return((char *) NULL);
1569}
1570
1571/*
1572 * Get system model type from OBP directly.
1573 */
1574extern char *OBPgetSysModel()
1575{
1576    int                         obp_fd;
1577    char                       *Name;
1578    char                       *SubName;
1579    static OBPprop_t           *OBPprop = NULL;
1580    register Define_t          *DefPtr;
1581    register Define_t          *SubSysDefs;
1582
1583    /*
1584     * Note: Only one process at a time can open _PATH_OPENPROM.
1585     */
1586    if ((obp_fd = open(_PATH_OPENPROM, O_RDONLY)) < 0) {
1587        SImsg(SIM_GERR, "Cannot open \"%s\": %s.", _PATH_OPENPROM, SYSERR);
1588        return((char *) NULL);
1589    }
1590
1591    /*
1592     * Position ourselves at root OBP node.
1593     */
1594    (void) OBPnodeNext((OBPnodeid_t) 0, obp_fd, OPROMNEXT);
1595
1596    /*
1597     * Get all the properties for the current node.
1598     */
1599    if (!OBPgetProps(obp_fd, &OBPprop)) {
1600        SImsg(SIM_GERR, "Get OBP Property table failed.");
1601        return((char *)NULL);
1602    }
1603
1604    (void) close(obp_fd);
1605
1606    /*
1607     * Find the root node's name
1608     */
1609    Name = OBPfindPropVal(OBP_NAME, OBPprop, NULL, NULL);
1610    if (!Name) {
1611        SImsg(SIM_GERR, "Could not find system model in OBP.");
1612        return((char *) NULL);
1613    }
1614
1615    /*
1616     * See if there is a sub system model name for this.
1617     */
1618    SubSysDefs = DefGet(DL_SUBSYSMODEL, Name, 0, 0);
1619    if (!SubSysDefs) {
1620        /* No Sub System Model defined, so we just return the base name */
1621        SImsg(SIM_DBG, "No sub system model defined for `%s'", Name);
1622        return(Name);
1623    }
1624
1625    for (DefPtr = SubSysDefs; DefPtr; DefPtr = DefPtr->Next)
1626        if (EQ(Name, DefPtr->KeyStr) && (SubName = OBPgetSubSysModel(DefPtr)))
1627            return(SubName);
1628
1629    return(Name);
1630}
1631
1632#endif  /* HAVE_OPENPROM */
Note: See TracBrowser for help on using the repository browser.