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