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 /* 226489Sjmcp * Copyright 2008 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> 466489Sjmcp #include <fwflash/fwflash.h> 476846Sjmcp #include <sys/modctl.h> /* for MAXMODCONFNAME */ 486489Sjmcp 496489Sjmcp 506489Sjmcp #if !defined(lint) 516489Sjmcp /* embedded software license agreement */ 526489Sjmcp static char *sla [] = { "Copyright 2007 Sun Microsystems, Inc., 4150 Network " 536489Sjmcp "Circle, Santa Clara, California 95054, U.S.A. All rights reserved. U.S. " 546489Sjmcp "Government Rights - Commercial software. Government users are subject to the " 556489Sjmcp "Sun Microsystems, Inc. standard license agreement and applicable provisions " 566489Sjmcp "of the FAR and its supplements. Use is subject to license terms. Parts of " 576489Sjmcp "the product may be derived from Berkeley BSD systems, licensed from the " 586489Sjmcp "University of California. UNIX is a registered trademark in the U.S. and in " 596489Sjmcp "other countries, exclusively licensed through X/Open Company, Ltd.Sun, Sun " 606489Sjmcp "Microsystems, the Sun logo and Solaris are trademarks or registered " 616489Sjmcp "trademarks of Sun Microsystems, Inc. in the U.S. and other countries. This " 626489Sjmcp "product is covered and controlled by U.S. Export Control laws and may be " 636489Sjmcp "subject to the export or import laws in other countries. Nuclear, missile, " 646489Sjmcp "chemical biological weapons or nuclear maritime end uses or end users, " 656489Sjmcp "whether direct or indirect, are strictly prohibited. Export or reexport " 666489Sjmcp "to countries subject to U.S. embargo or to entities identified on U.S. export " 676489Sjmcp "exclusion lists, including, but not limited to, the denied persons and " 686489Sjmcp "specially designated nationals lists is strictly prohibited." }; 696489Sjmcp #endif /* lint */ 706489Sjmcp 716489Sjmcp /* global arg list */ 726489Sjmcp int fwflash_arg_list = 0; 736489Sjmcp char *filelist[10]; 746489Sjmcp 756489Sjmcp /* are we writing to flash? */ 766489Sjmcp static int fwflash_in_write = 0; 776489Sjmcp 786489Sjmcp /* 796489Sjmcp * If we *must* track the version string for fwflash, then 806489Sjmcp * we should do so in this common file rather than the header 816489Sjmcp * file since it will then be in sync with what the customer 827317SJames.McPherson@Sun.COM * sees. We should deprecate the "-v" option since it is not 837317SJames.McPherson@Sun.COM * actually of any use - it doesn't line up with Mercurial's 847317SJames.McPherson@Sun.COM * concept of the changeset. 856489Sjmcp */ 86*8031SShantkumar.Hiremath@Sun.COM #define FWFLASH_VERSION "v1.7" 876489Sjmcp #define FWFLASH_PROG_NAME "fwflash" 886489Sjmcp 896489Sjmcp static int get_fileopts(char *options); 906489Sjmcp static int flash_device_list(); 916489Sjmcp static int flash_load_plugins(); 926489Sjmcp static int fwflash_update(char *device, char *filename, int flags); 936489Sjmcp static int fwflash_read_file(char *device, char *filename); 946489Sjmcp static int fwflash_list_fw(char *class); 956489Sjmcp static int fwflash_load_verifier(char *drv, char *vendorid, char *fwimg); 966489Sjmcp static void fwflash_intr(int sig); 976489Sjmcp static void fwflash_handle_signals(void); 987317SJames.McPherson@Sun.COM static void fwflash_usage(char *arg); 996489Sjmcp static void fwflash_version(void); 1006489Sjmcp static int confirm_target(struct devicelist *thisdev, char *file); 1016489Sjmcp 1026489Sjmcp /* 1036489Sjmcp * FWFlash main code 1046489Sjmcp */ 1056489Sjmcp int 106*8031SShantkumar.Hiremath@Sun.COM main(int argc, char **argv) 107*8031SShantkumar.Hiremath@Sun.COM { 1086489Sjmcp int rv = FWFLASH_SUCCESS; 1096489Sjmcp int i; 1106489Sjmcp char ch; 1116489Sjmcp char *read_file; 1126489Sjmcp extern char *optarg; 1136489Sjmcp char *devclass = NULL; 1146489Sjmcp char *devpath = NULL; 1156489Sjmcp 1166489Sjmcp /* local variables from env */ 1176489Sjmcp (void) setlocale(LC_ALL, ""); 1186489Sjmcp 1196489Sjmcp #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 1206489Sjmcp #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't. */ 1216489Sjmcp #endif 1226489Sjmcp 1236489Sjmcp (void) textdomain(TEXT_DOMAIN); 1246489Sjmcp 1256489Sjmcp read_file = NULL; 1266489Sjmcp 1276489Sjmcp if (argc < 2) { 1286489Sjmcp /* no args supplied */ 1296489Sjmcp fwflash_usage(NULL); 1306489Sjmcp return (FWFLASH_FAILURE); 1316489Sjmcp } 1326489Sjmcp 1336846Sjmcp while ((ch = getopt(argc, argv, "hvylc:f:r:Qd:M")) != EOF) { 1346489Sjmcp switch (ch) { 1356489Sjmcp case 'h': 1366489Sjmcp fwflash_arg_list |= FWFLASH_HELP_FLAG; 1376489Sjmcp break; 1386489Sjmcp case 'v': 1396489Sjmcp fwflash_arg_list |= FWFLASH_VER_FLAG; 1406489Sjmcp break; 1416489Sjmcp case 'y': 1426489Sjmcp fwflash_arg_list |= FWFLASH_YES_FLAG; 1436489Sjmcp break; 1446489Sjmcp case 'l': 1456489Sjmcp fwflash_arg_list |= FWFLASH_LIST_FLAG; 1466489Sjmcp break; 1476489Sjmcp case 'c': 1486489Sjmcp fwflash_arg_list |= FWFLASH_CLASS_FLAG; 1496489Sjmcp /* we validate later */ 1506489Sjmcp devclass = strdup(optarg); 1516489Sjmcp break; 1526489Sjmcp case 'd': 1536489Sjmcp fwflash_arg_list |= FWFLASH_DEVICE_FLAG; 1546489Sjmcp devpath = strdup(optarg); 1556489Sjmcp break; 1566489Sjmcp case 'f': 1576489Sjmcp fwflash_arg_list |= FWFLASH_FW_FLAG; 1586489Sjmcp if ((rv = get_fileopts(optarg)) != FWFLASH_SUCCESS) { 1597317SJames.McPherson@Sun.COM fwflash_usage(NULL); 1606489Sjmcp return (FWFLASH_FAILURE); 1616489Sjmcp } 1626489Sjmcp break; 1636489Sjmcp case 'r': 1646489Sjmcp fwflash_arg_list |= FWFLASH_READ_FLAG; 1656489Sjmcp read_file = strdup(optarg); 1666489Sjmcp break; 1676489Sjmcp case 'Q': 1686489Sjmcp /* NOT in the manpage */ 1696489Sjmcp fwflash_debug = 1; 1706489Sjmcp break; 1716846Sjmcp case 'M': 1726846Sjmcp /* NOT in the manpage */ 1736846Sjmcp #if (MANUFACTURING_MODE > 0) 1746846Sjmcp manufacturing_mode = 1; 1756846Sjmcp logmsg(MSG_WARN, "Enabling Manufacturing Mode " 1766846Sjmcp "operations. This can be destructive!\n"); 1776846Sjmcp break; 1786846Sjmcp #endif 1796846Sjmcp /* illegal options */ 1806489Sjmcp default: 1816489Sjmcp fwflash_usage(optarg); 1826489Sjmcp return (FWFLASH_FAILURE); 1836489Sjmcp } 1846489Sjmcp } 1856489Sjmcp 1866489Sjmcp /* Do Help */ 1876489Sjmcp if ((fwflash_arg_list & FWFLASH_HELP_FLAG) || 1886489Sjmcp ((fwflash_arg_list & FWFLASH_DEVICE_FLAG) && 189*8031SShantkumar.Hiremath@Sun.COM !((fwflash_arg_list & FWFLASH_FW_FLAG) || 190*8031SShantkumar.Hiremath@Sun.COM (fwflash_arg_list & FWFLASH_READ_FLAG)))) { 1917317SJames.McPherson@Sun.COM fwflash_usage(NULL); 1926489Sjmcp return (FWFLASH_SUCCESS); 1936489Sjmcp } 1946489Sjmcp 1956489Sjmcp /* Do Version */ 1966489Sjmcp if (fwflash_arg_list == FWFLASH_VER_FLAG) { 1976489Sjmcp fwflash_version(); 1986489Sjmcp return (FWFLASH_SUCCESS); 1996489Sjmcp } 2006489Sjmcp 2016489Sjmcp /* generate global list of devices */ 2026489Sjmcp if ((rv = flash_load_plugins()) != FWFLASH_SUCCESS) { 2036489Sjmcp logmsg(MSG_ERROR, 2046489Sjmcp gettext("Unable to load fwflash plugins\n")); 2056489Sjmcp fwflash_intr(0); 2066489Sjmcp return (rv); 2076489Sjmcp } 2086489Sjmcp 2096489Sjmcp if ((rv = flash_device_list()) != FWFLASH_SUCCESS) { 2106489Sjmcp logmsg(MSG_ERROR, 2116489Sjmcp gettext("No flashable devices in this system\n")); 2126489Sjmcp fwflash_intr(0); 2136489Sjmcp return (rv); 2146489Sjmcp } 2156489Sjmcp 2166489Sjmcp /* Do list */ 2176489Sjmcp if (fwflash_arg_list == (FWFLASH_LIST_FLAG) || 2186489Sjmcp fwflash_arg_list == (FWFLASH_LIST_FLAG | FWFLASH_CLASS_FLAG)) { 2196489Sjmcp rv = fwflash_list_fw(devclass); 2206489Sjmcp fwflash_intr(0); 2216489Sjmcp return (rv); 2226489Sjmcp } 2236489Sjmcp 2246489Sjmcp fwflash_handle_signals(); 2256489Sjmcp 2266489Sjmcp /* Do flash update (write) */ 2276489Sjmcp if ((fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG)) || 2286489Sjmcp (fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG | 229*8031SShantkumar.Hiremath@Sun.COM FWFLASH_YES_FLAG))) { 2306489Sjmcp /* the update function handles the real arg parsing */ 2316489Sjmcp i = 0; 2326489Sjmcp while (filelist[i] != NULL) { 2336489Sjmcp if ((rv = fwflash_update(devpath, filelist[i], 2346489Sjmcp fwflash_arg_list)) == FWFLASH_SUCCESS) { 2356489Sjmcp /* failed ops have already been noted */ 2366489Sjmcp logmsg(MSG_ERROR, 2376489Sjmcp gettext("New firmware will be activated " 238*8031SShantkumar.Hiremath@Sun.COM "after you reboot\n\n")); 2396489Sjmcp } 2406489Sjmcp ++i; 2416489Sjmcp } 2426489Sjmcp 2436489Sjmcp fwflash_intr(0); 2446489Sjmcp return (rv); 2456489Sjmcp } 2466489Sjmcp 2476489Sjmcp /* Do flash read */ 2486489Sjmcp if ((fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG)) || 2496489Sjmcp (fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG | 250*8031SShantkumar.Hiremath@Sun.COM FWFLASH_YES_FLAG))) { 2516489Sjmcp rv = fwflash_read_file(devpath, read_file); 2526489Sjmcp fwflash_intr(0); 2536489Sjmcp return (rv); 2546489Sjmcp } 2556489Sjmcp 2566489Sjmcp fwflash_usage(NULL); 2576489Sjmcp 2586489Sjmcp return (FWFLASH_FAILURE); 2596489Sjmcp } 2606489Sjmcp 2616489Sjmcp 2626489Sjmcp static int 263*8031SShantkumar.Hiremath@Sun.COM flash_load_plugins() 264*8031SShantkumar.Hiremath@Sun.COM { 2656489Sjmcp 2666489Sjmcp int rval = FWFLASH_SUCCESS; 2676489Sjmcp DIR *dirp; 2686489Sjmcp struct dirent *plugdir; 2696489Sjmcp char *plugname; 2706489Sjmcp struct fw_plugin *tmpplug; 2716489Sjmcp struct pluginlist *tmpelem; 2726489Sjmcp void *sym; 2736489Sjmcp char *fwplugdirpath, *tempdirpath; 2746489Sjmcp 2756489Sjmcp 2766489Sjmcp #define CLOSEFREE() { \ 2776489Sjmcp (void) dlclose(tmpplug->handle); \ 2786489Sjmcp free(tmpplug); } 2796489Sjmcp 2806489Sjmcp /* 2816489Sjmcp * Procedure: 2826489Sjmcp * 2836489Sjmcp * cd /usr/lib/fwflash/identify 2846489Sjmcp * open each .so file found therein 2856489Sjmcp * dlopen(.sofile) 2866489Sjmcp * if it's one of our plugins, add it to fw_pluginlist; 2876489Sjmcp * 2886489Sjmcp * functions we need here include dlopen and dlsym. 2896489Sjmcp * 2906489Sjmcp * If we get to the end and fw_pluginlist struct is empty, 2916489Sjmcp * return FWFLASH_FAILURE so we return to the shell. 2926489Sjmcp */ 2936489Sjmcp 2946489Sjmcp if ((fwplugdirpath = calloc(1, MAXPATHLEN + 1)) == NULL) { 2956489Sjmcp logmsg(MSG_ERROR, 2966489Sjmcp gettext("Unable to malloc %d bytes while " 2976489Sjmcp "trying to load plugins: %s\n"), 2986489Sjmcp MAXPATHLEN + 1, strerror(errno)); 2996489Sjmcp return (FWFLASH_FAILURE); 3006489Sjmcp } 3016489Sjmcp 3026489Sjmcp tempdirpath = getenv("FWPLUGINDIR"); 3036489Sjmcp 3046489Sjmcp if ((fwflash_debug > 0) && (tempdirpath != NULL)) { 3056489Sjmcp (void) strlcpy(fwplugdirpath, tempdirpath, 3066489Sjmcp strlen(tempdirpath) + 1); 3076489Sjmcp } else { 3086489Sjmcp (void) strlcpy(fwplugdirpath, FWPLUGINDIR, 3096489Sjmcp strlen(FWPLUGINDIR) + 1); 3106489Sjmcp } 3116489Sjmcp 3126489Sjmcp if ((dirp = opendir(fwplugdirpath)) == NULL) { 3136489Sjmcp logmsg(MSG_ERROR, 3146846Sjmcp gettext("Unable to open %s\n"), 3156489Sjmcp fwplugdirpath); 3166489Sjmcp return (errno); 3176489Sjmcp } 3186489Sjmcp 3196489Sjmcp if ((plugdir = calloc(1, sizeof (struct dirent) + MAXPATHLEN + 1)) 3206489Sjmcp == NULL) { 3216489Sjmcp logmsg(MSG_ERROR, 3226489Sjmcp gettext("Unable to malloc %d bytes while " 3236489Sjmcp "trying to load plugins: %s\n"), 3246489Sjmcp MAXPATHLEN + 1 + sizeof (struct dirent), 3256489Sjmcp strerror(errno)); 3266489Sjmcp return (FWFLASH_FAILURE); 3276489Sjmcp } 3286489Sjmcp 3296489Sjmcp if ((fw_pluginlist = calloc(1, sizeof (struct fw_plugin))) 3306489Sjmcp == NULL) { 3316489Sjmcp logmsg(MSG_ERROR, 3326489Sjmcp gettext("Unable to malloc %d bytes while " 333*8031SShantkumar.Hiremath@Sun.COM "trying to load plugins: %s\n"), 3346489Sjmcp sizeof (struct fw_plugin) + 1, strerror(errno)); 3356489Sjmcp return (FWFLASH_FAILURE); 3366489Sjmcp } 3376489Sjmcp 3386489Sjmcp TAILQ_INIT(fw_pluginlist); 3396489Sjmcp 3406489Sjmcp while ((readdir_r(dirp, plugdir, &plugdir) == 0) && (plugdir != NULL)) { 3416489Sjmcp 3426489Sjmcp errno = 0; /* remove chance of false results */ 3436489Sjmcp 3446489Sjmcp if ((plugdir->d_name[0] == '.') || 3456489Sjmcp (strstr(plugdir->d_name, ".so") == NULL)) { 3466489Sjmcp continue; 3476489Sjmcp } 3486489Sjmcp 3496489Sjmcp if ((plugname = calloc(1, MAXPATHLEN + 1)) == NULL) { 3506489Sjmcp logmsg(MSG_ERROR, 3516489Sjmcp gettext("Unable to malloc %d bytes while " 352*8031SShantkumar.Hiremath@Sun.COM "trying to load plugins: %s\n"), 3536489Sjmcp MAXPATHLEN + 1, strerror(errno)); 3546489Sjmcp return (FWFLASH_FAILURE); 3556489Sjmcp } 3566489Sjmcp 3576489Sjmcp (void) snprintf(plugname, MAXPATHLEN, "%s/%s", 3586489Sjmcp fwplugdirpath, plugdir->d_name); 3596489Sjmcp 3606489Sjmcp /* start allocating storage */ 3616489Sjmcp if ((tmpelem = calloc(1, sizeof (struct pluginlist))) 3626489Sjmcp == NULL) { 3636489Sjmcp logmsg(MSG_ERROR, 3646489Sjmcp gettext("Unable to malloc %d bytes while " 365*8031SShantkumar.Hiremath@Sun.COM "trying to load plugins: %s\n"), 3666489Sjmcp sizeof (struct pluginlist), strerror(errno)); 3676489Sjmcp return (FWFLASH_FAILURE); 3686489Sjmcp } 3696489Sjmcp 3706489Sjmcp if ((tmpplug = calloc(1, sizeof (struct fw_plugin))) 3716489Sjmcp == NULL) { 3726489Sjmcp logmsg(MSG_ERROR, 3736489Sjmcp gettext("Unable to malloc %d bytes while " 3746489Sjmcp "trying to load plugins: %s\n"), 3756489Sjmcp sizeof (struct fw_plugin), strerror(errno)); 3766489Sjmcp return (FWFLASH_FAILURE); 3776489Sjmcp } 3786489Sjmcp 3796489Sjmcp /* load 'er up! */ 3806489Sjmcp tmpplug->handle = dlopen(plugname, RTLD_NOW); 3816489Sjmcp if (tmpplug->handle == NULL) { 3826489Sjmcp free(tmpplug); 3836489Sjmcp continue; /* assume there are other plugins */ 3846489Sjmcp } 3856489Sjmcp 3866489Sjmcp if ((tmpplug->filename = calloc(1, strlen(plugname) + 1)) 3876489Sjmcp == NULL) { 3886489Sjmcp logmsg(MSG_ERROR, 3896489Sjmcp gettext("Unable to allocate %d bytes for plugin " 390*8031SShantkumar.Hiremath@Sun.COM "filename %s:%s\n"), 3916489Sjmcp strlen(plugname) + 1, plugname, 3926489Sjmcp strerror(errno)); 3936489Sjmcp return (rval); 3946489Sjmcp } 3956489Sjmcp 3966489Sjmcp (void) strlcpy(tmpplug->filename, plugname, 3976489Sjmcp strlen(plugname) + 1); 3986489Sjmcp 3996489Sjmcp /* now sanity check the file */ 4006489Sjmcp if ((sym = dlsym(tmpplug->handle, "drivername")) 4016489Sjmcp != NULL) { 4026489Sjmcp /* max length of drivername */ 4036846Sjmcp tmpplug->drvname = calloc(1, MAXMODCONFNAME); 4046846Sjmcp 4056846Sjmcp /* are we doing double-time? */ 4066846Sjmcp if (strncmp((char *)sym, plugdir->d_name, 4076846Sjmcp MAXMODCONFNAME) != 0) { 4086846Sjmcp char *tempnm = calloc(1, MAXMODCONFNAME); 4096846Sjmcp 4106846Sjmcp memcpy(tempnm, plugdir->d_name, MAXMODCONFNAME); 4116846Sjmcp (void) strlcpy(tmpplug->drvname, 4126846Sjmcp strtok(tempnm, "."), 4136846Sjmcp strlen(plugdir->d_name) + 1); 4146846Sjmcp free(tempnm); 4156846Sjmcp } else { 4166846Sjmcp (void) strlcpy(tmpplug->drvname, 4176846Sjmcp (char *)sym, strlen(sym) + 1); 4186846Sjmcp } 4196489Sjmcp } else { 4206489Sjmcp CLOSEFREE(); 4216489Sjmcp continue; 4226489Sjmcp } 4236489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_readfw")) 4246489Sjmcp != NULL) { 4256489Sjmcp tmpplug->fw_readfw = (int (*)())sym; 4266489Sjmcp } else { 4276489Sjmcp CLOSEFREE(); 4286489Sjmcp continue; 4296489Sjmcp } 4306489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_writefw")) 4316489Sjmcp != NULL) { 4326489Sjmcp tmpplug->fw_writefw = (int (*)())sym; 4336489Sjmcp } else { 4346489Sjmcp CLOSEFREE(); 4356489Sjmcp continue; 4366489Sjmcp } 4376489Sjmcp 4386489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_identify")) 4396489Sjmcp != NULL) { 4406489Sjmcp tmpplug->fw_identify = 4416489Sjmcp (int (*)(int))sym; 4426489Sjmcp } else { 4436489Sjmcp CLOSEFREE(); 4446489Sjmcp continue; 4456489Sjmcp } 4466489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_devinfo")) 4476489Sjmcp != NULL) { 4486489Sjmcp tmpplug->fw_devinfo = 4496489Sjmcp (int (*)(struct devicelist *))sym; 4506489Sjmcp } else { 4516489Sjmcp CLOSEFREE(); 4526489Sjmcp continue; 4536489Sjmcp } 4546489Sjmcp 4556846Sjmcp if ((tmpelem->drvname = calloc(1, MAXMODCONFNAME)) 4566489Sjmcp == NULL) { 4576489Sjmcp logmsg(MSG_ERROR, 4586846Sjmcp gettext("Unable to allocate space for a" 459*8031SShantkumar.Hiremath@Sun.COM "drivername %s\n"), 4606489Sjmcp tmpplug->drvname); 4616489Sjmcp return (FWFLASH_FAILURE); 4626489Sjmcp } 4636489Sjmcp 4646489Sjmcp (void) strlcpy(tmpelem->drvname, tmpplug->drvname, 4656489Sjmcp strlen(tmpplug->drvname) + 1); 4666489Sjmcp 4676489Sjmcp if ((tmpelem->filename = calloc(1, 4686489Sjmcp strlen(tmpplug->filename) + 1)) == NULL) { 4696489Sjmcp logmsg(MSG_ERROR, 4706489Sjmcp gettext("Unable to allocate %d bytes for " 471*8031SShantkumar.Hiremath@Sun.COM "filename %s\n"), 4726489Sjmcp strlen(tmpplug->filename) + 1, 4736846Sjmcp tmpplug->filename); 4746489Sjmcp return (FWFLASH_FAILURE); 4756489Sjmcp } 4766489Sjmcp 4776489Sjmcp (void) strlcpy(tmpelem->filename, plugname, 4786489Sjmcp strlen(plugname) + 1); 4796489Sjmcp tmpelem->plugin = tmpplug; 4806489Sjmcp 4816489Sjmcp /* CONSTCOND */ 4826489Sjmcp TAILQ_INSERT_TAIL(fw_pluginlist, tmpelem, nextplugin); 4836489Sjmcp } 4846489Sjmcp 4856489Sjmcp if ((plugdir == NULL) && TAILQ_EMPTY(fw_pluginlist)) { 4866489Sjmcp return (FWFLASH_FAILURE); 4876489Sjmcp } 4886489Sjmcp 4896489Sjmcp if (errno != 0) { 4906489Sjmcp logmsg(MSG_ERROR, 4916489Sjmcp gettext("Error reading directory entry in %s\n"), 4926489Sjmcp fwplugdirpath); 4936489Sjmcp (void) closedir(dirp); 4946489Sjmcp rval = errno; 4956489Sjmcp } 4966489Sjmcp 4976489Sjmcp (void) free(fwplugdirpath); 4986489Sjmcp (void) free(plugdir); 4996489Sjmcp (void) closedir(dirp); 5006489Sjmcp return (rval); 5016489Sjmcp } 5026489Sjmcp 5036489Sjmcp /* 5046489Sjmcp * fwflash_load_verifier dlload()s the appropriate firmware image 5056489Sjmcp * verification plugin, and attaches the designated fwimg's fd to 5066489Sjmcp * the vrfyplugin structure so we only have to load the image in 5076489Sjmcp * one place. 5086489Sjmcp */ 5096489Sjmcp int 510*8031SShantkumar.Hiremath@Sun.COM fwflash_load_verifier(char *drv, char *vendorid, char *fwimg) 511*8031SShantkumar.Hiremath@Sun.COM { 5126489Sjmcp 5136489Sjmcp int rv = FWFLASH_FAILURE; 5146489Sjmcp int imgfd; 5156489Sjmcp char *fwvrfydirpath, *tempdirpath, *filename; 5166489Sjmcp char *clean; /* for the space-removed vid */ 5176489Sjmcp struct stat fwstat; 5186489Sjmcp struct vrfyplugin *vrfy; 5196489Sjmcp void *vrfysym; 5206489Sjmcp 5216489Sjmcp /* 5226489Sjmcp * To make flashing multiple firmware images somewhat more 5236489Sjmcp * efficient, we start this function by checking whether a 5246489Sjmcp * verifier for this device has already been loaded. If it 5256489Sjmcp * has been loaded, we replace the imgfile information, and 5266489Sjmcp * then continue as if we were loading for the first time. 5276489Sjmcp */ 5286489Sjmcp 5296489Sjmcp if (verifier != NULL) { 5306489Sjmcp verifier->imgsize = 0; 5316489Sjmcp verifier->flashbuf = 0; /* set by the verifier function */ 5326489Sjmcp 5336489Sjmcp if (verifier->imgfile != NULL) 5346489Sjmcp (void) free(verifier->imgfile); 5356489Sjmcp 5366489Sjmcp if (verifier->fwimage != NULL) 5376489Sjmcp (void) free(verifier->fwimage); 5386489Sjmcp } else { 5396489Sjmcp if ((fwvrfydirpath = calloc(1, MAXPATHLEN + 1)) == NULL) { 5406489Sjmcp logmsg(MSG_ERROR, 5416489Sjmcp gettext("Unable to allocate space for a firmware " 542*8031SShantkumar.Hiremath@Sun.COM "verifier file(1)")); 5436489Sjmcp return (rv); 5446489Sjmcp } 5456489Sjmcp 5466489Sjmcp if ((filename = calloc(1, MAXPATHLEN + 1)) == NULL) { 5476489Sjmcp logmsg(MSG_ERROR, 5486489Sjmcp gettext("Unable to allocate space " 5496489Sjmcp "for a firmware verifier file(2)")); 5506489Sjmcp return (rv); 5516489Sjmcp } 5526489Sjmcp 5536489Sjmcp /* 5546489Sjmcp * Since SCSI devices can have a vendor id of up to 8 left-aligned 5556489Sjmcp * and _space-padded_ characters, we first need to strip off any 5566489Sjmcp * space characters before we try to make a filename out of it 5576489Sjmcp */ 5586489Sjmcp clean = strtok(vendorid, " "); 5596489Sjmcp if (clean == NULL) { 5606489Sjmcp /* invalid vendorid, something's really wrong */ 5616489Sjmcp logmsg(MSG_ERROR, 5626489Sjmcp gettext("Invalid vendorid (null) specified for " 563*8031SShantkumar.Hiremath@Sun.COM "device\n")); 5646489Sjmcp return (rv); 5656489Sjmcp } 5666489Sjmcp 5676489Sjmcp tempdirpath = getenv("FWVERIFYPLUGINDIR"); 5686489Sjmcp 5696489Sjmcp if ((fwflash_debug > 0) && (tempdirpath != NULL)) { 5706489Sjmcp (void) strlcpy(fwvrfydirpath, tempdirpath, 5716489Sjmcp strlen(tempdirpath) + 1); 5726489Sjmcp } else { 5736489Sjmcp (void) strlcpy(fwvrfydirpath, FWVERIFYPLUGINDIR, 5746489Sjmcp strlen(FWVERIFYPLUGINDIR) + 1); 5756489Sjmcp } 5766489Sjmcp 5776489Sjmcp if ((vrfy = calloc(1, sizeof (struct vrfyplugin))) == NULL) { 5786489Sjmcp logmsg(MSG_ERROR, 5796489Sjmcp gettext("Unable to allocate space " 5806489Sjmcp "for a firmware verifier structure")); 5816489Sjmcp free(filename); 5826489Sjmcp free(fwvrfydirpath); 5836489Sjmcp return (FWFLASH_FAILURE); 5846489Sjmcp } 5856489Sjmcp 5866489Sjmcp errno = 0; /* false positive removal */ 5876489Sjmcp 5886489Sjmcp (void) snprintf(filename, strlen(fwvrfydirpath) + 5896489Sjmcp strlen(drv) + 7 + strlen(clean), "%s/%s-%s.so\0", 5906489Sjmcp fwvrfydirpath, drv, clean); 5916489Sjmcp 5926489Sjmcp if ((vrfy->filename = calloc(1, strlen(filename) + 1)) 5936489Sjmcp == NULL) { 5946489Sjmcp logmsg(MSG_ERROR, 5956489Sjmcp gettext("Unable to allocate space to store " 596*8031SShantkumar.Hiremath@Sun.COM "a verifier filename\n")); 5976489Sjmcp free(filename); 5986489Sjmcp free(fwvrfydirpath); 5996489Sjmcp free(vrfy->handle); 6006489Sjmcp return (FWFLASH_FAILURE); 6016489Sjmcp } 6026489Sjmcp 6036489Sjmcp (void) strlcpy(vrfy->filename, filename, strlen(filename) + 1); 6046489Sjmcp 6056489Sjmcp if ((vrfy->handle = dlopen(filename, RTLD_NOW)) == NULL) { 6066489Sjmcp logmsg(MSG_ERROR, gettext(dlerror())); 6076489Sjmcp logmsg(MSG_ERROR, 6086489Sjmcp gettext("Unable to open verification plugin " 609*8031SShantkumar.Hiremath@Sun.COM "%s. Unable to verify firmware image. " 610*8031SShantkumar.Hiremath@Sun.COM "Aborting.\n"), 6116489Sjmcp filename); 6126489Sjmcp free(filename); 6136489Sjmcp free(fwvrfydirpath); 6146489Sjmcp return (FWFLASH_FAILURE); 6156489Sjmcp } 6166489Sjmcp 6176489Sjmcp if ((vrfysym = dlsym(vrfy->handle, "vendorvrfy")) == NULL) { 6186489Sjmcp logmsg(MSG_ERROR, 6196489Sjmcp gettext("%s is an invalid firmware verification " 620*8031SShantkumar.Hiremath@Sun.COM "plugin."), filename); 6216489Sjmcp (void) dlclose(vrfy->handle); 6226489Sjmcp free(filename); 6236489Sjmcp free(fwvrfydirpath); 6246489Sjmcp free(vrfy); 6256489Sjmcp return (FWFLASH_FAILURE); 6266489Sjmcp } else { 6276489Sjmcp vrfy->vendorvrfy = 6286489Sjmcp (int (*)(struct devicelist *))vrfysym; 6296489Sjmcp } 6306489Sjmcp 6316489Sjmcp vrfysym = dlsym(vrfy->handle, "vendor"); 6326489Sjmcp 6336489Sjmcp if (vrfysym == NULL) { 6346489Sjmcp logmsg(MSG_ERROR, 6356489Sjmcp gettext("Invalid vendor (null) in verification " 636*8031SShantkumar.Hiremath@Sun.COM "plugin %s\n"), filename); 6376489Sjmcp (void) dlclose(vrfy->handle); 6386489Sjmcp free(vrfy); 6396489Sjmcp return (NULL); 6406489Sjmcp } else { 6416489Sjmcp if (strncmp(vendorid, (char *)vrfysym, 6426489Sjmcp strlen(vendorid)) != 0) { 6436489Sjmcp logmsg(MSG_INFO, 6446489Sjmcp "Using a sym-linked (%s -> %s) " 6456489Sjmcp "verification plugin", 6466489Sjmcp vendorid, vrfysym); 6476489Sjmcp vrfy->vendor = calloc(1, strlen(vendorid) + 1); 6486489Sjmcp } else { 6496489Sjmcp vrfy->vendor = calloc(1, strlen(vrfysym) + 1); 6506489Sjmcp } 6516489Sjmcp (void) strlcpy(vrfy->vendor, (char *)vrfysym, 6526489Sjmcp strlen(vendorid) + 1); 6536489Sjmcp } 6546489Sjmcp 6556489Sjmcp verifier = vrfy; /* a convenience variable */ 6566489Sjmcp } 6576489Sjmcp 6586489Sjmcp 6596489Sjmcp /* 6606489Sjmcp * We don't do any verification that the fw image file is in 6616489Sjmcp * an approved location, but it's easy enough to modify this 6626489Sjmcp * function to do so. The verification plugin should provide 6636489Sjmcp * sufficient protection. 6646489Sjmcp */ 6656489Sjmcp 6666489Sjmcp if ((imgfd = open(fwimg, O_RDONLY)) < 0) { 6676489Sjmcp logmsg(MSG_ERROR, 6686489Sjmcp gettext("Unable to open designated firmware " 669*8031SShantkumar.Hiremath@Sun.COM "image file %s: %s\n"), 6706489Sjmcp (fwimg != NULL) ? fwimg : "(null)", 6716489Sjmcp strerror(errno)); 6726489Sjmcp rv = FWFLASH_FAILURE; 6736489Sjmcp goto cleanup; 6746489Sjmcp } 6756489Sjmcp 6766489Sjmcp if (stat(fwimg, &fwstat) == -1) { 6776489Sjmcp logmsg(MSG_ERROR, 6786489Sjmcp gettext("Unable to stat() firmware image file " 679*8031SShantkumar.Hiremath@Sun.COM "%s: %s\n"), 6806489Sjmcp fwimg, strerror(errno)); 6816489Sjmcp rv = FWFLASH_FAILURE; 6826489Sjmcp goto cleanup; 6836489Sjmcp } else { 6846489Sjmcp verifier->imgsize = fwstat.st_size; 6856489Sjmcp if ((verifier->fwimage = calloc(1, verifier->imgsize)) 6866489Sjmcp == NULL) { 6876489Sjmcp logmsg(MSG_ERROR, 6886489Sjmcp gettext("Unable to load firmware image " 689*8031SShantkumar.Hiremath@Sun.COM "%s: %s\n"), 6906489Sjmcp fwimg, strerror(errno)); 6916489Sjmcp rv = FWFLASH_FAILURE; 6926489Sjmcp goto cleanup; 6936489Sjmcp } 6946489Sjmcp } 6956489Sjmcp 6966489Sjmcp errno = 0; 6976489Sjmcp if ((rv = read(imgfd, verifier->fwimage, 6986489Sjmcp (size_t)verifier->imgsize)) < verifier->imgsize) { 6996489Sjmcp /* we haven't read enough data, bail */ 7006489Sjmcp logmsg(MSG_ERROR, 7016489Sjmcp gettext("Failed to read sufficient data " 702*8031SShantkumar.Hiremath@Sun.COM "(got %d bytes, expected %d bytes) from " 703*8031SShantkumar.Hiremath@Sun.COM "firmware image file %s: %s\n"), 7046489Sjmcp rv, verifier->imgsize, 7056489Sjmcp filename, strerror(errno)); 7066489Sjmcp rv = FWFLASH_FAILURE; 7076489Sjmcp } else { 7086489Sjmcp rv = FWFLASH_SUCCESS; 7096489Sjmcp } 7106489Sjmcp 7116489Sjmcp if ((verifier->imgfile = calloc(1, strlen(fwimg) + 1)) == NULL) { 7126489Sjmcp logmsg(MSG_ERROR, 7136489Sjmcp gettext("Unable to save name of firmware image\n")); 7146489Sjmcp rv = FWFLASH_FAILURE; 7156489Sjmcp } else { 7166489Sjmcp (void) strlcpy(verifier->imgfile, fwimg, strlen(fwimg) + 1); 7176489Sjmcp } 7186489Sjmcp 7196489Sjmcp if (rv != FWFLASH_SUCCESS) { 7206489Sjmcp /* cleanup and let's get outta here */ 7216489Sjmcp cleanup: 7226489Sjmcp free(verifier->filename); 7236489Sjmcp free(verifier->vendor); 7246489Sjmcp 7256489Sjmcp if (!(fwflash_arg_list & FWFLASH_READ_FLAG)) 7266489Sjmcp free(verifier->fwimage); 7276489Sjmcp 7286489Sjmcp verifier->filename = NULL; 7296489Sjmcp verifier->vendor = NULL; 7306489Sjmcp verifier->vendorvrfy = NULL; 7316489Sjmcp verifier->fwimage = NULL; 7326489Sjmcp (void) dlclose(verifier->handle); 7336489Sjmcp verifier->handle = NULL; 7346489Sjmcp free(verifier); 7356489Sjmcp if (imgfd >= 0) { 7366489Sjmcp (void) close(imgfd); 7376489Sjmcp } 7386489Sjmcp verifier = NULL; 7396489Sjmcp } 7406489Sjmcp 7416489Sjmcp return (rv); 7426489Sjmcp } 7436489Sjmcp 7446489Sjmcp /* 7456489Sjmcp * cycles through the global list of plugins to find 7466489Sjmcp * each flashable device, which is added to fw_devices 7476489Sjmcp * 7486489Sjmcp * Each plugin's identify routine must allocated storage 7496489Sjmcp * as required. 7506489Sjmcp * 7516489Sjmcp * Each plugin's identify routine must return 7526489Sjmcp * FWFLASH_FAILURE if it cannot find any devices 7536489Sjmcp * which it handles. 7546489Sjmcp */ 7556489Sjmcp static int 7566489Sjmcp flash_device_list() 7576489Sjmcp { 7586489Sjmcp int rv = FWFLASH_FAILURE; 7596489Sjmcp int startidx = 0; 7606489Sjmcp int sumrv = 0; 7616489Sjmcp struct pluginlist *plugins; 7626489Sjmcp 7636489Sjmcp /* we open rootnode here, and close it in fwflash_intr */ 7646489Sjmcp if ((rootnode = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { 7656489Sjmcp logmsg(MSG_ERROR, 7666489Sjmcp gettext("Unable to take device tree snapshot: %s\n"), 7676489Sjmcp strerror(errno)); 7686489Sjmcp return (rv); 7696489Sjmcp } 7706489Sjmcp 7716489Sjmcp if ((fw_devices = calloc(1, sizeof (struct devicelist))) == NULL) { 7726489Sjmcp logmsg(MSG_ERROR, 7736489Sjmcp gettext("Unable to malloc %d bytes while " 7746489Sjmcp "trying to find devices: %s\n"), 7756489Sjmcp sizeof (struct devicelist), strerror(errno)); 7766489Sjmcp return (FWFLASH_FAILURE); 7776489Sjmcp } 7786489Sjmcp 7796489Sjmcp /* CONSTCOND */ 7806489Sjmcp TAILQ_INIT(fw_devices); 7816489Sjmcp 7826489Sjmcp TAILQ_FOREACH(plugins, fw_pluginlist, nextplugin) { 7836489Sjmcp self = plugins->plugin; 7846489Sjmcp rv = plugins->plugin->fw_identify(startidx); 7856489Sjmcp 7866489Sjmcp logmsg(MSG_INFO, 7876489Sjmcp gettext("fwflash:flash_device_list() got %d from " 7886489Sjmcp "identify routine\n"), rv); 7896489Sjmcp 7906489Sjmcp /* only bump startidx if we've found at least one device */ 7916489Sjmcp if (rv == FWFLASH_SUCCESS) { 7926489Sjmcp startidx += 100; 7936489Sjmcp sumrv++; 7946489Sjmcp } else { 7956489Sjmcp logmsg(MSG_INFO, 7966489Sjmcp gettext("No flashable devices attached with " 7976489Sjmcp "the %s driver in this system\n"), 7986489Sjmcp plugins->drvname); 7996489Sjmcp } 8006489Sjmcp } 8016489Sjmcp 8026489Sjmcp if (sumrv > 0) 8036489Sjmcp rv = FWFLASH_SUCCESS; 8046489Sjmcp 8056489Sjmcp return (rv); 8066489Sjmcp } 8076489Sjmcp 8086489Sjmcp static int 8096489Sjmcp fwflash_list_fw(char *class) 8106489Sjmcp { 8116489Sjmcp int rv = 0; 8126489Sjmcp struct devicelist *curdev; 8136489Sjmcp int header = 1; 8146489Sjmcp 8156489Sjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) { 8166489Sjmcp 8176489Sjmcp /* we're either class-conscious, or we're not */ 8186489Sjmcp if (((class != NULL) && 8196489Sjmcp ((strncmp(curdev->classname, "ALL", 3) == 0) || 8206489Sjmcp (strcmp(curdev->classname, class) == 0))) || 8216489Sjmcp (class == NULL)) { 8226489Sjmcp 8236489Sjmcp if (header != 0) { 8246489Sjmcp (void) fprintf(stdout, 8256489Sjmcp gettext("List of available devices:\n")); 8266489Sjmcp header--; 8276489Sjmcp } 8286489Sjmcp /* 8296489Sjmcp * If any plugin's fw_devinfo() function returns 8306489Sjmcp * FWFLASH_FAILURE then we want to keep track of 8316489Sjmcp * it. _Most_ plugins should always return 8326489Sjmcp * FWFLASH_SUCCESS from this function. The only 8336489Sjmcp * exception known at this point is the tavor plugin. 8346489Sjmcp */ 8356489Sjmcp rv += curdev->plugin->fw_devinfo(curdev); 8366489Sjmcp } 8376489Sjmcp } 8386489Sjmcp return (rv); 8396489Sjmcp } 8406489Sjmcp 8416489Sjmcp static int 8427317SJames.McPherson@Sun.COM fwflash_update(char *device, char *filename, int flags) 8437317SJames.McPherson@Sun.COM { 8446489Sjmcp 8456489Sjmcp int rv = FWFLASH_FAILURE; 8466489Sjmcp int needsfree = 0; 8476846Sjmcp int found = 0; 8486489Sjmcp struct devicelist *curdev; 8496489Sjmcp char *realfile; 8506489Sjmcp 8516489Sjmcp /* 8526489Sjmcp * Here's how we operate: 8536489Sjmcp * 8546489Sjmcp * We perform some basic checks on the args, then walk 8556489Sjmcp * through the device list looking for the device which 8566489Sjmcp * matches. We then load the appropriate verifier for the 8576489Sjmcp * image file and device, verify the image, then call the 8586489Sjmcp * fw_writefw() function of the appropriate plugin. 8596489Sjmcp * 8606489Sjmcp * There is no "force" flag to enable you to flash a firmware 8616489Sjmcp * image onto an incompatible device because the verifier 8626489Sjmcp * will return FWFLASH_FAILURE if the image doesn't match. 8636489Sjmcp */ 8646489Sjmcp 8656489Sjmcp /* new firmware filename and device desc */ 8666489Sjmcp if (filename == NULL) { 8676489Sjmcp logmsg(MSG_ERROR, 8686489Sjmcp gettext("Invalid firmware filename (null)\n")); 8696489Sjmcp return (FWFLASH_FAILURE); 8706489Sjmcp } 8716489Sjmcp 8726489Sjmcp if (device == NULL) { 8736489Sjmcp logmsg(MSG_ERROR, 8746489Sjmcp gettext("Invalid device requested (null)\n")); 8756489Sjmcp return (FWFLASH_FAILURE); 8766489Sjmcp } 8776489Sjmcp 8786489Sjmcp if ((realfile = calloc(1, PATH_MAX + 1)) == NULL) { 8796489Sjmcp logmsg(MSG_ERROR, 8806489Sjmcp gettext("Unable to allocate space for device " 8817317SJames.McPherson@Sun.COM "filename, operation might fail if %s is" 8827317SJames.McPherson@Sun.COM "a symbolic link\n"), 8836489Sjmcp device); 8846489Sjmcp realfile = device; 8856489Sjmcp } else { 8866489Sjmcp /* 8876489Sjmcp * If realpath() succeeds, then we have a valid 8886489Sjmcp * device filename in realfile. 8896489Sjmcp */ 8906489Sjmcp if (realpath(device, realfile) == NULL) { 8916489Sjmcp logmsg(MSG_ERROR, 8926489Sjmcp gettext("Unable to resolve device filename" 8937317SJames.McPherson@Sun.COM ": %s\n"), 8946489Sjmcp strerror(errno)); 8956489Sjmcp /* tidy up */ 8966489Sjmcp free(realfile); 8976489Sjmcp /* realpath didn't succeed, use fallback */ 8986489Sjmcp realfile = device; 8996489Sjmcp } else { 9006489Sjmcp needsfree = 1; 9016489Sjmcp } 9026489Sjmcp } 9036489Sjmcp 9046489Sjmcp logmsg(MSG_INFO, 9056489Sjmcp gettext("fwflash_update: fw_filename (%s) device (%s)\n"), 9066489Sjmcp filename, device); 9076489Sjmcp 9086489Sjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) { 9096489Sjmcp 9106489Sjmcp if (strcmp(curdev->access_devname, realfile) == 0) { 9116846Sjmcp found++; 9126489Sjmcp rv = fwflash_load_verifier(curdev->drvname, 9136489Sjmcp curdev->ident->vid, filename); 9146489Sjmcp if (rv == FWFLASH_FAILURE) { 9156489Sjmcp logmsg(MSG_ERROR, 9166489Sjmcp gettext("Unable to load verifier " 9177317SJames.McPherson@Sun.COM "for device %s\n"), 9186489Sjmcp curdev->access_devname); 9196489Sjmcp return (FWFLASH_FAILURE); 9206489Sjmcp } 9216489Sjmcp rv = verifier->vendorvrfy(curdev); 9226489Sjmcp if (rv == FWFLASH_FAILURE) { 9236489Sjmcp /* the verifier prints a message */ 9246489Sjmcp logmsg(MSG_INFO, 9256489Sjmcp "verifier (%s) for %s :: %s returned " 9266489Sjmcp "FWFLASH_FAILURE\n", 9276489Sjmcp verifier->filename, 9286489Sjmcp filename, curdev->access_devname); 9296489Sjmcp return (rv); 9306489Sjmcp } 9316489Sjmcp 9327317SJames.McPherson@Sun.COM if (((flags & FWFLASH_YES_FLAG) == FWFLASH_YES_FLAG) || 9336489Sjmcp (rv = confirm_target(curdev, filename)) == 9346489Sjmcp FWFLASH_YES_FLAG) { 9356489Sjmcp logmsg(MSG_INFO, 9366489Sjmcp "about to flash using plugin %s\n", 9376489Sjmcp curdev->plugin->filename); 9386489Sjmcp rv = curdev->plugin->fw_writefw(curdev, 9396489Sjmcp filename); 9406489Sjmcp if (rv == FWFLASH_FAILURE) { 9416489Sjmcp logmsg(MSG_ERROR, 9426489Sjmcp gettext("Failed to flash " 9437317SJames.McPherson@Sun.COM "firmware file %s on " 9447317SJames.McPherson@Sun.COM "device %s: %d\n"), 9456489Sjmcp filename, 9466489Sjmcp curdev->access_devname, rv); 9476489Sjmcp } 9486489Sjmcp } else { 9496489Sjmcp logmsg(MSG_ERROR, 9506489Sjmcp gettext("Flash operation not confirmed " 9517317SJames.McPherson@Sun.COM "by user\n"), 9526489Sjmcp curdev->access_devname); 9536489Sjmcp rv = FWFLASH_FAILURE; 9546489Sjmcp } 9556489Sjmcp } 9566489Sjmcp } 9576489Sjmcp 9586846Sjmcp if (!found) 9596846Sjmcp /* report the same device that the user passed in */ 9606846Sjmcp logmsg(MSG_ERROR, 9616846Sjmcp gettext("Device %s does not appear " 9626846Sjmcp "to be flashable\n"), 9636846Sjmcp ((strncmp(device, realfile, strlen(device)) == 0) ? 9646846Sjmcp device : realfile)); 9656846Sjmcp 9666489Sjmcp if (needsfree) 9676489Sjmcp free(realfile); 9686489Sjmcp 9696489Sjmcp return (rv); 9706489Sjmcp } 9716489Sjmcp 9726489Sjmcp /* 9736489Sjmcp * We validate that the device path is in our global device list and 9746489Sjmcp * that the filename exists, then palm things off to the relevant plugin. 9756489Sjmcp */ 9766489Sjmcp static int 9776489Sjmcp fwflash_read_file(char *device, char *filename) 9786489Sjmcp { 9796489Sjmcp struct devicelist *curdev; 9806489Sjmcp int rv; 981*8031SShantkumar.Hiremath@Sun.COM int found = 0; 9826489Sjmcp 9836489Sjmcp /* new firmware filename and device desc */ 9846489Sjmcp 9856489Sjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) { 9866489Sjmcp if (strncmp(curdev->access_devname, device, 9876489Sjmcp MAXPATHLEN) == 0) { 9886489Sjmcp rv = curdev->plugin->fw_readfw(curdev, filename); 9896489Sjmcp 9906489Sjmcp if (rv != FWFLASH_SUCCESS) 9916489Sjmcp logmsg(MSG_ERROR, 9926489Sjmcp gettext("Unable to write out firmware " 9936489Sjmcp "image for %s to file %s\n"), 9946489Sjmcp curdev->access_devname, filename); 995*8031SShantkumar.Hiremath@Sun.COM found++; 9966489Sjmcp } 9976489Sjmcp 9986489Sjmcp } 999*8031SShantkumar.Hiremath@Sun.COM 1000*8031SShantkumar.Hiremath@Sun.COM if (!found) { 10016489Sjmcp logmsg(MSG_ERROR, 10026489Sjmcp gettext("No device matching %s was found.\n"), 10036489Sjmcp device); 10046489Sjmcp rv = FWFLASH_FAILURE; 10056489Sjmcp } 10066489Sjmcp 10076489Sjmcp return (rv); 10086489Sjmcp } 10096489Sjmcp 10106489Sjmcp static void 10116489Sjmcp fwflash_usage(char *arg) 10126489Sjmcp { 10136489Sjmcp 10146489Sjmcp (void) fprintf(stderr, "\n"); 10156489Sjmcp if (arg != NULL) { 10166489Sjmcp logmsg(MSG_ERROR, 10176489Sjmcp gettext("Invalid argument (%s) supplied\n"), arg); 10186489Sjmcp } 10196489Sjmcp 10206489Sjmcp (void) fprintf(stderr, "\n"); 10216489Sjmcp 10226489Sjmcp (void) fprintf(stdout, gettext("Usage:\n\t")); 10236489Sjmcp (void) fprintf(stdout, gettext("fwflash [-l [-c device_class " 10246489Sjmcp "| ALL]] | [-v] | [-h]\n\t")); 10256489Sjmcp (void) fprintf(stdout, gettext("fwflash [-f file1,file2,file3" 10266489Sjmcp ",... | -r file] [-y] -d device_path\n\n")); 10276489Sjmcp (void) fprintf(stdout, "\n"); /* workaround for xgettext */ 10286489Sjmcp 10296489Sjmcp (void) fprintf(stdout, 10306489Sjmcp gettext("\t-l\t\tlist flashable devices in this system\n" 10316489Sjmcp "\t-c device_class limit search to a specific class\n" 10326489Sjmcp "\t\t\teg IB for InfiniBand, ses for SCSI Enclosures\n" 10336489Sjmcp "\t-v\t\tprint version number of fwflash utility\n" 1034*8031SShantkumar.Hiremath@Sun.COM "\t-h\t\tprint this usage message\n\n")); 10356489Sjmcp (void) fprintf(stdout, 10366489Sjmcp gettext("\t-f file1,file2,file3,...\n" 10376489Sjmcp "\t\t\tfirmware image file list to flash\n" 10386489Sjmcp "\t-r file\t\tfile to dump device firmware to\n" 10396489Sjmcp "\t-y\t\tanswer Yes/Y/y to prompts\n" 10406489Sjmcp "\t-d device_path\tpathname of device to be flashed\n\n")); 10416489Sjmcp 10426489Sjmcp (void) fprintf(stdout, 10436489Sjmcp gettext("\tIf -d device_path is specified, then one of -f " 10446489Sjmcp "<files>\n" 10456489Sjmcp "\tor -r <file> must also be specified\n\n")); 10466489Sjmcp 10476489Sjmcp (void) fprintf(stdout, 10486489Sjmcp gettext("\tIf multiple firmware images are required to be " 10496489Sjmcp "flashed\n" 10506489Sjmcp "\tthey must be listed together, separated by commas. The\n" 10516489Sjmcp "\timages will be flashed in the order specified.\n\n")); 10526489Sjmcp 10536489Sjmcp (void) fprintf(stdout, "\n"); 10546489Sjmcp } 10556489Sjmcp 10566489Sjmcp static void 10576489Sjmcp fwflash_version(void) 10586489Sjmcp { 10596489Sjmcp (void) fprintf(stdout, gettext("\n%s: "), FWFLASH_PROG_NAME); 10606489Sjmcp (void) fprintf(stdout, gettext("version %s\n"), 10616489Sjmcp FWFLASH_VERSION); 10626489Sjmcp } 10636489Sjmcp 10646489Sjmcp static void 10656489Sjmcp fwflash_intr(int sig) 10666489Sjmcp { 10676489Sjmcp 10686489Sjmcp struct devicelist *thisdev; 10696489Sjmcp struct pluginlist *thisplug; 10706489Sjmcp 10716489Sjmcp 10726489Sjmcp (void) signal(SIGINT, SIG_IGN); 10736489Sjmcp (void) signal(SIGTERM, SIG_IGN); 10746846Sjmcp (void) signal(SIGABRT, SIG_IGN); 10756489Sjmcp if (fwflash_in_write) { 10766489Sjmcp (void) fprintf(stderr, 10776489Sjmcp gettext("WARNING: firmware image may be corrupted\n\t")); 10786489Sjmcp (void) fprintf(stderr, 10796489Sjmcp gettext("Reflash firmware before rebooting!\n")); 10806489Sjmcp } 10816489Sjmcp 10826489Sjmcp if (sig > 0) { 10836489Sjmcp (void) logmsg(MSG_ERROR, gettext("\n")); 10846489Sjmcp (void) logmsg(MSG_ERROR, 10856489Sjmcp gettext("fwflash exiting due to signal (%d)\n"), sig); 10866489Sjmcp } 10876489Sjmcp 10886489Sjmcp /* 10896489Sjmcp * we need to close everything down properly, so 10906489Sjmcp * call the plugin closure routines 10916489Sjmcp */ 10926489Sjmcp if (fw_devices != NULL) { 10936489Sjmcp TAILQ_FOREACH(thisdev, fw_devices, nextdev) { 10946489Sjmcp /* free the components first */ 10956489Sjmcp free(thisdev->access_devname); 10966489Sjmcp free(thisdev->drvname); 10976489Sjmcp free(thisdev->classname); 10986846Sjmcp if (thisdev->ident != NULL) 10996489Sjmcp free(thisdev->ident); 11006846Sjmcp 11016489Sjmcp thisdev->ident = NULL; 11026489Sjmcp thisdev->plugin = NULL; /* we free this elsewhere */ 11036489Sjmcp /* CONSTCOND */ 11046489Sjmcp TAILQ_REMOVE(fw_devices, thisdev, nextdev); 11056489Sjmcp } 11066489Sjmcp } 11076489Sjmcp 11086489Sjmcp if (fw_pluginlist != NULL) { 11096489Sjmcp TAILQ_FOREACH(thisplug, fw_pluginlist, nextplugin) { 11106489Sjmcp free(thisplug->filename); 11116489Sjmcp free(thisplug->drvname); 11126489Sjmcp free(thisplug->plugin->filename); 11136489Sjmcp free(thisplug->plugin->drvname); 11146489Sjmcp thisplug->filename = NULL; 11156489Sjmcp thisplug->drvname = NULL; 11166489Sjmcp thisplug->plugin->filename = NULL; 11176489Sjmcp thisplug->plugin->drvname = NULL; 11186489Sjmcp thisplug->plugin->fw_readfw = NULL; 11196489Sjmcp thisplug->plugin->fw_writefw = NULL; 11206489Sjmcp thisplug->plugin->fw_identify = NULL; 11216489Sjmcp thisplug->plugin->fw_devinfo = NULL; 11226489Sjmcp (void) dlclose(thisplug->plugin->handle); 11236489Sjmcp thisplug->plugin->handle = NULL; 11246489Sjmcp free(thisplug->plugin); 11256489Sjmcp thisplug->plugin = NULL; 11266489Sjmcp /* CONSTCOND */ 11276489Sjmcp TAILQ_REMOVE(fw_pluginlist, thisplug, nextplugin); 11286489Sjmcp } 11296489Sjmcp } 11306489Sjmcp 11316489Sjmcp if (verifier != NULL) { 11326489Sjmcp free(verifier->filename); 11336489Sjmcp free(verifier->vendor); 11346846Sjmcp free(verifier->imgfile); 11356846Sjmcp free(verifier->fwimage); 11366489Sjmcp verifier->filename = NULL; 11376489Sjmcp verifier->vendor = NULL; 11386489Sjmcp verifier->vendorvrfy = NULL; 11396846Sjmcp verifier->imgfile = NULL; 11406846Sjmcp verifier->fwimage = NULL; 11416489Sjmcp (void) dlclose(verifier->handle); 11426489Sjmcp verifier->handle = NULL; 11436489Sjmcp free(verifier); 11446489Sjmcp } 11456489Sjmcp di_fini(rootnode); 11466489Sjmcp } 11476489Sjmcp 11486489Sjmcp static void 11496489Sjmcp fwflash_handle_signals(void) 11506489Sjmcp { 11516489Sjmcp if (signal(SIGINT, fwflash_intr) == SIG_ERR) { 11526489Sjmcp perror("signal"); 11536489Sjmcp exit(FWFLASH_FAILURE); 11546489Sjmcp } 11556489Sjmcp 11566489Sjmcp if (signal(SIGTERM, fwflash_intr) == SIG_ERR) { 11576489Sjmcp perror("signal"); 11586489Sjmcp exit(FWFLASH_FAILURE); 11596489Sjmcp } 11606489Sjmcp } 11616489Sjmcp 11626489Sjmcp static int 11636489Sjmcp confirm_target(struct devicelist *thisdev, char *file) 11646489Sjmcp { 11656489Sjmcp int resp; 11666489Sjmcp 11676846Sjmcp (void) fflush(stdin); 11686846Sjmcp (void) printf(gettext("About to update firmware on %s\n"), 11696846Sjmcp thisdev->access_devname); 11706846Sjmcp (void) printf(gettext("with file %s. Do you want to continue? " 11716846Sjmcp "(Y/N): "), file); 11726489Sjmcp 11736489Sjmcp resp = getchar(); 11746489Sjmcp if (resp == 'Y' || resp == 'y') { 11756489Sjmcp return (FWFLASH_YES_FLAG); 11766489Sjmcp } else { 11776489Sjmcp logmsg(MSG_INFO, "flash operation NOT confirmed.\n"); 11786489Sjmcp } 11796489Sjmcp 11806489Sjmcp (void) fflush(stdin); 11816489Sjmcp return (FWFLASH_FAILURE); 11826489Sjmcp } 11836489Sjmcp 11846489Sjmcp int 11856489Sjmcp get_fileopts(char *options) 11866489Sjmcp { 11876489Sjmcp 11886489Sjmcp int i; 11896489Sjmcp char *files; 11906489Sjmcp 11916489Sjmcp if (files = strtok(options, ",")) { 11926489Sjmcp /* we have more than one */ 11936489Sjmcp if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) { 11946489Sjmcp logmsg(MSG_ERROR, 11956489Sjmcp gettext("Unable to allocate space for " 11966489Sjmcp "a firmware image filename\n")); 11976489Sjmcp return (FWFLASH_FAILURE); 11986489Sjmcp } 11996489Sjmcp (void) strlcpy(filelist[0], files, strlen(files) + 1); 12006489Sjmcp i = 1; 12016489Sjmcp 12026489Sjmcp logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n", 12036489Sjmcp filelist[0]); 12046489Sjmcp 12056489Sjmcp 12066489Sjmcp while (files = strtok(NULL, ",")) { 12076489Sjmcp if ((filelist[i] = calloc(1, MAXPATHLEN + 1)) 12086489Sjmcp == NULL) { 12096489Sjmcp logmsg(MSG_ERROR, 12106489Sjmcp gettext("Unable to allocate space for " 12116489Sjmcp "a firmware image filename\n")); 12126489Sjmcp return (FWFLASH_FAILURE); 12136489Sjmcp } 12146489Sjmcp (void) strlcpy(filelist[i], files, 12156489Sjmcp strlen(files) + 1); 12166489Sjmcp logmsg(MSG_INFO, "fwflash: filelist[%d]: %s\n", 12176489Sjmcp i, filelist[i]); 12186489Sjmcp ++i; 12196489Sjmcp } 12206489Sjmcp } else { 12216489Sjmcp if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) { 12226489Sjmcp logmsg(MSG_ERROR, 12236489Sjmcp gettext("Unable to allocate space for " 12246489Sjmcp "a firmware image filename\n")); 12256489Sjmcp return (FWFLASH_FAILURE); 12266489Sjmcp } 12276489Sjmcp (void) strlcpy(filelist[0], options, strlen(files) + 1); 12286489Sjmcp logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n", 12296489Sjmcp filelist[0]); 12306489Sjmcp } 12316489Sjmcp return (FWFLASH_SUCCESS); 12326489Sjmcp } 12336489Sjmcp 12346489Sjmcp /* 12356489Sjmcp * code reuse - cheerfully borrowed from stmsboot_util.c 12366489Sjmcp */ 12376489Sjmcp void 12387317SJames.McPherson@Sun.COM logmsg(int severity, const char *msg, ...) { 12396489Sjmcp 12406489Sjmcp va_list ap; 12416489Sjmcp 12426489Sjmcp if ((severity > MSG_INFO) || 12436489Sjmcp ((severity == MSG_INFO) && (fwflash_debug > 0))) { 12446489Sjmcp (void) fprintf(stderr, "%s: ", FWFLASH_PROG_NAME); 12456489Sjmcp va_start(ap, msg); 12466489Sjmcp (void) vfprintf(stderr, msg, ap); 12476489Sjmcp va_end(ap); 12486489Sjmcp } 12496489Sjmcp } 1250