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