#include <mem_spd.h>
#include <mem_seeprom.h>
#include <mem.h>
#include <fm/fmd_fmri.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <strings.h>
#include <sys/byteorder.h>
#include <sys/stat.h>
#include <sys/types.h>
#define BUFSIZ_SPD 256
#define BUFSIZ_SEEPROM 8192
#define SEEPROM_OFFSET_RO 0x1800
static int
mem_get_spd_serid(const char *buf, size_t bufsz, char *serid, size_t seridsz)
{
static const char hex_digits[] = "0123456789ABCDEF";
spd_data_t *spd = (spd_data_t *)buf;
char *c;
int i;
if (bufsz < sizeof (spd_data_t))
return (fmd_fmri_set_errno(EINVAL));
if (seridsz < sizeof (spd->asmb_serial_no) * 2 + 1)
return (fmd_fmri_set_errno(EINVAL));
for (c = serid, i = 0; i < sizeof (spd->asmb_serial_no); i++) {
*c++ = hex_digits[spd->asmb_serial_no[i] >> 4];
*c++ = hex_digits[spd->asmb_serial_no[i] & 0xf];
}
*c = '\0';
return (0);
}
static void *
seeprom_seg_lookup(const char *buf, size_t bufsz, char *segname, size_t *segszp)
{
seeprom_container_t *sc;
seeprom_seg_t *segp, seg;
int sidx;
if (strlen(segname) != sizeof (seg.sees_name))
return (NULL);
sc = (seeprom_container_t *)(buf + SEEPROM_OFFSET_RO);
if (bufsz < SEEPROM_OFFSET_RO + sizeof (seeprom_container_t) ||
bufsz < SEEPROM_OFFSET_RO + sizeof (seeprom_container_t) +
sc->seec_contsz)
return (NULL);
if (sc->seec_tag == 0 || sc->seec_contsz == 0 ||
sc->seec_nsegs == 0)
return (NULL);
for (sidx = 0; sidx < sc->seec_nsegs; sidx++) {
segp = ((seeprom_seg_t *)(sc + 1)) + sidx;
bcopy(segp, &seg, sizeof (seeprom_seg_t));
seg.sees_segoff = ntohs(seg.sees_segoff);
seg.sees_seglen = ntohs(seg.sees_seglen);
if (bufsz < seg.sees_segoff + seg.sees_seglen)
return (NULL);
if (strncmp(segname, seg.sees_name,
sizeof (seg.sees_name)) == 0) {
*segszp = seg.sees_seglen;
return ((void *)(buf + seg.sees_segoff));
}
}
return (NULL);
}
static int
mem_get_seeprom_serid(const char *buf, size_t bufsz, char *serid,
size_t seridsz)
{
seeprom_seg_sd_t *sd;
size_t segsz;
if (seridsz < sizeof (sd->seesd_sun_sno) + 1)
return (fmd_fmri_set_errno(EINVAL));
if ((sd = seeprom_seg_lookup(buf, bufsz, "SD", &segsz)) == NULL)
return (fmd_fmri_set_errno(EINVAL));
if (segsz < sizeof (seeprom_seg_sd_t))
return (fmd_fmri_set_errno(EINVAL));
bcopy(sd->seesd_sun_sno, serid, sizeof (sd->seesd_sun_sno));
serid[sizeof (sd->seesd_sun_sno)] = '\0';
return (0);
}
int
mem_get_serid(const char *device, char *serid, size_t seridsz)
{
char buf[8192];
int fd;
ssize_t sz;
if ((fd = open(device, O_RDONLY)) < 0)
return (-1);
if ((sz = read(fd, buf, sizeof (buf))) < 0) {
int err = errno;
(void) close(fd);
return (fmd_fmri_set_errno(err));
}
(void) close(fd);
switch (sz) {
case BUFSIZ_SPD:
return (mem_get_spd_serid(buf, BUFSIZ_SPD, serid, seridsz));
case BUFSIZ_SEEPROM:
return (mem_get_seeprom_serid(buf, BUFSIZ_SEEPROM, serid,
seridsz));
default:
return (fmd_fmri_set_errno(EINVAL));
}
}