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