1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.open2solaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Sun4v Platform specific functions.
29  *
30  * 	called when :
31  *      machine_type ==  erie
32  *
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <kstat.h>
41 #include <fcntl.h>
42 #include <string.h>
43 #include <assert.h>
44 #include <libintl.h>
45 #include <note.h>
46 #include <sys/systeminfo.h>
47 #include <sys/openpromio.h>
48 #include <sys/sysmacros.h>
49 #include <picl.h>
50 #include "picldefs.h"
51 #include <pdevinfo.h>
52 #include <display.h>
53 #include <display_sun4v.h>
54 #include <libprtdiag.h>
55 #include "erie.h"
56 
57 #if !defined(TEXT_DOMAIN)
58 #define	TEXT_DOMAIN	"SYS_TEST"
59 #endif
60 
61 
62 
63 /*
64  * Add all io picl nodes under pci in io list
65  */
66 /* ARGSUSED */
67 int
68 erie_pci_callback(picl_nodehdl_t pcih, void *args)
69 {
70 	int		err = PICL_SUCCESS;
71 	picl_nodehdl_t	nodeh;
72 	char		path[MAXSTRLEN];
73 	char		parent_path[MAXSTRLEN];
74 	char		piclclass[PICL_CLASSNAMELEN_MAX];
75 	char		name[MAXSTRLEN];
76 	char		model[MAXSTRLEN];
77 	char		nac[MAXSTRLEN];
78 	char		bus_type[MAXSTRLEN];
79 	int		slot = NO_SLOT;
80 
81 	/* Get the parent node's path - used to determine bus type of child */
82 	err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path,
83 	    sizeof (parent_path));
84 	if (err != PICL_SUCCESS) {
85 		return (err);
86 	}
87 
88 	/* Walk through this node's children */
89 	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
90 	    sizeof (picl_nodehdl_t));
91 	while (err == PICL_SUCCESS) {
92 
93 		/* Get child's class */
94 		if ((err = erie_get_class(nodeh, piclclass,
95 		    sizeof (piclclass))) != PICL_SUCCESS)
96 			return (err);
97 
98 		/* If this node is a pci bus or bridge, get node's sibling */
99 		if ((strcmp(piclclass, "pci") == 0 ||
100 		    (strcmp(piclclass, "pciex") == 0))) {
101 			err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
102 			    &nodeh, sizeof (picl_nodehdl_t));
103 			continue;
104 		}
105 
106 		/*
107 		 * In order to get certain values, it's necessary
108 		 * to search the picl tree. If there's a problem
109 		 * with these searches, we'll return the err
110 		 */
111 		if ((err = erie_get_path(nodeh, path, sizeof (path)))
112 		    != PICL_SUCCESS)
113 			return (err);
114 		if ((err = erie_get_name(nodeh, name, sizeof (name)))
115 		    != PICL_SUCCESS)
116 			return (err);
117 		if ((err = erie_get_model(nodeh, model, sizeof (model)))
118 		    != PICL_SUCCESS)
119 			return (err);
120 		erie_get_bus_type(parent_path, bus_type);
121 		slot = erie_get_slot_number(path);
122 		erie_get_nac(bus_type, path, slot, name, nac, sizeof (nac));
123 
124 
125 		/* Print out the data */
126 
127 		/* Print NAC */
128 		log_printf("%-11s", nac);
129 
130 		/* Print IO Type */
131 		log_printf("%-6s", bus_type);
132 
133 		/* Print Slot # */
134 		if (slot != NO_SLOT) {
135 			log_printf("%5d", slot);
136 			log_printf("%46s", path);
137 		} else {
138 			log_printf("%5s", MOTHERBOARD);
139 			log_printf("%46s", path);
140 		}
141 
142 		/* Printf Node Name */
143 		log_printf("%26s", name);
144 		if (strlen(name) > 30)
145 			log_printf(dgettext(TEXT_DOMAIN, "+ "));
146 		else
147 			log_printf(dgettext(TEXT_DOMAIN, "  "));
148 
149 		/* Print Card Model */
150 		log_printf("%-8s", model);
151 		if (strlen(model) > 8)
152 			log_printf(dgettext(TEXT_DOMAIN, "+"));
153 		log_printf("\n");
154 
155 		/* Grab the next child under parent node and do it again */
156 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
157 		    sizeof (picl_nodehdl_t));
158 	}
159 	return (PICL_WALK_CONTINUE);
160 }
161 
162 
163 /*
164  * ----------------------------------------------------------------------------
165  */
166 
167 /*
168  * Add all IO ASIC revisions to list
169  */
170 /* ARGSUSED */
171 int
172 erie_hw_rev_callback(picl_nodehdl_t pcih, void *args)
173 {
174 	int		err = PICL_SUCCESS;
175 	char		path[MAXSTRLEN] = "";
176 	char		nac[MAXSTRLEN];
177 	char		*compatible;
178 	int32_t		revision;
179 
180 	/* Get path of this device */
181 	err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, path,
182 	    sizeof (path));
183 	if (err != PICL_SUCCESS) {
184 		return (err);
185 	}
186 	/*
187 	 * If it's a network dev, then print network info.
188 	 * Else if it's not a network dev,  check for FIRE ASIC
189 	 * Else return PICL_WALK_CONTINUE
190 	 */
191 	if ((strcmp(path, ERIE_NETWORK_0) == 0) ||
192 	    (strcmp(path, ERIE_NETWORK_1) == 0)) {
193 		(void) snprintf(nac, sizeof (nac), "%s/%s%d", MOTHERBOARD,
194 		    OPHIR, 0);
195 		revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID,
196 		    &err);
197 	} else if ((strcmp(path, ERIE_NETWORK_2) == 0) ||
198 	    (strcmp(path, ERIE_NETWORK_3) == 0)) {
199 		(void) snprintf(nac, sizeof (nac), "%s/%s%d", MOTHERBOARD,
200 		    OPHIR, 1);
201 		revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID,
202 		    &err);
203 	} else if ((strcmp(path, ERIE_LSI_PATH) == 0)) {
204 		(void) snprintf(nac, sizeof (nac), "%s/%s", MOTHERBOARD,
205 		    SAS_SATA_HBA);
206 		revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID,
207 		    &err);
208 	} else if ((strcmp(path, FIRE0) == 0) || (strcmp(path, FIRE1) == 0)) {
209 		(void) snprintf(nac, sizeof (nac), "%s/%s", MOTHERBOARD,
210 		    IOBRIDGE);
211 		revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID,
212 		    &err);
213 	} else if ((strcmp(path, PCIE_PCIX) == 0) ||
214 	    (strcmp(path, PCIE_PCIE) == 0)) {
215 		(void) snprintf(nac, sizeof (nac), "%s/%s", MOTHERBOARD,
216 		    PCI_BRIDGE);
217 		revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID,
218 		    &err);
219 	} else {
220 		return (PICL_WALK_CONTINUE);
221 	}
222 
223 	/* Get first compatible value from picl compatible list */
224 	err = erie_get_first_compatible_value(pcih, &compatible);
225 	if (err != PICL_SUCCESS) {
226 		return (err);
227 	}
228 
229 	/* Print nacation */
230 	log_printf("%-20s", nac);
231 
232 	/* Print Device Path */
233 	log_printf("%41s", path);
234 
235 	/* Print Compatible # */
236 	log_printf("%31s", compatible);
237 	free(compatible);
238 
239 	/* Print Revision */
240 	log_printf("%6d", revision);
241 	log_printf("\n");
242 
243 	return (PICL_WALK_CONTINUE);
244 }
245 
246 /*
247  * ----------------------------------------------------------------------------
248  */
249 
250 /*
251  * Local functions
252  */
253 
254 
255 /*
256  * This function returns the first picl compatible value
257  */
258 int
259 erie_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
260 {
261 	int		err;
262 	picl_prophdl_t	proph;
263 	picl_propinfo_t	pinfo;
264 	picl_prophdl_t	tblh;
265 	picl_prophdl_t	rowproph;
266 	char		*pval;
267 
268 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
269 	    &pinfo, &proph);
270 	if (err != PICL_SUCCESS)
271 	    return (err);
272 
273 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
274 		pval = malloc(pinfo.size);
275 		if (pval == NULL)
276 			return (PICL_FAILURE);
277 		err = picl_get_propval(proph, pval, pinfo.size);
278 		if (err != PICL_SUCCESS) {
279 			free(pval);
280 			return (err);
281 		}
282 		*outbuf = pval;
283 		return (PICL_SUCCESS);
284 	}
285 
286 	if (pinfo.type != PICL_PTYPE_TABLE)
287 		return (PICL_FAILURE);
288 
289 	/* get first string from table */
290 	err = picl_get_propval(proph, &tblh, pinfo.size);
291 	if (err != PICL_SUCCESS)
292 		return (err);
293 
294 	err = picl_get_next_by_row(tblh, &rowproph);
295 	if (err != PICL_SUCCESS)
296 		return (err);
297 
298 	err = picl_get_propinfo(rowproph, &pinfo);
299 	if (err != PICL_SUCCESS)
300 	    return (err);
301 
302 	pval = malloc(pinfo.size);
303 	if (pval == NULL)
304 		return (PICL_FAILURE);
305 
306 	err = picl_get_propval(rowproph, pval, pinfo.size);
307 	if (err != PICL_SUCCESS) {
308 		free(pval);
309 		return (err);
310 	}
311 
312 	*outbuf = pval;
313 	return (PICL_SUCCESS);
314 }
315 
316 /*
317  * This function returns the revision of
318  * a device.
319  */
320 int64_t
321 erie_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
322 {
323 	int		err;
324 	picl_prophdl_t	proph;
325 	picl_propinfo_t	pinfo;
326 	int8_t		int8v;
327 	int16_t		int16v;
328 	int32_t		int32v;
329 	int64_t		int64v;
330 
331 	err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
332 	if (err != PICL_SUCCESS) {
333 		*ret = err;
334 		return (0);
335 	}
336 
337 	/*
338 	 * If it is not an int, uint or byte array prop, return failure
339 	 */
340 	if ((pinfo.type != PICL_PTYPE_INT) &&
341 		(pinfo.type != PICL_PTYPE_UNSIGNED_INT) &&
342 		(pinfo.type != PICL_PTYPE_BYTEARRAY)) {
343 		*ret = PICL_FAILURE;
344 		return (0);
345 	}
346 
347 	switch (pinfo.size) {
348 	case sizeof (int8_t):
349 		err = picl_get_propval(proph, &int8v, sizeof (int8v));
350 		*ret = err;
351 		return (int8v);
352 	case sizeof (int16_t):
353 		err = picl_get_propval(proph, &int16v, sizeof (int16v));
354 		*ret = err;
355 		return (int16v);
356 	case sizeof (int32_t):
357 		err = picl_get_propval(proph, &int32v, sizeof (int32v));
358 		*ret = err;
359 		return (int32v);
360 	case sizeof (int64_t):
361 		err = picl_get_propval(proph, &int64v, sizeof (int64v));
362 		*ret = err;
363 		return (int64v);
364 	default:	/* not supported size */
365 		*ret = PICL_FAILURE;
366 		return (0);
367 	}
368 }
369 
370 /*
371  * This function fills in the bus type for an IO device.
372  * If a device hangs off /pci@7c0/pci@0/pci@8, it's on
373  * the pci-x bus. Otherwise, it's on a pci-e bus.
374  *
375  */
376 void
377 erie_get_bus_type(char path[], char bus_type[])
378 {
379 	if (strncmp(path, PCIX_BUS, ERIE_PCIX_COMP) == 0) {
380 		(void) strcpy(bus_type, "PCIX");
381 	} else {
382 		(void) strcpy(bus_type, "PCIE");
383 	}
384 }
385 
386 /*
387  * Thie function indicates whether a device is in a pci-e slot
388  * or if it's on the motherboard. There's only one pci-e slot
389  * on erie, everything else is on the motherboard.
390  *
391  */
392 int
393 erie_get_slot_number(char path[])
394 {
395 	if (strncmp(path, FIRE0, ERIE_PCIE_COMP) == 0)
396 		return (0);
397 	return (NO_SLOT);
398 }
399 
400 /*
401  * This function takes a path to one of the on-board
402  * network devices and returns the instance# of that
403  * device.
404  *
405  */
406 int
407 erie_get_network_instance(char path[])
408 {
409 
410 	if (strncmp(path, ERIE_NETWORK_1, strlen(ERIE_NETWORK_1)) == 0) {
411 		return (1);
412 	} else if (strncmp(path, ERIE_NETWORK_3, strlen(ERIE_NETWORK_3)) == 0) {
413 		return (3);
414 	} else if (strncmp(path, ERIE_NETWORK_0, strlen(ERIE_NETWORK_0)) == 0) {
415 		return (0);
416 	} else if (strncmp(path, ERIE_NETWORK_2, strlen(ERIE_NETWORK_2)) == 0) {
417 		return (2);
418 	} else {
419 		return (-1);
420 	}
421 }
422 
423 /*
424  * This function gets the path of a node and
425  * the error code from the picl API
426  *
427  */
428 int
429 erie_get_path(picl_nodehdl_t nodeh, char path[], int size)
430 {
431 	int  err;
432 
433 	/* hardware path of this node */
434 	err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
435 	    path, size);
436 	return (err);
437 }
438 
439 /*
440  * This function returns assings the string passed in
441  * the value of the picl node's name
442  *
443  */
444 int
445 erie_get_name(picl_nodehdl_t nodeh, char name[], int size)
446 {
447 	int  err;
448 	char *compatible;
449 	char binding_name[MAXSTRLEN];
450 	char lname[MAXSTRLEN];
451 
452 	/* Get this node's name */
453 	err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &lname, size);
454 	if (err == PICL_PROPNOTFOUND) {
455 		(void) strcpy(lname, "");
456 		err = PICL_SUCCESS;
457 	}
458 
459 	/*
460 	 * If binding_name is found,
461 	 * name will be <nodename>-<binding_name>
462 	 */
463 	err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
464 	    &binding_name, sizeof (binding_name));
465 	if (err == PICL_SUCCESS) {
466 		if (strcmp(lname, binding_name) != 0) {
467 			(void) strlcat(lname, "-", MAXSTRLEN);
468 			(void) strlcat(lname, binding_name, MAXSTRLEN);
469 		}
470 	/*
471 	 * if compatible prop is not found, name will be
472 	 * <nodename>-<compatible>
473 	 */
474 	} else if (err == PICL_PROPNOTFOUND) {
475 		err = erie_get_first_compatible_value(nodeh, &compatible);
476 		if (err == PICL_SUCCESS) {
477 			(void) strlcat(lname, "-", MAXSTRLEN);
478 			(void) strlcat(lname, compatible, MAXSTRLEN);
479 		}
480 		err = PICL_SUCCESS;
481 	} else {
482 		return (err);
483 	}
484 
485 	/* The name was created fine, copy it to name var */
486 	(void) strcpy(name, lname);
487 	return (err);
488 }
489 
490 /*
491  * This functions assigns the string passed in the
492  * the value of the picl node's NAC name.
493  */
494 void
495 erie_get_nac(char bus_type[], char path[], int slot,  char name[], char nac[],
496     int size)
497 {
498 	int instance;
499 
500 	/* Figure out NAC name and instance, if onboard network node */
501 	if (strncmp(name, NETWORK, NET_COMP_NUM) == 0) {
502 		instance = erie_get_network_instance(path);
503 		(void) snprintf(nac, size, "%s/%s%d", MOTHERBOARD,
504 		    "NET", instance);
505 	} else if (slot != NO_SLOT) {
506 		(void) snprintf(nac, size, "%s/%s%d", MOTHERBOARD, bus_type,
507 		    slot);
508 	} else {
509 		(void) snprintf(nac, size, "%s/%s", MOTHERBOARD, bus_type);
510 	}
511 }
512 
513 /*
514  * This function copies the node's model into model string
515  *
516  */
517 int
518 erie_get_model(picl_nodehdl_t nodeh, char model[], int size)
519 {
520 	int err;
521 	char tmp_model[MAXSTRLEN];
522 
523 	/* Get the model of this node */
524 	err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
525 	    &tmp_model, size);
526 	if (err == PICL_PROPNOTFOUND) {
527 		(void) strcpy(model, "");
528 		err = PICL_SUCCESS;
529 	} else {
530 		(void) strcpy(model, tmp_model);
531 	}
532 	return (err);
533 }
534 
535 /*
536  * This function copies the node's class into class string
537  *
538  */
539 int
540 erie_get_class(picl_nodehdl_t nodeh, char piclclass[], int size)
541 {
542 	int err;
543 	err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
544 	    piclclass, size);
545 	return (err);
546 }
547