11898Shueston /*
21898Shueston * CDDL HEADER START
31898Shueston *
41898Shueston * The contents of this file are subject to the terms of the
51898Shueston * Common Development and Distribution License (the "License").
61898Shueston * You may not use this file except in compliance with the License.
71898Shueston *
81898Shueston * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91898Shueston * or http://www.opensolaris.org/os/licensing.
101898Shueston * See the License for the specific language governing permissions
111898Shueston * and limitations under the License.
121898Shueston *
131898Shueston * When distributing Covered Code, include this CDDL HEADER in each
141898Shueston * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151898Shueston * If applicable, add the following below this CDDL HEADER, with the
161898Shueston * fields enclosed by brackets "[]" replaced with your own identifying
171898Shueston * information: Portions Copyright [yyyy] [name of copyright owner]
181898Shueston *
191898Shueston * CDDL HEADER END
201898Shueston */
211898Shueston
221898Shueston /*
23*11583SSurya.Prakki@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
241898Shueston * Use is subject to license terms.
251898Shueston */
261898Shueston
271898Shueston /*
281898Shueston * SUNW,OPL-Enterprise platform ioboard topology enumerator
291898Shueston */
301898Shueston #include <string.h>
311898Shueston #include <strings.h>
321898Shueston #include <libdevinfo.h>
331898Shueston #include <fm/topo_mod.h>
343062Scindi #include <fm/topo_hc.h>
351898Shueston #include <sys/fm/protocol.h>
361898Shueston #include "opl_topo.h"
371898Shueston
381898Shueston #define IOB_ENUMR_VERS 1
391898Shueston #define FRUNAME "iou"
401898Shueston #define LABEL FRUNAME "#%d"
411898Shueston #define IOBDFRU "hc:///component=" LABEL
421898Shueston
436297Sjl139090 #define IKKAKU_FRUNAME "MBU_A"
446297Sjl139090 #define IKKAKU_LABEL IKKAKU_FRUNAME
456297Sjl139090 #define IKKAKU_IOBDFRU "hc:///component=" IKKAKU_LABEL
466297Sjl139090
471898Shueston static int opl_iob_enum(topo_mod_t *hdl, tnode_t *parent, const char *name,
483062Scindi topo_instance_t imin, topo_instance_t imax, void *notused1, void *notused2);
491898Shueston
503062Scindi static const topo_modops_t Iobops =
513062Scindi { opl_iob_enum, NULL };
523062Scindi
533062Scindi static const topo_modinfo_t IobInfo = {
541898Shueston IOBOARD,
553062Scindi FM_FMRI_SCHEME_HC,
561898Shueston IOB_ENUMR_VERS,
573062Scindi &Iobops};
581898Shueston
596297Sjl139090 /* OPL model type */
606297Sjl139090 typedef enum {
616297Sjl139090 MODEL_FF,
626297Sjl139090 MODEL_DC,
636297Sjl139090 MODEL_IKKAKU
646297Sjl139090 } opl_model_t;
656297Sjl139090
661898Shueston void
_topo_init(topo_mod_t * modhdl)671898Shueston _topo_init(topo_mod_t *modhdl)
681898Shueston {
691898Shueston /*
701898Shueston * Turn on module debugging output
711898Shueston */
721898Shueston if (getenv("TOPOIOBDBG") != NULL)
733062Scindi topo_mod_setdebug(modhdl);
741898Shueston topo_mod_dprintf(modhdl, "initializing ioboard enumerator\n");
751898Shueston
76*11583SSurya.Prakki@Sun.COM (void) topo_mod_register(modhdl, &IobInfo, TOPO_VERSION);
771898Shueston }
781898Shueston
791898Shueston void
_topo_fini(topo_mod_t * modhdl)801898Shueston _topo_fini(topo_mod_t *modhdl)
811898Shueston {
821898Shueston topo_mod_unregister(modhdl);
831898Shueston }
841898Shueston
851898Shueston /*
861898Shueston * Checks to see if there's a physical board number property on this
871898Shueston * device node.
881898Shueston */
891898Shueston static int
opl_get_physical_board(topo_mod_t * mod,di_node_t n)903062Scindi opl_get_physical_board(topo_mod_t *mod, di_node_t n)
911898Shueston {
923062Scindi di_prom_handle_t ptp = DI_PROM_HANDLE_NIL;
931898Shueston di_prom_prop_t pp = DI_PROM_PROP_NIL;
941898Shueston uchar_t *buf;
951898Shueston int val;
961898Shueston
973062Scindi if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL)
983062Scindi return (-1);
992499Shueston
1003062Scindi for (pp = di_prom_prop_next(ptp, n, pp);
1011898Shueston pp != DI_PROM_PROP_NIL;
1023062Scindi pp = di_prom_prop_next(ptp, n, pp)) {
1031898Shueston if (strcmp(di_prom_prop_name(pp), OPL_PHYSICAL_BD) == 0) {
1041898Shueston if (di_prom_prop_data(pp, &buf) < sizeof (val))
1051898Shueston continue;
1061898Shueston bcopy(buf, &val, sizeof (val));
1071898Shueston return (val);
1081898Shueston }
1091898Shueston }
1101898Shueston return (-1);
1111898Shueston }
1121898Shueston
1131898Shueston /*
1141898Shueston * Creates a map of logical boards to physical location.
1151898Shueston */
1161898Shueston static void
opl_map_boards(topo_mod_t * mod,di_node_t opl_devtree,int lsb_to_psb[OPL_IOB_MAX])1173062Scindi opl_map_boards(topo_mod_t *mod, di_node_t opl_devtree,
1183062Scindi int lsb_to_psb[OPL_IOB_MAX])
1191898Shueston {
1201898Shueston di_node_t n;
1211898Shueston int i;
1221898Shueston
1231898Shueston /* Initialize all entries to no mapping */
1241898Shueston for (i = 0; i < OPL_IOB_MAX; i++) {
1251898Shueston lsb_to_psb[i] = i;
1261898Shueston }
1271898Shueston /*
1281898Shueston * Get LSB-to-PSB (logical-to-physical board) mapping by finding the
1291898Shueston * memory controller driver per LSB. The MC driver will have a
1301898Shueston * physical-board# property.
1311898Shueston */
1321898Shueston for (n = di_drv_first_node(OPL_MC_DRV, opl_devtree);
1331898Shueston n != DI_NODE_NIL;
1341898Shueston n = di_drv_next_node(n)) {
1352499Shueston int a, lsb, psb;
1361898Shueston char *ba = di_bus_addr(n);
1372499Shueston if (ba == NULL) {
1382499Shueston /*
1392499Shueston * di_bus_addr returned NULL. This can happen during
1402499Shueston * DR attach/detach of the mc driver. Just skip this
1412499Shueston * node for now.
1422499Shueston */
1432499Shueston continue;
1442499Shueston }
1452499Shueston a = OPL_MC_STR2BA(ba);
1462499Shueston lsb = OPL_MC_LSB(a);
1471898Shueston
1483062Scindi psb = opl_get_physical_board(mod, n);
1491898Shueston if (psb < 0 || psb >= OPL_IOB_MAX) {
1501898Shueston /* psb mapping is out of range, skip */
1511898Shueston continue;
1521898Shueston }
1531898Shueston lsb_to_psb[lsb] = psb;
1541898Shueston }
1551898Shueston }
1561898Shueston
1571898Shueston /*
1581898Shueston * Create the ioboard node. Add fru and label properties, and create room
1591898Shueston * for child hostbridge nodes.
1606297Sjl139090 *
1616297Sjl139090 * Only IKKAKU model has different IO topology.
1621898Shueston */
1631898Shueston static tnode_t *
opl_iob_node_create(topo_mod_t * mp,tnode_t * parent,int inst,opl_model_t opl_model)1646297Sjl139090 opl_iob_node_create(topo_mod_t *mp, tnode_t *parent, int inst,
1656297Sjl139090 opl_model_t opl_model)
1661898Shueston {
1671898Shueston int err;
1681898Shueston tnode_t *ion;
1691898Shueston nvlist_t *fmri;
1701898Shueston char label[8];
1711898Shueston char fmri_str[32];
1723062Scindi nvlist_t *auth = topo_mod_auth(mp, parent);
1731898Shueston
1741898Shueston if (parent == NULL || inst < 0) {
1751898Shueston return (NULL);
1761898Shueston }
1771898Shueston
1781898Shueston /* Create ioboard FMRI */
1793062Scindi if ((fmri = topo_mod_hcfmri(mp, parent, FM_HC_SCHEME_VERSION, IOBOARD,
1803062Scindi inst, NULL, auth, NULL, NULL, NULL)) == NULL) {
1813062Scindi nvlist_free(auth);
1822499Shueston topo_mod_dprintf(mp, "create of tnode for ioboard failed: %s\n",
1831898Shueston topo_strerror(topo_mod_errno(mp)));
1841898Shueston return (NULL);
1851898Shueston }
1863062Scindi nvlist_free(auth);
1871898Shueston /* Create node for this ioboard */
1883062Scindi ion = topo_node_bind(mp, parent, IOBOARD, inst, fmri);
1891898Shueston if (ion == NULL) {
1901898Shueston nvlist_free(fmri);
1912499Shueston topo_mod_dprintf(mp, "unable to bind ioboard: %s\n",
1921898Shueston topo_strerror(topo_mod_errno(mp)));
1931898Shueston return (NULL); /* mod_errno already set */
1941898Shueston }
1951898Shueston nvlist_free(fmri);
1961898Shueston /* Create and add FRU fmri for this ioboard */
1976297Sjl139090 if (opl_model == MODEL_IKKAKU)
1986297Sjl139090 (void) snprintf(fmri_str, sizeof (fmri_str), IKKAKU_IOBDFRU);
1996297Sjl139090 else
2006297Sjl139090 (void) snprintf(fmri_str, sizeof (fmri_str), IOBDFRU, inst);
2013062Scindi if (topo_mod_str2nvl(mp, fmri_str, &fmri) == 0) {
2021898Shueston (void) topo_node_fru_set(ion, fmri, 0, &err);
2031898Shueston nvlist_free(fmri);
2041898Shueston }
2051898Shueston /* Add label for this ioboard */
2066297Sjl139090 if (opl_model == MODEL_IKKAKU)
2076297Sjl139090 (void) snprintf(label, sizeof (label), IKKAKU_LABEL);
2086297Sjl139090 else
2096297Sjl139090 (void) snprintf(label, sizeof (label), LABEL, inst);
2101898Shueston (void) topo_node_label_set(ion, label, &err);
2111898Shueston
2121898Shueston /* Create range of hostbridges on this ioboard */
2131898Shueston if (topo_node_range_create(mp, ion, HOSTBRIDGE, 0, OPL_HB_MAX) != 0) {
2142499Shueston topo_mod_dprintf(mp, "topo_node_range_create failed: %s\n",
2151898Shueston topo_strerror(topo_mod_errno(mp)));
2161898Shueston return (NULL);
2171898Shueston }
2181898Shueston
2191898Shueston return (ion);
2201898Shueston }
2211898Shueston
2226297Sjl139090 /*
2236297Sjl139090 * get the OPL model name from rootnode property "model"
2246297Sjl139090 */
2256297Sjl139090 static int
opl_get_model(topo_mod_t * mp,di_node_t opl_devtree,char * model)2266297Sjl139090 opl_get_model(topo_mod_t *mp, di_node_t opl_devtree, char *model)
2276297Sjl139090 {
2286297Sjl139090 char *bufp;
2296297Sjl139090 di_prom_handle_t promh = DI_PROM_HANDLE_NIL;
2306297Sjl139090
2316297Sjl139090 if (opl_devtree == DI_NODE_NIL ||
2326297Sjl139090 (promh = topo_mod_prominfo(mp)) == DI_PROM_HANDLE_NIL)
2336297Sjl139090 return (-1);
2346297Sjl139090
2356297Sjl139090 if (di_prom_prop_lookup_bytes(promh, opl_devtree, "model",
2366297Sjl139090 (unsigned char **)&bufp) != -1) {
2376297Sjl139090 (void) strlcpy(model, bufp, MAXNAMELEN);
2386297Sjl139090 return (0);
2396297Sjl139090 } else {
2406297Sjl139090 return (-1);
2416297Sjl139090 }
2426297Sjl139090
2436297Sjl139090 }
2446297Sjl139090
2451898Shueston /*ARGSUSED*/
2461898Shueston static int
opl_iob_enum(topo_mod_t * mp,tnode_t * parent,const char * name,topo_instance_t imin,topo_instance_t imax,void * notused1,void * notused2)2471898Shueston opl_iob_enum(topo_mod_t *mp, tnode_t *parent, const char *name,
2483062Scindi topo_instance_t imin, topo_instance_t imax, void *notused1, void *notused2)
2491898Shueston {
2503062Scindi di_node_t opl_devtree;
2511898Shueston di_node_t pnode;
2521898Shueston tnode_t *ion;
2531898Shueston topo_instance_t inst;
2541898Shueston int lsb_to_psb[OPL_IOB_MAX];
2551898Shueston ioboard_contents_t ioboard_list[OPL_IOB_MAX];
2561898Shueston int retval = 0;
2576297Sjl139090 char model[MAXNAMELEN];
2586297Sjl139090 opl_model_t opl_model = MODEL_FF;
2591898Shueston
2601898Shueston /* Validate the name is correct */
2611898Shueston if (strcmp(name, "ioboard") != 0) {
2621898Shueston return (-1);
2631898Shueston }
2641898Shueston /* Make sure we don't exceed OPL_IOB_MAX */
2651898Shueston if (imax >= OPL_IOB_MAX) {
2661898Shueston imax = OPL_IOB_MAX;
2671898Shueston }
2681898Shueston
2691898Shueston bzero(ioboard_list, sizeof (ioboard_list));
2701898Shueston
2713062Scindi opl_devtree = topo_mod_devinfo(mp);
2721898Shueston if (opl_devtree == DI_NODE_NIL) {
2731898Shueston (void) topo_mod_seterrno(mp, errno);
2742499Shueston topo_mod_dprintf(mp, "devinfo init failed.\n");
2751898Shueston return (-1);
2761898Shueston }
2771898Shueston
2786297Sjl139090 if (opl_get_model(mp, opl_devtree, model) == -1) {
2796297Sjl139090 topo_mod_dprintf(mp, "opl_get_model failed.\n");
2806297Sjl139090 } else {
2816297Sjl139090 if (strncmp(model, "FF", 2) == 0)
2826297Sjl139090 opl_model = MODEL_FF;
2836297Sjl139090 else if (strncmp(model, "DC", 2) == 0)
2846297Sjl139090 opl_model = MODEL_DC;
2856297Sjl139090 else if (strcmp(model, "IKKAKU") == 0)
2866297Sjl139090 opl_model = MODEL_IKKAKU;
2876297Sjl139090
2886297Sjl139090 topo_mod_dprintf(mp, "opl_get_model %s found.\n", model);
2896297Sjl139090 }
2906297Sjl139090
2911898Shueston /*
2921898Shueston * Create a mapping from logical board numbers (which are part of
2931898Shueston * the device node bus address) to physical board numbers, so we
2941898Shueston * can create meaningful fru labels.
2951898Shueston */
2963062Scindi opl_map_boards(mp, opl_devtree, lsb_to_psb);
2971898Shueston
2981898Shueston /*
2991898Shueston * Figure out which boards are installed by finding hostbridges
3001898Shueston * with matching bus addresses.
3011898Shueston */
3021898Shueston for (pnode = di_drv_first_node(OPL_PX_DRV, opl_devtree);
3031898Shueston pnode != DI_NODE_NIL;
3041898Shueston pnode = di_drv_next_node(pnode)) {
3051898Shueston int psb = -1;
3066216Skd93003 int a, lsb, hb, rc;
3076216Skd93003
3086216Skd93003 /* Get the bus address */
3091898Shueston char *ba = di_bus_addr(pnode);
3106216Skd93003 if (ba == NULL || (*ba == '\0')) {
3116216Skd93003 return (-1); /* Return if it's not assigned */
3126216Skd93003 }
3136216Skd93003
3146216Skd93003 a = OPL_PX_STR2BA(ba);
3156216Skd93003 lsb = OPL_PX_LSB(a);
3166216Skd93003 hb = OPL_PX_HB(a);
3176216Skd93003 rc = OPL_PX_RC(a);
3181898Shueston /* Map logical system board to physical system board */
3191898Shueston if (lsb >= 0 && lsb <= OPL_IOB_MAX) {
3201898Shueston psb = lsb_to_psb[lsb];
3211898Shueston }
3221898Shueston /* If valid psb, note that this board exists */
3231898Shueston if (psb >= 0 && psb < OPL_IOB_MAX) {
3241898Shueston ioboard_list[psb].count++;
3251898Shueston ioboard_list[psb].rcs[hb][rc] = pnode;
3261898Shueston }
3271898Shueston }
3281898Shueston
3291898Shueston /*
3301898Shueston * Now enumerate each existing board Exit loop if retval is
3311898Shueston * ever set to non-zero.
3321898Shueston */
3331898Shueston for (inst = imin; inst <= imax && retval == 0; inst++) {
3341898Shueston /* If this board doesn't contain any hostbridges, skip it */
3351898Shueston if (ioboard_list[inst].count == 0) {
3361898Shueston continue;
3371898Shueston }
3381898Shueston /* Create node for this ioboard */
3396297Sjl139090 ion = opl_iob_node_create(mp, parent, inst, opl_model);
3401898Shueston if (ion == NULL) {
3411898Shueston topo_mod_dprintf(mp,
3422499Shueston "enumeration of ioboard failed: %s\n",
3431898Shueston topo_strerror(topo_mod_errno(mp)));
3441898Shueston retval = -1;
3451898Shueston break;
3461898Shueston }
3471898Shueston /* Enumerate hostbridges on this ioboard, sets errno */
3483062Scindi retval = opl_hb_enum(mp, &ioboard_list[inst], ion, inst);
3491898Shueston }
3501898Shueston return (retval);
3511898Shueston }
352