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
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.
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]
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include "fru_access_impl.h"
31 static uchar_t sp_sec_hdr
[] = SP_SEC_HDR
;
32 static uchar_t sp_seg_hdr
[] = SP_SEG_HDR
;
33 static uchar_t sp_seg_body
[] = SP_DATA
;
36 * function to return section header for simulated SPD fruid
39 * sec_hdr buffer to receive section header
40 * sec_hdr_len size of buffer sec_hdr
42 * size of returned data (0 if sec_hdr_len too small)
45 get_sp_sec_hdr(void *sec_hdr
, size_t sec_hdr_len
)
47 if (sec_hdr_len
< sizeof (sp_sec_hdr
))
49 (void) memcpy(sec_hdr
, sp_sec_hdr
, sizeof (sp_sec_hdr
));
50 return (sizeof (sp_sec_hdr
));
54 * function to return segment header for simulated SPD fruid
57 * seg_hdr buffer to receive segment header
58 * seg_hdr_len size of buffer seg_hdr
60 * size of returned data (0 if seg_hdr_len too small)
63 get_sp_seg_hdr(void *seg_hdr
, size_t seg_hdr_len
)
65 if (seg_hdr_len
< sizeof (sp_seg_hdr
))
67 (void) memcpy(seg_hdr
, sp_seg_hdr
, sizeof (sp_seg_hdr
));
68 return (sizeof (sp_seg_hdr
));
72 * Function to convert SPD data into SPD fruid segment.
73 * The segment comprises two tagged records: DIMM_Capacity and SPD_R.
75 * DIMM_Capacity is a text string showing the total usable size of the
76 * DIMM (i.e. not including error correction bits). This record is derived
77 * from module row density and number of rows.
79 * SPD_R contains the entire SPD data area from the DIMM. It is slightly
80 * massaged to make it easier to display:
81 * bytes 0 - 63 are presented as is
82 * bytes 64 - 71 (JEDEC code) are compressed into 2 bytes, matching the
84 * bytes 72 - 92 are copied as is (to bytes 66 - 86)
85 * byte 93 year of manufacture is expanded to a 2 byte (big endian)
86 * field which includes the century (to bytes 87 - 88)
87 * bytes 94 - 127 are copied as is (to bytes 89 - 122)
90 * spd_data pointer to SPD data
91 * spd_data_len length of supplied SPD data
92 * sp_seg_ptr pointer to receive address of converted data
93 * sp_seg_len pointer for size of converted data
99 cvrt_dim_data(const char *spd_data
, size_t spd_data_len
, uchar_t
**sp_seg_ptr
,
108 if (spd_data_len
< sizeof (spd_data_t
))
111 spd
= (spd_data_t
*)spd_data
;
112 *sp_seg_ptr
= malloc(sizeof (sp_seg_body
));
114 if (*sp_seg_ptr
== NULL
)
117 /* set up template for SP seg */
118 (void) memcpy(*sp_seg_ptr
, sp_seg_body
, sizeof (sp_seg_body
));
120 year
= spd
->manu_year
;
128 * move first 64 bytes of SPD data into SPD-R record
130 (void) memcpy(*sp_seg_ptr
+ SPD_R_OFF
, spd_data
, 64);
133 * re-write full data width as big endian
135 (*sp_seg_ptr
+ SPD_R_OFF
+ DATA_WIDTH
)[0] = spd
->ms_data_width
;
136 (*sp_seg_ptr
+ SPD_R_OFF
+ DATA_WIDTH
)[1] = spd
->ls_data_width
;
139 * construct Sun compressed encoding for JEDEC code
141 for (c
= 0; c
< sizeof (spd
->jedec
) - 1; c
++) {
142 if (spd
->jedec
[c
] != 0x7F)
146 (*sp_seg_ptr
)[SPD_R_OFF
+ MANUF_ID
] = (uchar_t
)c
;
147 (*sp_seg_ptr
)[SPD_R_OFF
+ MANUF_ID
+ 1] = (uchar_t
)spd
->jedec
[c
];
150 * move other fields in place
152 (void) memcpy(*sp_seg_ptr
+ SPD_R_OFF
+ MANUF_LOC
,
153 &spd
->manu_loc
, MANUF_YEAR
- MANUF_LOC
);
155 (*sp_seg_ptr
+ SPD_R_OFF
+ MANUF_YEAR
)[0] = (uchar_t
)(year
>> 8);
156 (*sp_seg_ptr
+ SPD_R_OFF
+ MANUF_YEAR
)[1] = (uchar_t
)year
;
158 (void) memcpy(*sp_seg_ptr
+ SPD_R_OFF
+ MANUF_WEEK
,
159 &spd
->manu_week
, SPD_R_LEN
- MANUF_WEEK
);
162 * calculate the capacity and insert into capacity record
164 if ((spd
->spd_rev
>> 4) > 1) {
165 (void) snprintf((char *)(*sp_seg_ptr
+ DIMM_CAP_OFF
), 8,
166 "ver %x.%x", spd
->spd_rev
>> 4, spd
->spd_rev
& 0x0f);
167 } else if ((spd
->memory_type
!= SPDMEM_SDRAM
) &&
168 (spd
->memory_type
!= SPDMEM_SDRAM_DDR
) &&
169 (spd
->memory_type
!= SPDMEM_DDR2_SDRAM
)) {
171 * can't handle this memory type
173 ((char *)(*sp_seg_ptr
))[DIMM_CAP_OFF
] = '\0';
174 } else if ((((spd
->ms_data_width
<< 8) | spd
->ls_data_width
) == 72) &&
175 ((spd
->n_rows
& 0xf0) == 0) && ((spd
->n_cols
& 0xf0) == 0)) {
177 * OK it's 72-bits wide with equal width banks
180 capacity
= spd
->mod_row_density
;
181 if (((spd
->memory_type
== SPDMEM_DDR2_SDRAM
) &&
188 if (spd
->memory_type
== SPDMEM_DDR2_SDRAM
) {
193 if ((m_or_g
== 'M') && (capacity
>= 1024)) {
197 (void) snprintf((char *)(*sp_seg_ptr
+ DIMM_CAP_OFF
), 8,
198 "%d %cB", capacity
, m_or_g
);
200 ((char *)(*sp_seg_ptr
))[DIMM_CAP_OFF
] = '\0';
204 * finally, set the checksum
206 sum
= compute_crc32(*sp_seg_ptr
, sizeof (sp_seg_body
) - 5);
207 for (c
= 0; c
< 4; c
++) {
208 (*sp_seg_ptr
+ sizeof (sp_seg_body
) - 4)[c
] =
211 *sp_seg_len
= sizeof (sp_seg_body
);
216 * get_spd_data - reads raw data from container
218 * fd file descriptor for SPD device
219 * ctr_offset container offset
220 * ctr_len container size
221 * spd_data buffer to receive SPD data (length ctr_len)
227 get_spd_data(int fd
, char *spd_data
, size_t ctr_len
, off_t ctr_offset
)
229 if (ctr_len
< sizeof (spd_data_t
))
232 (void) memset(spd_data
, 0, ctr_len
);
234 if (pread(fd
, spd_data
, sizeof (spd_data_t
), ctr_offset
) !=