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 /* 229560SPei-Hong.Huang@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 236489Sjmcp * Use is subject to license terms. 246489Sjmcp */ 256489Sjmcp 266489Sjmcp /* 276489Sjmcp * fwflash.c 286489Sjmcp */ 296489Sjmcp #include <stdio.h> 306489Sjmcp #include <stdlib.h> 316489Sjmcp #include <unistd.h> 326489Sjmcp #include <strings.h> 336489Sjmcp #include <errno.h> 346489Sjmcp #include <sys/queue.h> 356489Sjmcp #include <signal.h> 366489Sjmcp #include <locale.h> 376489Sjmcp #include <sys/stat.h> 386489Sjmcp #include <sys/types.h> 396489Sjmcp #include <sys/param.h> 406489Sjmcp #include <fcntl.h> 416489Sjmcp #include <dlfcn.h> 426489Sjmcp #include <dirent.h> 436489Sjmcp #include <sys/varargs.h> 446489Sjmcp #include <libintl.h> /* for gettext(3c) */ 456489Sjmcp #include <libdevinfo.h> 469862SSherry.Moore@Sun.COM #include <libscf_priv.h> 476489Sjmcp #include <fwflash/fwflash.h> 486846Sjmcp #include <sys/modctl.h> /* for MAXMODCONFNAME */ 496489Sjmcp 506489Sjmcp 516489Sjmcp #if !defined(lint) 526489Sjmcp /* embedded software license agreement */ 536489Sjmcp static char *sla [] = { "Copyright 2007 Sun Microsystems, Inc., 4150 Network " 546489Sjmcp "Circle, Santa Clara, California 95054, U.S.A. All rights reserved. U.S. " 556489Sjmcp "Government Rights - Commercial software. Government users are subject to the " 566489Sjmcp "Sun Microsystems, Inc. standard license agreement and applicable provisions " 576489Sjmcp "of the FAR and its supplements. Use is subject to license terms. Parts of " 586489Sjmcp "the product may be derived from Berkeley BSD systems, licensed from the " 596489Sjmcp "University of California. UNIX is a registered trademark in the U.S. and in " 606489Sjmcp "other countries, exclusively licensed through X/Open Company, Ltd.Sun, Sun " 616489Sjmcp "Microsystems, the Sun logo and Solaris are trademarks or registered " 626489Sjmcp "trademarks of Sun Microsystems, Inc. in the U.S. and other countries. This " 636489Sjmcp "product is covered and controlled by U.S. Export Control laws and may be " 646489Sjmcp "subject to the export or import laws in other countries. Nuclear, missile, " 656489Sjmcp "chemical biological weapons or nuclear maritime end uses or end users, " 666489Sjmcp "whether direct or indirect, are strictly prohibited. Export or reexport " 676489Sjmcp "to countries subject to U.S. embargo or to entities identified on U.S. export " 686489Sjmcp "exclusion lists, including, but not limited to, the denied persons and " 696489Sjmcp "specially designated nationals lists is strictly prohibited." }; 706489Sjmcp #endif /* lint */ 716489Sjmcp 726489Sjmcp /* global arg list */ 736489Sjmcp int fwflash_arg_list = 0; 746489Sjmcp char *filelist[10]; 756489Sjmcp 76*10507SPei-Hong.Huang@Sun.COM /* exposed global args */ 77*10507SPei-Hong.Huang@Sun.COM di_node_t rootnode; 78*10507SPei-Hong.Huang@Sun.COM struct PLUGINLIST *fw_pluginlist; 79*10507SPei-Hong.Huang@Sun.COM struct DEVICELIST *fw_devices; 80*10507SPei-Hong.Huang@Sun.COM struct vrfyplugin *verifier; 81*10507SPei-Hong.Huang@Sun.COM struct fw_plugin *self; 82*10507SPei-Hong.Huang@Sun.COM int fwflash_debug = 0; 83*10507SPei-Hong.Huang@Sun.COM 846489Sjmcp /* are we writing to flash? */ 856489Sjmcp static int fwflash_in_write = 0; 866489Sjmcp 876489Sjmcp /* 886489Sjmcp * If we *must* track the version string for fwflash, then 896489Sjmcp * we should do so in this common file rather than the header 906489Sjmcp * file since it will then be in sync with what the customer 917317SJames.McPherson@Sun.COM * sees. We should deprecate the "-v" option since it is not 927317SJames.McPherson@Sun.COM * actually of any use - it doesn't line up with Mercurial's 937317SJames.McPherson@Sun.COM * concept of the changeset. 946489Sjmcp */ 959683SXin.Chen@Sun.COM #define FWFLASH_VERSION "v1.8" 966489Sjmcp #define FWFLASH_PROG_NAME "fwflash" 976489Sjmcp 986489Sjmcp static int get_fileopts(char *options); 996489Sjmcp static int flash_device_list(); 1006489Sjmcp static int flash_load_plugins(); 1016489Sjmcp static int fwflash_update(char *device, char *filename, int flags); 1026489Sjmcp static int fwflash_read_file(char *device, char *filename); 1036489Sjmcp static int fwflash_list_fw(char *class); 1046489Sjmcp static int fwflash_load_verifier(char *drv, char *vendorid, char *fwimg); 1056489Sjmcp static void fwflash_intr(int sig); 1066489Sjmcp static void fwflash_handle_signals(void); 1077317SJames.McPherson@Sun.COM static void fwflash_usage(char *arg); 1086489Sjmcp static void fwflash_version(void); 1096489Sjmcp static int confirm_target(struct devicelist *thisdev, char *file); 1106489Sjmcp 1116489Sjmcp /* 1126489Sjmcp * FWFlash main code 1136489Sjmcp */ 1146489Sjmcp int 1158031SShantkumar.Hiremath@Sun.COM main(int argc, char **argv) 1168031SShantkumar.Hiremath@Sun.COM { 1176489Sjmcp int rv = FWFLASH_SUCCESS; 1186489Sjmcp int i; 1196489Sjmcp char ch; 1206489Sjmcp char *read_file; 1216489Sjmcp extern char *optarg; 1226489Sjmcp char *devclass = NULL; 1236489Sjmcp char *devpath = NULL; 1246489Sjmcp 1256489Sjmcp /* local variables from env */ 1266489Sjmcp (void) setlocale(LC_ALL, ""); 1276489Sjmcp 1286489Sjmcp #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 1296489Sjmcp #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't. */ 1306489Sjmcp #endif 1316489Sjmcp 1326489Sjmcp (void) textdomain(TEXT_DOMAIN); 1336489Sjmcp 1346489Sjmcp read_file = NULL; 1356489Sjmcp 1366489Sjmcp if (argc < 2) { 1376489Sjmcp /* no args supplied */ 1386489Sjmcp fwflash_usage(NULL); 1396489Sjmcp return (FWFLASH_FAILURE); 1406489Sjmcp } 1416489Sjmcp 1429560SPei-Hong.Huang@Sun.COM while ((ch = getopt(argc, argv, "hvylc:f:r:Qd:")) != EOF) { 1436489Sjmcp switch (ch) { 1446489Sjmcp case 'h': 1456489Sjmcp fwflash_arg_list |= FWFLASH_HELP_FLAG; 1466489Sjmcp break; 1476489Sjmcp case 'v': 1486489Sjmcp fwflash_arg_list |= FWFLASH_VER_FLAG; 1496489Sjmcp break; 1506489Sjmcp case 'y': 1516489Sjmcp fwflash_arg_list |= FWFLASH_YES_FLAG; 1526489Sjmcp break; 1536489Sjmcp case 'l': 1546489Sjmcp fwflash_arg_list |= FWFLASH_LIST_FLAG; 1556489Sjmcp break; 1566489Sjmcp case 'c': 1576489Sjmcp fwflash_arg_list |= FWFLASH_CLASS_FLAG; 1586489Sjmcp /* we validate later */ 1596489Sjmcp devclass = strdup(optarg); 1606489Sjmcp break; 1616489Sjmcp case 'd': 1626489Sjmcp fwflash_arg_list |= FWFLASH_DEVICE_FLAG; 1636489Sjmcp devpath = strdup(optarg); 1646489Sjmcp break; 1656489Sjmcp case 'f': 1666489Sjmcp fwflash_arg_list |= FWFLASH_FW_FLAG; 1676489Sjmcp if ((rv = get_fileopts(optarg)) != FWFLASH_SUCCESS) { 1687317SJames.McPherson@Sun.COM fwflash_usage(NULL); 1696489Sjmcp return (FWFLASH_FAILURE); 1706489Sjmcp } 1716489Sjmcp break; 1726489Sjmcp case 'r': 1736489Sjmcp fwflash_arg_list |= FWFLASH_READ_FLAG; 1746489Sjmcp read_file = strdup(optarg); 1756489Sjmcp break; 1766489Sjmcp case 'Q': 1776489Sjmcp /* NOT in the manpage */ 1786489Sjmcp fwflash_debug = 1; 1796489Sjmcp break; 1806846Sjmcp /* illegal options */ 1816489Sjmcp default: 1826489Sjmcp fwflash_usage(optarg); 1836489Sjmcp return (FWFLASH_FAILURE); 1846489Sjmcp } 1856489Sjmcp } 1866489Sjmcp 1876489Sjmcp /* Do Help */ 1886489Sjmcp if ((fwflash_arg_list & FWFLASH_HELP_FLAG) || 1896489Sjmcp ((fwflash_arg_list & FWFLASH_DEVICE_FLAG) && 1908031SShantkumar.Hiremath@Sun.COM !((fwflash_arg_list & FWFLASH_FW_FLAG) || 1918031SShantkumar.Hiremath@Sun.COM (fwflash_arg_list & FWFLASH_READ_FLAG)))) { 1927317SJames.McPherson@Sun.COM fwflash_usage(NULL); 1936489Sjmcp return (FWFLASH_SUCCESS); 1946489Sjmcp } 1956489Sjmcp 1966489Sjmcp /* Do Version */ 1976489Sjmcp if (fwflash_arg_list == FWFLASH_VER_FLAG) { 1986489Sjmcp fwflash_version(); 1996489Sjmcp return (FWFLASH_SUCCESS); 2006489Sjmcp } 2016489Sjmcp 2026489Sjmcp /* generate global list of devices */ 2036489Sjmcp if ((rv = flash_load_plugins()) != FWFLASH_SUCCESS) { 2046489Sjmcp logmsg(MSG_ERROR, 2056489Sjmcp gettext("Unable to load fwflash plugins\n")); 2066489Sjmcp fwflash_intr(0); 2076489Sjmcp return (rv); 2086489Sjmcp } 2096489Sjmcp 2106489Sjmcp if ((rv = flash_device_list()) != FWFLASH_SUCCESS) { 2116489Sjmcp logmsg(MSG_ERROR, 2126489Sjmcp gettext("No flashable devices in this system\n")); 2136489Sjmcp fwflash_intr(0); 2146489Sjmcp return (rv); 2156489Sjmcp } 2166489Sjmcp 2176489Sjmcp /* Do list */ 2186489Sjmcp if (fwflash_arg_list == (FWFLASH_LIST_FLAG) || 2196489Sjmcp fwflash_arg_list == (FWFLASH_LIST_FLAG | FWFLASH_CLASS_FLAG)) { 2206489Sjmcp rv = fwflash_list_fw(devclass); 2216489Sjmcp fwflash_intr(0); 2226489Sjmcp return (rv); 2236489Sjmcp } 2246489Sjmcp 2256489Sjmcp fwflash_handle_signals(); 2266489Sjmcp 2276489Sjmcp /* Do flash update (write) */ 2286489Sjmcp if ((fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG)) || 2296489Sjmcp (fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG | 2308031SShantkumar.Hiremath@Sun.COM FWFLASH_YES_FLAG))) { 2319862SSherry.Moore@Sun.COM int fastreboot_disabled = 0; 2326489Sjmcp /* the update function handles the real arg parsing */ 2336489Sjmcp i = 0; 2346489Sjmcp while (filelist[i] != NULL) { 2356489Sjmcp if ((rv = fwflash_update(devpath, filelist[i], 2366489Sjmcp fwflash_arg_list)) == FWFLASH_SUCCESS) { 2376489Sjmcp /* failed ops have already been noted */ 2389862SSherry.Moore@Sun.COM if (!fastreboot_disabled && 2399862SSherry.Moore@Sun.COM scf_fastreboot_default_set_transient( 2409862SSherry.Moore@Sun.COM B_FALSE) != SCF_SUCCESS) 2419862SSherry.Moore@Sun.COM logmsg(MSG_ERROR, gettext( 2429862SSherry.Moore@Sun.COM "Failed to disable fast " 2439862SSherry.Moore@Sun.COM "reboot.\n")); 2449862SSherry.Moore@Sun.COM else 2459862SSherry.Moore@Sun.COM fastreboot_disabled = 1; 2466489Sjmcp logmsg(MSG_ERROR, 2476489Sjmcp gettext("New firmware will be activated " 2488031SShantkumar.Hiremath@Sun.COM "after you reboot\n\n")); 2496489Sjmcp } 2506489Sjmcp ++i; 2516489Sjmcp } 2526489Sjmcp 2536489Sjmcp fwflash_intr(0); 2546489Sjmcp return (rv); 2556489Sjmcp } 2566489Sjmcp 2576489Sjmcp /* Do flash read */ 2586489Sjmcp if ((fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG)) || 2596489Sjmcp (fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG | 2608031SShantkumar.Hiremath@Sun.COM FWFLASH_YES_FLAG))) { 2616489Sjmcp rv = fwflash_read_file(devpath, read_file); 2626489Sjmcp fwflash_intr(0); 2636489Sjmcp return (rv); 2646489Sjmcp } 2656489Sjmcp 2666489Sjmcp fwflash_usage(NULL); 2676489Sjmcp 2686489Sjmcp return (FWFLASH_FAILURE); 2696489Sjmcp } 2706489Sjmcp 2716489Sjmcp 2726489Sjmcp static int 2738031SShantkumar.Hiremath@Sun.COM flash_load_plugins() 2748031SShantkumar.Hiremath@Sun.COM { 2756489Sjmcp 2766489Sjmcp int rval = FWFLASH_SUCCESS; 2776489Sjmcp DIR *dirp; 2786489Sjmcp struct dirent *plugdir; 2796489Sjmcp char *plugname; 2806489Sjmcp struct fw_plugin *tmpplug; 2816489Sjmcp struct pluginlist *tmpelem; 2826489Sjmcp void *sym; 2836489Sjmcp char *fwplugdirpath, *tempdirpath; 2846489Sjmcp 2856489Sjmcp 2866489Sjmcp #define CLOSEFREE() { \ 2876489Sjmcp (void) dlclose(tmpplug->handle); \ 2886489Sjmcp free(tmpplug); } 2896489Sjmcp 2906489Sjmcp /* 2916489Sjmcp * Procedure: 2926489Sjmcp * 2936489Sjmcp * cd /usr/lib/fwflash/identify 2946489Sjmcp * open each .so file found therein 2956489Sjmcp * dlopen(.sofile) 2966489Sjmcp * if it's one of our plugins, add it to fw_pluginlist; 2976489Sjmcp * 2986489Sjmcp * functions we need here include dlopen and dlsym. 2996489Sjmcp * 3006489Sjmcp * If we get to the end and fw_pluginlist struct is empty, 3016489Sjmcp * return FWFLASH_FAILURE so we return to the shell. 3026489Sjmcp */ 3036489Sjmcp 3046489Sjmcp if ((fwplugdirpath = calloc(1, MAXPATHLEN + 1)) == NULL) { 3056489Sjmcp logmsg(MSG_ERROR, 3066489Sjmcp gettext("Unable to malloc %d bytes while " 3076489Sjmcp "trying to load plugins: %s\n"), 3086489Sjmcp MAXPATHLEN + 1, strerror(errno)); 3096489Sjmcp return (FWFLASH_FAILURE); 3106489Sjmcp } 3116489Sjmcp 3126489Sjmcp tempdirpath = getenv("FWPLUGINDIR"); 3136489Sjmcp 3146489Sjmcp if ((fwflash_debug > 0) && (tempdirpath != NULL)) { 3156489Sjmcp (void) strlcpy(fwplugdirpath, tempdirpath, 3166489Sjmcp strlen(tempdirpath) + 1); 3176489Sjmcp } else { 3186489Sjmcp (void) strlcpy(fwplugdirpath, FWPLUGINDIR, 3196489Sjmcp strlen(FWPLUGINDIR) + 1); 3206489Sjmcp } 3216489Sjmcp 3226489Sjmcp if ((dirp = opendir(fwplugdirpath)) == NULL) { 3236489Sjmcp logmsg(MSG_ERROR, 3246846Sjmcp gettext("Unable to open %s\n"), 3256489Sjmcp fwplugdirpath); 3266489Sjmcp return (errno); 3276489Sjmcp } 3286489Sjmcp 3296489Sjmcp if ((plugdir = calloc(1, sizeof (struct dirent) + MAXPATHLEN + 1)) 3306489Sjmcp == NULL) { 3316489Sjmcp logmsg(MSG_ERROR, 3326489Sjmcp gettext("Unable to malloc %d bytes while " 3336489Sjmcp "trying to load plugins: %s\n"), 3346489Sjmcp MAXPATHLEN + 1 + sizeof (struct dirent), 3356489Sjmcp strerror(errno)); 3366489Sjmcp return (FWFLASH_FAILURE); 3376489Sjmcp } 3386489Sjmcp 3396489Sjmcp if ((fw_pluginlist = calloc(1, sizeof (struct fw_plugin))) 3406489Sjmcp == NULL) { 3416489Sjmcp logmsg(MSG_ERROR, 3426489Sjmcp gettext("Unable to malloc %d bytes while " 3438031SShantkumar.Hiremath@Sun.COM "trying to load plugins: %s\n"), 3449683SXin.Chen@Sun.COM sizeof (struct fw_plugin), strerror(errno)); 3456489Sjmcp return (FWFLASH_FAILURE); 3466489Sjmcp } 3476489Sjmcp 3486489Sjmcp TAILQ_INIT(fw_pluginlist); 3496489Sjmcp 3506489Sjmcp while ((readdir_r(dirp, plugdir, &plugdir) == 0) && (plugdir != NULL)) { 3516489Sjmcp 3526489Sjmcp errno = 0; /* remove chance of false results */ 3536489Sjmcp 3546489Sjmcp if ((plugdir->d_name[0] == '.') || 3556489Sjmcp (strstr(plugdir->d_name, ".so") == NULL)) { 3566489Sjmcp continue; 3576489Sjmcp } 3586489Sjmcp 3596489Sjmcp if ((plugname = calloc(1, MAXPATHLEN + 1)) == NULL) { 3606489Sjmcp logmsg(MSG_ERROR, 3616489Sjmcp gettext("Unable to malloc %d bytes while " 3628031SShantkumar.Hiremath@Sun.COM "trying to load plugins: %s\n"), 3636489Sjmcp MAXPATHLEN + 1, strerror(errno)); 3646489Sjmcp return (FWFLASH_FAILURE); 3656489Sjmcp } 3666489Sjmcp 3676489Sjmcp (void) snprintf(plugname, MAXPATHLEN, "%s/%s", 3686489Sjmcp fwplugdirpath, plugdir->d_name); 3696489Sjmcp 3706489Sjmcp /* start allocating storage */ 3716489Sjmcp if ((tmpelem = calloc(1, sizeof (struct pluginlist))) 3726489Sjmcp == NULL) { 3736489Sjmcp logmsg(MSG_ERROR, 3746489Sjmcp gettext("Unable to malloc %d bytes while " 3758031SShantkumar.Hiremath@Sun.COM "trying to load plugins: %s\n"), 3766489Sjmcp sizeof (struct pluginlist), strerror(errno)); 3776489Sjmcp return (FWFLASH_FAILURE); 3786489Sjmcp } 3796489Sjmcp 3806489Sjmcp if ((tmpplug = calloc(1, sizeof (struct fw_plugin))) 3816489Sjmcp == NULL) { 3826489Sjmcp logmsg(MSG_ERROR, 3836489Sjmcp gettext("Unable to malloc %d bytes while " 3846489Sjmcp "trying to load plugins: %s\n"), 3856489Sjmcp sizeof (struct fw_plugin), strerror(errno)); 3866489Sjmcp return (FWFLASH_FAILURE); 3876489Sjmcp } 3886489Sjmcp 3896489Sjmcp /* load 'er up! */ 3906489Sjmcp tmpplug->handle = dlopen(plugname, RTLD_NOW); 3916489Sjmcp if (tmpplug->handle == NULL) { 3926489Sjmcp free(tmpplug); 3936489Sjmcp continue; /* assume there are other plugins */ 3946489Sjmcp } 3956489Sjmcp 3966489Sjmcp if ((tmpplug->filename = calloc(1, strlen(plugname) + 1)) 3976489Sjmcp == NULL) { 3986489Sjmcp logmsg(MSG_ERROR, 3996489Sjmcp gettext("Unable to allocate %d bytes for plugin " 4008031SShantkumar.Hiremath@Sun.COM "filename %s:%s\n"), 4016489Sjmcp strlen(plugname) + 1, plugname, 4026489Sjmcp strerror(errno)); 4036489Sjmcp return (rval); 4046489Sjmcp } 4056489Sjmcp 4066489Sjmcp (void) strlcpy(tmpplug->filename, plugname, 4076489Sjmcp strlen(plugname) + 1); 4086489Sjmcp 4096489Sjmcp /* now sanity check the file */ 4106489Sjmcp if ((sym = dlsym(tmpplug->handle, "drivername")) 4116489Sjmcp != NULL) { 4126489Sjmcp /* max length of drivername */ 4136846Sjmcp tmpplug->drvname = calloc(1, MAXMODCONFNAME); 4146846Sjmcp 4156846Sjmcp /* are we doing double-time? */ 4166846Sjmcp if (strncmp((char *)sym, plugdir->d_name, 4176846Sjmcp MAXMODCONFNAME) != 0) { 4186846Sjmcp char *tempnm = calloc(1, MAXMODCONFNAME); 4196846Sjmcp 4209683SXin.Chen@Sun.COM (void) memcpy(tempnm, plugdir->d_name, 4219683SXin.Chen@Sun.COM MAXMODCONFNAME); 4226846Sjmcp (void) strlcpy(tmpplug->drvname, 4236846Sjmcp strtok(tempnm, "."), 4246846Sjmcp strlen(plugdir->d_name) + 1); 4256846Sjmcp free(tempnm); 4266846Sjmcp } else { 4276846Sjmcp (void) strlcpy(tmpplug->drvname, 4286846Sjmcp (char *)sym, strlen(sym) + 1); 4296846Sjmcp } 4306489Sjmcp } else { 4316489Sjmcp CLOSEFREE(); 4326489Sjmcp continue; 4336489Sjmcp } 4346489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_readfw")) 4356489Sjmcp != NULL) { 4366489Sjmcp tmpplug->fw_readfw = (int (*)())sym; 4376489Sjmcp } else { 4386489Sjmcp CLOSEFREE(); 4396489Sjmcp continue; 4406489Sjmcp } 4416489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_writefw")) 4426489Sjmcp != NULL) { 4436489Sjmcp tmpplug->fw_writefw = (int (*)())sym; 4446489Sjmcp } else { 4456489Sjmcp CLOSEFREE(); 4466489Sjmcp continue; 4476489Sjmcp } 4486489Sjmcp 4496489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_identify")) 4506489Sjmcp != NULL) { 4516489Sjmcp tmpplug->fw_identify = 4526489Sjmcp (int (*)(int))sym; 4536489Sjmcp } else { 4546489Sjmcp CLOSEFREE(); 4556489Sjmcp continue; 4566489Sjmcp } 4576489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_devinfo")) 4586489Sjmcp != NULL) { 4596489Sjmcp tmpplug->fw_devinfo = 4606489Sjmcp (int (*)(struct devicelist *))sym; 4616489Sjmcp } else { 4626489Sjmcp CLOSEFREE(); 4636489Sjmcp continue; 4646489Sjmcp } 4656489Sjmcp 4669683SXin.Chen@Sun.COM if ((sym = dlsym(tmpplug->handle, "plugin_version")) 4679683SXin.Chen@Sun.COM != NULL) { 4689683SXin.Chen@Sun.COM if ((*(int *)sym) >= FWPLUGIN_VERSION_2) { 4699683SXin.Chen@Sun.COM if ((sym = dlsym(tmpplug->handle, 4709683SXin.Chen@Sun.COM "fw_cleanup")) != NULL) { 4719683SXin.Chen@Sun.COM tmpplug->fw_cleanup = 4729683SXin.Chen@Sun.COM (void (*)(struct devicelist *))sym; 4739683SXin.Chen@Sun.COM } else { 4749683SXin.Chen@Sun.COM logmsg(MSG_ERROR, 4759683SXin.Chen@Sun.COM gettext("ERROR: v2 plugin (%s) " 4769683SXin.Chen@Sun.COM "has no fw_cleanup function\n"), 4779683SXin.Chen@Sun.COM tmpplug->filename); 4789683SXin.Chen@Sun.COM CLOSEFREE(); 4799683SXin.Chen@Sun.COM continue; 4809683SXin.Chen@Sun.COM } 4819683SXin.Chen@Sun.COM } else { 4829683SXin.Chen@Sun.COM logmsg(MSG_INFO, 4839683SXin.Chen@Sun.COM "Identification plugin %s defined " 4849683SXin.Chen@Sun.COM "plugin_version < FWPLUGIN_VERSION_2 !"); 4859683SXin.Chen@Sun.COM } 4869683SXin.Chen@Sun.COM } 4879683SXin.Chen@Sun.COM 4886846Sjmcp if ((tmpelem->drvname = calloc(1, MAXMODCONFNAME)) 4896489Sjmcp == NULL) { 4906489Sjmcp logmsg(MSG_ERROR, 4916846Sjmcp gettext("Unable to allocate space for a" 4928031SShantkumar.Hiremath@Sun.COM "drivername %s\n"), 4936489Sjmcp tmpplug->drvname); 4946489Sjmcp return (FWFLASH_FAILURE); 4956489Sjmcp } 4966489Sjmcp 4976489Sjmcp (void) strlcpy(tmpelem->drvname, tmpplug->drvname, 4986489Sjmcp strlen(tmpplug->drvname) + 1); 4996489Sjmcp 5006489Sjmcp if ((tmpelem->filename = calloc(1, 5016489Sjmcp strlen(tmpplug->filename) + 1)) == NULL) { 5026489Sjmcp logmsg(MSG_ERROR, 5036489Sjmcp gettext("Unable to allocate %d bytes for " 5048031SShantkumar.Hiremath@Sun.COM "filename %s\n"), 5056489Sjmcp strlen(tmpplug->filename) + 1, 5066846Sjmcp tmpplug->filename); 5076489Sjmcp return (FWFLASH_FAILURE); 5086489Sjmcp } 5096489Sjmcp 5106489Sjmcp (void) strlcpy(tmpelem->filename, plugname, 5116489Sjmcp strlen(plugname) + 1); 5126489Sjmcp tmpelem->plugin = tmpplug; 5136489Sjmcp 5146489Sjmcp /* CONSTCOND */ 5156489Sjmcp TAILQ_INSERT_TAIL(fw_pluginlist, tmpelem, nextplugin); 5166489Sjmcp } 5176489Sjmcp 5186489Sjmcp if ((plugdir == NULL) && TAILQ_EMPTY(fw_pluginlist)) { 5196489Sjmcp return (FWFLASH_FAILURE); 5206489Sjmcp } 5216489Sjmcp 5226489Sjmcp if (errno != 0) { 5236489Sjmcp logmsg(MSG_ERROR, 5246489Sjmcp gettext("Error reading directory entry in %s\n"), 5256489Sjmcp fwplugdirpath); 5266489Sjmcp rval = errno; 5276489Sjmcp } 5286489Sjmcp 5299683SXin.Chen@Sun.COM free(fwplugdirpath); 5309683SXin.Chen@Sun.COM free(plugdir); 5316489Sjmcp (void) closedir(dirp); 5326489Sjmcp return (rval); 5336489Sjmcp } 5346489Sjmcp 5356489Sjmcp /* 5366489Sjmcp * fwflash_load_verifier dlload()s the appropriate firmware image 5376489Sjmcp * verification plugin, and attaches the designated fwimg's fd to 5386489Sjmcp * the vrfyplugin structure so we only have to load the image in 5396489Sjmcp * one place. 5406489Sjmcp */ 5416489Sjmcp int 5428031SShantkumar.Hiremath@Sun.COM fwflash_load_verifier(char *drv, char *vendorid, char *fwimg) 5438031SShantkumar.Hiremath@Sun.COM { 5446489Sjmcp 5456489Sjmcp int rv = FWFLASH_FAILURE; 5466489Sjmcp int imgfd; 5476489Sjmcp char *fwvrfydirpath, *tempdirpath, *filename; 5486489Sjmcp char *clean; /* for the space-removed vid */ 5496489Sjmcp struct stat fwstat; 5506489Sjmcp struct vrfyplugin *vrfy; 5516489Sjmcp void *vrfysym; 5526489Sjmcp 5536489Sjmcp /* 5546489Sjmcp * To make flashing multiple firmware images somewhat more 5556489Sjmcp * efficient, we start this function by checking whether a 5566489Sjmcp * verifier for this device has already been loaded. If it 5576489Sjmcp * has been loaded, we replace the imgfile information, and 5586489Sjmcp * then continue as if we were loading for the first time. 5596489Sjmcp */ 5606489Sjmcp 5616489Sjmcp if (verifier != NULL) { 5626489Sjmcp verifier->imgsize = 0; 5636489Sjmcp verifier->flashbuf = 0; /* set by the verifier function */ 5646489Sjmcp 5659683SXin.Chen@Sun.COM if (verifier->imgfile != NULL) { 5669683SXin.Chen@Sun.COM free(verifier->imgfile); 5679683SXin.Chen@Sun.COM verifier->imgfile = NULL; 5689683SXin.Chen@Sun.COM } 5696489Sjmcp 5709683SXin.Chen@Sun.COM if (verifier->fwimage != NULL) { 5719683SXin.Chen@Sun.COM free(verifier->fwimage); 5729683SXin.Chen@Sun.COM verifier->fwimage = NULL; 5739683SXin.Chen@Sun.COM } 5746489Sjmcp } else { 5756489Sjmcp if ((fwvrfydirpath = calloc(1, MAXPATHLEN + 1)) == NULL) { 5766489Sjmcp logmsg(MSG_ERROR, 5776489Sjmcp gettext("Unable to allocate space for a firmware " 5788031SShantkumar.Hiremath@Sun.COM "verifier file(1)")); 5796489Sjmcp return (rv); 5806489Sjmcp } 5816489Sjmcp 5826489Sjmcp if ((filename = calloc(1, MAXPATHLEN + 1)) == NULL) { 5836489Sjmcp logmsg(MSG_ERROR, 5846489Sjmcp gettext("Unable to allocate space " 5856489Sjmcp "for a firmware verifier file(2)")); 5869683SXin.Chen@Sun.COM free(fwvrfydirpath); 5876489Sjmcp return (rv); 5886489Sjmcp } 5896489Sjmcp 5909683SXin.Chen@Sun.COM /* 5919683SXin.Chen@Sun.COM * Since SCSI devices can have a vendor id of up to 8 5929683SXin.Chen@Sun.COM * left-aligned and _space-padded_ characters, we first need to 5939683SXin.Chen@Sun.COM * strip off any space characters before we try to make a 5949683SXin.Chen@Sun.COM * filename out of it 5959683SXin.Chen@Sun.COM */ 5966489Sjmcp clean = strtok(vendorid, " "); 5976489Sjmcp if (clean == NULL) { 5986489Sjmcp /* invalid vendorid, something's really wrong */ 5996489Sjmcp logmsg(MSG_ERROR, 6006489Sjmcp gettext("Invalid vendorid (null) specified for " 6018031SShantkumar.Hiremath@Sun.COM "device\n")); 6029683SXin.Chen@Sun.COM free(filename); 6039683SXin.Chen@Sun.COM free(fwvrfydirpath); 6046489Sjmcp return (rv); 6056489Sjmcp } 6066489Sjmcp 6076489Sjmcp tempdirpath = getenv("FWVERIFYPLUGINDIR"); 6086489Sjmcp 6096489Sjmcp if ((fwflash_debug > 0) && (tempdirpath != NULL)) { 6106489Sjmcp (void) strlcpy(fwvrfydirpath, tempdirpath, 6116489Sjmcp strlen(tempdirpath) + 1); 6126489Sjmcp } else { 6136489Sjmcp (void) strlcpy(fwvrfydirpath, FWVERIFYPLUGINDIR, 6146489Sjmcp strlen(FWVERIFYPLUGINDIR) + 1); 6156489Sjmcp } 6166489Sjmcp 6176489Sjmcp if ((vrfy = calloc(1, sizeof (struct vrfyplugin))) == NULL) { 6186489Sjmcp logmsg(MSG_ERROR, 6196489Sjmcp gettext("Unable to allocate space " 6206489Sjmcp "for a firmware verifier structure")); 6216489Sjmcp free(filename); 6226489Sjmcp free(fwvrfydirpath); 6239683SXin.Chen@Sun.COM return (rv); 6246489Sjmcp } 6256489Sjmcp 6266489Sjmcp errno = 0; /* false positive removal */ 6276489Sjmcp 6289683SXin.Chen@Sun.COM (void) snprintf(filename, MAXPATHLEN, "%s/%s-%s.so", 6296489Sjmcp fwvrfydirpath, drv, clean); 6309683SXin.Chen@Sun.COM if ((vrfy->handle = dlopen(filename, RTLD_NOW)) == NULL) { 6319683SXin.Chen@Sun.COM logmsg(MSG_INFO, gettext(dlerror())); 6329683SXin.Chen@Sun.COM logmsg(MSG_INFO, 6339683SXin.Chen@Sun.COM gettext("\nUnable to open verification plugin " 6349683SXin.Chen@Sun.COM "%s. Looking for %s-GENERIC plugin instead.\n"), 6359683SXin.Chen@Sun.COM filename, drv); 6369683SXin.Chen@Sun.COM 6379683SXin.Chen@Sun.COM /* Try the drv-GENERIC.so form, _then_ die */ 6389683SXin.Chen@Sun.COM bzero(filename, strlen(filename) + 1); 6399683SXin.Chen@Sun.COM (void) snprintf(filename, MAXPATHLEN, 6409683SXin.Chen@Sun.COM "%s/%s-GENERIC.so", fwvrfydirpath, drv); 6419683SXin.Chen@Sun.COM 6429683SXin.Chen@Sun.COM if ((vrfy->handle = dlopen(filename, RTLD_NOW)) 6439683SXin.Chen@Sun.COM == NULL) { 6449683SXin.Chen@Sun.COM logmsg(MSG_INFO, gettext(dlerror())); 6459683SXin.Chen@Sun.COM logmsg(MSG_ERROR, 6469683SXin.Chen@Sun.COM gettext("\nUnable to open either " 6479683SXin.Chen@Sun.COM "verification plugin %s/%s-%s.so or " 6489683SXin.Chen@Sun.COM "generic plugin %s.\nUnable to verify " 6499683SXin.Chen@Sun.COM "firmware image. Aborting.\n"), 6509683SXin.Chen@Sun.COM fwvrfydirpath, drv, clean, filename); 6519683SXin.Chen@Sun.COM free(filename); 6529683SXin.Chen@Sun.COM free(fwvrfydirpath); 6539683SXin.Chen@Sun.COM return (rv); 6549683SXin.Chen@Sun.COM } 6559683SXin.Chen@Sun.COM } 6566489Sjmcp 6576489Sjmcp if ((vrfy->filename = calloc(1, strlen(filename) + 1)) 6586489Sjmcp == NULL) { 6596489Sjmcp logmsg(MSG_ERROR, 6606489Sjmcp gettext("Unable to allocate space to store " 6618031SShantkumar.Hiremath@Sun.COM "a verifier filename\n")); 6626489Sjmcp free(filename); 6636489Sjmcp free(fwvrfydirpath); 6646489Sjmcp free(vrfy->handle); 6659683SXin.Chen@Sun.COM return (rv); 6666489Sjmcp } 6676489Sjmcp (void) strlcpy(vrfy->filename, filename, strlen(filename) + 1); 6686489Sjmcp 6696489Sjmcp if ((vrfysym = dlsym(vrfy->handle, "vendorvrfy")) == NULL) { 6706489Sjmcp logmsg(MSG_ERROR, 6716489Sjmcp gettext("%s is an invalid firmware verification " 6728031SShantkumar.Hiremath@Sun.COM "plugin."), filename); 6736489Sjmcp (void) dlclose(vrfy->handle); 6746489Sjmcp free(filename); 6756489Sjmcp free(fwvrfydirpath); 6766489Sjmcp free(vrfy); 6779683SXin.Chen@Sun.COM return (rv); 6786489Sjmcp } else { 6796489Sjmcp vrfy->vendorvrfy = 6806489Sjmcp (int (*)(struct devicelist *))vrfysym; 6816489Sjmcp } 6826489Sjmcp 6836489Sjmcp vrfysym = dlsym(vrfy->handle, "vendor"); 6846489Sjmcp 6856489Sjmcp if (vrfysym == NULL) { 6866489Sjmcp logmsg(MSG_ERROR, 6876489Sjmcp gettext("Invalid vendor (null) in verification " 6888031SShantkumar.Hiremath@Sun.COM "plugin %s\n"), filename); 6896489Sjmcp (void) dlclose(vrfy->handle); 6906489Sjmcp free(vrfy); 6919683SXin.Chen@Sun.COM return (rv); 6926489Sjmcp } else { 6936489Sjmcp if (strncmp(vendorid, (char *)vrfysym, 6946489Sjmcp strlen(vendorid)) != 0) { 6956489Sjmcp logmsg(MSG_INFO, 6966489Sjmcp "Using a sym-linked (%s -> %s) " 6979683SXin.Chen@Sun.COM "verification plugin\n", 6986489Sjmcp vendorid, vrfysym); 6996489Sjmcp vrfy->vendor = calloc(1, strlen(vendorid) + 1); 7006489Sjmcp } else { 7016489Sjmcp vrfy->vendor = calloc(1, strlen(vrfysym) + 1); 7026489Sjmcp } 7036489Sjmcp (void) strlcpy(vrfy->vendor, (char *)vrfysym, 7046489Sjmcp strlen(vendorid) + 1); 7056489Sjmcp } 7066489Sjmcp 7076489Sjmcp verifier = vrfy; /* a convenience variable */ 7089683SXin.Chen@Sun.COM free(filename); 7099683SXin.Chen@Sun.COM free(fwvrfydirpath); 7106489Sjmcp } 7116489Sjmcp 7126489Sjmcp /* 7136489Sjmcp * We don't do any verification that the fw image file is in 7146489Sjmcp * an approved location, but it's easy enough to modify this 7156489Sjmcp * function to do so. The verification plugin should provide 7166489Sjmcp * sufficient protection. 7176489Sjmcp */ 7186489Sjmcp 7196489Sjmcp if ((imgfd = open(fwimg, O_RDONLY)) < 0) { 7206489Sjmcp logmsg(MSG_ERROR, 7216489Sjmcp gettext("Unable to open designated firmware " 7228031SShantkumar.Hiremath@Sun.COM "image file %s: %s\n"), 7236489Sjmcp (fwimg != NULL) ? fwimg : "(null)", 7246489Sjmcp strerror(errno)); 7256489Sjmcp rv = FWFLASH_FAILURE; 7266489Sjmcp goto cleanup; 7276489Sjmcp } 7286489Sjmcp 7296489Sjmcp if (stat(fwimg, &fwstat) == -1) { 7306489Sjmcp logmsg(MSG_ERROR, 7316489Sjmcp gettext("Unable to stat() firmware image file " 7328031SShantkumar.Hiremath@Sun.COM "%s: %s\n"), 7336489Sjmcp fwimg, strerror(errno)); 7346489Sjmcp rv = FWFLASH_FAILURE; 7356489Sjmcp goto cleanup; 7366489Sjmcp } else { 7376489Sjmcp verifier->imgsize = fwstat.st_size; 7386489Sjmcp if ((verifier->fwimage = calloc(1, verifier->imgsize)) 7396489Sjmcp == NULL) { 7406489Sjmcp logmsg(MSG_ERROR, 7416489Sjmcp gettext("Unable to load firmware image " 7428031SShantkumar.Hiremath@Sun.COM "%s: %s\n"), 7436489Sjmcp fwimg, strerror(errno)); 7446489Sjmcp rv = FWFLASH_FAILURE; 7456489Sjmcp goto cleanup; 7466489Sjmcp } 7476489Sjmcp } 7486489Sjmcp 7496489Sjmcp errno = 0; 7506489Sjmcp if ((rv = read(imgfd, verifier->fwimage, 7516489Sjmcp (size_t)verifier->imgsize)) < verifier->imgsize) { 7526489Sjmcp /* we haven't read enough data, bail */ 7536489Sjmcp logmsg(MSG_ERROR, 7546489Sjmcp gettext("Failed to read sufficient data " 7558031SShantkumar.Hiremath@Sun.COM "(got %d bytes, expected %d bytes) from " 7568031SShantkumar.Hiremath@Sun.COM "firmware image file %s: %s\n"), 7576489Sjmcp rv, verifier->imgsize, 7589683SXin.Chen@Sun.COM verifier->filename, strerror(errno)); 7596489Sjmcp rv = FWFLASH_FAILURE; 7606489Sjmcp } else { 7616489Sjmcp rv = FWFLASH_SUCCESS; 7626489Sjmcp } 7636489Sjmcp 7646489Sjmcp if ((verifier->imgfile = calloc(1, strlen(fwimg) + 1)) == NULL) { 7656489Sjmcp logmsg(MSG_ERROR, 7666489Sjmcp gettext("Unable to save name of firmware image\n")); 7676489Sjmcp rv = FWFLASH_FAILURE; 7686489Sjmcp } else { 7696489Sjmcp (void) strlcpy(verifier->imgfile, fwimg, strlen(fwimg) + 1); 7706489Sjmcp } 7716489Sjmcp 7726489Sjmcp if (rv != FWFLASH_SUCCESS) { 7736489Sjmcp /* cleanup and let's get outta here */ 7746489Sjmcp cleanup: 7756489Sjmcp free(verifier->filename); 7766489Sjmcp free(verifier->vendor); 7776489Sjmcp 7789683SXin.Chen@Sun.COM if (!(fwflash_arg_list & FWFLASH_READ_FLAG) && 7799683SXin.Chen@Sun.COM verifier->fwimage) 7806489Sjmcp free(verifier->fwimage); 7816489Sjmcp 7826489Sjmcp verifier->filename = NULL; 7836489Sjmcp verifier->vendor = NULL; 7846489Sjmcp verifier->vendorvrfy = NULL; 7856489Sjmcp verifier->fwimage = NULL; 7866489Sjmcp (void) dlclose(verifier->handle); 7876489Sjmcp verifier->handle = NULL; 7886489Sjmcp free(verifier); 7896489Sjmcp if (imgfd >= 0) { 7906489Sjmcp (void) close(imgfd); 7916489Sjmcp } 7926489Sjmcp verifier = NULL; 7936489Sjmcp } 7946489Sjmcp 7956489Sjmcp return (rv); 7966489Sjmcp } 7976489Sjmcp 7986489Sjmcp /* 7996489Sjmcp * cycles through the global list of plugins to find 8006489Sjmcp * each flashable device, which is added to fw_devices 8016489Sjmcp * 8026489Sjmcp * Each plugin's identify routine must allocated storage 8036489Sjmcp * as required. 8046489Sjmcp * 8056489Sjmcp * Each plugin's identify routine must return 8066489Sjmcp * FWFLASH_FAILURE if it cannot find any devices 8076489Sjmcp * which it handles. 8086489Sjmcp */ 8096489Sjmcp static int 8106489Sjmcp flash_device_list() 8116489Sjmcp { 8126489Sjmcp int rv = FWFLASH_FAILURE; 8136489Sjmcp int startidx = 0; 8146489Sjmcp int sumrv = 0; 8156489Sjmcp struct pluginlist *plugins; 8166489Sjmcp 8176489Sjmcp /* we open rootnode here, and close it in fwflash_intr */ 8189683SXin.Chen@Sun.COM if ((rootnode = di_init("/", DINFOCPYALL|DINFOFORCE)) == DI_NODE_NIL) { 8196489Sjmcp logmsg(MSG_ERROR, 8206489Sjmcp gettext("Unable to take device tree snapshot: %s\n"), 8216489Sjmcp strerror(errno)); 8226489Sjmcp return (rv); 8236489Sjmcp } 8246489Sjmcp 8256489Sjmcp if ((fw_devices = calloc(1, sizeof (struct devicelist))) == NULL) { 8266489Sjmcp logmsg(MSG_ERROR, 8276489Sjmcp gettext("Unable to malloc %d bytes while " 8286489Sjmcp "trying to find devices: %s\n"), 8296489Sjmcp sizeof (struct devicelist), strerror(errno)); 8306489Sjmcp return (FWFLASH_FAILURE); 8316489Sjmcp } 8326489Sjmcp 8336489Sjmcp /* CONSTCOND */ 8346489Sjmcp TAILQ_INIT(fw_devices); 8356489Sjmcp 8366489Sjmcp TAILQ_FOREACH(plugins, fw_pluginlist, nextplugin) { 8376489Sjmcp self = plugins->plugin; 8386489Sjmcp rv = plugins->plugin->fw_identify(startidx); 8396489Sjmcp 8406489Sjmcp logmsg(MSG_INFO, 8416489Sjmcp gettext("fwflash:flash_device_list() got %d from " 8426489Sjmcp "identify routine\n"), rv); 8436489Sjmcp 8446489Sjmcp /* only bump startidx if we've found at least one device */ 8456489Sjmcp if (rv == FWFLASH_SUCCESS) { 8466489Sjmcp startidx += 100; 8476489Sjmcp sumrv++; 8486489Sjmcp } else { 8496489Sjmcp logmsg(MSG_INFO, 8506489Sjmcp gettext("No flashable devices attached with " 8516489Sjmcp "the %s driver in this system\n"), 8526489Sjmcp plugins->drvname); 8536489Sjmcp } 8546489Sjmcp } 8556489Sjmcp 8566489Sjmcp if (sumrv > 0) 8576489Sjmcp rv = FWFLASH_SUCCESS; 8586489Sjmcp 8596489Sjmcp return (rv); 8606489Sjmcp } 8616489Sjmcp 8626489Sjmcp static int 8636489Sjmcp fwflash_list_fw(char *class) 8646489Sjmcp { 8656489Sjmcp int rv = 0; 8666489Sjmcp struct devicelist *curdev; 8676489Sjmcp int header = 1; 8686489Sjmcp 8696489Sjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) { 8706489Sjmcp 8716489Sjmcp /* we're either class-conscious, or we're not */ 8726489Sjmcp if (((class != NULL) && 8736489Sjmcp ((strncmp(curdev->classname, "ALL", 3) == 0) || 8746489Sjmcp (strcmp(curdev->classname, class) == 0))) || 8756489Sjmcp (class == NULL)) { 8766489Sjmcp 8776489Sjmcp if (header != 0) { 8786489Sjmcp (void) fprintf(stdout, 8796489Sjmcp gettext("List of available devices:\n")); 8806489Sjmcp header--; 8816489Sjmcp } 8826489Sjmcp /* 8836489Sjmcp * If any plugin's fw_devinfo() function returns 8846489Sjmcp * FWFLASH_FAILURE then we want to keep track of 8856489Sjmcp * it. _Most_ plugins should always return 8866489Sjmcp * FWFLASH_SUCCESS from this function. The only 8876489Sjmcp * exception known at this point is the tavor plugin. 8886489Sjmcp */ 8896489Sjmcp rv += curdev->plugin->fw_devinfo(curdev); 8906489Sjmcp } 8916489Sjmcp } 8926489Sjmcp return (rv); 8936489Sjmcp } 8946489Sjmcp 8956489Sjmcp static int 8967317SJames.McPherson@Sun.COM fwflash_update(char *device, char *filename, int flags) 8977317SJames.McPherson@Sun.COM { 8986489Sjmcp 8996489Sjmcp int rv = FWFLASH_FAILURE; 9006489Sjmcp int needsfree = 0; 9016846Sjmcp int found = 0; 9026489Sjmcp struct devicelist *curdev; 9036489Sjmcp char *realfile; 9046489Sjmcp 9056489Sjmcp /* 9066489Sjmcp * Here's how we operate: 9076489Sjmcp * 9086489Sjmcp * We perform some basic checks on the args, then walk 9096489Sjmcp * through the device list looking for the device which 9106489Sjmcp * matches. We then load the appropriate verifier for the 9116489Sjmcp * image file and device, verify the image, then call the 9126489Sjmcp * fw_writefw() function of the appropriate plugin. 9136489Sjmcp * 9146489Sjmcp * There is no "force" flag to enable you to flash a firmware 9156489Sjmcp * image onto an incompatible device because the verifier 9166489Sjmcp * will return FWFLASH_FAILURE if the image doesn't match. 9176489Sjmcp */ 9186489Sjmcp 9196489Sjmcp /* new firmware filename and device desc */ 9206489Sjmcp if (filename == NULL) { 9216489Sjmcp logmsg(MSG_ERROR, 9226489Sjmcp gettext("Invalid firmware filename (null)\n")); 9236489Sjmcp return (FWFLASH_FAILURE); 9246489Sjmcp } 9256489Sjmcp 9266489Sjmcp if (device == NULL) { 9276489Sjmcp logmsg(MSG_ERROR, 9286489Sjmcp gettext("Invalid device requested (null)\n")); 9296489Sjmcp return (FWFLASH_FAILURE); 9306489Sjmcp } 9316489Sjmcp 9326489Sjmcp if ((realfile = calloc(1, PATH_MAX + 1)) == NULL) { 9336489Sjmcp logmsg(MSG_ERROR, 9346489Sjmcp gettext("Unable to allocate space for device " 9357317SJames.McPherson@Sun.COM "filename, operation might fail if %s is" 9367317SJames.McPherson@Sun.COM "a symbolic link\n"), 9376489Sjmcp device); 9386489Sjmcp realfile = device; 9396489Sjmcp } else { 9406489Sjmcp /* 9416489Sjmcp * If realpath() succeeds, then we have a valid 9426489Sjmcp * device filename in realfile. 9436489Sjmcp */ 9446489Sjmcp if (realpath(device, realfile) == NULL) { 9456489Sjmcp logmsg(MSG_ERROR, 9466489Sjmcp gettext("Unable to resolve device filename" 9477317SJames.McPherson@Sun.COM ": %s\n"), 9486489Sjmcp strerror(errno)); 9496489Sjmcp /* tidy up */ 9506489Sjmcp free(realfile); 9516489Sjmcp /* realpath didn't succeed, use fallback */ 9526489Sjmcp realfile = device; 9536489Sjmcp } else { 9546489Sjmcp needsfree = 1; 9556489Sjmcp } 9566489Sjmcp } 9576489Sjmcp 9586489Sjmcp logmsg(MSG_INFO, 9596489Sjmcp gettext("fwflash_update: fw_filename (%s) device (%s)\n"), 9606489Sjmcp filename, device); 9616489Sjmcp 9626489Sjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) { 9636489Sjmcp if (strcmp(curdev->access_devname, realfile) == 0) { 9646846Sjmcp found++; 9656489Sjmcp rv = fwflash_load_verifier(curdev->drvname, 9666489Sjmcp curdev->ident->vid, filename); 9676489Sjmcp if (rv == FWFLASH_FAILURE) { 9686489Sjmcp logmsg(MSG_ERROR, 9696489Sjmcp gettext("Unable to load verifier " 9707317SJames.McPherson@Sun.COM "for device %s\n"), 9716489Sjmcp curdev->access_devname); 9726489Sjmcp return (FWFLASH_FAILURE); 9736489Sjmcp } 9746489Sjmcp rv = verifier->vendorvrfy(curdev); 9756489Sjmcp if (rv == FWFLASH_FAILURE) { 9766489Sjmcp /* the verifier prints a message */ 9776489Sjmcp logmsg(MSG_INFO, 9786489Sjmcp "verifier (%s) for %s :: %s returned " 9796489Sjmcp "FWFLASH_FAILURE\n", 9806489Sjmcp verifier->filename, 9816489Sjmcp filename, curdev->access_devname); 9826489Sjmcp return (rv); 9836489Sjmcp } 9846489Sjmcp 9857317SJames.McPherson@Sun.COM if (((flags & FWFLASH_YES_FLAG) == FWFLASH_YES_FLAG) || 9866489Sjmcp (rv = confirm_target(curdev, filename)) == 9876489Sjmcp FWFLASH_YES_FLAG) { 9886489Sjmcp logmsg(MSG_INFO, 9896489Sjmcp "about to flash using plugin %s\n", 9906489Sjmcp curdev->plugin->filename); 9916489Sjmcp rv = curdev->plugin->fw_writefw(curdev, 9926489Sjmcp filename); 9936489Sjmcp if (rv == FWFLASH_FAILURE) { 9946489Sjmcp logmsg(MSG_ERROR, 9956489Sjmcp gettext("Failed to flash " 9967317SJames.McPherson@Sun.COM "firmware file %s on " 9977317SJames.McPherson@Sun.COM "device %s: %d\n"), 9986489Sjmcp filename, 9996489Sjmcp curdev->access_devname, rv); 10006489Sjmcp } 10016489Sjmcp } else { 10026489Sjmcp logmsg(MSG_ERROR, 10036489Sjmcp gettext("Flash operation not confirmed " 10047317SJames.McPherson@Sun.COM "by user\n"), 10056489Sjmcp curdev->access_devname); 10066489Sjmcp rv = FWFLASH_FAILURE; 10076489Sjmcp } 10086489Sjmcp } 10096489Sjmcp } 10106489Sjmcp 10116846Sjmcp if (!found) 10126846Sjmcp /* report the same device that the user passed in */ 10136846Sjmcp logmsg(MSG_ERROR, 10146846Sjmcp gettext("Device %s does not appear " 10156846Sjmcp "to be flashable\n"), 10166846Sjmcp ((strncmp(device, realfile, strlen(device)) == 0) ? 10179683SXin.Chen@Sun.COM realfile : device)); 10186846Sjmcp 10196489Sjmcp if (needsfree) 10206489Sjmcp free(realfile); 10216489Sjmcp 10226489Sjmcp return (rv); 10236489Sjmcp } 10246489Sjmcp 10256489Sjmcp /* 10266489Sjmcp * We validate that the device path is in our global device list and 10276489Sjmcp * that the filename exists, then palm things off to the relevant plugin. 10286489Sjmcp */ 10296489Sjmcp static int 10306489Sjmcp fwflash_read_file(char *device, char *filename) 10316489Sjmcp { 10326489Sjmcp struct devicelist *curdev; 10336489Sjmcp int rv; 10348031SShantkumar.Hiremath@Sun.COM int found = 0; 10356489Sjmcp 10366489Sjmcp /* new firmware filename and device desc */ 10376489Sjmcp 10386489Sjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) { 10396489Sjmcp if (strncmp(curdev->access_devname, device, 10406489Sjmcp MAXPATHLEN) == 0) { 10416489Sjmcp rv = curdev->plugin->fw_readfw(curdev, filename); 10426489Sjmcp 10436489Sjmcp if (rv != FWFLASH_SUCCESS) 10446489Sjmcp logmsg(MSG_ERROR, 10456489Sjmcp gettext("Unable to write out firmware " 10466489Sjmcp "image for %s to file %s\n"), 10476489Sjmcp curdev->access_devname, filename); 10488031SShantkumar.Hiremath@Sun.COM found++; 10496489Sjmcp } 10506489Sjmcp 10516489Sjmcp } 10528031SShantkumar.Hiremath@Sun.COM 10538031SShantkumar.Hiremath@Sun.COM if (!found) { 10546489Sjmcp logmsg(MSG_ERROR, 10556489Sjmcp gettext("No device matching %s was found.\n"), 10566489Sjmcp device); 10576489Sjmcp rv = FWFLASH_FAILURE; 10586489Sjmcp } 10596489Sjmcp 10606489Sjmcp return (rv); 10616489Sjmcp } 10626489Sjmcp 10636489Sjmcp static void 10646489Sjmcp fwflash_usage(char *arg) 10656489Sjmcp { 10666489Sjmcp 10676489Sjmcp (void) fprintf(stderr, "\n"); 10686489Sjmcp if (arg != NULL) { 10696489Sjmcp logmsg(MSG_ERROR, 10706489Sjmcp gettext("Invalid argument (%s) supplied\n"), arg); 10716489Sjmcp } 10726489Sjmcp 10736489Sjmcp (void) fprintf(stderr, "\n"); 10746489Sjmcp 10756489Sjmcp (void) fprintf(stdout, gettext("Usage:\n\t")); 10766489Sjmcp (void) fprintf(stdout, gettext("fwflash [-l [-c device_class " 10776489Sjmcp "| ALL]] | [-v] | [-h]\n\t")); 10786489Sjmcp (void) fprintf(stdout, gettext("fwflash [-f file1,file2,file3" 10796489Sjmcp ",... | -r file] [-y] -d device_path\n\n")); 10806489Sjmcp (void) fprintf(stdout, "\n"); /* workaround for xgettext */ 10816489Sjmcp 10826489Sjmcp (void) fprintf(stdout, 10836489Sjmcp gettext("\t-l\t\tlist flashable devices in this system\n" 10846489Sjmcp "\t-c device_class limit search to a specific class\n" 10856489Sjmcp "\t\t\teg IB for InfiniBand, ses for SCSI Enclosures\n" 10866489Sjmcp "\t-v\t\tprint version number of fwflash utility\n" 10878031SShantkumar.Hiremath@Sun.COM "\t-h\t\tprint this usage message\n\n")); 10886489Sjmcp (void) fprintf(stdout, 10896489Sjmcp gettext("\t-f file1,file2,file3,...\n" 10906489Sjmcp "\t\t\tfirmware image file list to flash\n" 10916489Sjmcp "\t-r file\t\tfile to dump device firmware to\n" 10926489Sjmcp "\t-y\t\tanswer Yes/Y/y to prompts\n" 10936489Sjmcp "\t-d device_path\tpathname of device to be flashed\n\n")); 10946489Sjmcp 10956489Sjmcp (void) fprintf(stdout, 10966489Sjmcp gettext("\tIf -d device_path is specified, then one of -f " 10976489Sjmcp "<files>\n" 10986489Sjmcp "\tor -r <file> must also be specified\n\n")); 10996489Sjmcp 11006489Sjmcp (void) fprintf(stdout, 11016489Sjmcp gettext("\tIf multiple firmware images are required to be " 11026489Sjmcp "flashed\n" 11036489Sjmcp "\tthey must be listed together, separated by commas. The\n" 11046489Sjmcp "\timages will be flashed in the order specified.\n\n")); 11056489Sjmcp 11066489Sjmcp (void) fprintf(stdout, "\n"); 11076489Sjmcp } 11086489Sjmcp 11096489Sjmcp static void 11106489Sjmcp fwflash_version(void) 11116489Sjmcp { 11126489Sjmcp (void) fprintf(stdout, gettext("\n%s: "), FWFLASH_PROG_NAME); 11136489Sjmcp (void) fprintf(stdout, gettext("version %s\n"), 11146489Sjmcp FWFLASH_VERSION); 11156489Sjmcp } 11166489Sjmcp 11176489Sjmcp static void 11186489Sjmcp fwflash_intr(int sig) 11196489Sjmcp { 11206489Sjmcp 11216489Sjmcp struct devicelist *thisdev; 11226489Sjmcp struct pluginlist *thisplug; 11236489Sjmcp 11246489Sjmcp (void) signal(SIGINT, SIG_IGN); 11256489Sjmcp (void) signal(SIGTERM, SIG_IGN); 11266846Sjmcp (void) signal(SIGABRT, SIG_IGN); 11279683SXin.Chen@Sun.COM 11286489Sjmcp if (fwflash_in_write) { 11296489Sjmcp (void) fprintf(stderr, 11306489Sjmcp gettext("WARNING: firmware image may be corrupted\n\t")); 11316489Sjmcp (void) fprintf(stderr, 11326489Sjmcp gettext("Reflash firmware before rebooting!\n")); 11336489Sjmcp } 11346489Sjmcp 11356489Sjmcp if (sig > 0) { 11366489Sjmcp (void) logmsg(MSG_ERROR, gettext("\n")); 11376489Sjmcp (void) logmsg(MSG_ERROR, 11386489Sjmcp gettext("fwflash exiting due to signal (%d)\n"), sig); 11396489Sjmcp } 11406489Sjmcp 11416489Sjmcp /* 11426489Sjmcp * we need to close everything down properly, so 11436489Sjmcp * call the plugin closure routines 11446489Sjmcp */ 11456489Sjmcp if (fw_devices != NULL) { 11466489Sjmcp TAILQ_FOREACH(thisdev, fw_devices, nextdev) { 11479683SXin.Chen@Sun.COM if (thisdev->plugin->fw_cleanup != NULL) { 11489683SXin.Chen@Sun.COM /* 11499683SXin.Chen@Sun.COM * If we've got a cleanup routine, it 11509683SXin.Chen@Sun.COM * cleans up _everything_ for thisdev 11519683SXin.Chen@Sun.COM */ 11529683SXin.Chen@Sun.COM thisdev->plugin->fw_cleanup(thisdev); 11539683SXin.Chen@Sun.COM } else { 11549683SXin.Chen@Sun.COM /* free the components first */ 11559683SXin.Chen@Sun.COM free(thisdev->access_devname); 11569683SXin.Chen@Sun.COM free(thisdev->drvname); 11579683SXin.Chen@Sun.COM free(thisdev->classname); 11589683SXin.Chen@Sun.COM if (thisdev->ident != NULL) 11599683SXin.Chen@Sun.COM free(thisdev->ident); 11609683SXin.Chen@Sun.COM /* We don't free address[] for old plugins */ 11619683SXin.Chen@Sun.COM thisdev->ident = NULL; 11629683SXin.Chen@Sun.COM thisdev->plugin = NULL; 11639683SXin.Chen@Sun.COM } 11646489Sjmcp /* CONSTCOND */ 11656489Sjmcp TAILQ_REMOVE(fw_devices, thisdev, nextdev); 11666489Sjmcp } 11676489Sjmcp } 11686489Sjmcp 11696489Sjmcp if (fw_pluginlist != NULL) { 11706489Sjmcp TAILQ_FOREACH(thisplug, fw_pluginlist, nextplugin) { 11716489Sjmcp free(thisplug->filename); 11726489Sjmcp free(thisplug->drvname); 11736489Sjmcp free(thisplug->plugin->filename); 11746489Sjmcp free(thisplug->plugin->drvname); 11756489Sjmcp thisplug->filename = NULL; 11766489Sjmcp thisplug->drvname = NULL; 11776489Sjmcp thisplug->plugin->filename = NULL; 11786489Sjmcp thisplug->plugin->drvname = NULL; 11796489Sjmcp thisplug->plugin->fw_readfw = NULL; 11806489Sjmcp thisplug->plugin->fw_writefw = NULL; 11816489Sjmcp thisplug->plugin->fw_identify = NULL; 11826489Sjmcp thisplug->plugin->fw_devinfo = NULL; 11839683SXin.Chen@Sun.COM thisplug->plugin->fw_cleanup = NULL; 11846489Sjmcp (void) dlclose(thisplug->plugin->handle); 11856489Sjmcp thisplug->plugin->handle = NULL; 11866489Sjmcp free(thisplug->plugin); 11876489Sjmcp thisplug->plugin = NULL; 11886489Sjmcp /* CONSTCOND */ 11896489Sjmcp TAILQ_REMOVE(fw_pluginlist, thisplug, nextplugin); 11906489Sjmcp } 11916489Sjmcp } 11926489Sjmcp 11936489Sjmcp if (verifier != NULL) { 11946489Sjmcp free(verifier->filename); 11956489Sjmcp free(verifier->vendor); 11966846Sjmcp free(verifier->imgfile); 11976846Sjmcp free(verifier->fwimage); 11986489Sjmcp verifier->filename = NULL; 11996489Sjmcp verifier->vendor = NULL; 12006489Sjmcp verifier->vendorvrfy = NULL; 12016846Sjmcp verifier->imgfile = NULL; 12026846Sjmcp verifier->fwimage = NULL; 12036489Sjmcp (void) dlclose(verifier->handle); 12046489Sjmcp verifier->handle = NULL; 12056489Sjmcp free(verifier); 12066489Sjmcp } 12076489Sjmcp di_fini(rootnode); 12089683SXin.Chen@Sun.COM 12099683SXin.Chen@Sun.COM if (sig > 0) 12109683SXin.Chen@Sun.COM exit(FWFLASH_FAILURE); 12116489Sjmcp } 12126489Sjmcp 12136489Sjmcp static void 12146489Sjmcp fwflash_handle_signals(void) 12156489Sjmcp { 12166489Sjmcp if (signal(SIGINT, fwflash_intr) == SIG_ERR) { 12176489Sjmcp perror("signal"); 12186489Sjmcp exit(FWFLASH_FAILURE); 12196489Sjmcp } 12206489Sjmcp 12216489Sjmcp if (signal(SIGTERM, fwflash_intr) == SIG_ERR) { 12226489Sjmcp perror("signal"); 12236489Sjmcp exit(FWFLASH_FAILURE); 12246489Sjmcp } 12256489Sjmcp } 12266489Sjmcp 12276489Sjmcp static int 12286489Sjmcp confirm_target(struct devicelist *thisdev, char *file) 12296489Sjmcp { 12306489Sjmcp int resp; 12316489Sjmcp 12326846Sjmcp (void) fflush(stdin); 12336846Sjmcp (void) printf(gettext("About to update firmware on %s\n"), 12346846Sjmcp thisdev->access_devname); 12359683SXin.Chen@Sun.COM (void) printf(gettext("with file %s.\n" 12369683SXin.Chen@Sun.COM "Do you want to continue? (Y/N): "), file); 12376489Sjmcp 12386489Sjmcp resp = getchar(); 12396489Sjmcp if (resp == 'Y' || resp == 'y') { 12406489Sjmcp return (FWFLASH_YES_FLAG); 12416489Sjmcp } else { 12426489Sjmcp logmsg(MSG_INFO, "flash operation NOT confirmed.\n"); 12436489Sjmcp } 12446489Sjmcp 12456489Sjmcp (void) fflush(stdin); 12466489Sjmcp return (FWFLASH_FAILURE); 12476489Sjmcp } 12486489Sjmcp 12496489Sjmcp int 12506489Sjmcp get_fileopts(char *options) 12516489Sjmcp { 12526489Sjmcp 12536489Sjmcp int i; 12546489Sjmcp char *files; 12556489Sjmcp 12566489Sjmcp if (files = strtok(options, ",")) { 12576489Sjmcp /* we have more than one */ 12586489Sjmcp if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) { 12596489Sjmcp logmsg(MSG_ERROR, 12606489Sjmcp gettext("Unable to allocate space for " 12616489Sjmcp "a firmware image filename\n")); 12626489Sjmcp return (FWFLASH_FAILURE); 12636489Sjmcp } 12646489Sjmcp (void) strlcpy(filelist[0], files, strlen(files) + 1); 12656489Sjmcp i = 1; 12666489Sjmcp 12676489Sjmcp logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n", 12686489Sjmcp filelist[0]); 12696489Sjmcp 12706489Sjmcp 12716489Sjmcp while (files = strtok(NULL, ",")) { 12726489Sjmcp if ((filelist[i] = calloc(1, MAXPATHLEN + 1)) 12736489Sjmcp == NULL) { 12746489Sjmcp logmsg(MSG_ERROR, 12756489Sjmcp gettext("Unable to allocate space for " 12766489Sjmcp "a firmware image filename\n")); 12776489Sjmcp return (FWFLASH_FAILURE); 12786489Sjmcp } 12796489Sjmcp (void) strlcpy(filelist[i], files, 12806489Sjmcp strlen(files) + 1); 12816489Sjmcp logmsg(MSG_INFO, "fwflash: filelist[%d]: %s\n", 12826489Sjmcp i, filelist[i]); 12836489Sjmcp ++i; 12846489Sjmcp } 12856489Sjmcp } else { 12866489Sjmcp if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) { 12876489Sjmcp logmsg(MSG_ERROR, 12886489Sjmcp gettext("Unable to allocate space for " 12896489Sjmcp "a firmware image filename\n")); 12906489Sjmcp return (FWFLASH_FAILURE); 12916489Sjmcp } 12926489Sjmcp (void) strlcpy(filelist[0], options, strlen(files) + 1); 12936489Sjmcp logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n", 12946489Sjmcp filelist[0]); 12956489Sjmcp } 12966489Sjmcp return (FWFLASH_SUCCESS); 12976489Sjmcp } 12986489Sjmcp 12996489Sjmcp /* 13006489Sjmcp * code reuse - cheerfully borrowed from stmsboot_util.c 13016489Sjmcp */ 13026489Sjmcp void 13039683SXin.Chen@Sun.COM logmsg(int severity, const char *msg, ...) 13049683SXin.Chen@Sun.COM { 13056489Sjmcp va_list ap; 13066489Sjmcp 13076489Sjmcp if ((severity > MSG_INFO) || 13086489Sjmcp ((severity == MSG_INFO) && (fwflash_debug > 0))) { 13096489Sjmcp (void) fprintf(stderr, "%s: ", FWFLASH_PROG_NAME); 13106489Sjmcp va_start(ap, msg); 13116489Sjmcp (void) vfprintf(stderr, msg, ap); 13126489Sjmcp va_end(ap); 13136489Sjmcp } 13146489Sjmcp } 1315