16489Sjmcp /*
26489Sjmcp * CDDL HEADER START
36489Sjmcp *
46489Sjmcp * The contents of this file are subject to the terms of the
56489Sjmcp * Common Development and Distribution License (the "License").
66489Sjmcp * You may not use this file except in compliance with the License.
76489Sjmcp *
86489Sjmcp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96489Sjmcp * or http://www.opensolaris.org/os/licensing.
106489Sjmcp * See the License for the specific language governing permissions
116489Sjmcp * and limitations under the License.
126489Sjmcp *
136489Sjmcp * When distributing Covered Code, include this CDDL HEADER in each
146489Sjmcp * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156489Sjmcp * If applicable, add the following below this CDDL HEADER, with the
166489Sjmcp * fields enclosed by brackets "[]" replaced with your own identifying
176489Sjmcp * information: Portions Copyright [yyyy] [name of copyright owner]
186489Sjmcp *
196489Sjmcp * CDDL HEADER END
206489Sjmcp */
216489Sjmcp /*
22*13016SXin.Chen@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
236489Sjmcp */
246489Sjmcp
256489Sjmcp /*
266489Sjmcp * fwflash.c
276489Sjmcp */
286489Sjmcp #include <stdio.h>
296489Sjmcp #include <stdlib.h>
306489Sjmcp #include <unistd.h>
316489Sjmcp #include <strings.h>
326489Sjmcp #include <errno.h>
336489Sjmcp #include <sys/queue.h>
346489Sjmcp #include <signal.h>
356489Sjmcp #include <locale.h>
366489Sjmcp #include <sys/stat.h>
376489Sjmcp #include <sys/types.h>
386489Sjmcp #include <sys/param.h>
396489Sjmcp #include <fcntl.h>
406489Sjmcp #include <dlfcn.h>
416489Sjmcp #include <dirent.h>
426489Sjmcp #include <sys/varargs.h>
436489Sjmcp #include <libintl.h> /* for gettext(3c) */
446489Sjmcp #include <libdevinfo.h>
459862SSherry.Moore@Sun.COM #include <libscf_priv.h>
466489Sjmcp #include <fwflash/fwflash.h>
476846Sjmcp #include <sys/modctl.h> /* for MAXMODCONFNAME */
486489Sjmcp
496489Sjmcp /* global arg list */
506489Sjmcp int fwflash_arg_list = 0;
516489Sjmcp char *filelist[10];
526489Sjmcp
5310507SPei-Hong.Huang@Sun.COM /* exposed global args */
5410507SPei-Hong.Huang@Sun.COM di_node_t rootnode;
5510507SPei-Hong.Huang@Sun.COM struct PLUGINLIST *fw_pluginlist;
5610507SPei-Hong.Huang@Sun.COM struct DEVICELIST *fw_devices;
5710507SPei-Hong.Huang@Sun.COM struct vrfyplugin *verifier;
5810507SPei-Hong.Huang@Sun.COM struct fw_plugin *self;
5910507SPei-Hong.Huang@Sun.COM int fwflash_debug = 0;
6010507SPei-Hong.Huang@Sun.COM
616489Sjmcp /* are we writing to flash? */
626489Sjmcp static int fwflash_in_write = 0;
636489Sjmcp
646489Sjmcp /*
656489Sjmcp * If we *must* track the version string for fwflash, then
666489Sjmcp * we should do so in this common file rather than the header
676489Sjmcp * file since it will then be in sync with what the customer
687317SJames.McPherson@Sun.COM * sees. We should deprecate the "-v" option since it is not
697317SJames.McPherson@Sun.COM * actually of any use - it doesn't line up with Mercurial's
707317SJames.McPherson@Sun.COM * concept of the changeset.
716489Sjmcp */
7210869SXin.Chen@Sun.COM #define FWFLASH_VERSION "v1.9"
736489Sjmcp #define FWFLASH_PROG_NAME "fwflash"
746489Sjmcp
756489Sjmcp static int get_fileopts(char *options);
766489Sjmcp static int flash_device_list();
776489Sjmcp static int flash_load_plugins();
786489Sjmcp static int fwflash_update(char *device, char *filename, int flags);
796489Sjmcp static int fwflash_read_file(char *device, char *filename);
806489Sjmcp static int fwflash_list_fw(char *class);
816489Sjmcp static int fwflash_load_verifier(char *drv, char *vendorid, char *fwimg);
826489Sjmcp static void fwflash_intr(int sig);
836489Sjmcp static void fwflash_handle_signals(void);
847317SJames.McPherson@Sun.COM static void fwflash_usage(char *arg);
856489Sjmcp static void fwflash_version(void);
866489Sjmcp static int confirm_target(struct devicelist *thisdev, char *file);
876489Sjmcp
886489Sjmcp /*
896489Sjmcp * FWFlash main code
906489Sjmcp */
916489Sjmcp int
main(int argc,char ** argv)928031SShantkumar.Hiremath@Sun.COM main(int argc, char **argv)
938031SShantkumar.Hiremath@Sun.COM {
946489Sjmcp int rv = FWFLASH_SUCCESS;
956489Sjmcp int i;
966489Sjmcp char ch;
976489Sjmcp char *read_file;
986489Sjmcp extern char *optarg;
996489Sjmcp char *devclass = NULL;
1006489Sjmcp char *devpath = NULL;
1016489Sjmcp
1026489Sjmcp /* local variables from env */
1036489Sjmcp (void) setlocale(LC_ALL, "");
1046489Sjmcp
1056489Sjmcp #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
1066489Sjmcp #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't. */
1076489Sjmcp #endif
1086489Sjmcp
1096489Sjmcp (void) textdomain(TEXT_DOMAIN);
1106489Sjmcp
1116489Sjmcp read_file = NULL;
1126489Sjmcp
1136489Sjmcp if (argc < 2) {
1146489Sjmcp /* no args supplied */
1156489Sjmcp fwflash_usage(NULL);
1166489Sjmcp return (FWFLASH_FAILURE);
1176489Sjmcp }
1186489Sjmcp
1199560SPei-Hong.Huang@Sun.COM while ((ch = getopt(argc, argv, "hvylc:f:r:Qd:")) != EOF) {
1206489Sjmcp switch (ch) {
1216489Sjmcp case 'h':
1226489Sjmcp fwflash_arg_list |= FWFLASH_HELP_FLAG;
1236489Sjmcp break;
1246489Sjmcp case 'v':
1256489Sjmcp fwflash_arg_list |= FWFLASH_VER_FLAG;
1266489Sjmcp break;
1276489Sjmcp case 'y':
1286489Sjmcp fwflash_arg_list |= FWFLASH_YES_FLAG;
1296489Sjmcp break;
1306489Sjmcp case 'l':
1316489Sjmcp fwflash_arg_list |= FWFLASH_LIST_FLAG;
1326489Sjmcp break;
1336489Sjmcp case 'c':
1346489Sjmcp fwflash_arg_list |= FWFLASH_CLASS_FLAG;
1356489Sjmcp /* we validate later */
1366489Sjmcp devclass = strdup(optarg);
1376489Sjmcp break;
1386489Sjmcp case 'd':
1396489Sjmcp fwflash_arg_list |= FWFLASH_DEVICE_FLAG;
1406489Sjmcp devpath = strdup(optarg);
1416489Sjmcp break;
1426489Sjmcp case 'f':
1436489Sjmcp fwflash_arg_list |= FWFLASH_FW_FLAG;
1446489Sjmcp if ((rv = get_fileopts(optarg)) != FWFLASH_SUCCESS) {
1457317SJames.McPherson@Sun.COM fwflash_usage(NULL);
1466489Sjmcp return (FWFLASH_FAILURE);
1476489Sjmcp }
1486489Sjmcp break;
1496489Sjmcp case 'r':
1506489Sjmcp fwflash_arg_list |= FWFLASH_READ_FLAG;
1516489Sjmcp read_file = strdup(optarg);
1526489Sjmcp break;
1536489Sjmcp case 'Q':
1546489Sjmcp /* NOT in the manpage */
1556489Sjmcp fwflash_debug = 1;
1566489Sjmcp break;
1576846Sjmcp /* illegal options */
1586489Sjmcp default:
1596489Sjmcp fwflash_usage(optarg);
1606489Sjmcp return (FWFLASH_FAILURE);
1616489Sjmcp }
1626489Sjmcp }
1636489Sjmcp
1646489Sjmcp /* Do Help */
1656489Sjmcp if ((fwflash_arg_list & FWFLASH_HELP_FLAG) ||
1666489Sjmcp ((fwflash_arg_list & FWFLASH_DEVICE_FLAG) &&
1678031SShantkumar.Hiremath@Sun.COM !((fwflash_arg_list & FWFLASH_FW_FLAG) ||
1688031SShantkumar.Hiremath@Sun.COM (fwflash_arg_list & FWFLASH_READ_FLAG)))) {
1697317SJames.McPherson@Sun.COM fwflash_usage(NULL);
1706489Sjmcp return (FWFLASH_SUCCESS);
1716489Sjmcp }
1726489Sjmcp
1736489Sjmcp /* Do Version */
1746489Sjmcp if (fwflash_arg_list == FWFLASH_VER_FLAG) {
1756489Sjmcp fwflash_version();
1766489Sjmcp return (FWFLASH_SUCCESS);
1776489Sjmcp }
1786489Sjmcp
1796489Sjmcp /* generate global list of devices */
1806489Sjmcp if ((rv = flash_load_plugins()) != FWFLASH_SUCCESS) {
1816489Sjmcp logmsg(MSG_ERROR,
1826489Sjmcp gettext("Unable to load fwflash plugins\n"));
1836489Sjmcp fwflash_intr(0);
1846489Sjmcp return (rv);
1856489Sjmcp }
1866489Sjmcp
1876489Sjmcp if ((rv = flash_device_list()) != FWFLASH_SUCCESS) {
1886489Sjmcp logmsg(MSG_ERROR,
1896489Sjmcp gettext("No flashable devices in this system\n"));
1906489Sjmcp fwflash_intr(0);
1916489Sjmcp return (rv);
1926489Sjmcp }
1936489Sjmcp
1946489Sjmcp /* Do list */
1956489Sjmcp if (fwflash_arg_list == (FWFLASH_LIST_FLAG) ||
1966489Sjmcp fwflash_arg_list == (FWFLASH_LIST_FLAG | FWFLASH_CLASS_FLAG)) {
1976489Sjmcp rv = fwflash_list_fw(devclass);
1986489Sjmcp fwflash_intr(0);
1996489Sjmcp return (rv);
2006489Sjmcp }
2016489Sjmcp
2026489Sjmcp fwflash_handle_signals();
2036489Sjmcp
2046489Sjmcp /* Do flash update (write) */
2056489Sjmcp if ((fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG)) ||
2066489Sjmcp (fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG |
2078031SShantkumar.Hiremath@Sun.COM FWFLASH_YES_FLAG))) {
2089862SSherry.Moore@Sun.COM int fastreboot_disabled = 0;
2096489Sjmcp /* the update function handles the real arg parsing */
2106489Sjmcp i = 0;
2116489Sjmcp while (filelist[i] != NULL) {
2126489Sjmcp if ((rv = fwflash_update(devpath, filelist[i],
2136489Sjmcp fwflash_arg_list)) == FWFLASH_SUCCESS) {
2146489Sjmcp /* failed ops have already been noted */
2159862SSherry.Moore@Sun.COM if (!fastreboot_disabled &&
2169862SSherry.Moore@Sun.COM scf_fastreboot_default_set_transient(
2179862SSherry.Moore@Sun.COM B_FALSE) != SCF_SUCCESS)
2189862SSherry.Moore@Sun.COM logmsg(MSG_ERROR, gettext(
2199862SSherry.Moore@Sun.COM "Failed to disable fast "
2209862SSherry.Moore@Sun.COM "reboot.\n"));
2219862SSherry.Moore@Sun.COM else
2229862SSherry.Moore@Sun.COM fastreboot_disabled = 1;
2236489Sjmcp logmsg(MSG_ERROR,
2246489Sjmcp gettext("New firmware will be activated "
2258031SShantkumar.Hiremath@Sun.COM "after you reboot\n\n"));
2266489Sjmcp }
2276489Sjmcp ++i;
2286489Sjmcp }
2296489Sjmcp
2306489Sjmcp fwflash_intr(0);
2316489Sjmcp return (rv);
2326489Sjmcp }
2336489Sjmcp
2346489Sjmcp /* Do flash read */
2356489Sjmcp if ((fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG)) ||
2366489Sjmcp (fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG |
2378031SShantkumar.Hiremath@Sun.COM FWFLASH_YES_FLAG))) {
2386489Sjmcp rv = fwflash_read_file(devpath, read_file);
2396489Sjmcp fwflash_intr(0);
2406489Sjmcp return (rv);
2416489Sjmcp }
2426489Sjmcp
2436489Sjmcp fwflash_usage(NULL);
2446489Sjmcp
2456489Sjmcp return (FWFLASH_FAILURE);
2466489Sjmcp }
2476489Sjmcp
2486489Sjmcp
2496489Sjmcp static int
flash_load_plugins()2508031SShantkumar.Hiremath@Sun.COM flash_load_plugins()
2518031SShantkumar.Hiremath@Sun.COM {
2526489Sjmcp
2536489Sjmcp int rval = FWFLASH_SUCCESS;
2546489Sjmcp DIR *dirp;
2556489Sjmcp struct dirent *plugdir;
2566489Sjmcp char *plugname;
2576489Sjmcp struct fw_plugin *tmpplug;
2586489Sjmcp struct pluginlist *tmpelem;
2596489Sjmcp void *sym;
2606489Sjmcp char *fwplugdirpath, *tempdirpath;
2616489Sjmcp
2626489Sjmcp
2636489Sjmcp #define CLOSEFREE() { \
2646489Sjmcp (void) dlclose(tmpplug->handle); \
2656489Sjmcp free(tmpplug); }
2666489Sjmcp
2676489Sjmcp /*
2686489Sjmcp * Procedure:
2696489Sjmcp *
2706489Sjmcp * cd /usr/lib/fwflash/identify
2716489Sjmcp * open each .so file found therein
2726489Sjmcp * dlopen(.sofile)
2736489Sjmcp * if it's one of our plugins, add it to fw_pluginlist;
2746489Sjmcp *
2756489Sjmcp * functions we need here include dlopen and dlsym.
2766489Sjmcp *
2776489Sjmcp * If we get to the end and fw_pluginlist struct is empty,
2786489Sjmcp * return FWFLASH_FAILURE so we return to the shell.
2796489Sjmcp */
2806489Sjmcp
2816489Sjmcp if ((fwplugdirpath = calloc(1, MAXPATHLEN + 1)) == NULL) {
2826489Sjmcp logmsg(MSG_ERROR,
2836489Sjmcp gettext("Unable to malloc %d bytes while "
2846489Sjmcp "trying to load plugins: %s\n"),
2856489Sjmcp MAXPATHLEN + 1, strerror(errno));
2866489Sjmcp return (FWFLASH_FAILURE);
2876489Sjmcp }
2886489Sjmcp
2896489Sjmcp tempdirpath = getenv("FWPLUGINDIR");
2906489Sjmcp
2916489Sjmcp if ((fwflash_debug > 0) && (tempdirpath != NULL)) {
2926489Sjmcp (void) strlcpy(fwplugdirpath, tempdirpath,
2936489Sjmcp strlen(tempdirpath) + 1);
2946489Sjmcp } else {
2956489Sjmcp (void) strlcpy(fwplugdirpath, FWPLUGINDIR,
2966489Sjmcp strlen(FWPLUGINDIR) + 1);
2976489Sjmcp }
2986489Sjmcp
2996489Sjmcp if ((dirp = opendir(fwplugdirpath)) == NULL) {
3006489Sjmcp logmsg(MSG_ERROR,
3016846Sjmcp gettext("Unable to open %s\n"),
3026489Sjmcp fwplugdirpath);
3036489Sjmcp return (errno);
3046489Sjmcp }
3056489Sjmcp
3066489Sjmcp if ((plugdir = calloc(1, sizeof (struct dirent) + MAXPATHLEN + 1))
3076489Sjmcp == NULL) {
3086489Sjmcp logmsg(MSG_ERROR,
3096489Sjmcp gettext("Unable to malloc %d bytes while "
3106489Sjmcp "trying to load plugins: %s\n"),
3116489Sjmcp MAXPATHLEN + 1 + sizeof (struct dirent),
3126489Sjmcp strerror(errno));
3136489Sjmcp return (FWFLASH_FAILURE);
3146489Sjmcp }
3156489Sjmcp
3166489Sjmcp if ((fw_pluginlist = calloc(1, sizeof (struct fw_plugin)))
3176489Sjmcp == NULL) {
3186489Sjmcp logmsg(MSG_ERROR,
3196489Sjmcp gettext("Unable to malloc %d bytes while "
3208031SShantkumar.Hiremath@Sun.COM "trying to load plugins: %s\n"),
3219683SXin.Chen@Sun.COM sizeof (struct fw_plugin), strerror(errno));
3226489Sjmcp return (FWFLASH_FAILURE);
3236489Sjmcp }
3246489Sjmcp
3256489Sjmcp TAILQ_INIT(fw_pluginlist);
3266489Sjmcp
3276489Sjmcp while ((readdir_r(dirp, plugdir, &plugdir) == 0) && (plugdir != NULL)) {
3286489Sjmcp
3296489Sjmcp errno = 0; /* remove chance of false results */
3306489Sjmcp
3316489Sjmcp if ((plugdir->d_name[0] == '.') ||
3326489Sjmcp (strstr(plugdir->d_name, ".so") == NULL)) {
3336489Sjmcp continue;
3346489Sjmcp }
3356489Sjmcp
3366489Sjmcp if ((plugname = calloc(1, MAXPATHLEN + 1)) == NULL) {
3376489Sjmcp logmsg(MSG_ERROR,
3386489Sjmcp gettext("Unable to malloc %d bytes while "
3398031SShantkumar.Hiremath@Sun.COM "trying to load plugins: %s\n"),
3406489Sjmcp MAXPATHLEN + 1, strerror(errno));
3416489Sjmcp return (FWFLASH_FAILURE);
3426489Sjmcp }
3436489Sjmcp
3446489Sjmcp (void) snprintf(plugname, MAXPATHLEN, "%s/%s",
3456489Sjmcp fwplugdirpath, plugdir->d_name);
3466489Sjmcp
3476489Sjmcp /* start allocating storage */
3486489Sjmcp if ((tmpelem = calloc(1, sizeof (struct pluginlist)))
3496489Sjmcp == NULL) {
3506489Sjmcp logmsg(MSG_ERROR,
3516489Sjmcp gettext("Unable to malloc %d bytes while "
3528031SShantkumar.Hiremath@Sun.COM "trying to load plugins: %s\n"),
3536489Sjmcp sizeof (struct pluginlist), strerror(errno));
3546489Sjmcp return (FWFLASH_FAILURE);
3556489Sjmcp }
3566489Sjmcp
3576489Sjmcp if ((tmpplug = calloc(1, sizeof (struct fw_plugin)))
3586489Sjmcp == NULL) {
3596489Sjmcp logmsg(MSG_ERROR,
3606489Sjmcp gettext("Unable to malloc %d bytes while "
3616489Sjmcp "trying to load plugins: %s\n"),
3626489Sjmcp sizeof (struct fw_plugin), strerror(errno));
3636489Sjmcp return (FWFLASH_FAILURE);
3646489Sjmcp }
3656489Sjmcp
3666489Sjmcp /* load 'er up! */
3676489Sjmcp tmpplug->handle = dlopen(plugname, RTLD_NOW);
3686489Sjmcp if (tmpplug->handle == NULL) {
3696489Sjmcp free(tmpplug);
3706489Sjmcp continue; /* assume there are other plugins */
3716489Sjmcp }
3726489Sjmcp
3736489Sjmcp if ((tmpplug->filename = calloc(1, strlen(plugname) + 1))
3746489Sjmcp == NULL) {
3756489Sjmcp logmsg(MSG_ERROR,
3766489Sjmcp gettext("Unable to allocate %d bytes for plugin "
3778031SShantkumar.Hiremath@Sun.COM "filename %s:%s\n"),
3786489Sjmcp strlen(plugname) + 1, plugname,
3796489Sjmcp strerror(errno));
3806489Sjmcp return (rval);
3816489Sjmcp }
3826489Sjmcp
3836489Sjmcp (void) strlcpy(tmpplug->filename, plugname,
3846489Sjmcp strlen(plugname) + 1);
3856489Sjmcp
3866489Sjmcp /* now sanity check the file */
3876489Sjmcp if ((sym = dlsym(tmpplug->handle, "drivername"))
3886489Sjmcp != NULL) {
3896489Sjmcp /* max length of drivername */
3906846Sjmcp tmpplug->drvname = calloc(1, MAXMODCONFNAME);
3916846Sjmcp
3926846Sjmcp /* are we doing double-time? */
3936846Sjmcp if (strncmp((char *)sym, plugdir->d_name,
3946846Sjmcp MAXMODCONFNAME) != 0) {
3956846Sjmcp char *tempnm = calloc(1, MAXMODCONFNAME);
3966846Sjmcp
3979683SXin.Chen@Sun.COM (void) memcpy(tempnm, plugdir->d_name,
3989683SXin.Chen@Sun.COM MAXMODCONFNAME);
3996846Sjmcp (void) strlcpy(tmpplug->drvname,
4006846Sjmcp strtok(tempnm, "."),
4016846Sjmcp strlen(plugdir->d_name) + 1);
4026846Sjmcp free(tempnm);
4036846Sjmcp } else {
4046846Sjmcp (void) strlcpy(tmpplug->drvname,
4056846Sjmcp (char *)sym, strlen(sym) + 1);
4066846Sjmcp }
4076489Sjmcp } else {
4086489Sjmcp CLOSEFREE();
4096489Sjmcp continue;
4106489Sjmcp }
4116489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_readfw"))
4126489Sjmcp != NULL) {
4136489Sjmcp tmpplug->fw_readfw = (int (*)())sym;
4146489Sjmcp } else {
4156489Sjmcp CLOSEFREE();
4166489Sjmcp continue;
4176489Sjmcp }
4186489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_writefw"))
4196489Sjmcp != NULL) {
4206489Sjmcp tmpplug->fw_writefw = (int (*)())sym;
4216489Sjmcp } else {
4226489Sjmcp CLOSEFREE();
4236489Sjmcp continue;
4246489Sjmcp }
4256489Sjmcp
4266489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_identify"))
4276489Sjmcp != NULL) {
4286489Sjmcp tmpplug->fw_identify =
4296489Sjmcp (int (*)(int))sym;
4306489Sjmcp } else {
4316489Sjmcp CLOSEFREE();
4326489Sjmcp continue;
4336489Sjmcp }
4346489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_devinfo"))
4356489Sjmcp != NULL) {
4366489Sjmcp tmpplug->fw_devinfo =
4376489Sjmcp (int (*)(struct devicelist *))sym;
4386489Sjmcp } else {
4396489Sjmcp CLOSEFREE();
4406489Sjmcp continue;
4416489Sjmcp }
4426489Sjmcp
4439683SXin.Chen@Sun.COM if ((sym = dlsym(tmpplug->handle, "plugin_version"))
4449683SXin.Chen@Sun.COM != NULL) {
4459683SXin.Chen@Sun.COM if ((*(int *)sym) >= FWPLUGIN_VERSION_2) {
4469683SXin.Chen@Sun.COM if ((sym = dlsym(tmpplug->handle,
4479683SXin.Chen@Sun.COM "fw_cleanup")) != NULL) {
4489683SXin.Chen@Sun.COM tmpplug->fw_cleanup =
4499683SXin.Chen@Sun.COM (void (*)(struct devicelist *))sym;
4509683SXin.Chen@Sun.COM } else {
4519683SXin.Chen@Sun.COM logmsg(MSG_ERROR,
4529683SXin.Chen@Sun.COM gettext("ERROR: v2 plugin (%s) "
4539683SXin.Chen@Sun.COM "has no fw_cleanup function\n"),
4549683SXin.Chen@Sun.COM tmpplug->filename);
4559683SXin.Chen@Sun.COM CLOSEFREE();
4569683SXin.Chen@Sun.COM continue;
4579683SXin.Chen@Sun.COM }
4589683SXin.Chen@Sun.COM } else {
4599683SXin.Chen@Sun.COM logmsg(MSG_INFO,
4609683SXin.Chen@Sun.COM "Identification plugin %s defined "
4619683SXin.Chen@Sun.COM "plugin_version < FWPLUGIN_VERSION_2 !");
4629683SXin.Chen@Sun.COM }
4639683SXin.Chen@Sun.COM }
4649683SXin.Chen@Sun.COM
4656846Sjmcp if ((tmpelem->drvname = calloc(1, MAXMODCONFNAME))
4666489Sjmcp == NULL) {
4676489Sjmcp logmsg(MSG_ERROR,
4686846Sjmcp gettext("Unable to allocate space for a"
4698031SShantkumar.Hiremath@Sun.COM "drivername %s\n"),
4706489Sjmcp tmpplug->drvname);
4716489Sjmcp return (FWFLASH_FAILURE);
4726489Sjmcp }
4736489Sjmcp
4746489Sjmcp (void) strlcpy(tmpelem->drvname, tmpplug->drvname,
4756489Sjmcp strlen(tmpplug->drvname) + 1);
4766489Sjmcp
4776489Sjmcp if ((tmpelem->filename = calloc(1,
4786489Sjmcp strlen(tmpplug->filename) + 1)) == NULL) {
4796489Sjmcp logmsg(MSG_ERROR,
4806489Sjmcp gettext("Unable to allocate %d bytes for "
4818031SShantkumar.Hiremath@Sun.COM "filename %s\n"),
4826489Sjmcp strlen(tmpplug->filename) + 1,
4836846Sjmcp tmpplug->filename);
4846489Sjmcp return (FWFLASH_FAILURE);
4856489Sjmcp }
4866489Sjmcp
4876489Sjmcp (void) strlcpy(tmpelem->filename, plugname,
4886489Sjmcp strlen(plugname) + 1);
4896489Sjmcp tmpelem->plugin = tmpplug;
4906489Sjmcp
4916489Sjmcp /* CONSTCOND */
4926489Sjmcp TAILQ_INSERT_TAIL(fw_pluginlist, tmpelem, nextplugin);
4936489Sjmcp }
4946489Sjmcp
4956489Sjmcp if ((plugdir == NULL) && TAILQ_EMPTY(fw_pluginlist)) {
4966489Sjmcp return (FWFLASH_FAILURE);
4976489Sjmcp }
4986489Sjmcp
4996489Sjmcp if (errno != 0) {
5006489Sjmcp logmsg(MSG_ERROR,
5016489Sjmcp gettext("Error reading directory entry in %s\n"),
5026489Sjmcp fwplugdirpath);
5036489Sjmcp rval = errno;
5046489Sjmcp }
5056489Sjmcp
5069683SXin.Chen@Sun.COM free(fwplugdirpath);
5079683SXin.Chen@Sun.COM free(plugdir);
5086489Sjmcp (void) closedir(dirp);
5096489Sjmcp return (rval);
5106489Sjmcp }
5116489Sjmcp
5126489Sjmcp /*
5136489Sjmcp * fwflash_load_verifier dlload()s the appropriate firmware image
5146489Sjmcp * verification plugin, and attaches the designated fwimg's fd to
5156489Sjmcp * the vrfyplugin structure so we only have to load the image in
5166489Sjmcp * one place.
5176489Sjmcp */
5186489Sjmcp int
fwflash_load_verifier(char * drv,char * vendorid,char * fwimg)5198031SShantkumar.Hiremath@Sun.COM fwflash_load_verifier(char *drv, char *vendorid, char *fwimg)
5208031SShantkumar.Hiremath@Sun.COM {
5216489Sjmcp
5226489Sjmcp int rv = FWFLASH_FAILURE;
5236489Sjmcp int imgfd;
5246489Sjmcp char *fwvrfydirpath, *tempdirpath, *filename;
5256489Sjmcp char *clean; /* for the space-removed vid */
5266489Sjmcp struct stat fwstat;
5276489Sjmcp struct vrfyplugin *vrfy;
5286489Sjmcp void *vrfysym;
5296489Sjmcp
5306489Sjmcp /*
5316489Sjmcp * To make flashing multiple firmware images somewhat more
5326489Sjmcp * efficient, we start this function by checking whether a
5336489Sjmcp * verifier for this device has already been loaded. If it
5346489Sjmcp * has been loaded, we replace the imgfile information, and
5356489Sjmcp * then continue as if we were loading for the first time.
5366489Sjmcp */
5376489Sjmcp
5386489Sjmcp if (verifier != NULL) {
5396489Sjmcp verifier->imgsize = 0;
5406489Sjmcp verifier->flashbuf = 0; /* set by the verifier function */
5416489Sjmcp
5429683SXin.Chen@Sun.COM if (verifier->imgfile != NULL) {
5439683SXin.Chen@Sun.COM free(verifier->imgfile);
5449683SXin.Chen@Sun.COM verifier->imgfile = NULL;
5459683SXin.Chen@Sun.COM }
5466489Sjmcp
5479683SXin.Chen@Sun.COM if (verifier->fwimage != NULL) {
5489683SXin.Chen@Sun.COM free(verifier->fwimage);
5499683SXin.Chen@Sun.COM verifier->fwimage = NULL;
5509683SXin.Chen@Sun.COM }
5516489Sjmcp } else {
5526489Sjmcp if ((fwvrfydirpath = calloc(1, MAXPATHLEN + 1)) == NULL) {
5536489Sjmcp logmsg(MSG_ERROR,
5546489Sjmcp gettext("Unable to allocate space for a firmware "
5558031SShantkumar.Hiremath@Sun.COM "verifier file(1)"));
5566489Sjmcp return (rv);
5576489Sjmcp }
5586489Sjmcp
5596489Sjmcp if ((filename = calloc(1, MAXPATHLEN + 1)) == NULL) {
5606489Sjmcp logmsg(MSG_ERROR,
5616489Sjmcp gettext("Unable to allocate space "
5626489Sjmcp "for a firmware verifier file(2)"));
5639683SXin.Chen@Sun.COM free(fwvrfydirpath);
5646489Sjmcp return (rv);
5656489Sjmcp }
5666489Sjmcp
5679683SXin.Chen@Sun.COM /*
5689683SXin.Chen@Sun.COM * Since SCSI devices can have a vendor id of up to 8
5699683SXin.Chen@Sun.COM * left-aligned and _space-padded_ characters, we first need to
5709683SXin.Chen@Sun.COM * strip off any space characters before we try to make a
5719683SXin.Chen@Sun.COM * filename out of it
5729683SXin.Chen@Sun.COM */
5736489Sjmcp clean = strtok(vendorid, " ");
5746489Sjmcp if (clean == NULL) {
5756489Sjmcp /* invalid vendorid, something's really wrong */
5766489Sjmcp logmsg(MSG_ERROR,
5776489Sjmcp gettext("Invalid vendorid (null) specified for "
5788031SShantkumar.Hiremath@Sun.COM "device\n"));
5799683SXin.Chen@Sun.COM free(filename);
5809683SXin.Chen@Sun.COM free(fwvrfydirpath);
5816489Sjmcp return (rv);
5826489Sjmcp }
5836489Sjmcp
5846489Sjmcp tempdirpath = getenv("FWVERIFYPLUGINDIR");
5856489Sjmcp
5866489Sjmcp if ((fwflash_debug > 0) && (tempdirpath != NULL)) {
5876489Sjmcp (void) strlcpy(fwvrfydirpath, tempdirpath,
5886489Sjmcp strlen(tempdirpath) + 1);
5896489Sjmcp } else {
5906489Sjmcp (void) strlcpy(fwvrfydirpath, FWVERIFYPLUGINDIR,
5916489Sjmcp strlen(FWVERIFYPLUGINDIR) + 1);
5926489Sjmcp }
5936489Sjmcp
5946489Sjmcp if ((vrfy = calloc(1, sizeof (struct vrfyplugin))) == NULL) {
5956489Sjmcp logmsg(MSG_ERROR,
5966489Sjmcp gettext("Unable to allocate space "
5976489Sjmcp "for a firmware verifier structure"));
5986489Sjmcp free(filename);
5996489Sjmcp free(fwvrfydirpath);
6009683SXin.Chen@Sun.COM return (rv);
6016489Sjmcp }
6026489Sjmcp
6036489Sjmcp errno = 0; /* false positive removal */
6046489Sjmcp
6059683SXin.Chen@Sun.COM (void) snprintf(filename, MAXPATHLEN, "%s/%s-%s.so",
6066489Sjmcp fwvrfydirpath, drv, clean);
6079683SXin.Chen@Sun.COM if ((vrfy->handle = dlopen(filename, RTLD_NOW)) == NULL) {
6089683SXin.Chen@Sun.COM logmsg(MSG_INFO, gettext(dlerror()));
6099683SXin.Chen@Sun.COM logmsg(MSG_INFO,
6109683SXin.Chen@Sun.COM gettext("\nUnable to open verification plugin "
6119683SXin.Chen@Sun.COM "%s. Looking for %s-GENERIC plugin instead.\n"),
6129683SXin.Chen@Sun.COM filename, drv);
6139683SXin.Chen@Sun.COM
6149683SXin.Chen@Sun.COM /* Try the drv-GENERIC.so form, _then_ die */
6159683SXin.Chen@Sun.COM bzero(filename, strlen(filename) + 1);
6169683SXin.Chen@Sun.COM (void) snprintf(filename, MAXPATHLEN,
6179683SXin.Chen@Sun.COM "%s/%s-GENERIC.so", fwvrfydirpath, drv);
6189683SXin.Chen@Sun.COM
6199683SXin.Chen@Sun.COM if ((vrfy->handle = dlopen(filename, RTLD_NOW))
6209683SXin.Chen@Sun.COM == NULL) {
6219683SXin.Chen@Sun.COM logmsg(MSG_INFO, gettext(dlerror()));
6229683SXin.Chen@Sun.COM logmsg(MSG_ERROR,
6239683SXin.Chen@Sun.COM gettext("\nUnable to open either "
6249683SXin.Chen@Sun.COM "verification plugin %s/%s-%s.so or "
6259683SXin.Chen@Sun.COM "generic plugin %s.\nUnable to verify "
6269683SXin.Chen@Sun.COM "firmware image. Aborting.\n"),
6279683SXin.Chen@Sun.COM fwvrfydirpath, drv, clean, filename);
6289683SXin.Chen@Sun.COM free(filename);
6299683SXin.Chen@Sun.COM free(fwvrfydirpath);
6309683SXin.Chen@Sun.COM return (rv);
6319683SXin.Chen@Sun.COM }
6329683SXin.Chen@Sun.COM }
6336489Sjmcp
6346489Sjmcp if ((vrfy->filename = calloc(1, strlen(filename) + 1))
6356489Sjmcp == NULL) {
6366489Sjmcp logmsg(MSG_ERROR,
6376489Sjmcp gettext("Unable to allocate space to store "
6388031SShantkumar.Hiremath@Sun.COM "a verifier filename\n"));
6396489Sjmcp free(filename);
6406489Sjmcp free(fwvrfydirpath);
6416489Sjmcp free(vrfy->handle);
6429683SXin.Chen@Sun.COM return (rv);
6436489Sjmcp }
6446489Sjmcp (void) strlcpy(vrfy->filename, filename, strlen(filename) + 1);
6456489Sjmcp
6466489Sjmcp if ((vrfysym = dlsym(vrfy->handle, "vendorvrfy")) == NULL) {
6476489Sjmcp logmsg(MSG_ERROR,
6486489Sjmcp gettext("%s is an invalid firmware verification "
6498031SShantkumar.Hiremath@Sun.COM "plugin."), filename);
6506489Sjmcp (void) dlclose(vrfy->handle);
6516489Sjmcp free(filename);
6526489Sjmcp free(fwvrfydirpath);
6536489Sjmcp free(vrfy);
6549683SXin.Chen@Sun.COM return (rv);
6556489Sjmcp } else {
6566489Sjmcp vrfy->vendorvrfy =
6576489Sjmcp (int (*)(struct devicelist *))vrfysym;
6586489Sjmcp }
6596489Sjmcp
6606489Sjmcp vrfysym = dlsym(vrfy->handle, "vendor");
6616489Sjmcp
6626489Sjmcp if (vrfysym == NULL) {
6636489Sjmcp logmsg(MSG_ERROR,
6646489Sjmcp gettext("Invalid vendor (null) in verification "
6658031SShantkumar.Hiremath@Sun.COM "plugin %s\n"), filename);
6666489Sjmcp (void) dlclose(vrfy->handle);
6676489Sjmcp free(vrfy);
6689683SXin.Chen@Sun.COM return (rv);
6696489Sjmcp } else {
6706489Sjmcp if (strncmp(vendorid, (char *)vrfysym,
6716489Sjmcp strlen(vendorid)) != 0) {
6726489Sjmcp logmsg(MSG_INFO,
6736489Sjmcp "Using a sym-linked (%s -> %s) "
6749683SXin.Chen@Sun.COM "verification plugin\n",
6756489Sjmcp vendorid, vrfysym);
6766489Sjmcp vrfy->vendor = calloc(1, strlen(vendorid) + 1);
6776489Sjmcp } else {
6786489Sjmcp vrfy->vendor = calloc(1, strlen(vrfysym) + 1);
6796489Sjmcp }
6806489Sjmcp (void) strlcpy(vrfy->vendor, (char *)vrfysym,
6816489Sjmcp strlen(vendorid) + 1);
6826489Sjmcp }
6836489Sjmcp
6846489Sjmcp verifier = vrfy; /* a convenience variable */
6859683SXin.Chen@Sun.COM free(filename);
6869683SXin.Chen@Sun.COM free(fwvrfydirpath);
6876489Sjmcp }
6886489Sjmcp
6896489Sjmcp /*
6906489Sjmcp * We don't do any verification that the fw image file is in
6916489Sjmcp * an approved location, but it's easy enough to modify this
6926489Sjmcp * function to do so. The verification plugin should provide
6936489Sjmcp * sufficient protection.
6946489Sjmcp */
6956489Sjmcp
6966489Sjmcp if ((imgfd = open(fwimg, O_RDONLY)) < 0) {
6976489Sjmcp logmsg(MSG_ERROR,
6986489Sjmcp gettext("Unable to open designated firmware "
6998031SShantkumar.Hiremath@Sun.COM "image file %s: %s\n"),
7006489Sjmcp (fwimg != NULL) ? fwimg : "(null)",
7016489Sjmcp strerror(errno));
7026489Sjmcp rv = FWFLASH_FAILURE;
7036489Sjmcp goto cleanup;
7046489Sjmcp }
7056489Sjmcp
7066489Sjmcp if (stat(fwimg, &fwstat) == -1) {
7076489Sjmcp logmsg(MSG_ERROR,
7086489Sjmcp gettext("Unable to stat() firmware image file "
7098031SShantkumar.Hiremath@Sun.COM "%s: %s\n"),
7106489Sjmcp fwimg, strerror(errno));
7116489Sjmcp rv = FWFLASH_FAILURE;
7126489Sjmcp goto cleanup;
7136489Sjmcp } else {
7146489Sjmcp verifier->imgsize = fwstat.st_size;
7156489Sjmcp if ((verifier->fwimage = calloc(1, verifier->imgsize))
7166489Sjmcp == NULL) {
7176489Sjmcp logmsg(MSG_ERROR,
7186489Sjmcp gettext("Unable to load firmware image "
7198031SShantkumar.Hiremath@Sun.COM "%s: %s\n"),
7206489Sjmcp fwimg, strerror(errno));
7216489Sjmcp rv = FWFLASH_FAILURE;
7226489Sjmcp goto cleanup;
7236489Sjmcp }
7246489Sjmcp }
7256489Sjmcp
7266489Sjmcp errno = 0;
7276489Sjmcp if ((rv = read(imgfd, verifier->fwimage,
7286489Sjmcp (size_t)verifier->imgsize)) < verifier->imgsize) {
7296489Sjmcp /* we haven't read enough data, bail */
7306489Sjmcp logmsg(MSG_ERROR,
7316489Sjmcp gettext("Failed to read sufficient data "
7328031SShantkumar.Hiremath@Sun.COM "(got %d bytes, expected %d bytes) from "
7338031SShantkumar.Hiremath@Sun.COM "firmware image file %s: %s\n"),
7346489Sjmcp rv, verifier->imgsize,
7359683SXin.Chen@Sun.COM verifier->filename, strerror(errno));
7366489Sjmcp rv = FWFLASH_FAILURE;
7376489Sjmcp } else {
7386489Sjmcp rv = FWFLASH_SUCCESS;
7396489Sjmcp }
7406489Sjmcp
7416489Sjmcp if ((verifier->imgfile = calloc(1, strlen(fwimg) + 1)) == NULL) {
7426489Sjmcp logmsg(MSG_ERROR,
7436489Sjmcp gettext("Unable to save name of firmware image\n"));
7446489Sjmcp rv = FWFLASH_FAILURE;
7456489Sjmcp } else {
7466489Sjmcp (void) strlcpy(verifier->imgfile, fwimg, strlen(fwimg) + 1);
7476489Sjmcp }
7486489Sjmcp
7496489Sjmcp if (rv != FWFLASH_SUCCESS) {
7506489Sjmcp /* cleanup and let's get outta here */
7516489Sjmcp cleanup:
7526489Sjmcp free(verifier->filename);
7536489Sjmcp free(verifier->vendor);
7546489Sjmcp
7559683SXin.Chen@Sun.COM if (!(fwflash_arg_list & FWFLASH_READ_FLAG) &&
7569683SXin.Chen@Sun.COM verifier->fwimage)
7576489Sjmcp free(verifier->fwimage);
7586489Sjmcp
7596489Sjmcp verifier->filename = NULL;
7606489Sjmcp verifier->vendor = NULL;
7616489Sjmcp verifier->vendorvrfy = NULL;
7626489Sjmcp verifier->fwimage = NULL;
7636489Sjmcp (void) dlclose(verifier->handle);
7646489Sjmcp verifier->handle = NULL;
7656489Sjmcp free(verifier);
7666489Sjmcp if (imgfd >= 0) {
7676489Sjmcp (void) close(imgfd);
7686489Sjmcp }
7696489Sjmcp verifier = NULL;
7706489Sjmcp }
7716489Sjmcp
7726489Sjmcp return (rv);
7736489Sjmcp }
7746489Sjmcp
7756489Sjmcp /*
7766489Sjmcp * cycles through the global list of plugins to find
7776489Sjmcp * each flashable device, which is added to fw_devices
7786489Sjmcp *
7796489Sjmcp * Each plugin's identify routine must allocated storage
7806489Sjmcp * as required.
7816489Sjmcp *
7826489Sjmcp * Each plugin's identify routine must return
7836489Sjmcp * FWFLASH_FAILURE if it cannot find any devices
7846489Sjmcp * which it handles.
7856489Sjmcp */
7866489Sjmcp static int
flash_device_list()7876489Sjmcp flash_device_list()
7886489Sjmcp {
7896489Sjmcp int rv = FWFLASH_FAILURE;
7906489Sjmcp int startidx = 0;
7916489Sjmcp int sumrv = 0;
7926489Sjmcp struct pluginlist *plugins;
7936489Sjmcp
7946489Sjmcp /* we open rootnode here, and close it in fwflash_intr */
7959683SXin.Chen@Sun.COM if ((rootnode = di_init("/", DINFOCPYALL|DINFOFORCE)) == DI_NODE_NIL) {
7966489Sjmcp logmsg(MSG_ERROR,
7976489Sjmcp gettext("Unable to take device tree snapshot: %s\n"),
7986489Sjmcp strerror(errno));
7996489Sjmcp return (rv);
8006489Sjmcp }
8016489Sjmcp
8026489Sjmcp if ((fw_devices = calloc(1, sizeof (struct devicelist))) == NULL) {
8036489Sjmcp logmsg(MSG_ERROR,
8046489Sjmcp gettext("Unable to malloc %d bytes while "
8056489Sjmcp "trying to find devices: %s\n"),
8066489Sjmcp sizeof (struct devicelist), strerror(errno));
8076489Sjmcp return (FWFLASH_FAILURE);
8086489Sjmcp }
8096489Sjmcp
8106489Sjmcp /* CONSTCOND */
8116489Sjmcp TAILQ_INIT(fw_devices);
8126489Sjmcp
8136489Sjmcp TAILQ_FOREACH(plugins, fw_pluginlist, nextplugin) {
8146489Sjmcp self = plugins->plugin;
8156489Sjmcp rv = plugins->plugin->fw_identify(startidx);
8166489Sjmcp
8176489Sjmcp logmsg(MSG_INFO,
8186489Sjmcp gettext("fwflash:flash_device_list() got %d from "
8196489Sjmcp "identify routine\n"), rv);
8206489Sjmcp
8216489Sjmcp /* only bump startidx if we've found at least one device */
8226489Sjmcp if (rv == FWFLASH_SUCCESS) {
8236489Sjmcp startidx += 100;
8246489Sjmcp sumrv++;
8256489Sjmcp } else {
8266489Sjmcp logmsg(MSG_INFO,
8276489Sjmcp gettext("No flashable devices attached with "
8286489Sjmcp "the %s driver in this system\n"),
8296489Sjmcp plugins->drvname);
8306489Sjmcp }
8316489Sjmcp }
8326489Sjmcp
8336489Sjmcp if (sumrv > 0)
8346489Sjmcp rv = FWFLASH_SUCCESS;
8356489Sjmcp
8366489Sjmcp return (rv);
8376489Sjmcp }
8386489Sjmcp
8396489Sjmcp static int
fwflash_list_fw(char * class)8406489Sjmcp fwflash_list_fw(char *class)
8416489Sjmcp {
8426489Sjmcp int rv = 0;
8436489Sjmcp struct devicelist *curdev;
8446489Sjmcp int header = 1;
8456489Sjmcp
8466489Sjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) {
8476489Sjmcp
8486489Sjmcp /* we're either class-conscious, or we're not */
8496489Sjmcp if (((class != NULL) &&
8506489Sjmcp ((strncmp(curdev->classname, "ALL", 3) == 0) ||
8516489Sjmcp (strcmp(curdev->classname, class) == 0))) ||
8526489Sjmcp (class == NULL)) {
8536489Sjmcp
8546489Sjmcp if (header != 0) {
8556489Sjmcp (void) fprintf(stdout,
8566489Sjmcp gettext("List of available devices:\n"));
8576489Sjmcp header--;
8586489Sjmcp }
8596489Sjmcp /*
8606489Sjmcp * If any plugin's fw_devinfo() function returns
8616489Sjmcp * FWFLASH_FAILURE then we want to keep track of
8626489Sjmcp * it. _Most_ plugins should always return
8636489Sjmcp * FWFLASH_SUCCESS from this function. The only
8646489Sjmcp * exception known at this point is the tavor plugin.
8656489Sjmcp */
8666489Sjmcp rv += curdev->plugin->fw_devinfo(curdev);
8676489Sjmcp }
8686489Sjmcp }
8696489Sjmcp return (rv);
8706489Sjmcp }
8716489Sjmcp
8726489Sjmcp static int
fwflash_update(char * device,char * filename,int flags)8737317SJames.McPherson@Sun.COM fwflash_update(char *device, char *filename, int flags)
8747317SJames.McPherson@Sun.COM {
8756489Sjmcp
8766489Sjmcp int rv = FWFLASH_FAILURE;
8776489Sjmcp int needsfree = 0;
8786846Sjmcp int found = 0;
8796489Sjmcp struct devicelist *curdev;
8806489Sjmcp char *realfile;
8816489Sjmcp
8826489Sjmcp /*
8836489Sjmcp * Here's how we operate:
8846489Sjmcp *
8856489Sjmcp * We perform some basic checks on the args, then walk
8866489Sjmcp * through the device list looking for the device which
8876489Sjmcp * matches. We then load the appropriate verifier for the
8886489Sjmcp * image file and device, verify the image, then call the
8896489Sjmcp * fw_writefw() function of the appropriate plugin.
8906489Sjmcp *
8916489Sjmcp * There is no "force" flag to enable you to flash a firmware
8926489Sjmcp * image onto an incompatible device because the verifier
8936489Sjmcp * will return FWFLASH_FAILURE if the image doesn't match.
8946489Sjmcp */
8956489Sjmcp
8966489Sjmcp /* new firmware filename and device desc */
8976489Sjmcp if (filename == NULL) {
8986489Sjmcp logmsg(MSG_ERROR,
8996489Sjmcp gettext("Invalid firmware filename (null)\n"));
9006489Sjmcp return (FWFLASH_FAILURE);
9016489Sjmcp }
9026489Sjmcp
9036489Sjmcp if (device == NULL) {
9046489Sjmcp logmsg(MSG_ERROR,
9056489Sjmcp gettext("Invalid device requested (null)\n"));
9066489Sjmcp return (FWFLASH_FAILURE);
9076489Sjmcp }
9086489Sjmcp
9096489Sjmcp if ((realfile = calloc(1, PATH_MAX + 1)) == NULL) {
9106489Sjmcp logmsg(MSG_ERROR,
9116489Sjmcp gettext("Unable to allocate space for device "
9127317SJames.McPherson@Sun.COM "filename, operation might fail if %s is"
9137317SJames.McPherson@Sun.COM "a symbolic link\n"),
9146489Sjmcp device);
9156489Sjmcp realfile = device;
9166489Sjmcp } else {
9176489Sjmcp /*
9186489Sjmcp * If realpath() succeeds, then we have a valid
9196489Sjmcp * device filename in realfile.
9206489Sjmcp */
9216489Sjmcp if (realpath(device, realfile) == NULL) {
9226489Sjmcp logmsg(MSG_ERROR,
9236489Sjmcp gettext("Unable to resolve device filename"
9247317SJames.McPherson@Sun.COM ": %s\n"),
9256489Sjmcp strerror(errno));
9266489Sjmcp /* tidy up */
9276489Sjmcp free(realfile);
9286489Sjmcp /* realpath didn't succeed, use fallback */
9296489Sjmcp realfile = device;
9306489Sjmcp } else {
9316489Sjmcp needsfree = 1;
9326489Sjmcp }
9336489Sjmcp }
9346489Sjmcp
9356489Sjmcp logmsg(MSG_INFO,
9366489Sjmcp gettext("fwflash_update: fw_filename (%s) device (%s)\n"),
9376489Sjmcp filename, device);
9386489Sjmcp
9396489Sjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) {
9406489Sjmcp if (strcmp(curdev->access_devname, realfile) == 0) {
9416846Sjmcp found++;
9426489Sjmcp rv = fwflash_load_verifier(curdev->drvname,
9436489Sjmcp curdev->ident->vid, filename);
9446489Sjmcp if (rv == FWFLASH_FAILURE) {
9456489Sjmcp logmsg(MSG_ERROR,
9466489Sjmcp gettext("Unable to load verifier "
9477317SJames.McPherson@Sun.COM "for device %s\n"),
9486489Sjmcp curdev->access_devname);
9496489Sjmcp return (FWFLASH_FAILURE);
9506489Sjmcp }
9516489Sjmcp rv = verifier->vendorvrfy(curdev);
9526489Sjmcp if (rv == FWFLASH_FAILURE) {
9536489Sjmcp /* the verifier prints a message */
9546489Sjmcp logmsg(MSG_INFO,
9556489Sjmcp "verifier (%s) for %s :: %s returned "
9566489Sjmcp "FWFLASH_FAILURE\n",
9576489Sjmcp verifier->filename,
9586489Sjmcp filename, curdev->access_devname);
9596489Sjmcp return (rv);
9606489Sjmcp }
9616489Sjmcp
9627317SJames.McPherson@Sun.COM if (((flags & FWFLASH_YES_FLAG) == FWFLASH_YES_FLAG) ||
9636489Sjmcp (rv = confirm_target(curdev, filename)) ==
9646489Sjmcp FWFLASH_YES_FLAG) {
9656489Sjmcp logmsg(MSG_INFO,
9666489Sjmcp "about to flash using plugin %s\n",
9676489Sjmcp curdev->plugin->filename);
9686489Sjmcp rv = curdev->plugin->fw_writefw(curdev,
9696489Sjmcp filename);
9706489Sjmcp if (rv == FWFLASH_FAILURE) {
9716489Sjmcp logmsg(MSG_ERROR,
9726489Sjmcp gettext("Failed to flash "
9737317SJames.McPherson@Sun.COM "firmware file %s on "
9747317SJames.McPherson@Sun.COM "device %s: %d\n"),
9756489Sjmcp filename,
9766489Sjmcp curdev->access_devname, rv);
9776489Sjmcp }
9786489Sjmcp } else {
9796489Sjmcp logmsg(MSG_ERROR,
9806489Sjmcp gettext("Flash operation not confirmed "
9817317SJames.McPherson@Sun.COM "by user\n"),
9826489Sjmcp curdev->access_devname);
9836489Sjmcp rv = FWFLASH_FAILURE;
9846489Sjmcp }
9856489Sjmcp }
9866489Sjmcp }
9876489Sjmcp
9886846Sjmcp if (!found)
9896846Sjmcp /* report the same device that the user passed in */
9906846Sjmcp logmsg(MSG_ERROR,
9916846Sjmcp gettext("Device %s does not appear "
9926846Sjmcp "to be flashable\n"),
9936846Sjmcp ((strncmp(device, realfile, strlen(device)) == 0) ?
9949683SXin.Chen@Sun.COM realfile : device));
9956846Sjmcp
9966489Sjmcp if (needsfree)
9976489Sjmcp free(realfile);
9986489Sjmcp
9996489Sjmcp return (rv);
10006489Sjmcp }
10016489Sjmcp
10026489Sjmcp /*
10036489Sjmcp * We validate that the device path is in our global device list and
10046489Sjmcp * that the filename exists, then palm things off to the relevant plugin.
10056489Sjmcp */
10066489Sjmcp static int
fwflash_read_file(char * device,char * filename)10076489Sjmcp fwflash_read_file(char *device, char *filename)
10086489Sjmcp {
10096489Sjmcp struct devicelist *curdev;
10106489Sjmcp int rv;
10118031SShantkumar.Hiremath@Sun.COM int found = 0;
10126489Sjmcp
10136489Sjmcp /* new firmware filename and device desc */
10146489Sjmcp
10156489Sjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) {
10166489Sjmcp if (strncmp(curdev->access_devname, device,
10176489Sjmcp MAXPATHLEN) == 0) {
10186489Sjmcp rv = curdev->plugin->fw_readfw(curdev, filename);
10196489Sjmcp
10206489Sjmcp if (rv != FWFLASH_SUCCESS)
10216489Sjmcp logmsg(MSG_ERROR,
10226489Sjmcp gettext("Unable to write out firmware "
10236489Sjmcp "image for %s to file %s\n"),
10246489Sjmcp curdev->access_devname, filename);
10258031SShantkumar.Hiremath@Sun.COM found++;
10266489Sjmcp }
10276489Sjmcp
10286489Sjmcp }
10298031SShantkumar.Hiremath@Sun.COM
10308031SShantkumar.Hiremath@Sun.COM if (!found) {
10316489Sjmcp logmsg(MSG_ERROR,
10326489Sjmcp gettext("No device matching %s was found.\n"),
10336489Sjmcp device);
10346489Sjmcp rv = FWFLASH_FAILURE;
10356489Sjmcp }
10366489Sjmcp
10376489Sjmcp return (rv);
10386489Sjmcp }
10396489Sjmcp
10406489Sjmcp static void
fwflash_usage(char * arg)10416489Sjmcp fwflash_usage(char *arg)
10426489Sjmcp {
10436489Sjmcp
10446489Sjmcp (void) fprintf(stderr, "\n");
10456489Sjmcp if (arg != NULL) {
10466489Sjmcp logmsg(MSG_ERROR,
10476489Sjmcp gettext("Invalid argument (%s) supplied\n"), arg);
10486489Sjmcp }
10496489Sjmcp
10506489Sjmcp (void) fprintf(stderr, "\n");
10516489Sjmcp
10526489Sjmcp (void) fprintf(stdout, gettext("Usage:\n\t"));
10536489Sjmcp (void) fprintf(stdout, gettext("fwflash [-l [-c device_class "
10546489Sjmcp "| ALL]] | [-v] | [-h]\n\t"));
10556489Sjmcp (void) fprintf(stdout, gettext("fwflash [-f file1,file2,file3"
10566489Sjmcp ",... | -r file] [-y] -d device_path\n\n"));
10576489Sjmcp (void) fprintf(stdout, "\n"); /* workaround for xgettext */
10586489Sjmcp
10596489Sjmcp (void) fprintf(stdout,
10606489Sjmcp gettext("\t-l\t\tlist flashable devices in this system\n"
10616489Sjmcp "\t-c device_class limit search to a specific class\n"
10626489Sjmcp "\t\t\teg IB for InfiniBand, ses for SCSI Enclosures\n"
10636489Sjmcp "\t-v\t\tprint version number of fwflash utility\n"
10648031SShantkumar.Hiremath@Sun.COM "\t-h\t\tprint this usage message\n\n"));
10656489Sjmcp (void) fprintf(stdout,
10666489Sjmcp gettext("\t-f file1,file2,file3,...\n"
10676489Sjmcp "\t\t\tfirmware image file list to flash\n"
10686489Sjmcp "\t-r file\t\tfile to dump device firmware to\n"
10696489Sjmcp "\t-y\t\tanswer Yes/Y/y to prompts\n"
10706489Sjmcp "\t-d device_path\tpathname of device to be flashed\n\n"));
10716489Sjmcp
10726489Sjmcp (void) fprintf(stdout,
10736489Sjmcp gettext("\tIf -d device_path is specified, then one of -f "
10746489Sjmcp "<files>\n"
10756489Sjmcp "\tor -r <file> must also be specified\n\n"));
10766489Sjmcp
10776489Sjmcp (void) fprintf(stdout,
10786489Sjmcp gettext("\tIf multiple firmware images are required to be "
10796489Sjmcp "flashed\n"
10806489Sjmcp "\tthey must be listed together, separated by commas. The\n"
10816489Sjmcp "\timages will be flashed in the order specified.\n\n"));
10826489Sjmcp
10836489Sjmcp (void) fprintf(stdout, "\n");
10846489Sjmcp }
10856489Sjmcp
10866489Sjmcp static void
fwflash_version(void)10876489Sjmcp fwflash_version(void)
10886489Sjmcp {
10896489Sjmcp (void) fprintf(stdout, gettext("\n%s: "), FWFLASH_PROG_NAME);
10906489Sjmcp (void) fprintf(stdout, gettext("version %s\n"),
10916489Sjmcp FWFLASH_VERSION);
10926489Sjmcp }
10936489Sjmcp
10946489Sjmcp static void
fwflash_intr(int sig)10956489Sjmcp fwflash_intr(int sig)
10966489Sjmcp {
10976489Sjmcp
10986489Sjmcp struct devicelist *thisdev;
10996489Sjmcp struct pluginlist *thisplug;
11006489Sjmcp
11016489Sjmcp (void) signal(SIGINT, SIG_IGN);
11026489Sjmcp (void) signal(SIGTERM, SIG_IGN);
11036846Sjmcp (void) signal(SIGABRT, SIG_IGN);
11049683SXin.Chen@Sun.COM
11056489Sjmcp if (fwflash_in_write) {
11066489Sjmcp (void) fprintf(stderr,
11076489Sjmcp gettext("WARNING: firmware image may be corrupted\n\t"));
11086489Sjmcp (void) fprintf(stderr,
11096489Sjmcp gettext("Reflash firmware before rebooting!\n"));
11106489Sjmcp }
11116489Sjmcp
11126489Sjmcp if (sig > 0) {
11136489Sjmcp (void) logmsg(MSG_ERROR, gettext("\n"));
11146489Sjmcp (void) logmsg(MSG_ERROR,
11156489Sjmcp gettext("fwflash exiting due to signal (%d)\n"), sig);
11166489Sjmcp }
11176489Sjmcp
11186489Sjmcp /*
11196489Sjmcp * we need to close everything down properly, so
11206489Sjmcp * call the plugin closure routines
11216489Sjmcp */
11226489Sjmcp if (fw_devices != NULL) {
11236489Sjmcp TAILQ_FOREACH(thisdev, fw_devices, nextdev) {
11249683SXin.Chen@Sun.COM if (thisdev->plugin->fw_cleanup != NULL) {
11259683SXin.Chen@Sun.COM /*
11269683SXin.Chen@Sun.COM * If we've got a cleanup routine, it
11279683SXin.Chen@Sun.COM * cleans up _everything_ for thisdev
11289683SXin.Chen@Sun.COM */
11299683SXin.Chen@Sun.COM thisdev->plugin->fw_cleanup(thisdev);
11309683SXin.Chen@Sun.COM } else {
11319683SXin.Chen@Sun.COM /* free the components first */
11329683SXin.Chen@Sun.COM free(thisdev->access_devname);
11339683SXin.Chen@Sun.COM free(thisdev->drvname);
11349683SXin.Chen@Sun.COM free(thisdev->classname);
11359683SXin.Chen@Sun.COM if (thisdev->ident != NULL)
11369683SXin.Chen@Sun.COM free(thisdev->ident);
11379683SXin.Chen@Sun.COM /* We don't free address[] for old plugins */
11389683SXin.Chen@Sun.COM thisdev->ident = NULL;
11399683SXin.Chen@Sun.COM thisdev->plugin = NULL;
11409683SXin.Chen@Sun.COM }
11416489Sjmcp /* CONSTCOND */
11426489Sjmcp TAILQ_REMOVE(fw_devices, thisdev, nextdev);
11436489Sjmcp }
11446489Sjmcp }
11456489Sjmcp
11466489Sjmcp if (fw_pluginlist != NULL) {
11476489Sjmcp TAILQ_FOREACH(thisplug, fw_pluginlist, nextplugin) {
11486489Sjmcp free(thisplug->filename);
11496489Sjmcp free(thisplug->drvname);
11506489Sjmcp free(thisplug->plugin->filename);
11516489Sjmcp free(thisplug->plugin->drvname);
11526489Sjmcp thisplug->filename = NULL;
11536489Sjmcp thisplug->drvname = NULL;
11546489Sjmcp thisplug->plugin->filename = NULL;
11556489Sjmcp thisplug->plugin->drvname = NULL;
11566489Sjmcp thisplug->plugin->fw_readfw = NULL;
11576489Sjmcp thisplug->plugin->fw_writefw = NULL;
11586489Sjmcp thisplug->plugin->fw_identify = NULL;
11596489Sjmcp thisplug->plugin->fw_devinfo = NULL;
11609683SXin.Chen@Sun.COM thisplug->plugin->fw_cleanup = NULL;
11616489Sjmcp (void) dlclose(thisplug->plugin->handle);
11626489Sjmcp thisplug->plugin->handle = NULL;
11636489Sjmcp free(thisplug->plugin);
11646489Sjmcp thisplug->plugin = NULL;
11656489Sjmcp /* CONSTCOND */
11666489Sjmcp TAILQ_REMOVE(fw_pluginlist, thisplug, nextplugin);
11676489Sjmcp }
11686489Sjmcp }
11696489Sjmcp
11706489Sjmcp if (verifier != NULL) {
11716489Sjmcp free(verifier->filename);
11726489Sjmcp free(verifier->vendor);
11736846Sjmcp free(verifier->imgfile);
11746846Sjmcp free(verifier->fwimage);
11756489Sjmcp verifier->filename = NULL;
11766489Sjmcp verifier->vendor = NULL;
11776489Sjmcp verifier->vendorvrfy = NULL;
11786846Sjmcp verifier->imgfile = NULL;
11796846Sjmcp verifier->fwimage = NULL;
11806489Sjmcp (void) dlclose(verifier->handle);
11816489Sjmcp verifier->handle = NULL;
11826489Sjmcp free(verifier);
11836489Sjmcp }
11846489Sjmcp di_fini(rootnode);
11859683SXin.Chen@Sun.COM
11869683SXin.Chen@Sun.COM if (sig > 0)
11879683SXin.Chen@Sun.COM exit(FWFLASH_FAILURE);
11886489Sjmcp }
11896489Sjmcp
11906489Sjmcp static void
fwflash_handle_signals(void)11916489Sjmcp fwflash_handle_signals(void)
11926489Sjmcp {
11936489Sjmcp if (signal(SIGINT, fwflash_intr) == SIG_ERR) {
11946489Sjmcp perror("signal");
11956489Sjmcp exit(FWFLASH_FAILURE);
11966489Sjmcp }
11976489Sjmcp
11986489Sjmcp if (signal(SIGTERM, fwflash_intr) == SIG_ERR) {
11996489Sjmcp perror("signal");
12006489Sjmcp exit(FWFLASH_FAILURE);
12016489Sjmcp }
12026489Sjmcp }
12036489Sjmcp
12046489Sjmcp static int
confirm_target(struct devicelist * thisdev,char * file)12056489Sjmcp confirm_target(struct devicelist *thisdev, char *file)
12066489Sjmcp {
12076489Sjmcp int resp;
12086489Sjmcp
12096846Sjmcp (void) fflush(stdin);
12106846Sjmcp (void) printf(gettext("About to update firmware on %s\n"),
12116846Sjmcp thisdev->access_devname);
12129683SXin.Chen@Sun.COM (void) printf(gettext("with file %s.\n"
12139683SXin.Chen@Sun.COM "Do you want to continue? (Y/N): "), file);
12146489Sjmcp
12156489Sjmcp resp = getchar();
12166489Sjmcp if (resp == 'Y' || resp == 'y') {
12176489Sjmcp return (FWFLASH_YES_FLAG);
12186489Sjmcp } else {
12196489Sjmcp logmsg(MSG_INFO, "flash operation NOT confirmed.\n");
12206489Sjmcp }
12216489Sjmcp
12226489Sjmcp (void) fflush(stdin);
12236489Sjmcp return (FWFLASH_FAILURE);
12246489Sjmcp }
12256489Sjmcp
12266489Sjmcp int
get_fileopts(char * options)12276489Sjmcp get_fileopts(char *options)
12286489Sjmcp {
12296489Sjmcp
12306489Sjmcp int i;
12316489Sjmcp char *files;
12326489Sjmcp
12336489Sjmcp if (files = strtok(options, ",")) {
12346489Sjmcp /* we have more than one */
12356489Sjmcp if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) {
12366489Sjmcp logmsg(MSG_ERROR,
12376489Sjmcp gettext("Unable to allocate space for "
12386489Sjmcp "a firmware image filename\n"));
12396489Sjmcp return (FWFLASH_FAILURE);
12406489Sjmcp }
12416489Sjmcp (void) strlcpy(filelist[0], files, strlen(files) + 1);
12426489Sjmcp i = 1;
12436489Sjmcp
12446489Sjmcp logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n",
12456489Sjmcp filelist[0]);
12466489Sjmcp
12476489Sjmcp
12486489Sjmcp while (files = strtok(NULL, ",")) {
12496489Sjmcp if ((filelist[i] = calloc(1, MAXPATHLEN + 1))
12506489Sjmcp == NULL) {
12516489Sjmcp logmsg(MSG_ERROR,
12526489Sjmcp gettext("Unable to allocate space for "
12536489Sjmcp "a firmware image filename\n"));
12546489Sjmcp return (FWFLASH_FAILURE);
12556489Sjmcp }
12566489Sjmcp (void) strlcpy(filelist[i], files,
12576489Sjmcp strlen(files) + 1);
12586489Sjmcp logmsg(MSG_INFO, "fwflash: filelist[%d]: %s\n",
12596489Sjmcp i, filelist[i]);
12606489Sjmcp ++i;
12616489Sjmcp }
12626489Sjmcp } else {
12636489Sjmcp if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) {
12646489Sjmcp logmsg(MSG_ERROR,
12656489Sjmcp gettext("Unable to allocate space for "
12666489Sjmcp "a firmware image filename\n"));
12676489Sjmcp return (FWFLASH_FAILURE);
12686489Sjmcp }
12696489Sjmcp (void) strlcpy(filelist[0], options, strlen(files) + 1);
12706489Sjmcp logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n",
12716489Sjmcp filelist[0]);
12726489Sjmcp }
12736489Sjmcp return (FWFLASH_SUCCESS);
12746489Sjmcp }
12756489Sjmcp
12766489Sjmcp /*
12776489Sjmcp * code reuse - cheerfully borrowed from stmsboot_util.c
12786489Sjmcp */
12796489Sjmcp void
logmsg(int severity,const char * msg,...)12809683SXin.Chen@Sun.COM logmsg(int severity, const char *msg, ...)
12819683SXin.Chen@Sun.COM {
12826489Sjmcp va_list ap;
12836489Sjmcp
12846489Sjmcp if ((severity > MSG_INFO) ||
12856489Sjmcp ((severity == MSG_INFO) && (fwflash_debug > 0))) {
12866489Sjmcp (void) fprintf(stderr, "%s: ", FWFLASH_PROG_NAME);
12876489Sjmcp va_start(ap, msg);
12886489Sjmcp (void) vfprintf(stderr, msg, ap);
12896489Sjmcp va_end(ap);
12906489Sjmcp }
12916489Sjmcp }
1292