15a7763bfSjmcp /* 25a7763bfSjmcp * CDDL HEADER START 35a7763bfSjmcp * 45a7763bfSjmcp * The contents of this file are subject to the terms of the 55a7763bfSjmcp * Common Development and Distribution License (the "License"). 65a7763bfSjmcp * You may not use this file except in compliance with the License. 75a7763bfSjmcp * 85a7763bfSjmcp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95a7763bfSjmcp * or http://www.opensolaris.org/os/licensing. 105a7763bfSjmcp * See the License for the specific language governing permissions 115a7763bfSjmcp * and limitations under the License. 125a7763bfSjmcp * 135a7763bfSjmcp * When distributing Covered Code, include this CDDL HEADER in each 145a7763bfSjmcp * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155a7763bfSjmcp * If applicable, add the following below this CDDL HEADER, with the 165a7763bfSjmcp * fields enclosed by brackets "[]" replaced with your own identifying 175a7763bfSjmcp * information: Portions Copyright [yyyy] [name of copyright owner] 185a7763bfSjmcp * 195a7763bfSjmcp * CDDL HEADER END 205a7763bfSjmcp */ 215a7763bfSjmcp /* 220f59e5a7Speihong huang * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235a7763bfSjmcp * Use is subject to license terms. 245a7763bfSjmcp */ 255a7763bfSjmcp 265a7763bfSjmcp /* 275a7763bfSjmcp * ses (SCSI Generic Device) specific functions. 285a7763bfSjmcp */ 295a7763bfSjmcp 305a7763bfSjmcp #include <libnvpair.h> 315a7763bfSjmcp #include <stdio.h> 325a7763bfSjmcp #include <stdlib.h> 335a7763bfSjmcp #include <unistd.h> 345a7763bfSjmcp #include <sys/types.h> 355a7763bfSjmcp #include <sys/sysmacros.h> 365a7763bfSjmcp #include <sys/queue.h> 375a7763bfSjmcp #include <fcntl.h> 385a7763bfSjmcp #include <string.h> 39c4800545Sjmcp #include <scsi/libscsi.h> 405a7763bfSjmcp #include <scsi/libses.h> 415a7763bfSjmcp #include <libintl.h> /* for gettext(3c) */ 425a7763bfSjmcp #include <fwflash/fwflash.h> 435a7763bfSjmcp 445a7763bfSjmcp 455a7763bfSjmcp #define VIDLEN 0x08 465a7763bfSjmcp #define PIDLEN 0x10 475a7763bfSjmcp #define REVLEN 0x04 485a7763bfSjmcp #define SASADDRLEN 0x10 495a7763bfSjmcp #define PCBUFLEN 0x40 505a7763bfSjmcp #define RQBUFLEN 0xfe 515a7763bfSjmcp #define STATBUFLEN 0xfe 525a7763bfSjmcp #define INQBUFLEN 0x80 535a7763bfSjmcp 545a7763bfSjmcp /* useful defines */ 555a7763bfSjmcp #define UCODE_CHECK_STATUS 0 565a7763bfSjmcp #define UCODE_CHECK_SUPPORTED 1 575a7763bfSjmcp 585a7763bfSjmcp typedef struct ucode_statdesc { 595a7763bfSjmcp uint64_t us_value; 605a7763bfSjmcp const char *us_desc; 615a7763bfSjmcp boolean_t us_pending; 625a7763bfSjmcp boolean_t us_iserr; 635a7763bfSjmcp } ucode_statdesc_t; 645a7763bfSjmcp 655a7763bfSjmcp static ucode_statdesc_t ucode_statdesc_table[] = { 665a7763bfSjmcp { SES2_DLUCODE_S_NOP, "none", B_FALSE, B_FALSE }, 675a7763bfSjmcp { SES2_DLUCODE_S_INPROGRESS, "in progress", B_TRUE, B_FALSE }, 685a7763bfSjmcp { SES2_DLUCODE_S_SAVING, "saved", B_TRUE, B_FALSE }, 695a7763bfSjmcp { SES2_DLUCODE_S_COMPLETE_NOW, "completed (available)", B_FALSE, 705a7763bfSjmcp B_FALSE }, 715a7763bfSjmcp { SES2_DLUCODE_S_COMPLETE_AT_RESET, 725a7763bfSjmcp "completed (need reset or power on)", B_FALSE, B_FALSE }, 735a7763bfSjmcp { SES2_DLUCODE_S_COMPLETE_AT_POWERON, "completed (need power on)", 745a7763bfSjmcp B_FALSE, B_FALSE }, 755a7763bfSjmcp { SES2_DLUCODE_S_PAGE_ERR, "page error (offset %d)", 765a7763bfSjmcp B_FALSE, B_TRUE }, 775a7763bfSjmcp { SES2_DLUCODE_S_IMAGE_ERR, "invalid image", 785a7763bfSjmcp B_FALSE, B_TRUE }, 795a7763bfSjmcp { SES2_DLUCODE_S_TIMEOUT, "download timeout", 805a7763bfSjmcp B_FALSE, B_TRUE }, 815a7763bfSjmcp { SES2_DLUCODE_S_INTERNAL_NEEDIMAGE, 825a7763bfSjmcp "internal error (NEED NEW IMAGE BEFORE RESET)", 835a7763bfSjmcp B_FALSE, B_TRUE }, 845a7763bfSjmcp { SES2_DLUCODE_S_INTERNAL_SAFE, 855a7763bfSjmcp "internal error (reset to revert to backup)", 865a7763bfSjmcp B_FALSE, B_TRUE }, 875a7763bfSjmcp }; 885a7763bfSjmcp 895a7763bfSjmcp #define NUCODE_STATUS \ 905a7763bfSjmcp (sizeof (ucode_statdesc_table) / sizeof (ucode_statdesc_table[0])) 915a7763bfSjmcp 925a7763bfSjmcp typedef struct ucode_status { 935a7763bfSjmcp uint64_t us_status; 945a7763bfSjmcp boolean_t us_iserr; 955a7763bfSjmcp boolean_t us_pending; 965a7763bfSjmcp char us_desc[128]; 975a7763bfSjmcp } ucode_status_t; 985a7763bfSjmcp 995a7763bfSjmcp typedef struct ucode_wait { 1005a7763bfSjmcp uint64_t uw_prevstatus; 1015a7763bfSjmcp boolean_t uw_pending; 1025a7763bfSjmcp ses_node_t *uw_oldnp; 1035a7763bfSjmcp } ucode_wait_t; 1045a7763bfSjmcp 1055a7763bfSjmcp 106c4800545Sjmcp typedef struct sam4_statdesc { 107c4800545Sjmcp int status; 108c4800545Sjmcp char *message; 109c4800545Sjmcp } sam4_statdesc_t; 110c4800545Sjmcp 111c4800545Sjmcp 112c4800545Sjmcp static sam4_statdesc_t sam4_status[] = { 113c4800545Sjmcp { SAM4_STATUS_GOOD, "Status: GOOD (success)" }, 114c4800545Sjmcp { SAM4_STATUS_CHECK_CONDITION, "Status: CHECK CONDITION" }, 115c4800545Sjmcp { SAM4_STATUS_CONDITION_MET, "Status: CONDITION MET" }, 116c4800545Sjmcp { SAM4_STATUS_BUSY, "Status: Device is BUSY" }, 117c4800545Sjmcp { SAM4_STATUS_RESERVATION_CONFLICT, "Status: Device is RESERVED" }, 118c4800545Sjmcp { SAM4_STATUS_TASK_SET_FULL, 119c4800545Sjmcp "Status: TASK SET FULL (insufficient resources in command queue" }, 120c4800545Sjmcp { SAM4_STATUS_TASK_ABORTED, "Status: TASK ABORTED" }, 121c4800545Sjmcp { NULL, NULL } 122c4800545Sjmcp }; 123c4800545Sjmcp 124c4800545Sjmcp #define NSAM4_STATUS \ 125c4800545Sjmcp (sizeof (sam4_status) / sizeof (sam4_status[0])) 126c4800545Sjmcp 127c4800545Sjmcp 128c4800545Sjmcp 1295a7763bfSjmcp char drivername[] = "ses\0"; 1305a7763bfSjmcp static char *devprefix = "/devices"; 131c4800545Sjmcp static char *sessuffix = ":0"; 132c4800545Sjmcp static char *sgensuffix = ":ses"; 133c4800545Sjmcp 134d73e86dbSsuha 135c4800545Sjmcp static ses_target_t *ses_target; 1365a7763bfSjmcp 1375a7763bfSjmcp extern di_node_t rootnode; 1385a7763bfSjmcp extern int errno; 1395a7763bfSjmcp extern struct fw_plugin *self; 1405a7763bfSjmcp extern struct vrfyplugin *verifier; 1415a7763bfSjmcp extern int fwflash_debug; 1425a7763bfSjmcp 1435a7763bfSjmcp 1445a7763bfSjmcp /* required functions for this plugin */ 1455a7763bfSjmcp int fw_readfw(struct devicelist *device, char *filename); 1465a7763bfSjmcp int fw_writefw(struct devicelist *device); 1475a7763bfSjmcp int fw_identify(int start); 1485a7763bfSjmcp int fw_devinfo(struct devicelist *thisdev); 1495a7763bfSjmcp 1505a7763bfSjmcp 1515a7763bfSjmcp /* helper functions */ 152*d65b419eSXinChen static int print_updated_status(ses_node_t *np, void *arg); 1535a7763bfSjmcp static int get_status(nvlist_t *props, ucode_status_t *sp); 154c4800545Sjmcp static int sendimg(ses_node_t *np, void *data); 155c4800545Sjmcp static int scsi_writebuf(); 1565a7763bfSjmcp 1575a7763bfSjmcp /* 158c4800545Sjmcp * We don't currently support reading firmware from a SAS 159c4800545Sjmcp * expander. If we do eventually support it, we would use 160c4800545Sjmcp * the scsi READ BUFFER command to do so. 1615a7763bfSjmcp */ 1625a7763bfSjmcp int 1635a7763bfSjmcp fw_readfw(struct devicelist *flashdev, char *filename) 1645a7763bfSjmcp { 1655a7763bfSjmcp 1665a7763bfSjmcp logmsg(MSG_INFO, 167c4800545Sjmcp "%s: not writing firmware for device %s to file %s\n", 168c4800545Sjmcp flashdev->drvname, flashdev->access_devname, filename); 169c4800545Sjmcp logmsg(MSG_ERROR, 170c4800545Sjmcp gettext("\n\nReading of firmware images from %s-attached " 171c4800545Sjmcp "devices is not supported\n\n"), 172c4800545Sjmcp flashdev->drvname); 1735a7763bfSjmcp 174c4800545Sjmcp return (FWFLASH_SUCCESS); 1755a7763bfSjmcp } 1765a7763bfSjmcp 1775a7763bfSjmcp 1785a7763bfSjmcp /* 1795a7763bfSjmcp * If we're invoking fw_writefw, then flashdev is a valid, 1805a7763bfSjmcp * flashable device supporting the SES2 Download Microcode Diagnostic 1815a7763bfSjmcp * Control page (0x0e). 1825a7763bfSjmcp * 1835a7763bfSjmcp * If verifier is null, then we haven't been called following a firmware 1845a7763bfSjmcp * image verification load operation. 1855a7763bfSjmcp * 1865a7763bfSjmcp * *THIS* function uses scsi SEND DIAGNOSTIC/download microcode to 1875a7763bfSjmcp * achieve the task... if you chase down to the bottom of libses you 1885a7763bfSjmcp * can see that too. 1895a7763bfSjmcp */ 1905a7763bfSjmcp int 1915a7763bfSjmcp fw_writefw(struct devicelist *flashdev) 1925a7763bfSjmcp { 193*d65b419eSXinChen int rv = FWFLASH_FAILURE; 1945a7763bfSjmcp nvlist_t *nvl; 1955a7763bfSjmcp ses_snap_t *snapshot; 196c4800545Sjmcp ses_node_t *targetnode; 1975a7763bfSjmcp 198c4800545Sjmcp if ((verifier == NULL) || (verifier->imgsize == 0) || 199c4800545Sjmcp (verifier->fwimage == NULL)) { 200c4800545Sjmcp /* should _not_ happen */ 201c4800545Sjmcp logmsg(MSG_ERROR, 202c4800545Sjmcp gettext("%s: Firmware image has not " 203c4800545Sjmcp "been verified.\n"), 204c4800545Sjmcp flashdev->drvname); 205c4800545Sjmcp return (FWFLASH_FAILURE); 206c4800545Sjmcp } 2075a7763bfSjmcp 2085a7763bfSjmcp if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 2095a7763bfSjmcp nvlist_add_uint64(nvl, SES_CTL_PROP_UCODE_MODE, 2105a7763bfSjmcp SES_DLUCODE_M_WITH_OFFS) != 0) { 211c4800545Sjmcp logmsg(MSG_ERROR, 212c4800545Sjmcp gettext("%s: Unable to allocate " 213c4800545Sjmcp "space for device prop list\n"), 214c4800545Sjmcp flashdev->drvname); 2155a7763bfSjmcp return (FWFLASH_FAILURE); 2165a7763bfSjmcp } 2175a7763bfSjmcp 2185a7763bfSjmcp fprintf(stdout, "\n"); /* get a fresh line for progress updates */ 2195a7763bfSjmcp 2205a7763bfSjmcp if (nvlist_add_uint64(nvl, SES_CTL_PROP_UCODE_BUFID, 2215a7763bfSjmcp verifier->flashbuf) != 0) { 222c4800545Sjmcp logmsg(MSG_ERROR, 223c4800545Sjmcp gettext("%s: Unable to add buffer id " 224c4800545Sjmcp "property, hence unable to flash device\n"), 225c4800545Sjmcp flashdev->drvname); 2265a7763bfSjmcp goto cancel; 2275a7763bfSjmcp } 2285a7763bfSjmcp 2295a7763bfSjmcp if (nvlist_add_byte_array(nvl, SES_CTL_PROP_UCODE_DATA, 2305a7763bfSjmcp (uint8_t *)verifier->fwimage, verifier->imgsize) != 0) { 2315a7763bfSjmcp logmsg(MSG_ERROR, 2325a7763bfSjmcp "%s: Out of memory for property addition\n", 233c4800545Sjmcp flashdev->drvname); 2345a7763bfSjmcp goto cancel; 2355a7763bfSjmcp } 2365a7763bfSjmcp 2375a7763bfSjmcp if ((ses_target = 2385a7763bfSjmcp ses_open(LIBSES_VERSION, flashdev->access_devname)) == NULL) { 2395a7763bfSjmcp logmsg(MSG_ERROR, 240c4800545Sjmcp gettext("%s: Unable to open flashable device %s\n"), 241c4800545Sjmcp flashdev->drvname, flashdev->access_devname); 2425a7763bfSjmcp goto cancel; 2435a7763bfSjmcp } 2445a7763bfSjmcp 245c4800545Sjmcp snapshot = ses_snap_hold(ses_target); 246d73e86dbSsuha 247c4800545Sjmcp if ((targetnode = ses_snap_primary_enclosure(snapshot)) == NULL) { 248c4800545Sjmcp logmsg(MSG_ERROR, 249c4800545Sjmcp gettext("%s: Unable to locate primary enclosure for " 250c4800545Sjmcp "device %s\n"), 251c4800545Sjmcp flashdev->access_devname); 252c4800545Sjmcp } else { 253c4800545Sjmcp rv = sendimg(targetnode, nvl); 254c4800545Sjmcp if (rv == FWFLASH_SUCCESS) { 255c4800545Sjmcp logmsg(MSG_ERROR, 256c4800545Sjmcp gettext("%s: Done. New image will be active " 257c4800545Sjmcp "after the system is rebooted.\n\n"), 258c4800545Sjmcp flashdev->drvname); 259c4800545Sjmcp } else { 260c4800545Sjmcp logmsg(MSG_INFO, 261c4800545Sjmcp "%s: unable to flash image %s to device %s\n\n", 262c4800545Sjmcp flashdev->drvname, verifier->imgfile, 263c4800545Sjmcp flashdev->access_devname); 264c4800545Sjmcp } 265c4800545Sjmcp } 2665a7763bfSjmcp 2675a7763bfSjmcp ses_snap_rele(snapshot); 2685a7763bfSjmcp ses_close(ses_target); 2695a7763bfSjmcp cancel: 2705a7763bfSjmcp nvlist_free(nvl); 2715a7763bfSjmcp 272*d65b419eSXinChen return (rv); 2735a7763bfSjmcp } 2745a7763bfSjmcp 2755a7763bfSjmcp 2765a7763bfSjmcp /* 2775a7763bfSjmcp * The fw_identify() function walks the device 2785a7763bfSjmcp * tree trying to find devices which this plugin 2795a7763bfSjmcp * can work with. 2805a7763bfSjmcp * 2815a7763bfSjmcp * The parameter "start" gives us the starting index number 2825a7763bfSjmcp * to give the device when we add it to the fw_devices list. 2835a7763bfSjmcp * 2845a7763bfSjmcp * firstdev is allocated by us and we add space as needed 2855a7763bfSjmcp */ 2865a7763bfSjmcp int 2875a7763bfSjmcp fw_identify(int start) 2885a7763bfSjmcp { 2895a7763bfSjmcp 2905a7763bfSjmcp int rv = FWFLASH_FAILURE; 2915a7763bfSjmcp di_node_t thisnode; 2925a7763bfSjmcp struct devicelist *newdev; 2935a7763bfSjmcp char *devpath; 294c4800545Sjmcp char *devsuffix; 295c4800545Sjmcp char *driver; 2965a7763bfSjmcp int idx = start; 297f1c23465SJames C. McPherson size_t devlength = 0; 298c4800545Sjmcp nvlist_t *props; 299c4800545Sjmcp ses_snap_t *snapshot; 300c4800545Sjmcp ses_node_t *rootnodep, *nodep; 301c4800545Sjmcp 3025a7763bfSjmcp 303c4800545Sjmcp if (strcmp(self->drvname, "sgen") == 0) { 304c4800545Sjmcp devsuffix = sgensuffix; 305c4800545Sjmcp driver = self->drvname; 306c4800545Sjmcp } else { 307c4800545Sjmcp devsuffix = sessuffix; 308c4800545Sjmcp driver = drivername; 309c4800545Sjmcp } 3105a7763bfSjmcp 311c4800545Sjmcp thisnode = di_drv_first_node(driver, rootnode); 3125a7763bfSjmcp 3135a7763bfSjmcp if (thisnode == DI_NODE_NIL) { 3145a7763bfSjmcp logmsg(MSG_INFO, gettext("No %s nodes in this system\n"), 315c4800545Sjmcp driver); 316f1c23465SJames C. McPherson return (FWFLASH_FAILURE); 3175a7763bfSjmcp } 3185a7763bfSjmcp 3195a7763bfSjmcp if ((devpath = calloc(1, MAXPATHLEN + 1)) == NULL) { 320c4800545Sjmcp logmsg(MSG_ERROR, 321c4800545Sjmcp gettext("%s: Unable to allocate space " 322c4800545Sjmcp "for a device node\n"), 323c4800545Sjmcp driver); 324f1c23465SJames C. McPherson return (FWFLASH_FAILURE); 3255a7763bfSjmcp } 3265a7763bfSjmcp 3275a7763bfSjmcp /* we've found one, at least */ 3285a7763bfSjmcp 3295a7763bfSjmcp for (; thisnode != DI_NODE_NIL; thisnode = di_drv_next_node(thisnode)) { 3305a7763bfSjmcp 3315a7763bfSjmcp devpath = di_devfs_path(thisnode); 3325a7763bfSjmcp 3335a7763bfSjmcp if ((newdev = calloc(1, sizeof (struct devicelist))) 3345a7763bfSjmcp == NULL) { 3355a7763bfSjmcp logmsg(MSG_ERROR, 336c4800545Sjmcp gettext("%s: identification function unable " 337c4800545Sjmcp "to allocate space for device entry\n"), 338c4800545Sjmcp driver); 339c4800545Sjmcp free(devpath); 340f1c23465SJames C. McPherson return (FWFLASH_FAILURE); 3415a7763bfSjmcp } 3425a7763bfSjmcp 343c4800545Sjmcp /* calloc enough for /devices + devpath + devsuffix + '\0' */ 3445a7763bfSjmcp devlength = strlen(devpath) + strlen(devprefix) + 3455a7763bfSjmcp strlen(devsuffix) + 2; 3465a7763bfSjmcp 3475a7763bfSjmcp if ((newdev->access_devname = calloc(1, devlength)) == NULL) { 348c4800545Sjmcp logmsg(MSG_ERROR, 349c4800545Sjmcp gettext("%s: Unable to allocate " 350c4800545Sjmcp "space for a devfs name\n"), 351c4800545Sjmcp driver); 3525a7763bfSjmcp free(devpath); 353c4800545Sjmcp free(newdev); 3545a7763bfSjmcp return (FWFLASH_FAILURE); 3555a7763bfSjmcp } 3565a7763bfSjmcp snprintf(newdev->access_devname, devlength, 3575a7763bfSjmcp "%s%s%s", devprefix, devpath, devsuffix); 3585a7763bfSjmcp 359c4800545Sjmcp if ((newdev->drvname = calloc(1, strlen(driver) + 1)) 3605a7763bfSjmcp == NULL) { 361c4800545Sjmcp logmsg(MSG_ERROR, 362c4800545Sjmcp gettext("%s: Unable to allocate " 363c4800545Sjmcp "space to store a driver name\n"), 364c4800545Sjmcp driver); 3655a7763bfSjmcp free(newdev->access_devname); 3665a7763bfSjmcp free(newdev); 367c4800545Sjmcp free(devpath); 3685a7763bfSjmcp return (FWFLASH_FAILURE); 3695a7763bfSjmcp } 370c4800545Sjmcp (void) strlcpy(newdev->drvname, driver, 371c4800545Sjmcp strlen(driver) + 1); 3725a7763bfSjmcp 373c4800545Sjmcp if ((newdev->classname = calloc(1, strlen(driver) + 1)) 3745a7763bfSjmcp == NULL) { 375c4800545Sjmcp logmsg(MSG_ERROR, 376c4800545Sjmcp gettext("%s: Unable to malloc " 377c4800545Sjmcp "space for a class name\n"), 378c4800545Sjmcp drivername); 3795a7763bfSjmcp free(newdev->access_devname); 3805a7763bfSjmcp free(newdev->drvname); 3815a7763bfSjmcp free(newdev); 382c4800545Sjmcp free(devpath); 3835a7763bfSjmcp return (FWFLASH_FAILURE); 3845a7763bfSjmcp } 385c4800545Sjmcp (void) strlcpy(newdev->classname, driver, 386c4800545Sjmcp strlen(driver) + 1); 3875a7763bfSjmcp 3885a7763bfSjmcp /* 389c4800545Sjmcp * Only alloc as much as we truly need, and DON'T forget 390c4800545Sjmcp * that libnvpair manages the memory for property lookups! 391c4800545Sjmcp * The same goes for libdevinfo properties. 392c4800545Sjmcp * 393c4800545Sjmcp * Also note that we're allocating here before we try to 394c4800545Sjmcp * ses_open() the target, because if we can't allocate 395c4800545Sjmcp * sufficient space then we might as well go home. 3965a7763bfSjmcp */ 397c4800545Sjmcp newdev->ident = calloc(1, VIDLEN + PIDLEN + REVLEN + 3); 398d73e86dbSsuha if (newdev->ident == NULL) { 399c4800545Sjmcp logmsg(MSG_ERROR, 400c4800545Sjmcp gettext("%s: Unable to malloc space for" 401c4800545Sjmcp "SCSI INQUIRY data\n"), driver); 402c4800545Sjmcp free(newdev->classname); 403c4800545Sjmcp free(newdev->drvname); 404c4800545Sjmcp free(newdev->access_devname); 405c4800545Sjmcp free(newdev); 406c4800545Sjmcp free(devpath); 407c4800545Sjmcp return (FWFLASH_FAILURE); 408c4800545Sjmcp } 409c4800545Sjmcp 410c4800545Sjmcp if ((ses_target = 411c4800545Sjmcp ses_open(LIBSES_VERSION, newdev->access_devname)) 412c4800545Sjmcp == NULL) { 4135a7763bfSjmcp logmsg(MSG_INFO, 414c4800545Sjmcp gettext("%s: Unable to open device %s\n"), 415c4800545Sjmcp driver, newdev->access_devname); 416c4800545Sjmcp free(newdev->ident); 417c4800545Sjmcp free(newdev->classname); 4185a7763bfSjmcp free(newdev->access_devname); 4195a7763bfSjmcp free(newdev->drvname); 4205a7763bfSjmcp free(newdev); 421c4800545Sjmcp free(devpath); 4225a7763bfSjmcp continue; 4235a7763bfSjmcp } 424c4800545Sjmcp snapshot = ses_snap_hold(ses_target); 425c4800545Sjmcp rootnodep = ses_root_node(snapshot); 4265a7763bfSjmcp 4275a7763bfSjmcp /* 428c4800545Sjmcp * If the node has no properties, or the INQUIRY properties 429c4800545Sjmcp * don't exist, this device does not comply with SES2 so we 430c4800545Sjmcp * won't touch it. 4315a7763bfSjmcp */ 432c4800545Sjmcp if ((props = ses_node_props(rootnodep)) == NULL) { 433c4800545Sjmcp free(newdev->ident); 434c4800545Sjmcp ses_snap_rele(snapshot); 435c4800545Sjmcp ses_close(ses_target); 436c4800545Sjmcp free(newdev->classname); 437c4800545Sjmcp free(newdev->access_devname); 438c4800545Sjmcp free(newdev->drvname); 439c4800545Sjmcp free(newdev); 440c4800545Sjmcp free(devpath); 441c4800545Sjmcp continue; 442c4800545Sjmcp } 443c4800545Sjmcp 444c4800545Sjmcp if ((nvlist_lookup_string(props, SCSI_PROP_VENDOR, 445c4800545Sjmcp &newdev->ident->vid) != 0) || 446c4800545Sjmcp (nvlist_lookup_string(props, SCSI_PROP_PRODUCT, 447c4800545Sjmcp &newdev->ident->pid) != 0) || 448c4800545Sjmcp (nvlist_lookup_string(props, SCSI_PROP_REVISION, 449c4800545Sjmcp &newdev->ident->revid) != 0)) { 450c4800545Sjmcp free(newdev->ident); 451c4800545Sjmcp ses_snap_rele(snapshot); 452c4800545Sjmcp ses_close(ses_target); 453c4800545Sjmcp free(newdev->classname); 4545a7763bfSjmcp free(newdev->access_devname); 4555a7763bfSjmcp free(newdev->drvname); 456c4800545Sjmcp free(newdev); 457c4800545Sjmcp free(devpath); 458c4800545Sjmcp continue; 459c4800545Sjmcp } 460c4800545Sjmcp 461c4800545Sjmcp nodep = ses_snap_primary_enclosure(snapshot); 462c4800545Sjmcp 463c4800545Sjmcp if ((props = ses_node_props(nodep)) == NULL) { 464c4800545Sjmcp free(newdev->ident); 465c4800545Sjmcp ses_snap_rele(snapshot); 466c4800545Sjmcp ses_close(ses_target); 4675a7763bfSjmcp free(newdev->classname); 468c4800545Sjmcp free(newdev->access_devname); 469c4800545Sjmcp free(newdev->drvname); 4705a7763bfSjmcp free(newdev); 471c4800545Sjmcp free(devpath); 4725a7763bfSjmcp continue; 473c4800545Sjmcp } 474c4800545Sjmcp 475c4800545Sjmcp logmsg(MSG_INFO, 476c4800545Sjmcp "\nvid: %s\npid: %s\nrevid: %s\n", 477c4800545Sjmcp newdev->ident->vid, 478c4800545Sjmcp newdev->ident->pid, 479c4800545Sjmcp newdev->ident->revid); 480c4800545Sjmcp 481c4800545Sjmcp if (nvlist_lookup_string(props, LIBSES_EN_PROP_CSN, 482c4800545Sjmcp &newdev->addresses[0]) == 0) { 483c4800545Sjmcp logmsg(MSG_INFO, 484c4800545Sjmcp "Chassis Serial Number: %s\n", 485c4800545Sjmcp newdev->addresses[0]); 4860f59e5a7Speihong huang } else 4870f59e5a7Speihong huang logmsg(MSG_INFO, 4880f59e5a7Speihong huang "%s: no chassis-serial-number property " 4890f59e5a7Speihong huang "for device %s\n", 4900f59e5a7Speihong huang driver, newdev->access_devname); 4915a7763bfSjmcp 4925a7763bfSjmcp 493f1c23465SJames C. McPherson rv = di_prop_lookup_strings(DDI_DEV_T_ANY, 494f1c23465SJames C. McPherson thisnode, "target-port", &newdev->addresses[1]); 495f1c23465SJames C. McPherson if (rv < 0) { 496c4800545Sjmcp logmsg(MSG_INFO, 497c4800545Sjmcp "%s: no target-port property " 498c4800545Sjmcp "for device %s\n", 499c4800545Sjmcp driver, newdev->access_devname); 500c4800545Sjmcp } else 501c4800545Sjmcp logmsg(MSG_INFO, 502c4800545Sjmcp "target-port property: %s\n", 503c4800545Sjmcp newdev->addresses[1]); 504c4800545Sjmcp 505c4800545Sjmcp 5065a7763bfSjmcp newdev->index = idx; 5075a7763bfSjmcp ++idx; 5085a7763bfSjmcp newdev->plugin = self; 5095a7763bfSjmcp 510c4800545Sjmcp ses_snap_rele(snapshot); 5115a7763bfSjmcp TAILQ_INSERT_TAIL(fw_devices, newdev, nextdev); 5125a7763bfSjmcp } 5135a7763bfSjmcp 5145a7763bfSjmcp 5155a7763bfSjmcp if (fwflash_debug != 0) { 5165a7763bfSjmcp struct devicelist *tempdev; 5175a7763bfSjmcp 5185a7763bfSjmcp TAILQ_FOREACH(tempdev, fw_devices, nextdev) { 519c4800545Sjmcp logmsg(MSG_INFO, "%s:fw_identify:\n", 520c4800545Sjmcp driver); 521c4800545Sjmcp logmsg(MSG_INFO, 522c4800545Sjmcp "\ttempdev @ 0x%lx\n" 5235a7763bfSjmcp "\t\taccess_devname: %s\n" 5245a7763bfSjmcp "\t\tdrvname: %s\tclassname: %s\n" 5255a7763bfSjmcp "\t\tident->vid: %s\n" 5265a7763bfSjmcp "\t\tident->pid: %s\n" 5275a7763bfSjmcp "\t\tident->revid: %s\n" 5285a7763bfSjmcp "\t\tindex: %d\n" 5295a7763bfSjmcp "\t\taddress[0]: %s\n" 5305a7763bfSjmcp "\t\taddress[1]: %s\n" 5315a7763bfSjmcp "\t\tplugin @ 0x%lx\n\n", 5325a7763bfSjmcp &tempdev, 5335a7763bfSjmcp tempdev->access_devname, 5345a7763bfSjmcp tempdev->drvname, newdev->classname, 5355a7763bfSjmcp tempdev->ident->vid, 5365a7763bfSjmcp tempdev->ident->pid, 5375a7763bfSjmcp tempdev->ident->revid, 5385a7763bfSjmcp tempdev->index, 5390f59e5a7Speihong huang (tempdev->addresses[0] ? tempdev->addresses[0] : 5400f59e5a7Speihong huang "(not supported)"), 5410f59e5a7Speihong huang (tempdev->addresses[1] ? tempdev->addresses[1] : 5420f59e5a7Speihong huang "(not supported)"), 543c4800545Sjmcp &tempdev->plugin); 5445a7763bfSjmcp } 5455a7763bfSjmcp } 5465a7763bfSjmcp 5475a7763bfSjmcp return (FWFLASH_SUCCESS); 5485a7763bfSjmcp } 5495a7763bfSjmcp 5505a7763bfSjmcp 5515a7763bfSjmcp 5525a7763bfSjmcp int 5535a7763bfSjmcp fw_devinfo(struct devicelist *thisdev) 5545a7763bfSjmcp { 5555a7763bfSjmcp 5565a7763bfSjmcp fprintf(stdout, gettext("Device[%d] %s\n Class [%s]\n"), 5575a7763bfSjmcp thisdev->index, thisdev->access_devname, thisdev->classname); 5585a7763bfSjmcp 5595a7763bfSjmcp fprintf(stdout, 5605a7763bfSjmcp gettext("\tVendor : %s\n" 5615a7763bfSjmcp "\tProduct : %s\n" 5625a7763bfSjmcp "\tFirmware revision : %s\n" 563c4800545Sjmcp "\tChassis Serial Number : %s\n" 5645a7763bfSjmcp "\tTarget-port identifier : %s\n"), 5655a7763bfSjmcp thisdev->ident->vid, 5665a7763bfSjmcp thisdev->ident->pid, 5675a7763bfSjmcp thisdev->ident->revid, 5680f59e5a7Speihong huang (thisdev->addresses[0] ? thisdev->addresses[0] : 5690f59e5a7Speihong huang "(not supported)"), 5700f59e5a7Speihong huang (thisdev->addresses[1] ? thisdev->addresses[1] : 5710f59e5a7Speihong huang "(not supported)")); 5725a7763bfSjmcp 5735a7763bfSjmcp fprintf(stdout, "\n\n"); 5745a7763bfSjmcp 5755a7763bfSjmcp return (FWFLASH_SUCCESS); 5765a7763bfSjmcp } 5775a7763bfSjmcp 5785a7763bfSjmcp 5795a7763bfSjmcp 5805a7763bfSjmcp 5815a7763bfSjmcp 5825a7763bfSjmcp /*ARGSUSED*/ 5835a7763bfSjmcp static int 5845a7763bfSjmcp get_status(nvlist_t *props, ucode_status_t *sp) 5855a7763bfSjmcp { 5865a7763bfSjmcp int i; 5875a7763bfSjmcp uint64_t status, astatus; 5885a7763bfSjmcp 5895a7763bfSjmcp if (nvlist_lookup_uint64(props, SES_EN_PROP_UCODE, &status) != 0) { 5905a7763bfSjmcp sp->us_status = -1ULL; 5915a7763bfSjmcp (void) snprintf(sp->us_desc, sizeof (sp->us_desc), 5925a7763bfSjmcp "not supported"); 593*d65b419eSXinChen return (FWFLASH_FAILURE); 5945a7763bfSjmcp } 5955a7763bfSjmcp 596c4800545Sjmcp if (nvlist_lookup_uint64(props, SES_EN_PROP_UCODE_A, 597c4800545Sjmcp &astatus) != 0) { 598c4800545Sjmcp logmsg(MSG_ERROR, 599c4800545Sjmcp gettext("\nError: Unable to retrieve current status\n")); 600*d65b419eSXinChen return (FWFLASH_FAILURE); 601c4800545Sjmcp } 6025a7763bfSjmcp 6035a7763bfSjmcp for (i = 0; i < NUCODE_STATUS; i++) { 6045a7763bfSjmcp if (ucode_statdesc_table[i].us_value == status) 6055a7763bfSjmcp break; 6065a7763bfSjmcp } 6075a7763bfSjmcp 6085a7763bfSjmcp sp->us_status = status; 6095a7763bfSjmcp 6105a7763bfSjmcp if (i == NUCODE_STATUS) { 6115a7763bfSjmcp (void) snprintf(sp->us_desc, sizeof (sp->us_desc), 6125a7763bfSjmcp "unknown (0x%02x)", (int)status); 613*d65b419eSXinChen sp->us_iserr = sp->us_pending = B_TRUE; 614*d65b419eSXinChen return (FWFLASH_FAILURE); 6155a7763bfSjmcp } else { 6165a7763bfSjmcp /* LINTED */ 6175a7763bfSjmcp (void) snprintf(sp->us_desc, sizeof (sp->us_desc), 6185a7763bfSjmcp ucode_statdesc_table[i].us_desc, (int)astatus); 6195a7763bfSjmcp sp->us_iserr = ucode_statdesc_table[i].us_iserr; 6205a7763bfSjmcp sp->us_pending = ucode_statdesc_table[i].us_pending; 6215a7763bfSjmcp } 6225a7763bfSjmcp 623*d65b419eSXinChen return (FWFLASH_SUCCESS); 6245a7763bfSjmcp } 6255a7763bfSjmcp 6265a7763bfSjmcp 627*d65b419eSXinChen static int 6285a7763bfSjmcp print_updated_status(ses_node_t *np, void *arg) 6295a7763bfSjmcp { 6305a7763bfSjmcp ucode_wait_t *uwp = arg; 631c4800545Sjmcp nvlist_t *props; 6325a7763bfSjmcp ucode_status_t status; 6335a7763bfSjmcp 6345a7763bfSjmcp 635c4800545Sjmcp if ((props = ses_node_props(np)) == NULL) { 636*d65b419eSXinChen return (FWFLASH_FAILURE); 637c4800545Sjmcp } 6385a7763bfSjmcp 639*d65b419eSXinChen if (get_status(props, &status) != FWFLASH_SUCCESS) 640*d65b419eSXinChen return (FWFLASH_FAILURE); 6415a7763bfSjmcp 6425a7763bfSjmcp if (status.us_status != uwp->uw_prevstatus) 6435a7763bfSjmcp (void) printf("%30s: %s\n", "status", status.us_desc); 644c4800545Sjmcp 6455a7763bfSjmcp uwp->uw_prevstatus = status.us_status; 6465a7763bfSjmcp uwp->uw_pending = status.us_pending; 6475a7763bfSjmcp 648c4800545Sjmcp if (status.us_iserr) { 6495a7763bfSjmcp logmsg(MSG_INFO, 650c4800545Sjmcp "libses: status.us_iserr: 0x%0x\n", 6515a7763bfSjmcp status.us_iserr); 652*d65b419eSXinChen return (FWFLASH_FAILURE); 653*d65b419eSXinChen } 654*d65b419eSXinChen return (FWFLASH_SUCCESS); 6555a7763bfSjmcp } 6565a7763bfSjmcp 6575a7763bfSjmcp /*ARGSUSED*/ 658c4800545Sjmcp static int 6595a7763bfSjmcp sendimg(ses_node_t *np, void *data) 6605a7763bfSjmcp { 6615a7763bfSjmcp nvlist_t *props; 6625a7763bfSjmcp nvlist_t *arg = data; 6635a7763bfSjmcp char *vendor, *product, *revision, *csn; 6645a7763bfSjmcp char buf[128]; 6655a7763bfSjmcp ses_snap_t *newsnap; 6665a7763bfSjmcp int ret; 6675a7763bfSjmcp ucode_status_t statdesc; 6685a7763bfSjmcp ucode_wait_t wait; 6695a7763bfSjmcp uint8_t *imagedata; 670c4800545Sjmcp uint_t len; 6715a7763bfSjmcp 6725a7763bfSjmcp 673c4800545Sjmcp /* If we've been called without data, eject */ 674c4800545Sjmcp if (nvlist_lookup_byte_array(arg, SES_CTL_PROP_UCODE_DATA, 675c4800545Sjmcp &imagedata, &len) != 0) { 676c4800545Sjmcp return (FWFLASH_FAILURE); 677c4800545Sjmcp } 6785a7763bfSjmcp 679c4800545Sjmcp props = ses_node_props(np); 680c4800545Sjmcp if ((props == NULL) || 681c4800545Sjmcp (nvlist_lookup_string(props, SES_EN_PROP_VID, &vendor) != 0) || 682c4800545Sjmcp (nvlist_lookup_string(props, SES_EN_PROP_PID, &product) != 0) || 683c4800545Sjmcp (nvlist_lookup_string(props, SES_EN_PROP_REV, &revision) != 0) || 684c4800545Sjmcp (nvlist_lookup_string(props, LIBSES_EN_PROP_CSN, &csn) != 0)) { 685c4800545Sjmcp return (FWFLASH_FAILURE); 686c4800545Sjmcp } 6875a7763bfSjmcp 6885a7763bfSjmcp (void) printf("%30s: %s\n", "vendor", vendor); 6895a7763bfSjmcp (void) printf("%30s: %s\n", "product", product); 6905a7763bfSjmcp (void) printf("%30s: %s\n", "revision", revision); 6915a7763bfSjmcp (void) printf("%30s: %s\n", "serial", csn); 6925a7763bfSjmcp 6935a7763bfSjmcp ret = get_status(props, &statdesc); 6945a7763bfSjmcp (void) printf("%30s: %s\n", "current status", statdesc.us_desc); 695*d65b419eSXinChen if (ret != FWFLASH_SUCCESS) { 696c4800545Sjmcp return (FWFLASH_FAILURE); 6975a7763bfSjmcp } 6985a7763bfSjmcp 6995a7763bfSjmcp (void) snprintf(buf, sizeof (buf), "downloading %u bytes", len); 7005a7763bfSjmcp (void) printf("\n%30s: ", buf); 701c4800545Sjmcp 702c4800545Sjmcp /* 703c4800545Sjmcp * If the bufferid isn't 2, then the verifier has already 70487d06e46Speihong huang * OK'd the image that the user has provided. 705c4800545Sjmcp * 706c4800545Sjmcp * At present the non-"standard" images need to be flashed 707c4800545Sjmcp * using the scsi WRITE BUFFER command 708c4800545Sjmcp */ 709c4800545Sjmcp if (verifier->flashbuf != 2) 710c4800545Sjmcp return (scsi_writebuf()); 711c4800545Sjmcp 712c4800545Sjmcp 713*d65b419eSXinChen if (ses_node_ctl(np, SES_CTL_OP_DL_UCODE, arg) != FWFLASH_SUCCESS) { 7145a7763bfSjmcp (void) printf("failed!\n"); 7155a7763bfSjmcp (void) printf("%s\n", ses_errmsg()); 716c4800545Sjmcp return (FWFLASH_FAILURE); 7175a7763bfSjmcp } else { 7185a7763bfSjmcp (void) printf("ok\n"); 7195a7763bfSjmcp } 7205a7763bfSjmcp 7215a7763bfSjmcp wait.uw_prevstatus = -1ULL; 7225a7763bfSjmcp wait.uw_oldnp = np; 7235a7763bfSjmcp 724*d65b419eSXinChen if ((newsnap = ses_snap_new(ses_target)) == NULL) { 725d73e86dbSsuha logmsg(MSG_ERROR, 726c4800545Sjmcp "failed to update SES snapshot: %s", 727c4800545Sjmcp ses_errmsg()); 728*d65b419eSXinChen return (FWFLASH_FAILURE); 729*d65b419eSXinChen } 730d73e86dbSsuha 731c4800545Sjmcp print_updated_status(ses_snap_primary_enclosure(newsnap), 732c4800545Sjmcp &wait); 733c4800545Sjmcp ses_snap_rele(newsnap); 734d73e86dbSsuha 735*d65b419eSXinChen return (FWFLASH_SUCCESS); 736d73e86dbSsuha } 737d73e86dbSsuha 738c4800545Sjmcp static int 739c4800545Sjmcp scsi_writebuf() 7405a7763bfSjmcp { 741c4800545Sjmcp int ret; 742d73e86dbSsuha int i = 0; 743c4800545Sjmcp libscsi_action_t *action; 744c4800545Sjmcp spc3_write_buffer_cdb_t *wb_cdb; 745c4800545Sjmcp libscsi_hdl_t *handle; 746c4800545Sjmcp libscsi_target_t *target; 747c4800545Sjmcp sam4_status_t samstatus; 748d73e86dbSsuha 749d73e86dbSsuha 750c4800545Sjmcp target = ses_scsi_target(ses_target); 751c4800545Sjmcp handle = libscsi_get_handle(target); 752c4800545Sjmcp action = libscsi_action_alloc(handle, SPC3_CMD_WRITE_BUFFER, 753c4800545Sjmcp LIBSCSI_AF_WRITE|LIBSCSI_AF_RQSENSE, 754c4800545Sjmcp (void *)verifier->fwimage, (size_t)verifier->imgsize); 755d73e86dbSsuha 756c4800545Sjmcp wb_cdb = (spc3_write_buffer_cdb_t *)libscsi_action_get_cdb(action); 757*d65b419eSXinChen 758c4800545Sjmcp wb_cdb->wbc_mode = SPC3_WB_MODE_DATA; 759c4800545Sjmcp wb_cdb->wbc_bufferid = verifier->flashbuf; 760*d65b419eSXinChen 761*d65b419eSXinChen wb_cdb->wbc_buffer_offset[0] = 0; 762*d65b419eSXinChen wb_cdb->wbc_buffer_offset[1] = 0; 763*d65b419eSXinChen wb_cdb->wbc_buffer_offset[2] = 0; 764*d65b419eSXinChen 765*d65b419eSXinChen wb_cdb->wbc_parameter_list_len[0] = 766*d65b419eSXinChen (verifier->imgsize & 0xff0000) >> 16; 767*d65b419eSXinChen wb_cdb->wbc_parameter_list_len[1] = (verifier->imgsize & 0xff00) >> 8; 768*d65b419eSXinChen wb_cdb->wbc_parameter_list_len[2] = (verifier->imgsize & 0xff); 769d73e86dbSsuha 770c4800545Sjmcp ret = libscsi_exec(action, target); 771c4800545Sjmcp samstatus = libscsi_action_get_status(action); 772d73e86dbSsuha 773c4800545Sjmcp logmsg(MSG_INFO, 774c4800545Sjmcp "\nscsi_writebuffer: ret 0x%0x, samstatus 0x%0x\n", 775c4800545Sjmcp ret, samstatus); 776d73e86dbSsuha 777*d65b419eSXinChen if ((ret != FWFLASH_SUCCESS) || samstatus != SAM4_STATUS_GOOD) { 778c4800545Sjmcp libscsi_action_free(action); 779*d65b419eSXinChen return (FWFLASH_FAILURE); 780c4800545Sjmcp } else { 781c4800545Sjmcp (void) printf("ok\n"); 782d73e86dbSsuha } 783d73e86dbSsuha 784c4800545Sjmcp for (i = 0; i < NSAM4_STATUS; i++) { 785c4800545Sjmcp if (sam4_status[i].status == samstatus) { 786c4800545Sjmcp (void) printf("%s\n", (sam4_status[i].message)); 787c4800545Sjmcp break; 788d73e86dbSsuha } 789d73e86dbSsuha } 790d73e86dbSsuha 791c4800545Sjmcp if (i == NSAM4_STATUS) 792c4800545Sjmcp (void) printf("Status: UNKNOWN\n"); 793c4800545Sjmcp 794c4800545Sjmcp if (samstatus == SAM4_STATUS_GOOD) { 795c4800545Sjmcp return (FWFLASH_SUCCESS); 796c4800545Sjmcp } 797c4800545Sjmcp 798c4800545Sjmcp return (FWFLASH_FAILURE); 7995a7763bfSjmcp } 800