xref: /illumos-gate/usr/src/lib/libprtdiag_psr/sparc/ontario/common/stpaul.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 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 ==  StPaul
32  *
33  */
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <kstat.h>
39 #include <fcntl.h>
40 #include <string.h>
41 #include <assert.h>
42 #include <libintl.h>
43 #include <note.h>
44 #include <sys/systeminfo.h>
45 #include <sys/openpromio.h>
46 #include <sys/sysmacros.h>
47 #include <picl.h>
48 #include "picldefs.h"
49 #include <pdevinfo.h>
50 #include <display.h>
51 #include <display_sun4v.h>
52 #include <libprtdiag.h>
53 #include "stpaul.h"
54 
55 /* prototypes for local functions */
56 static void get_bus_type(char *path, struct io_card *card);
57 static void get_slot_number(char *path, struct io_card *card);
58 static int stpaul_get_network_instance(char *path);
59 static int stpaul_get_usb_instance(char *path);
60 static int stpaul_get_io_instance(char *path, char *type);
61 static int stpaul_get_first_compatible_value(picl_nodehdl_t nodeh,
62     char **outbuf);
63 static int64_t stpaul_get_int_propval(picl_nodehdl_t modh, char *prop_name,
64     int *ret);
65 
66 /* ARGSUSED */
67 int
68 stpaul_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		*compatible;
78 	char		binding_name[MAXSTRLEN];
79 	struct io_card	pci_card;
80 	int32_t		instance;
81 	char		pn_type;
82 
83 	err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path,
84 	    sizeof (parent_path));
85 	if (err != PICL_SUCCESS)
86 		return (err);
87 
88 	/* Walk through the children */
89 
90 	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
91 	    sizeof (picl_nodehdl_t));
92 
93 	while (err == PICL_SUCCESS) {
94 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
95 		    piclclass, sizeof (piclclass));
96 		if (err !=  PICL_SUCCESS)
97 			return (err);
98 
99 		if (strcmp(piclclass, PICL_CLASS_PCIEX) == 0) {
100 			err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
101 			    &nodeh, sizeof (picl_nodehdl_t));
102 			continue;
103 		}
104 
105 		if (strcmp(piclclass, PICL_CLASS_PCI) == 0) {
106 			err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
107 			    &nodeh, sizeof (picl_nodehdl_t));
108 			continue;
109 		}
110 
111 		err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
112 		    path, sizeof (path));
113 		if (err != PICL_SUCCESS)
114 			return (err);
115 
116 		(void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes));
117 
118 		get_bus_type(path, &pci_card);
119 
120 		get_slot_number(path, &pci_card);
121 
122 		err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &name,
123 		    sizeof (name));
124 		if (err == PICL_PROPNOTFOUND)
125 			(void) strlcpy(name, "", sizeof (name));
126 		else if (err != PICL_SUCCESS)
127 			return (err);
128 
129 		/* Figure NAC name */
130 		if ((strcmp(name, NETWORK) == 0) &&
131 		    (strcmp(pci_card.slot_str, MOTHERBOARD) == 0)) {
132 			instance = stpaul_get_network_instance(path);
133 			(void) snprintf(pci_card.status,
134 			    sizeof (pci_card.status), "%s/%s%d",
135 			    MOTHERBOARD, "NET", instance);
136 
137 
138 		} else if ((strcmp(name, SCSI) == 0) &&
139 		    (strcmp(pci_card.slot_str, MOTHERBOARD) == 0)) {
140 			(void) snprintf(pci_card.status,
141 			    sizeof (pci_card.status), "%s/%s",
142 			    MOTHERBOARD, SPL_SCSI_TAG);
143 
144 		} else {
145 			if (pci_card.slot != -1) {
146 				(void) snprintf(pci_card.status,
147 				    sizeof (pci_card.status), "%s/%s%d",
148 				    MOTHERBOARD, pci_card.bus_type,
149 				    pci_card.slot);
150 			} else {
151 				(void) snprintf(pci_card.status,
152 				    sizeof (pci_card.status), "%s/%s",
153 				    MOTHERBOARD, pci_card.bus_type);
154 			}
155 		}
156 
157 		/* Special case for USB */
158 		if (strncmp(name, USB, strlen(USB)) == 0) {
159 			instance = stpaul_get_usb_instance(path);
160 			if (instance != -1)
161 				(void) snprintf(pci_card.status,
162 				    sizeof (pci_card.status), "%s/%s%d",
163 				    MOTHERBOARD, "USB", instance);
164 		}
165 
166 		/* PEM/NEM case is handled here */
167 		if ((instance = stpaul_get_io_instance(path, &pn_type)) != -1) {
168 			if (pn_type == SPL_PEM_TYPE)
169 				(void) snprintf(pci_card.status,
170 				    sizeof (pci_card.status), "%s/%s%d",
171 				    MOTHERBOARD, "PCI-EM", instance);
172 			else if (pn_type == SPL_NEM_TYPE)
173 				(void) snprintf(pci_card.status,
174 				    sizeof (pci_card.status), "%s/%s%d",
175 				    MOTHERBOARD, "NEM", instance);
176 		}
177 		/*
178 		 * Get the name of this card. If binding_name is found,
179 		 * name will be <nodename>-<binding_name>
180 		 */
181 
182 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
183 		    &binding_name, sizeof (binding_name));
184 		if (err == PICL_PROPNOTFOUND) {
185 			/*
186 			 * if compatible prop is found, name will be
187 			 * <nodename>-<compatible>
188 			 */
189 			err = stpaul_get_first_compatible_value(nodeh,
190 			    &compatible);
191 			if (err == PICL_SUCCESS) {
192 				(void) strlcat(name, "-", MAXSTRLEN);
193 				(void) strlcat(name, compatible, MAXSTRLEN);
194 				free(compatible);
195 			} else if (err != PICL_PROPNOTFOUND)
196 				return (err);
197 		} else if (err != PICL_SUCCESS)
198 			return (err);
199 		else if (strcmp(name, binding_name) != 0) {
200 			(void) strlcat(name, "-", MAXSTRLEN);
201 			(void) strlcat(name, binding_name, MAXSTRLEN);
202 		}
203 
204 		(void) strlcpy(pci_card.name, name, sizeof (pci_card.name));
205 
206 		/* Get the model of this card */
207 
208 		err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
209 		    &model, sizeof (model));
210 		if (err == PICL_PROPNOTFOUND)
211 			(void) strlcpy(model, "", sizeof (model));
212 		else if (err != PICL_SUCCESS)
213 			return (err);
214 		(void) strlcpy(pci_card.model, model, sizeof (pci_card.model));
215 
216 		/* Print NAC name */
217 		log_printf("%-11s", pci_card.status);
218 		/* Print IO Type */
219 		log_printf("%6s", pci_card.bus_type);
220 		/* Print Slot # */
221 		log_printf("%5s", pci_card.slot_str);
222 		/* Print Parent Path */
223 		log_printf("%46.45s", pci_card.notes);
224 		/* Printf Card Name */
225 		if (strlen(pci_card.name) > 24)
226 			log_printf("%25.24s+", pci_card.name);
227 		else
228 			log_printf("%26s", pci_card.name);
229 		/* Print Card Model */
230 		if (strlen(pci_card.model) > 10)
231 			log_printf("%10.9s+", pci_card.model);
232 		else
233 			log_printf("%10s", pci_card.model);
234 		log_printf("\n");
235 
236 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
237 		    sizeof (picl_nodehdl_t));
238 
239 	}
240 
241 	return (PICL_WALK_CONTINUE);
242 }
243 
244 /* ARGSUSED */
245 int
246 stpaul_hw_rev_callback(picl_nodehdl_t pcih, void *args)
247 {
248 	int		err = PICL_SUCCESS;
249 	char		path[MAXSTRLEN];
250 	char		device_path[MAXSTRLEN];
251 	char		NAC[MAXSTRLEN];
252 	char		*compatible;
253 	int32_t		revision;
254 	int		device_found = 0;
255 	char		name[MAXSTRLEN];
256 	picl_nodehdl_t	nodeh;
257 
258 	err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, path,
259 	    sizeof (path));
260 	if (err != PICL_SUCCESS)
261 		return (err);
262 
263 	/* usb is special as a child of PCIE2PCI bridge */
264 	if (strcmp(path, SPL_PCIE2PCI) == 0) {
265 		err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
266 		    sizeof (picl_nodehdl_t));
267 		if (err != PICL_SUCCESS)
268 			return (err);
269 		err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &name,
270 		    sizeof (name));
271 		if (err != PICL_SUCCESS)
272 			return (err);
273 		if (strcmp(name, USB) == 0) {
274 			err = stpaul_hw_rev_callback(nodeh, &nodeh);
275 			if (err != PICL_SUCCESS)
276 				return (err);
277 		}
278 	}
279 
280 	if ((strcmp(path, SPL_NETWORK_0_PATH) == 0) ||
281 	    (strcmp(path, SPL_NETWORK_1_PATH) == 0)) {
282 		device_found = 1;
283 		(void) snprintf(NAC, sizeof (NAC), "%s/%s%d", MOTHERBOARD,
284 		    OPHIR, 0);
285 		revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID,
286 		    &err);
287 	}
288 
289 	if ((strcmp(path, SPL_USB0_PATH) == 0) ||
290 	    (strcmp(path, SPL_USB1_PATH) == 0) ||
291 	    (strcmp(path, SPL_USB2_PATH) == 0)) {
292 		device_found = 1;
293 		(void) snprintf(NAC, sizeof (NAC), "%s/%s%d", MOTHERBOARD,
294 		    USB_TAG, 0);
295 		revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID,
296 		    &err);
297 	}
298 
299 	if ((strcmp(path, FIRE_PATH0) == 0) ||
300 	    (strcmp(path, FIRE_PATH1) == 0)) {
301 		device_found = 1;
302 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD,
303 		    "IO-BRIDGE");
304 		revision = stpaul_get_int_propval(pcih, OBP_PROP_VERSION_NUM,
305 		    &err);
306 	}
307 
308 	if (strcmp(path, SWITCH_A_PATH) == 0) {
309 		device_found = 1;
310 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD,
311 		    SWITCH_A);
312 		revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID,
313 		    &err);
314 	}
315 
316 	if (strcmp(path, SWITCH_B_PATH) == 0) {
317 		device_found = 1;
318 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD,
319 		    SWITCH_B);
320 		revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID,
321 		    &err);
322 	}
323 
324 	if (strcmp(path, SPL_LSI_PATH) == 0) {
325 		device_found = 1;
326 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD,
327 		    SPL_SAS_HBA);
328 		revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID,
329 		    &err);
330 	}
331 
332 	if (strcmp(path, SPL_PCIE2PCI) == 0) {
333 		device_found = 1;
334 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD,
335 		    PCI_BRIDGE);
336 		revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID,
337 		    &err);
338 	}
339 
340 	if (device_found == 1) {
341 
342 		(void) strlcpy(device_path, path, sizeof (device_path));
343 		err = stpaul_get_first_compatible_value(pcih, &compatible);
344 
345 		/* Print NAC name */
346 		log_printf("%-20s", NAC);
347 		/* Print Device Path */
348 		if (strlen(device_path) > 38)
349 			log_printf("%38.37s+", device_path);
350 		else
351 			log_printf("%39s", device_path);
352 		/* Print Compatible # */
353 		if (err == PICL_SUCCESS) {
354 			log_printf("%31s", compatible);
355 			free(compatible);
356 		} else
357 			log_printf("%31s", " ");
358 		/* Print Revision */
359 		log_printf("%6d", revision);
360 		log_printf("\n");
361 	}
362 
363 	return (PICL_WALK_CONTINUE);
364 }
365 
366 static void
367 get_bus_type(char *path, struct io_card *card)
368 {
369 	if (strncmp(path, SPL_PCIE_PEM0, strlen(SPL_PCIE_PEM0)) == 0) {
370 		(void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type));
371 	} else if (strncmp(path, SPL_PCIE_PEM1, strlen(SPL_PCIE_PEM1)) == 0) {
372 		(void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type));
373 	} else if (strncmp(path, SPL_PCIE_NEM0, strlen(SPL_PCIE_NEM0)) == 0) {
374 		(void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type));
375 	} else if (strncmp(path, SPL_PCIE_NEM1, strlen(SPL_PCIE_NEM1)) == 0) {
376 		(void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type));
377 	} else if (strncmp(path, SWITCH_A_PATH, strlen(SWITCH_A_PATH)) == 0) {
378 		(void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type));
379 	} else if (strncmp(path, SWITCH_B_PATH, strlen(SWITCH_B_PATH)) == 0) {
380 		(void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type));
381 	} else {
382 		(void) strlcpy(card->bus_type, "NONE", sizeof (card->bus_type));
383 	}
384 }
385 
386 static void
387 get_slot_number(char *path, struct io_card *card)
388 {
389 	if (strncmp(path, SPL_PCIE_PEM0, strlen(SPL_PCIE_PEM0)) == 0) {
390 		(void) strlcpy(card->slot_str, "0", sizeof (card->slot_str));
391 		card->slot = 0;
392 	} else if (strncmp(path, SPL_PCIE_NEM0, strlen(SPL_PCIE_NEM0)) == 0) {
393 		(void) strlcpy(card->slot_str, "0", sizeof (card->slot_str));
394 		card->slot = 0;
395 	} else if (strncmp(path, SPL_PCIE_PEM1, strlen(SPL_PCIE_PEM1)) == 0) {
396 		(void) strlcpy(card->slot_str, "1", sizeof (card->slot_str));
397 		card->slot = 1;
398 	} else if (strncmp(path, SPL_PCIE_NEM1, strlen(SPL_PCIE_NEM1)) == 0) {
399 		(void) strlcpy(card->slot_str, "1", sizeof (card->slot_str));
400 		card->slot = 1;
401 	} else {
402 		(void) strlcpy(card->slot_str, MOTHERBOARD,
403 		    sizeof (card->slot_str));
404 		card->slot = -1;
405 	}
406 }
407 
408 static int
409 stpaul_get_network_instance(char *path)
410 {
411 	if (strncmp(path, SPL_NETWORK_1_PATH,
412 	    strlen(SPL_NETWORK_1_PATH)) == 0)
413 		return (1);
414 	else if (strncmp(path, SPL_NETWORK_0_PATH,
415 	    strlen(SPL_NETWORK_0_PATH)) == 0)
416 		return (0);
417 	else
418 		return (-1);
419 }
420 
421 static int
422 stpaul_get_usb_instance(char *path)
423 {
424 	if (strncmp(path, SPL_USB2_PATH, strlen(SPL_USB2_PATH)) == 0)
425 		return (2);
426 	else if (strncmp(path, SPL_USB1_PATH, strlen(SPL_USB1_PATH)) == 0)
427 		return (1);
428 	else if (strncmp(path, SPL_USB0_PATH, strlen(path)) == 0)
429 		return (0);
430 	else
431 		return (-1);
432 }
433 
434 static int
435 stpaul_get_io_instance(char *path, char *type)
436 {
437 	if (strncmp(path, SPL_PCIE_PEM1, strlen(SPL_PCIE_PEM1)) == 0) {
438 		*type = SPL_PEM_TYPE;
439 		return (1);
440 	} else if (strncmp(path, SPL_PCIE_PEM0, strlen(SPL_PCIE_PEM0)) == 0) {
441 		*type = SPL_PEM_TYPE;
442 		return (0);
443 	} else if (strncmp(path, SPL_PCIE_NEM1, strlen(SPL_PCIE_NEM1)) == 0) {
444 		*type = SPL_NEM_TYPE;
445 		return (1);
446 	} else if (strncmp(path, SPL_PCIE_NEM0, strlen(SPL_PCIE_NEM0)) == 0) {
447 		*type = SPL_NEM_TYPE;
448 		return (0);
449 	} else
450 		return (-1);
451 }
452 /*
453  * return the first compatible value
454  */
455 static int
456 stpaul_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
457 {
458 	int		err;
459 	picl_prophdl_t	proph;
460 	picl_propinfo_t	pinfo;
461 	picl_prophdl_t	tblh;
462 	picl_prophdl_t	rowproph;
463 	char		*pval;
464 
465 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
466 	    &pinfo, &proph);
467 	if (err != PICL_SUCCESS)
468 		return (err);
469 
470 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
471 		pval = malloc(pinfo.size);
472 		if (pval == NULL)
473 			return (PICL_FAILURE);
474 		err = picl_get_propval(proph, pval, pinfo.size);
475 		if (err != PICL_SUCCESS) {
476 			free(pval);
477 			return (err);
478 		}
479 		*outbuf = pval;
480 		return (PICL_SUCCESS);
481 	}
482 
483 	if (pinfo.type != PICL_PTYPE_TABLE)
484 		return (PICL_FAILURE);
485 
486 	/* get first string from table */
487 	err = picl_get_propval(proph, &tblh, pinfo.size);
488 	if (err != PICL_SUCCESS)
489 		return (err);
490 
491 	err = picl_get_next_by_row(tblh, &rowproph);
492 	if (err != PICL_SUCCESS)
493 		return (err);
494 
495 	err = picl_get_propinfo(rowproph, &pinfo);
496 	if (err != PICL_SUCCESS)
497 		return (err);
498 
499 	pval = malloc(pinfo.size);
500 	if (pval == NULL)
501 		return (PICL_FAILURE);
502 
503 	err = picl_get_propval(rowproph, pval, pinfo.size);
504 	if (err != PICL_SUCCESS) {
505 		free(pval);
506 		return (err);
507 	}
508 
509 	*outbuf = pval;
510 	return (PICL_SUCCESS);
511 }
512 
513 static int64_t
514 stpaul_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
515 {
516 	int		err;
517 	picl_prophdl_t	proph;
518 	picl_propinfo_t	pinfo;
519 	int8_t		int8v;
520 	int16_t		int16v;
521 	int32_t		int32v;
522 	int64_t		int64v;
523 
524 	err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
525 	if (err != PICL_SUCCESS) {
526 		*ret = err;
527 		return (0);
528 	}
529 
530 	/*
531 	 * If it is not an int, uint or byte array prop, return failure
532 	 */
533 	if ((pinfo.type != PICL_PTYPE_INT) &&
534 	    (pinfo.type != PICL_PTYPE_UNSIGNED_INT) &&
535 	    (pinfo.type != PICL_PTYPE_BYTEARRAY)) {
536 		*ret = PICL_FAILURE;
537 		return (0);
538 	}
539 
540 	switch (pinfo.size) {
541 	case sizeof (int8_t):
542 		err = picl_get_propval(proph, &int8v, sizeof (int8v));
543 		*ret = err;
544 		return (int8v);
545 	case sizeof (int16_t):
546 		err = picl_get_propval(proph, &int16v, sizeof (int16v));
547 		*ret = err;
548 		return (int16v);
549 	case sizeof (int32_t):
550 		err = picl_get_propval(proph, &int32v, sizeof (int32v));
551 		*ret = err;
552 		return (int32v);
553 	case sizeof (int64_t):
554 		err = picl_get_propval(proph, &int64v, sizeof (int64v));
555 		*ret = err;
556 		return (int64v);
557 	default:	/* not supported size */
558 		*ret = PICL_FAILURE;
559 		return (0);
560 	}
561 }
562