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