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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Sun4v Platform specific functions.
28  *
29  * 	called when :
30  *      machine_type ==  pelton
31  *
32  */
33 
34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <kstat.h>
40 #include <fcntl.h>
41 #include <string.h>
42 #include <assert.h>
43 #include <libintl.h>
44 #include <note.h>
45 #include <sys/systeminfo.h>
46 #include <sys/openpromio.h>
47 #include <sys/sysmacros.h>
48 #include <picl.h>
49 #include "picldefs.h"
50 #include <pdevinfo.h>
51 #include <display.h>
52 #include <display_sun4v.h>
53 #include <libprtdiag.h>
54 #include "pelton.h"
55 
56 #if !defined(TEXT_DOMAIN)
57 #define	TEXT_DOMAIN	"SYS_TEST"
58 #endif
59 
60 
61 /* local functions */
62 static int pelton_get_first_compatible_value(picl_nodehdl_t nodeh,
63     char **outbuf);
64 static int64_t pelton_get_int_propval(picl_nodehdl_t modh, char *prop_name,
65     int *ret);
66 
67 static void
68 get_bus_type(char *path, struct io_card *card)
69 {
70 	if (strncmp(path, PEL_PCIX_SLOT0, PCIX_COMP_NUM) == 0) {
71 		(void) strcpy(card->bus_type, "PCIX");
72 	} else if (strncmp(path, PEL_PCIX_SLOT1, PCIX_COMP_NUM) == 0) {
73 		(void) strcpy(card->bus_type, "PCIX");
74 	} else if (strncmp(path, PEL_PCIX_SLOT2, PCIX_COMP_NUM) == 0) {
75 		(void) strcpy(card->bus_type, "PCIX");
76 	} else if (strncmp(path, PEL_PCIX_SLOT3, PCIX_COMP_NUM) == 0) {
77 		(void) strcpy(card->bus_type, "PCIX");
78 	} else {
79 		(void) strcpy(card->bus_type, "PCIE");
80 	}
81 }
82 
83 static void
84 get_slot_number(char *path, struct io_card *card)
85 {
86 	if (strncmp(path, PEL_PCIE_SLOT0, PCIE_COMP_NUM) == 0) {
87 		(void) strcpy(card->slot_str, "0");
88 		card->slot = 0;
89 	} else if (strncmp(path, PEL_PCIX_SLOT2, strlen(PEL_PCIX_SLOT2)) == 0) {
90 		(void) strcpy(card->slot_str, "PCIX");
91 		card->slot = -1;
92 	} else if (strncmp(path, PEL_PCIX_SLOT1, strlen(PEL_PCIX_SLOT1)) == 0) {
93 		(void) strcpy(card->slot_str, "PCIX");
94 		card->slot = -1;
95 	} else if (strncmp(path, PEL_PCIX_SLOT0, strlen(PEL_PCIX_SLOT0)) == 0) {
96 		(void) strcpy(card->slot_str, "PCIX");
97 		card->slot = -1;
98 	} else {
99 		(void) strcpy(card->slot_str, IOBOARD);
100 		card->slot = -1;
101 	}
102 }
103 
104 static int
105 pelton_get_network_instance(char *path)
106 {
107 	if (strncmp(path, PEL_NETWORK_1_PATH,
108 		strlen(PEL_NETWORK_1_PATH)) == 0) {
109 		return (1);
110 	} else if (strncmp(path, PEL_NETWORK_3_PATH,
111 		strlen(PEL_NETWORK_3_PATH)) == 0) {
112 		return (3);
113 	} else if (strncmp(path, PEL_NETWORK_0_PATH,
114 		strlen(PEL_NETWORK_0_PATH)) == 0) {
115 		return (0);
116 	} else if (strncmp(path, PEL_NETWORK_2_PATH,
117 		strlen(PEL_NETWORK_2_PATH)) == 0) {
118 		return (2);
119 	} else {
120 		return (-1);
121 	}
122 }
123 /*
124  * add all io devices under pci in io list
125  */
126 /* ARGSUSED */
127 int
128 pelton_pci_callback(picl_nodehdl_t pcih, void *args)
129 {
130 	int		err = PICL_SUCCESS;
131 	picl_nodehdl_t	nodeh;
132 	char		path[MAXSTRLEN];
133 	char		parent_path[MAXSTRLEN];
134 	char		piclclass[PICL_CLASSNAMELEN_MAX];
135 	char		name[MAXSTRLEN];
136 	char		model[MAXSTRLEN];
137 	char		*compatible;
138 	char		binding_name[MAXSTRLEN];
139 	struct io_card	pci_card;
140 	int32_t		instance;
141 
142 	err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path,
143 	    sizeof (parent_path));
144 	if (err != PICL_SUCCESS) {
145 		return (err);
146 	}
147 
148 	/* Walk through the children */
149 
150 	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
151 	    sizeof (picl_nodehdl_t));
152 
153 	while (err == PICL_SUCCESS) {
154 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
155 		    piclclass, sizeof (piclclass));
156 		if (err !=  PICL_SUCCESS)
157 			return (err);
158 
159 		if (strcmp(piclclass, "pciex") == 0) {
160 			err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
161 			    &nodeh, sizeof (picl_nodehdl_t));
162 			continue;
163 		}
164 
165 		if (strcmp(piclclass, PICL_CLASS_PCI) == 0) {
166 			err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
167 			    &nodeh, sizeof (picl_nodehdl_t));
168 			continue;
169 		}
170 
171 		err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
172 		    path, sizeof (path));
173 		if (err != PICL_SUCCESS) {
174 			return (err);
175 		}
176 
177 		(void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes));
178 
179 		get_bus_type(parent_path, &pci_card);
180 
181 		get_slot_number(parent_path, &pci_card);
182 
183 		err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &name,
184 		    sizeof (name));
185 		if (err == PICL_PROPNOTFOUND)
186 			(void) strcpy(name, "");
187 		else if (err != PICL_SUCCESS)
188 			return (err);
189 
190 
191 		/* Figure NAC name */
192 		if ((strcmp(name, NETWORK) == 0) &&
193 		    (strcmp(pci_card.slot_str, IOBOARD) == 0)) {
194 			instance = pelton_get_network_instance(path);
195 
196 			(void) snprintf(pci_card.status,
197 			    sizeof (pci_card.status), "%s/%s%d", IOBOARD,
198 			    "NET", instance);
199 		} else {
200 			if (pci_card.slot != -1) {
201 				(void) snprintf(pci_card.status,
202 				    sizeof (pci_card.status), "%s/%s%d",
203 				    IOBOARD, pci_card.bus_type, pci_card.slot);
204 			} else {
205 				(void) snprintf(pci_card.status,
206 				    sizeof (pci_card.status), "%s/%s", IOBOARD,
207 				    pci_card.bus_type);
208 			}
209 		}
210 
211 		/*
212 		 * Get the name of this card. Iif binding_name is found,
213 		 * name will be <nodename>-<binding_name>
214 		 */
215 
216 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
217 		    &binding_name, sizeof (binding_name));
218 		if (err == PICL_PROPNOTFOUND) {
219 			/*
220 			 * if compatible prop is found, name will be
221 			 * <nodename>-<compatible>
222 			 */
223 			err = pelton_get_first_compatible_value(nodeh,
224 			    &compatible);
225 			if (err == PICL_SUCCESS) {
226 				(void) strlcat(name, "-", MAXSTRLEN);
227 				(void) strlcat(name, compatible, MAXSTRLEN);
228 				free(compatible);
229 			} else if (err != PICL_PROPNOTFOUND) {
230 				return (err);
231 			}
232 		} else if (err != PICL_SUCCESS) {
233 			return (err);
234 		} else if (strcmp(name, binding_name) != 0) {
235 			(void) strlcat(name, "-", MAXSTRLEN);
236 			(void) strlcat(name, binding_name, MAXSTRLEN);
237 		}
238 
239 		(void) strlcpy(pci_card.name, name, sizeof (pci_card.name));
240 		free(name);
241 
242 		/* Get the model of this card */
243 
244 		err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
245 		    &model, sizeof (model));
246 		if (err == PICL_PROPNOTFOUND)
247 			(void) strcpy(model, "");
248 		else if (err != PICL_SUCCESS)
249 			return (err);
250 		(void) strlcpy(pci_card.model, model, sizeof (pci_card.model));
251 
252 		/* Print NAC name */
253 		log_printf("%-11s", pci_card.status);
254 		/* Print IO Type */
255 		log_printf("%6s", pci_card.bus_type);
256 		/* Print Slot # */
257 		log_printf("%5s", pci_card.slot_str);
258 		/* Print Parent Path */
259 		log_printf("%46.45s", pci_card.notes);
260 		/* Printf Card Name */
261 		if (strlen(pci_card.name) > 24)
262 			log_printf("%25.24s+", pci_card.name);
263 		else
264 			log_printf("%26s", pci_card.name);
265 		/* Print Card Model */
266 		if (strlen(pci_card.model) > 10)
267 			log_printf("%10.9s+", pci_card.model);
268 		else
269 			log_printf("%10s", pci_card.model);
270 		log_printf("\n");
271 
272 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
273 		    sizeof (picl_nodehdl_t));
274 
275 	}
276 
277 	return (PICL_WALK_CONTINUE);
278 }
279 
280 /*
281  * local functions
282  */
283 /*
284  * add all io devices under pci in io list
285  */
286 /* ARGSUSED */
287 int
288 pelton_hw_rev_callback(picl_nodehdl_t pcih, void *args)
289 {
290 	int		err = PICL_SUCCESS;
291 	char		path[MAXSTRLEN] = "";
292 	char		device_path[MAXSTRLEN];
293 	char		NAC[MAXSTRLEN];
294 	char		*compatible;
295 	int32_t		revision;
296 	int		device_found;
297 
298 	device_found = 0;
299 
300 	err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, path,
301 	    sizeof (path));
302 	if (err != PICL_SUCCESS) {
303 		return (err);
304 	}
305 
306 	if ((strcmp(path, PEL_NETWORK_0_PATH) == 0) ||
307 	    (strcmp(path, PEL_NETWORK_1_PATH) == 0)) {
308 		device_found = 1;
309 		(void) snprintf(NAC, sizeof (NAC), "%s/%s%d", IOBOARD, OPHIR,
310 		    0);
311 		revision = pelton_get_int_propval(pcih, OBP_PROP_REVISION_ID,
312 		    &err);
313 	}
314 
315 	if ((strcmp(path, PEL_NETWORK_2_PATH) == 0) ||
316 	    (strcmp(path, PEL_NETWORK_3_PATH) == 0)) {
317 		device_found = 1;
318 		(void) snprintf(NAC, sizeof (NAC), "%s/%s%d", IOBOARD, OPHIR,
319 		    1);
320 		revision = pelton_get_int_propval(pcih, OBP_PROP_REVISION_ID,
321 		    &err);
322 	}
323 
324 	if ((strcmp(path, FIRE_PATH0) == 0) ||
325 	    (strcmp(path, FIRE_PATH1) == 0)) {
326 		device_found = 1;
327 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD,
328 		    "IO-BRIDGE");
329 		revision = pelton_get_int_propval(pcih, OBP_PROP_VERSION_NUM,
330 		    &err);
331 	}
332 
333 	if ((strcmp(path, PEL_PCIX_SLOT0) == 0) ||
334 	    (strcmp(path, PEL_PCIX_SLOT1) == 0) ||
335 	    (strcmp(path, PEL_PCIX_SLOT2) == 0) ||
336 	    (strcmp(path, PEL_PCIX_SLOT3) == 0)) {
337 		device_found = 1;
338 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD,
339 		    PCI_BRIDGE);
340 		revision = pelton_get_int_propval(pcih, OBP_PROP_REVISION_ID,
341 		    &err);
342 	}
343 
344 	if (strcmp(path, SWITCH_A_PATH) == 0) {
345 		device_found = 1;
346 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, SWITCH_A);
347 		revision = pelton_get_int_propval(pcih, OBP_PROP_REVISION_ID,
348 		    &err);
349 	}
350 
351 	if (strcmp(path, SWITCH_B_PATH) == 0) {
352 		device_found = 1;
353 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, SWITCH_B);
354 		revision = pelton_get_int_propval(pcih, OBP_PROP_REVISION_ID,
355 		    &err);
356 	}
357 
358 	if (strcmp(path, PEL_LSI_PATH) == 0) {
359 		device_found = 1;
360 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD,
361 		    PEL_SAS_HBA);
362 		revision = pelton_get_int_propval(pcih, OBP_PROP_REVISION_ID,
363 		    &err);
364 	}
365 	if (device_found == 1) {
366 		(void) strcpy(device_path, path);
367 		err = pelton_get_first_compatible_value(pcih, &compatible);
368 
369 		/* Print NAC name */
370 		log_printf("%-20s", NAC);
371 		/* Print Device Path */
372 		if (strlen(device_path) > 38)
373 			log_printf("%38.37s+", device_path);
374 		else
375 			log_printf("%39s", device_path);
376 		/* Print Compatible # */
377 		log_printf("%31s", compatible);
378 		free(compatible);
379 		/* Print Revision */
380 		log_printf("%6d", revision);
381 		log_printf("\n");
382 	}
383 
384 	return (PICL_WALK_CONTINUE);
385 }
386 
387 /*
388  * return the first compatible value
389  */
390 static int
391 pelton_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
392 {
393 	int		err;
394 	picl_prophdl_t	proph;
395 	picl_propinfo_t	pinfo;
396 	picl_prophdl_t	tblh;
397 	picl_prophdl_t	rowproph;
398 	char		*pval;
399 
400 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
401 	    &pinfo, &proph);
402 	if (err != PICL_SUCCESS)
403 	    return (err);
404 
405 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
406 		pval = malloc(pinfo.size);
407 		if (pval == NULL)
408 			return (PICL_FAILURE);
409 		err = picl_get_propval(proph, pval, pinfo.size);
410 		if (err != PICL_SUCCESS) {
411 			free(pval);
412 			return (err);
413 		}
414 		*outbuf = pval;
415 		return (PICL_SUCCESS);
416 	}
417 
418 	if (pinfo.type != PICL_PTYPE_TABLE)
419 		return (PICL_FAILURE);
420 
421 	/* get first string from table */
422 	err = picl_get_propval(proph, &tblh, pinfo.size);
423 	if (err != PICL_SUCCESS)
424 		return (err);
425 
426 	err = picl_get_next_by_row(tblh, &rowproph);
427 	if (err != PICL_SUCCESS)
428 		return (err);
429 
430 	err = picl_get_propinfo(rowproph, &pinfo);
431 	if (err != PICL_SUCCESS)
432 	    return (err);
433 
434 	pval = malloc(pinfo.size);
435 	if (pval == NULL)
436 		return (PICL_FAILURE);
437 
438 	err = picl_get_propval(rowproph, pval, pinfo.size);
439 	if (err != PICL_SUCCESS) {
440 		free(pval);
441 		return (err);
442 	}
443 
444 	*outbuf = pval;
445 	return (PICL_SUCCESS);
446 }
447 
448 static int64_t
449 pelton_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
450 {
451 	int		err;
452 	picl_prophdl_t	proph;
453 	picl_propinfo_t	pinfo;
454 	int8_t		int8v;
455 	int16_t		int16v;
456 	int32_t		int32v;
457 	int64_t		int64v;
458 
459 	err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
460 	if (err != PICL_SUCCESS) {
461 		*ret = err;
462 		return (0);
463 	}
464 
465 	/*
466 	 * If it is not an int, uint or byte array prop, return failure
467 	 */
468 	if ((pinfo.type != PICL_PTYPE_INT) &&
469 		(pinfo.type != PICL_PTYPE_UNSIGNED_INT) &&
470 		(pinfo.type != PICL_PTYPE_BYTEARRAY)) {
471 		*ret = PICL_FAILURE;
472 		return (0);
473 	}
474 
475 	switch (pinfo.size) {
476 	case sizeof (int8_t):
477 		err = picl_get_propval(proph, &int8v, sizeof (int8v));
478 		*ret = err;
479 		return (int8v);
480 	case sizeof (int16_t):
481 		err = picl_get_propval(proph, &int16v, sizeof (int16v));
482 		*ret = err;
483 		return (int16v);
484 	case sizeof (int32_t):
485 		err = picl_get_propval(proph, &int32v, sizeof (int32v));
486 		*ret = err;
487 		return (int32v);
488 	case sizeof (int64_t):
489 		err = picl_get_propval(proph, &int64v, sizeof (int64v));
490 		*ret = err;
491 		return (int64v);
492 	default:	/* not supported size */
493 		*ret = PICL_FAILURE;
494 		return (0);
495 	}
496 }
497