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