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_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 
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 	/* Walk through the children */
88 
89 	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
90 	    sizeof (picl_nodehdl_t));
91 
92 	while (err == PICL_SUCCESS) {
93 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
94 		    piclclass, sizeof (piclclass));
95 		if (err !=  PICL_SUCCESS)
96 			return (err);
97 
98 		if (strcmp(piclclass, "pciex") == 0) {
99 			err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
100 			    &nodeh, sizeof (picl_nodehdl_t));
101 			continue;
102 		}
103 
104 		if (strcmp(piclclass, PICL_CLASS_PCI) == 0) {
105 			err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
106 			    &nodeh, sizeof (picl_nodehdl_t));
107 			continue;
108 		}
109 
110 		err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
111 		    path, sizeof (path));
112 		if (err != PICL_SUCCESS)
113 			return (err);
114 
115 		(void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes));
116 
117 		get_bus_type(parent_path, &pci_card);
118 
119 		get_slot_number(parent_path, &pci_card);
120 
121 		err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &name,
122 		    sizeof (name));
123 		if (err == PICL_PROPNOTFOUND)
124 			(void) strcpy(name, "");
125 		else if (err != PICL_SUCCESS)
126 			return (err);
127 
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 
134 			(void) snprintf(pci_card.status,
135 			    sizeof (pci_card.status), "%s/%s%d", MOTHERBOARD,
136 			    "NET", instance);
137 		} else {
138 			if (pci_card.slot != -1) {
139 				(void) snprintf(pci_card.status,
140 				    sizeof (pci_card.status), "%s/%s%d",
141 				    MOTHERBOARD, pci_card.bus_type,
142 				    pci_card.slot);
143 			} else {
144 				(void) snprintf(pci_card.status,
145 				    sizeof (pci_card.status), "%s/%s",
146 				    MOTHERBOARD, pci_card.bus_type);
147 			}
148 		}
149 
150 		/*
151 		 * Get the name of this card. If binding_name is found,
152 		 * name will be <nodename>-<binding_name>
153 		 */
154 
155 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
156 		    &binding_name, sizeof (binding_name));
157 		if (err == PICL_PROPNOTFOUND) {
158 			/*
159 			 * if compatible prop is found, name will be
160 			 * <nodename>-<compatible>
161 			 */
162 			err = stpaul_get_first_compatible_value(nodeh,
163 			    &compatible);
164 			if (err == PICL_SUCCESS) {
165 				(void) strlcat(name, "-", MAXSTRLEN);
166 				(void) strlcat(name, compatible, MAXSTRLEN);
167 				free(compatible);
168 			} else if (err != PICL_PROPNOTFOUND)
169 				return (err);
170 		} else if (err != PICL_SUCCESS)
171 			return (err);
172 		else if (strcmp(name, binding_name) != 0) {
173 			(void) strlcat(name, "-", MAXSTRLEN);
174 			(void) strlcat(name, binding_name, MAXSTRLEN);
175 		}
176 
177 		(void) strlcpy(pci_card.name, name, sizeof (pci_card.name));
178 
179 		/* Get the model of this card */
180 
181 		err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
182 		    &model, sizeof (model));
183 		if (err == PICL_PROPNOTFOUND)
184 			(void) strcpy(model, "");
185 		else if (err != PICL_SUCCESS)
186 			return (err);
187 		(void) strlcpy(pci_card.model, model, sizeof (pci_card.model));
188 
189 		/* Print NAC name */
190 		log_printf("%-11s", pci_card.status);
191 		/* Print IO Type */
192 		log_printf("%6s", pci_card.bus_type);
193 		/* Print Slot # */
194 		log_printf("%5s", pci_card.slot_str);
195 		/* Print Parent Path */
196 		log_printf("%46.45s", pci_card.notes);
197 		/* Printf Card Name */
198 		if (strlen(pci_card.name) > 24)
199 			log_printf("%25.24s+", pci_card.name);
200 		else
201 			log_printf("%26s", pci_card.name);
202 		/* Print Card Model */
203 		if (strlen(pci_card.model) > 10)
204 			log_printf("%10.9s+", pci_card.model);
205 		else
206 			log_printf("%10s", pci_card.model);
207 		log_printf("\n");
208 
209 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
210 		    sizeof (picl_nodehdl_t));
211 
212 	}
213 
214 	return (PICL_WALK_CONTINUE);
215 }
216 
217 /* ARGSUSED */
218 int
219 stpaul_hw_rev_callback(picl_nodehdl_t pcih, void *args)
220 {
221 	int		err = PICL_SUCCESS;
222 	char		path[MAXSTRLEN] = "";
223 	char		device_path[MAXSTRLEN];
224 	char		NAC[MAXSTRLEN];
225 	char		*compatible;
226 	int32_t		revision;
227 	int		device_found = 0;
228 
229 	err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, path,
230 	    sizeof (path));
231 	if (err != PICL_SUCCESS)
232 		return (err);
233 
234 	if ((strcmp(path, SPL_NETWORK_0_PATH) == 0) ||
235 	    (strcmp(path, SPL_NETWORK_1_PATH) == 0)) {
236 		device_found = 1;
237 		(void) snprintf(NAC, sizeof (NAC), "%s/%s%d", MOTHERBOARD,
238 		    OPHIR, 0);
239 		revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID,
240 		    &err);
241 	}
242 
243 	if ((strcmp(path, SPL_NSC_USB0_PATH) == 0) ||
244 	    (strcmp(path, SPL_NSC_USB1_PATH) == 0) ||
245 	    (strcmp(path, SPL_NSC_USB2_PATH) == 0) ||
246 	    (strcmp(path, SPL_NSC_USB3_PATH) == 0)) {
247 		device_found = 1;
248 		(void) snprintf(NAC, sizeof (NAC), "%s/%s%d", MOTHERBOARD,
249 		    USB, 0);
250 		revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID,
251 		    &err);
252 	}
253 
254 	if ((strcmp(path, FIRE_PATH0) == 0) ||
255 	    (strcmp(path, FIRE_PATH1) == 0)) {
256 		device_found = 1;
257 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD,
258 		    "IO-BRIDGE");
259 		revision = stpaul_get_int_propval(pcih, OBP_PROP_VERSION_NUM,
260 		    &err);
261 	}
262 
263 	if ((strcmp(path, SPL_PCIE_SLOT0) == 0) ||
264 	    (strcmp(path, SPL_PCIE_SLOT1) == 0) ||
265 	    (strcmp(path, SPL_PCIE_SLOT2) == 0) ||
266 	    (strcmp(path, SPL_PCIE_SLOT3) == 0)) {
267 		device_found = 1;
268 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD,
269 		    PCI_BRIDGE);
270 		revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID,
271 		    &err);
272 	}
273 
274 	if (strcmp(path, SWITCH_A_PATH) == 0) {
275 		device_found = 1;
276 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD,
277 		    SWITCH_A);
278 		revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID,
279 		    &err);
280 	}
281 
282 	if (strcmp(path, SWITCH_B_PATH) == 0) {
283 		device_found = 1;
284 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD,
285 		    SWITCH_B);
286 		revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID,
287 		    &err);
288 	}
289 
290 	if (strcmp(path, SPL_LSI_PATH) == 0) {
291 		device_found = 1;
292 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD,
293 		    SPL_SAS_HBA);
294 		revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID,
295 		    &err);
296 	}
297 
298 	if (strcmp(path, SPL_PCIE2PCI) == 0) {
299 		device_found = 1;
300 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD,
301 		    PCI_BRIDGE);
302 		revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID,
303 		    &err);
304 	}
305 
306 	if (device_found == 1) {
307 
308 		(void) strcpy(device_path, path);
309 		err = stpaul_get_first_compatible_value(pcih, &compatible);
310 
311 		/* Print NAC name */
312 		log_printf("%-20s", NAC);
313 		/* Print Device Path */
314 		if (strlen(device_path) > 38)
315 			log_printf("%38.37s+", device_path);
316 		else
317 			log_printf("%39s", device_path);
318 		/* Print Compatible # */
319 		log_printf("%31s", compatible);
320 		free(compatible);
321 		/* Print Revision */
322 		log_printf("%6d", revision);
323 		log_printf("\n");
324 	}
325 
326 	return (PICL_WALK_CONTINUE);
327 }
328 
329 static void
330 get_bus_type(char *path, struct io_card *card)
331 {
332 	if (strncmp(path, SPL_PCIE_SLOT0, strlen(SPL_PCIE_SLOT0)) == 0) {
333 		(void) strcpy(card->bus_type, "PCIE");
334 	} else if (strncmp(path, SPL_PCIE_SLOT1, strlen(SPL_PCIE_SLOT1)) == 0) {
335 		(void) strcpy(card->bus_type, "PCIE");
336 	} else if (strncmp(path, SPL_PCIE_SLOT2, strlen(SPL_PCIE_SLOT2)) == 0) {
337 		(void) strcpy(card->bus_type, "PCIE");
338 	} else if (strncmp(path, SPL_PCIE_SLOT3, strlen(SPL_PCIE_SLOT3)) == 0) {
339 		(void) strcpy(card->bus_type, "PCIE");
340 	} else if (strncmp(path, SWITCH_A_PATH, strlen(SWITCH_A_PATH)) == 0) {
341 		(void) strcpy(card->bus_type, "PCIE");
342 	} else if (strncmp(path, SWITCH_B_PATH, strlen(SWITCH_B_PATH)) == 0) {
343 		(void) strcpy(card->bus_type, "PCIE");
344 	} else {
345 		(void) strcpy(card->bus_type, "NONE");
346 	}
347 }
348 
349 static void
350 get_slot_number(char *path, struct io_card *card)
351 {
352 	if (strncmp(path, SPL_PCIE_SLOT0, strlen(SPL_PCIE_SLOT0)) == 0) {
353 		(void) strcpy(card->slot_str, "0");
354 		card->slot = 0;
355 	} else if (strncmp(path, SPL_PCIE_SLOT1, strlen(SPL_PCIE_SLOT1)) == 0) {
356 		(void) strcpy(card->slot_str, "1");
357 		card->slot = 1;
358 	} else if (strncmp(path, SPL_PCIE_SLOT2, strlen(SPL_PCIE_SLOT2)) == 0) {
359 		(void) strcpy(card->slot_str, "2");
360 		card->slot = 2;
361 	} else if (strncmp(path, SPL_PCIE_SLOT3, strlen(SPL_PCIE_SLOT3)) == 0) {
362 		(void) strcpy(card->slot_str, "3");
363 		card->slot = 3;
364 	} else {
365 		(void) strcpy(card->slot_str, MOTHERBOARD);
366 		card->slot = -1;
367 	}
368 }
369 
370 static int
371 stpaul_get_network_instance(char *path)
372 {
373 	if (strncmp(path, SPL_NETWORK_1_PATH,
374 		strlen(SPL_NETWORK_1_PATH)) == 0)
375 		return (1);
376 	else if (strncmp(path, SPL_NETWORK_0_PATH,
377 		strlen(SPL_NETWORK_0_PATH)) == 0)
378 		return (0);
379 	else
380 		return (-1);
381 }
382 
383 /*
384  * return the first compatible value
385  */
386 static int
387 stpaul_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
388 {
389 	int		err;
390 	picl_prophdl_t	proph;
391 	picl_propinfo_t	pinfo;
392 	picl_prophdl_t	tblh;
393 	picl_prophdl_t	rowproph;
394 	char		*pval;
395 
396 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
397 	    &pinfo, &proph);
398 	if (err != PICL_SUCCESS)
399 	    return (err);
400 
401 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
402 		pval = malloc(pinfo.size);
403 		if (pval == NULL)
404 			return (PICL_FAILURE);
405 		err = picl_get_propval(proph, pval, pinfo.size);
406 		if (err != PICL_SUCCESS) {
407 			free(pval);
408 			return (err);
409 		}
410 		*outbuf = pval;
411 		return (PICL_SUCCESS);
412 	}
413 
414 	if (pinfo.type != PICL_PTYPE_TABLE)
415 		return (PICL_FAILURE);
416 
417 	/* get first string from table */
418 	err = picl_get_propval(proph, &tblh, pinfo.size);
419 	if (err != PICL_SUCCESS)
420 		return (err);
421 
422 	err = picl_get_next_by_row(tblh, &rowproph);
423 	if (err != PICL_SUCCESS)
424 		return (err);
425 
426 	err = picl_get_propinfo(rowproph, &pinfo);
427 	if (err != PICL_SUCCESS)
428 	    return (err);
429 
430 	pval = malloc(pinfo.size);
431 	if (pval == NULL)
432 		return (PICL_FAILURE);
433 
434 	err = picl_get_propval(rowproph, pval, pinfo.size);
435 	if (err != PICL_SUCCESS) {
436 		free(pval);
437 		return (err);
438 	}
439 
440 	*outbuf = pval;
441 	return (PICL_SUCCESS);
442 }
443 
444 static int64_t
445 stpaul_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
446 {
447 	int		err;
448 	picl_prophdl_t	proph;
449 	picl_propinfo_t	pinfo;
450 	int8_t		int8v;
451 	int16_t		int16v;
452 	int32_t		int32v;
453 	int64_t		int64v;
454 
455 	err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
456 	if (err != PICL_SUCCESS) {
457 		*ret = err;
458 		return (0);
459 	}
460 
461 	/*
462 	 * If it is not an int, uint or byte array prop, return failure
463 	 */
464 	if ((pinfo.type != PICL_PTYPE_INT) &&
465 		(pinfo.type != PICL_PTYPE_UNSIGNED_INT) &&
466 		(pinfo.type != PICL_PTYPE_BYTEARRAY)) {
467 		*ret = PICL_FAILURE;
468 		return (0);
469 	}
470 
471 	switch (pinfo.size) {
472 	case sizeof (int8_t):
473 		err = picl_get_propval(proph, &int8v, sizeof (int8v));
474 		*ret = err;
475 		return (int8v);
476 	case sizeof (int16_t):
477 		err = picl_get_propval(proph, &int16v, sizeof (int16v));
478 		*ret = err;
479 		return (int16v);
480 	case sizeof (int32_t):
481 		err = picl_get_propval(proph, &int32v, sizeof (int32v));
482 		*ret = err;
483 		return (int32v);
484 	case sizeof (int64_t):
485 		err = picl_get_propval(proph, &int64v, sizeof (int64v));
486 		*ret = err;
487 		return (int64v);
488 	default:	/* not supported size */
489 		*ret = PICL_FAILURE;
490 		return (0);
491 	}
492 }
493