xref: /illumos-gate/usr/src/cmd/fm/schemes/mem/mem_read.c (revision d2a70789f056fc6c9ce3ab047b52126d80b0e3da)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Retrieval of the DIMM serial number from data encoded in the SPD and
31  * SEEPROM formats.
32  */
33 
34 #include <mem_spd.h>
35 #include <mem_seeprom.h>
36 #include <mem.h>
37 
38 #include <fm/fmd_fmri.h>
39 
40 #include <stdio.h>
41 #include <fcntl.h>
42 #include <errno.h>
43 #include <unistd.h>
44 #include <strings.h>
45 #include <sys/byteorder.h>
46 #include <sys/stat.h>
47 #include <sys/types.h>
48 
49 #define	BUFSIZ_SPD	256
50 #define	BUFSIZ_SEEPROM	8192
51 
52 /*
53  * SEEPROMs are composed of self-describing containers.  The first container,
54  * starting at offset 0, is r/w.  The second container, starting at 0x1800, is
55  * r/o, and contains identification information supplied by the manufacturer.
56  */
57 #define	SEEPROM_OFFSET_RO	0x1800
58 
59 static int
60 mem_get_spd_serid(const char *buf, size_t bufsz, char *serid, size_t seridsz)
61 {
62 	static const char hex_digits[] = "0123456789ABCDEF";
63 	spd_data_t *spd = (spd_data_t *)buf;
64 	char *c;
65 	int i;
66 
67 	if (bufsz < sizeof (spd_data_t))
68 		return (fmd_fmri_set_errno(EINVAL));
69 
70 	if (seridsz < sizeof (spd->asmb_serial_no) * 2 + 1)
71 		return (fmd_fmri_set_errno(EINVAL));
72 
73 	for (c = serid, i = 0; i < sizeof (spd->asmb_serial_no); i++) {
74 		*c++ = hex_digits[spd->asmb_serial_no[i] >> 4];
75 		*c++ = hex_digits[spd->asmb_serial_no[i] & 0xf];
76 	}
77 	*c = '\0';
78 
79 	return (0);
80 }
81 
82 static void *
83 seeprom_seg_lookup(const char *buf, size_t bufsz, char *segname, size_t *segszp)
84 {
85 	seeprom_container_t *sc;
86 	seeprom_seg_t *segp, seg;
87 	int sidx;
88 
89 	if (strlen(segname) != sizeof (seg.sees_name))
90 		return (NULL);
91 
92 	sc = (seeprom_container_t *)(buf + SEEPROM_OFFSET_RO);
93 
94 	/* Validate sc size then dereference it */
95 	if (bufsz < SEEPROM_OFFSET_RO + sizeof (seeprom_container_t) ||
96 	    bufsz < SEEPROM_OFFSET_RO + sizeof (seeprom_container_t) +
97 	    sc->seec_contsz)
98 		return (NULL);
99 
100 	if (sc->seec_tag == 0 || sc->seec_contsz == 0 ||
101 	    sc->seec_nsegs == 0)
102 		return (NULL);
103 
104 	for (sidx = 0; sidx < sc->seec_nsegs; sidx++) {
105 		/* LINTED - pointer alignment */
106 		segp = ((seeprom_seg_t *)(sc + 1)) + sidx;
107 
108 		bcopy(segp, &seg, sizeof (seeprom_seg_t));
109 		seg.sees_segoff = ntohs(seg.sees_segoff);
110 		seg.sees_seglen = ntohs(seg.sees_seglen);
111 
112 		if (bufsz < seg.sees_segoff + seg.sees_seglen)
113 			return (NULL);
114 
115 		if (strncmp(segname, seg.sees_name,
116 		    sizeof (seg.sees_name)) == 0) {
117 			*segszp = seg.sees_seglen;
118 			return ((void *)(buf + seg.sees_segoff));
119 		}
120 
121 	}
122 
123 	return (NULL);
124 }
125 
126 static int
127 mem_get_seeprom_serid(const char *buf, size_t bufsz, char *serid,
128     size_t seridsz)
129 {
130 	seeprom_seg_sd_t *sd;
131 	size_t segsz;
132 
133 	if (seridsz < sizeof (sd->seesd_sun_sno) + 1)
134 		return (fmd_fmri_set_errno(EINVAL));
135 
136 	if ((sd = seeprom_seg_lookup(buf, bufsz, "SD", &segsz)) == NULL)
137 		return (fmd_fmri_set_errno(EINVAL));
138 
139 	if (segsz < sizeof (seeprom_seg_sd_t))
140 		return (fmd_fmri_set_errno(EINVAL));
141 
142 	bcopy(sd->seesd_sun_sno, serid, sizeof (sd->seesd_sun_sno));
143 	serid[sizeof (sd->seesd_sun_sno)] = '\0';
144 
145 	return (0);
146 }
147 
148 int
149 mem_get_serid(const char *device, char *serid, size_t seridsz)
150 {
151 	char buf[8192];
152 	int fd;
153 	ssize_t sz;
154 
155 	if ((fd = open(device, O_RDONLY)) < 0)
156 		return (-1); /* errno is set for us */
157 
158 	if ((sz = read(fd, buf, sizeof (buf))) < 0) {
159 		int err = errno;
160 		(void) close(fd);
161 		return (fmd_fmri_set_errno(err));
162 	}
163 
164 	(void) close(fd);
165 
166 	switch (sz) {
167 	case BUFSIZ_SPD:
168 		return (mem_get_spd_serid(buf, BUFSIZ_SPD, serid, seridsz));
169 	case BUFSIZ_SEEPROM:
170 		return (mem_get_seeprom_serid(buf, BUFSIZ_SEEPROM, serid,
171 		    seridsz));
172 	default:
173 		return (fmd_fmri_set_errno(EINVAL));
174 	}
175 }
176