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 2007 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 == erie
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 "erie.h"
53
54 #if !defined(TEXT_DOMAIN)
55 #define TEXT_DOMAIN "SYS_TEST"
56 #endif
57
58
59
60 /*
61 * Add all io picl nodes under pci in io list
62 */
63 /* ARGSUSED */
64 int
erie_pci_callback(picl_nodehdl_t pcih,void * args)65 erie_pci_callback(picl_nodehdl_t pcih, void *args)
66 {
67 int err = PICL_SUCCESS;
68 picl_nodehdl_t nodeh;
69 char path[MAXSTRLEN];
70 char parent_path[MAXSTRLEN];
71 char piclclass[PICL_CLASSNAMELEN_MAX];
72 char name[MAXSTRLEN];
73 char model[MAXSTRLEN];
74 char nac[MAXSTRLEN];
75 char bus_type[MAXSTRLEN];
76 int slot = NO_SLOT;
77
78 /* Get the parent node's path - used to determine bus type of child */
79 err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path,
80 sizeof (parent_path));
81 if (err != PICL_SUCCESS) {
82 return (err);
83 }
84
85 /* Walk through this node's children */
86 err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
87 sizeof (picl_nodehdl_t));
88 while (err == PICL_SUCCESS) {
89
90 /* Get child's class */
91 if ((err = erie_get_class(nodeh, piclclass,
92 sizeof (piclclass))) != PICL_SUCCESS)
93 return (err);
94
95 /* If this node is a pci bus or bridge, get node's sibling */
96 if ((strcmp(piclclass, "pci") == 0 ||
97 (strcmp(piclclass, "pciex") == 0))) {
98 err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
99 &nodeh, sizeof (picl_nodehdl_t));
100 continue;
101 }
102
103 /*
104 * In order to get certain values, it's necessary
105 * to search the picl tree. If there's a problem
106 * with these searches, we'll return the err
107 */
108 if ((err = erie_get_path(nodeh, path, sizeof (path)))
109 != PICL_SUCCESS)
110 return (err);
111 if ((err = erie_get_name(nodeh, name, sizeof (name)))
112 != PICL_SUCCESS)
113 return (err);
114 if ((err = erie_get_model(nodeh, model, sizeof (model)))
115 != PICL_SUCCESS)
116 return (err);
117 erie_get_bus_type(parent_path, bus_type);
118 slot = erie_get_slot_number(path);
119 erie_get_nac(bus_type, path, slot, name, nac, sizeof (nac));
120
121
122 /* Print out the data */
123
124 /* Print NAC */
125 log_printf("%-11s", nac);
126
127 /* Print IO Type */
128 log_printf("%-6s", bus_type);
129
130 /* Print Slot # */
131 if (slot != NO_SLOT) {
132 log_printf("%5d", slot);
133 log_printf("%46s", path);
134 } else {
135 log_printf("%5s", MOTHERBOARD);
136 log_printf("%46s", path);
137 }
138
139 /* Printf Node Name */
140 if (strlen(name) > 25)
141 log_printf("%25.24s+", name);
142 else
143 log_printf("%26s", name);
144 /* Print Card Model */
145 if (strlen(model) > 10)
146 log_printf("%10.9s+", model);
147 else
148 log_printf("%11s", model);
149 log_printf("\n");
150
151 /* Grab the next child under parent node and do it again */
152 err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
153 sizeof (picl_nodehdl_t));
154 }
155 return (PICL_WALK_CONTINUE);
156 }
157
158
159 /*
160 * ----------------------------------------------------------------------------
161 */
162
163 /*
164 * Add all IO ASIC revisions to list
165 */
166 /* ARGSUSED */
167 int
erie_hw_rev_callback(picl_nodehdl_t pcih,void * args)168 erie_hw_rev_callback(picl_nodehdl_t pcih, void *args)
169 {
170 int err = PICL_SUCCESS;
171 char path[MAXSTRLEN] = "";
172 char nac[MAXSTRLEN];
173 char *compatible;
174 int32_t revision;
175
176 /* Get path of this device */
177 err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, path,
178 sizeof (path));
179 if (err != PICL_SUCCESS) {
180 return (err);
181 }
182 /*
183 * If it's a network dev, then print network info.
184 * Else if it's not a network dev, check for FIRE ASIC
185 * Else return PICL_WALK_CONTINUE
186 */
187 if ((strcmp(path, ERIE_NETWORK_0) == 0) ||
188 (strcmp(path, ERIE_NETWORK_1) == 0)) {
189 (void) snprintf(nac, sizeof (nac), "%s/%s%d", MOTHERBOARD,
190 OPHIR, 0);
191 revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID,
192 &err);
193 } else if ((strcmp(path, ERIE_NETWORK_2) == 0) ||
194 (strcmp(path, ERIE_NETWORK_3) == 0)) {
195 (void) snprintf(nac, sizeof (nac), "%s/%s%d", MOTHERBOARD,
196 OPHIR, 1);
197 revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID,
198 &err);
199 } else if ((strcmp(path, ERIE_LSI_PATH) == 0)) {
200 (void) snprintf(nac, sizeof (nac), "%s/%s", MOTHERBOARD,
201 SAS_SATA_HBA);
202 revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID,
203 &err);
204 } else if ((strcmp(path, FIRE0) == 0) || (strcmp(path, FIRE1) == 0)) {
205 (void) snprintf(nac, sizeof (nac), "%s/%s", MOTHERBOARD,
206 IOBRIDGE);
207 revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID,
208 &err);
209 } else if ((strcmp(path, PCIE_PCIX) == 0) ||
210 (strcmp(path, PCIE_PCIE) == 0)) {
211 (void) snprintf(nac, sizeof (nac), "%s/%s", MOTHERBOARD,
212 PCI_BRIDGE);
213 revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID,
214 &err);
215 } else {
216 return (PICL_WALK_CONTINUE);
217 }
218
219 /* Get first compatible value from picl compatible list */
220 err = erie_get_first_compatible_value(pcih, &compatible);
221 if (err != PICL_SUCCESS) {
222 return (err);
223 }
224
225 /* Print nacation */
226 log_printf("%-20s", nac);
227
228 /* Print Device Path */
229 log_printf("%41s", path);
230
231 /* Print Compatible # */
232 log_printf("%31s", compatible);
233 free(compatible);
234
235 /* Print Revision */
236 log_printf("%6d", revision);
237 log_printf("\n");
238
239 return (PICL_WALK_CONTINUE);
240 }
241
242 /*
243 * ----------------------------------------------------------------------------
244 */
245
246 /*
247 * Local functions
248 */
249
250
251 /*
252 * This function returns the first picl compatible value
253 */
254 int
erie_get_first_compatible_value(picl_nodehdl_t nodeh,char ** outbuf)255 erie_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
256 {
257 int err;
258 picl_prophdl_t proph;
259 picl_propinfo_t pinfo;
260 picl_prophdl_t tblh;
261 picl_prophdl_t rowproph;
262 char *pval;
263
264 err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
265 &pinfo, &proph);
266 if (err != PICL_SUCCESS)
267 return (err);
268
269 if (pinfo.type == PICL_PTYPE_CHARSTRING) {
270 pval = malloc(pinfo.size);
271 if (pval == NULL)
272 return (PICL_FAILURE);
273 err = picl_get_propval(proph, pval, pinfo.size);
274 if (err != PICL_SUCCESS) {
275 free(pval);
276 return (err);
277 }
278 *outbuf = pval;
279 return (PICL_SUCCESS);
280 }
281
282 if (pinfo.type != PICL_PTYPE_TABLE)
283 return (PICL_FAILURE);
284
285 /* get first string from table */
286 err = picl_get_propval(proph, &tblh, pinfo.size);
287 if (err != PICL_SUCCESS)
288 return (err);
289
290 err = picl_get_next_by_row(tblh, &rowproph);
291 if (err != PICL_SUCCESS)
292 return (err);
293
294 err = picl_get_propinfo(rowproph, &pinfo);
295 if (err != PICL_SUCCESS)
296 return (err);
297
298 pval = malloc(pinfo.size);
299 if (pval == NULL)
300 return (PICL_FAILURE);
301
302 err = picl_get_propval(rowproph, pval, pinfo.size);
303 if (err != PICL_SUCCESS) {
304 free(pval);
305 return (err);
306 }
307
308 *outbuf = pval;
309 return (PICL_SUCCESS);
310 }
311
312 /*
313 * This function returns the revision of
314 * a device.
315 */
316 int64_t
erie_get_int_propval(picl_nodehdl_t modh,char * prop_name,int * ret)317 erie_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
318 {
319 int err;
320 picl_prophdl_t proph;
321 picl_propinfo_t pinfo;
322 int8_t int8v;
323 int16_t int16v;
324 int32_t int32v;
325 int64_t int64v;
326
327 err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
328 if (err != PICL_SUCCESS) {
329 *ret = err;
330 return (0);
331 }
332
333 /*
334 * If it is not an int, uint or byte array prop, return failure
335 */
336 if ((pinfo.type != PICL_PTYPE_INT) &&
337 (pinfo.type != PICL_PTYPE_UNSIGNED_INT) &&
338 (pinfo.type != PICL_PTYPE_BYTEARRAY)) {
339 *ret = PICL_FAILURE;
340 return (0);
341 }
342
343 switch (pinfo.size) {
344 case sizeof (int8_t):
345 err = picl_get_propval(proph, &int8v, sizeof (int8v));
346 *ret = err;
347 return (int8v);
348 case sizeof (int16_t):
349 err = picl_get_propval(proph, &int16v, sizeof (int16v));
350 *ret = err;
351 return (int16v);
352 case sizeof (int32_t):
353 err = picl_get_propval(proph, &int32v, sizeof (int32v));
354 *ret = err;
355 return (int32v);
356 case sizeof (int64_t):
357 err = picl_get_propval(proph, &int64v, sizeof (int64v));
358 *ret = err;
359 return (int64v);
360 default: /* not supported size */
361 *ret = PICL_FAILURE;
362 return (0);
363 }
364 }
365
366 /*
367 * This function fills in the bus type for an IO device.
368 * If a device hangs off /pci@7c0/pci@0/pci@8, it's on
369 * the pci-x bus. Otherwise, it's on a pci-e bus.
370 *
371 */
372 void
erie_get_bus_type(char path[],char bus_type[])373 erie_get_bus_type(char path[], char bus_type[])
374 {
375 if (strncmp(path, PCIX_BUS, ERIE_PCIX_COMP) == 0) {
376 (void) strcpy(bus_type, "PCIX");
377 } else {
378 (void) strcpy(bus_type, "PCIE");
379 }
380 }
381
382 /*
383 * Thie function indicates whether a device is in a pci-e slot
384 * or if it's on the motherboard. There's only one pci-e slot
385 * on erie, everything else is on the motherboard.
386 *
387 */
388 int
erie_get_slot_number(char path[])389 erie_get_slot_number(char path[])
390 {
391 if (strncmp(path, FIRE0, ERIE_PCIE_COMP) == 0)
392 return (0);
393 return (NO_SLOT);
394 }
395
396 /*
397 * This function takes a path to one of the on-board
398 * network devices and returns the instance# of that
399 * device.
400 *
401 */
402 int
erie_get_network_instance(char path[])403 erie_get_network_instance(char path[])
404 {
405
406 if (strncmp(path, ERIE_NETWORK_1, strlen(ERIE_NETWORK_1)) == 0) {
407 return (1);
408 } else if (strncmp(path, ERIE_NETWORK_3, strlen(ERIE_NETWORK_3)) == 0) {
409 return (3);
410 } else if (strncmp(path, ERIE_NETWORK_0, strlen(ERIE_NETWORK_0)) == 0) {
411 return (0);
412 } else if (strncmp(path, ERIE_NETWORK_2, strlen(ERIE_NETWORK_2)) == 0) {
413 return (2);
414 } else {
415 return (-1);
416 }
417 }
418
419 /*
420 * This function gets the path of a node and
421 * the error code from the picl API
422 *
423 */
424 int
erie_get_path(picl_nodehdl_t nodeh,char path[],int size)425 erie_get_path(picl_nodehdl_t nodeh, char path[], int size)
426 {
427 int err;
428
429 /* hardware path of this node */
430 err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
431 path, size);
432 return (err);
433 }
434
435 /*
436 * This function returns assings the string passed in
437 * the value of the picl node's name
438 *
439 */
440 int
erie_get_name(picl_nodehdl_t nodeh,char name[],int size)441 erie_get_name(picl_nodehdl_t nodeh, char name[], int size)
442 {
443 int err;
444 char *compatible;
445 char binding_name[MAXSTRLEN];
446 char lname[MAXSTRLEN];
447
448 /* Get this node's name */
449 err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &lname, size);
450 if (err == PICL_PROPNOTFOUND) {
451 (void) strcpy(lname, "");
452 err = PICL_SUCCESS;
453 }
454
455 /*
456 * If binding_name is found,
457 * name will be <nodename>-<binding_name>
458 */
459 err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
460 &binding_name, sizeof (binding_name));
461 if (err == PICL_SUCCESS) {
462 if (strcmp(lname, binding_name) != 0) {
463 (void) strlcat(lname, "-", MAXSTRLEN);
464 (void) strlcat(lname, binding_name, MAXSTRLEN);
465 }
466 /*
467 * if compatible prop is not found, name will be
468 * <nodename>-<compatible>
469 */
470 } else if (err == PICL_PROPNOTFOUND) {
471 err = erie_get_first_compatible_value(nodeh, &compatible);
472 if (err == PICL_SUCCESS) {
473 (void) strlcat(lname, "-", MAXSTRLEN);
474 (void) strlcat(lname, compatible, MAXSTRLEN);
475 }
476 err = PICL_SUCCESS;
477 } else {
478 return (err);
479 }
480
481 /* The name was created fine, copy it to name var */
482 (void) strcpy(name, lname);
483 return (err);
484 }
485
486 /*
487 * This functions assigns the string passed in the
488 * the value of the picl node's NAC name.
489 */
490 void
erie_get_nac(char bus_type[],char path[],int slot,char name[],char nac[],int size)491 erie_get_nac(char bus_type[], char path[], int slot, char name[], char nac[],
492 int size)
493 {
494 int instance;
495
496 /* Figure out NAC name and instance, if onboard network node */
497 if (strncmp(name, NETWORK, NET_COMP_NUM) == 0) {
498 instance = erie_get_network_instance(path);
499 (void) snprintf(nac, size, "%s/%s%d", MOTHERBOARD,
500 "NET", instance);
501 } else if (slot != NO_SLOT) {
502 (void) snprintf(nac, size, "%s/%s%d", MOTHERBOARD, bus_type,
503 slot);
504 } else {
505 (void) snprintf(nac, size, "%s/%s", MOTHERBOARD, bus_type);
506 }
507 }
508
509 /*
510 * This function copies the node's model into model string
511 *
512 */
513 int
erie_get_model(picl_nodehdl_t nodeh,char model[],int size)514 erie_get_model(picl_nodehdl_t nodeh, char model[], int size)
515 {
516 int err;
517 char tmp_model[MAXSTRLEN];
518
519 /* Get the model of this node */
520 err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
521 &tmp_model, size);
522 if (err == PICL_PROPNOTFOUND) {
523 (void) strcpy(model, "");
524 err = PICL_SUCCESS;
525 } else {
526 (void) strcpy(model, tmp_model);
527 }
528 return (err);
529 }
530
531 /*
532 * This function copies the node's class into class string
533 *
534 */
535 int
erie_get_class(picl_nodehdl_t nodeh,char piclclass[],int size)536 erie_get_class(picl_nodehdl_t nodeh, char piclclass[], int size)
537 {
538 int err;
539 err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
540 piclclass, size);
541 return (err);
542 }
543