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