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 /*
228920SPei-Hong.Huang@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
236489Sjmcp * Use is subject to license terms.
246489Sjmcp */
256489Sjmcp
266489Sjmcp /*
276489Sjmcp * ses (SCSI Generic Device) specific functions.
286489Sjmcp */
296489Sjmcp
306489Sjmcp #include <libnvpair.h>
316489Sjmcp #include <stdio.h>
326489Sjmcp #include <stdlib.h>
336489Sjmcp #include <unistd.h>
346489Sjmcp #include <sys/types.h>
356489Sjmcp #include <sys/sysmacros.h>
366489Sjmcp #include <sys/queue.h>
376489Sjmcp #include <fcntl.h>
386489Sjmcp #include <string.h>
396846Sjmcp #include <scsi/libscsi.h>
406489Sjmcp #include <scsi/libses.h>
416489Sjmcp #include <libintl.h> /* for gettext(3c) */
426489Sjmcp #include <fwflash/fwflash.h>
436489Sjmcp
446489Sjmcp
456489Sjmcp #define VIDLEN 0x08
466489Sjmcp #define PIDLEN 0x10
476489Sjmcp #define REVLEN 0x04
486489Sjmcp #define SASADDRLEN 0x10
496489Sjmcp #define PCBUFLEN 0x40
506489Sjmcp #define RQBUFLEN 0xfe
516489Sjmcp #define STATBUFLEN 0xfe
526489Sjmcp #define INQBUFLEN 0x80
536489Sjmcp
546489Sjmcp /* useful defines */
556489Sjmcp #define UCODE_CHECK_STATUS 0
566489Sjmcp #define UCODE_CHECK_SUPPORTED 1
576489Sjmcp
586489Sjmcp typedef struct ucode_statdesc {
596489Sjmcp uint64_t us_value;
606489Sjmcp const char *us_desc;
616489Sjmcp boolean_t us_pending;
626489Sjmcp boolean_t us_iserr;
636489Sjmcp } ucode_statdesc_t;
646489Sjmcp
656489Sjmcp static ucode_statdesc_t ucode_statdesc_table[] = {
666489Sjmcp { SES2_DLUCODE_S_NOP, "none", B_FALSE, B_FALSE },
676489Sjmcp { SES2_DLUCODE_S_INPROGRESS, "in progress", B_TRUE, B_FALSE },
686489Sjmcp { SES2_DLUCODE_S_SAVING, "saved", B_TRUE, B_FALSE },
696489Sjmcp { SES2_DLUCODE_S_COMPLETE_NOW, "completed (available)", B_FALSE,
706489Sjmcp B_FALSE },
716489Sjmcp { SES2_DLUCODE_S_COMPLETE_AT_RESET,
726489Sjmcp "completed (need reset or power on)", B_FALSE, B_FALSE },
736489Sjmcp { SES2_DLUCODE_S_COMPLETE_AT_POWERON, "completed (need power on)",
746489Sjmcp B_FALSE, B_FALSE },
756489Sjmcp { SES2_DLUCODE_S_PAGE_ERR, "page error (offset %d)",
766489Sjmcp B_FALSE, B_TRUE },
776489Sjmcp { SES2_DLUCODE_S_IMAGE_ERR, "invalid image",
786489Sjmcp B_FALSE, B_TRUE },
796489Sjmcp { SES2_DLUCODE_S_TIMEOUT, "download timeout",
806489Sjmcp B_FALSE, B_TRUE },
816489Sjmcp { SES2_DLUCODE_S_INTERNAL_NEEDIMAGE,
826489Sjmcp "internal error (NEED NEW IMAGE BEFORE RESET)",
836489Sjmcp B_FALSE, B_TRUE },
846489Sjmcp { SES2_DLUCODE_S_INTERNAL_SAFE,
856489Sjmcp "internal error (reset to revert to backup)",
866489Sjmcp B_FALSE, B_TRUE },
876489Sjmcp };
886489Sjmcp
896489Sjmcp #define NUCODE_STATUS \
906489Sjmcp (sizeof (ucode_statdesc_table) / sizeof (ucode_statdesc_table[0]))
916489Sjmcp
926489Sjmcp typedef struct ucode_status {
936489Sjmcp uint64_t us_status;
946489Sjmcp boolean_t us_iserr;
956489Sjmcp boolean_t us_pending;
966489Sjmcp char us_desc[128];
976489Sjmcp } ucode_status_t;
986489Sjmcp
996489Sjmcp typedef struct ucode_wait {
1006489Sjmcp uint64_t uw_prevstatus;
1016489Sjmcp boolean_t uw_pending;
1026489Sjmcp ses_node_t *uw_oldnp;
1036489Sjmcp } ucode_wait_t;
1046489Sjmcp
1056489Sjmcp
1066846Sjmcp typedef struct sam4_statdesc {
1076846Sjmcp int status;
1086846Sjmcp char *message;
1096846Sjmcp } sam4_statdesc_t;
1106846Sjmcp
1116846Sjmcp
1126846Sjmcp static sam4_statdesc_t sam4_status[] = {
1136846Sjmcp { SAM4_STATUS_GOOD, "Status: GOOD (success)" },
1146846Sjmcp { SAM4_STATUS_CHECK_CONDITION, "Status: CHECK CONDITION" },
1156846Sjmcp { SAM4_STATUS_CONDITION_MET, "Status: CONDITION MET" },
1166846Sjmcp { SAM4_STATUS_BUSY, "Status: Device is BUSY" },
1176846Sjmcp { SAM4_STATUS_RESERVATION_CONFLICT, "Status: Device is RESERVED" },
1186846Sjmcp { SAM4_STATUS_TASK_SET_FULL,
1196846Sjmcp "Status: TASK SET FULL (insufficient resources in command queue" },
1206846Sjmcp { SAM4_STATUS_TASK_ABORTED, "Status: TASK ABORTED" },
1216846Sjmcp { NULL, NULL }
1226846Sjmcp };
1236846Sjmcp
1246846Sjmcp #define NSAM4_STATUS \
1256846Sjmcp (sizeof (sam4_status) / sizeof (sam4_status[0]))
1266846Sjmcp
1276846Sjmcp
1286846Sjmcp
1296489Sjmcp char drivername[] = "ses\0";
1306489Sjmcp static char *devprefix = "/devices";
1316846Sjmcp static char *sessuffix = ":0";
1326846Sjmcp static char *sgensuffix = ":ses";
1336846Sjmcp
1346846Sjmcp
1356736Ssuha static ses_target_t *ses_target;
1366708Sjmcp
1376489Sjmcp extern di_node_t rootnode;
1386489Sjmcp extern int errno;
1396489Sjmcp extern struct fw_plugin *self;
1406489Sjmcp extern struct vrfyplugin *verifier;
1416489Sjmcp extern int fwflash_debug;
1426489Sjmcp
1436489Sjmcp
1446489Sjmcp /* required functions for this plugin */
1456489Sjmcp int fw_readfw(struct devicelist *device, char *filename);
1466489Sjmcp int fw_writefw(struct devicelist *device);
1476489Sjmcp int fw_identify(int start);
1486489Sjmcp int fw_devinfo(struct devicelist *thisdev);
1496489Sjmcp
1506489Sjmcp
1516489Sjmcp /* helper functions */
152*9683SXin.Chen@Sun.COM static int print_updated_status(ses_node_t *np, void *arg);
1536489Sjmcp static int get_status(nvlist_t *props, ucode_status_t *sp);
1546846Sjmcp static int sendimg(ses_node_t *np, void *data);
1556846Sjmcp static int scsi_writebuf();
1566489Sjmcp
1576489Sjmcp /*
1586846Sjmcp * We don't currently support reading firmware from a SAS
1596846Sjmcp * expander. If we do eventually support it, we would use
1606846Sjmcp * the scsi READ BUFFER command to do so.
1616489Sjmcp */
1626489Sjmcp int
fw_readfw(struct devicelist * flashdev,char * filename)1636489Sjmcp fw_readfw(struct devicelist *flashdev, char *filename)
1646489Sjmcp {
1656489Sjmcp
1666489Sjmcp logmsg(MSG_INFO,
1676846Sjmcp "%s: not writing firmware for device %s to file %s\n",
1686846Sjmcp flashdev->drvname, flashdev->access_devname, filename);
1696846Sjmcp logmsg(MSG_ERROR,
1706846Sjmcp gettext("\n\nReading of firmware images from %s-attached "
1716846Sjmcp "devices is not supported\n\n"),
1726846Sjmcp flashdev->drvname);
1736489Sjmcp
1746846Sjmcp return (FWFLASH_SUCCESS);
1756489Sjmcp }
1766489Sjmcp
1776489Sjmcp
1786489Sjmcp /*
1796489Sjmcp * If we're invoking fw_writefw, then flashdev is a valid,
1806489Sjmcp * flashable device supporting the SES2 Download Microcode Diagnostic
1816489Sjmcp * Control page (0x0e).
1826489Sjmcp *
1836489Sjmcp * If verifier is null, then we haven't been called following a firmware
1846489Sjmcp * image verification load operation.
1856489Sjmcp *
1866489Sjmcp * *THIS* function uses scsi SEND DIAGNOSTIC/download microcode to
1876489Sjmcp * achieve the task... if you chase down to the bottom of libses you
1886489Sjmcp * can see that too.
1896489Sjmcp */
1906489Sjmcp int
fw_writefw(struct devicelist * flashdev)1916489Sjmcp fw_writefw(struct devicelist *flashdev)
1926489Sjmcp {
193*9683SXin.Chen@Sun.COM int rv = FWFLASH_FAILURE;
1946489Sjmcp nvlist_t *nvl;
1956489Sjmcp ses_snap_t *snapshot;
1966846Sjmcp ses_node_t *targetnode;
1976489Sjmcp
1986846Sjmcp if ((verifier == NULL) || (verifier->imgsize == 0) ||
1996846Sjmcp (verifier->fwimage == NULL)) {
2006846Sjmcp /* should _not_ happen */
2016846Sjmcp logmsg(MSG_ERROR,
2026846Sjmcp gettext("%s: Firmware image has not "
2036846Sjmcp "been verified.\n"),
2046846Sjmcp flashdev->drvname);
2056846Sjmcp return (FWFLASH_FAILURE);
2066846Sjmcp }
2076489Sjmcp
2086489Sjmcp if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
2096489Sjmcp nvlist_add_uint64(nvl, SES_CTL_PROP_UCODE_MODE,
2106489Sjmcp SES_DLUCODE_M_WITH_OFFS) != 0) {
2116846Sjmcp logmsg(MSG_ERROR,
2126846Sjmcp gettext("%s: Unable to allocate "
2136846Sjmcp "space for device prop list\n"),
2146846Sjmcp flashdev->drvname);
2156489Sjmcp return (FWFLASH_FAILURE);
2166489Sjmcp }
2176489Sjmcp
2186489Sjmcp fprintf(stdout, "\n"); /* get a fresh line for progress updates */
2196489Sjmcp
2206489Sjmcp if (nvlist_add_uint64(nvl, SES_CTL_PROP_UCODE_BUFID,
2216489Sjmcp verifier->flashbuf) != 0) {
2226846Sjmcp logmsg(MSG_ERROR,
2236846Sjmcp gettext("%s: Unable to add buffer id "
2246846Sjmcp "property, hence unable to flash device\n"),
2256846Sjmcp flashdev->drvname);
2266489Sjmcp goto cancel;
2276489Sjmcp }
2286489Sjmcp
2296489Sjmcp if (nvlist_add_byte_array(nvl, SES_CTL_PROP_UCODE_DATA,
2306489Sjmcp (uint8_t *)verifier->fwimage, verifier->imgsize) != 0) {
2316489Sjmcp logmsg(MSG_ERROR,
2326489Sjmcp "%s: Out of memory for property addition\n",
2336846Sjmcp flashdev->drvname);
2346489Sjmcp goto cancel;
2356489Sjmcp }
2366489Sjmcp
2376489Sjmcp if ((ses_target =
2386489Sjmcp ses_open(LIBSES_VERSION, flashdev->access_devname)) == NULL) {
2396489Sjmcp logmsg(MSG_ERROR,
2406846Sjmcp gettext("%s: Unable to open flashable device %s\n"),
2416846Sjmcp flashdev->drvname, flashdev->access_devname);
2426489Sjmcp goto cancel;
2436489Sjmcp }
2446846Sjmcp
2456489Sjmcp snapshot = ses_snap_hold(ses_target);
2466489Sjmcp
2476846Sjmcp if ((targetnode = ses_snap_primary_enclosure(snapshot)) == NULL) {
2486846Sjmcp logmsg(MSG_ERROR,
2496846Sjmcp gettext("%s: Unable to locate primary enclosure for "
2506846Sjmcp "device %s\n"),
2516846Sjmcp flashdev->access_devname);
2526846Sjmcp } else {
2536846Sjmcp rv = sendimg(targetnode, nvl);
2546846Sjmcp if (rv == FWFLASH_SUCCESS) {
2556846Sjmcp logmsg(MSG_ERROR,
2566846Sjmcp gettext("%s: Done. New image will be active "
2576846Sjmcp "after the system is rebooted.\n\n"),
2586846Sjmcp flashdev->drvname);
2596846Sjmcp } else {
2606846Sjmcp logmsg(MSG_INFO,
2616846Sjmcp "%s: unable to flash image %s to device %s\n\n",
2626846Sjmcp flashdev->drvname, verifier->imgfile,
2636846Sjmcp flashdev->access_devname);
2646846Sjmcp }
2656846Sjmcp }
2666489Sjmcp
2676489Sjmcp ses_snap_rele(snapshot);
2686489Sjmcp ses_close(ses_target);
2696489Sjmcp cancel:
2706489Sjmcp nvlist_free(nvl);
2716489Sjmcp
272*9683SXin.Chen@Sun.COM return (rv);
2736489Sjmcp }
2746489Sjmcp
2756489Sjmcp
2766489Sjmcp /*
2776489Sjmcp * The fw_identify() function walks the device
2786489Sjmcp * tree trying to find devices which this plugin
2796489Sjmcp * can work with.
2806489Sjmcp *
2816489Sjmcp * The parameter "start" gives us the starting index number
2826489Sjmcp * to give the device when we add it to the fw_devices list.
2836489Sjmcp *
2846489Sjmcp * firstdev is allocated by us and we add space as needed
2856489Sjmcp */
2866489Sjmcp int
fw_identify(int start)2876489Sjmcp fw_identify(int start)
2886489Sjmcp {
2896489Sjmcp
2906489Sjmcp int rv = FWFLASH_FAILURE;
2916489Sjmcp di_node_t thisnode;
2926489Sjmcp struct devicelist *newdev;
2936489Sjmcp char *devpath;
2946846Sjmcp char *devsuffix;
2956846Sjmcp char *driver;
2966489Sjmcp int idx = start;
2977317SJames.McPherson@Sun.COM size_t devlength = 0;
2986846Sjmcp nvlist_t *props;
2996846Sjmcp ses_snap_t *snapshot;
3006846Sjmcp ses_node_t *rootnodep, *nodep;
3016489Sjmcp
3026489Sjmcp
3036846Sjmcp if (strcmp(self->drvname, "sgen") == 0) {
3046846Sjmcp devsuffix = sgensuffix;
3056846Sjmcp driver = self->drvname;
3066846Sjmcp } else {
3076846Sjmcp devsuffix = sessuffix;
3086846Sjmcp driver = drivername;
3096846Sjmcp }
3106846Sjmcp
3116846Sjmcp thisnode = di_drv_first_node(driver, rootnode);
3126489Sjmcp
3136489Sjmcp if (thisnode == DI_NODE_NIL) {
3146489Sjmcp logmsg(MSG_INFO, gettext("No %s nodes in this system\n"),
3156846Sjmcp driver);
3167317SJames.McPherson@Sun.COM return (FWFLASH_FAILURE);
3176489Sjmcp }
3186489Sjmcp
3196489Sjmcp if ((devpath = calloc(1, MAXPATHLEN + 1)) == NULL) {
3206846Sjmcp logmsg(MSG_ERROR,
3216846Sjmcp gettext("%s: Unable to allocate space "
3226846Sjmcp "for a device node\n"),
3236846Sjmcp driver);
3247317SJames.McPherson@Sun.COM return (FWFLASH_FAILURE);
3256489Sjmcp }
3266489Sjmcp
3276489Sjmcp /* we've found one, at least */
3286489Sjmcp
3296489Sjmcp for (; thisnode != DI_NODE_NIL; thisnode = di_drv_next_node(thisnode)) {
3306489Sjmcp
3316489Sjmcp devpath = di_devfs_path(thisnode);
3326489Sjmcp
3336489Sjmcp if ((newdev = calloc(1, sizeof (struct devicelist)))
3346489Sjmcp == NULL) {
3356489Sjmcp logmsg(MSG_ERROR,
3366846Sjmcp gettext("%s: identification function unable "
3376846Sjmcp "to allocate space for device entry\n"),
3386846Sjmcp driver);
3396846Sjmcp free(devpath);
3407317SJames.McPherson@Sun.COM return (FWFLASH_FAILURE);
3416489Sjmcp }
3426489Sjmcp
3436846Sjmcp /* calloc enough for /devices + devpath + devsuffix + '\0' */
3446489Sjmcp devlength = strlen(devpath) + strlen(devprefix) +
3456489Sjmcp strlen(devsuffix) + 2;
3466489Sjmcp
3476489Sjmcp if ((newdev->access_devname = calloc(1, devlength)) == NULL) {
3486846Sjmcp logmsg(MSG_ERROR,
3496846Sjmcp gettext("%s: Unable to allocate "
3506846Sjmcp "space for a devfs name\n"),
3516846Sjmcp driver);
3526489Sjmcp free(devpath);
3536846Sjmcp free(newdev);
3546489Sjmcp return (FWFLASH_FAILURE);
3556489Sjmcp }
3566489Sjmcp snprintf(newdev->access_devname, devlength,
3576489Sjmcp "%s%s%s", devprefix, devpath, devsuffix);
3586489Sjmcp
3596846Sjmcp if ((newdev->drvname = calloc(1, strlen(driver) + 1))
3606489Sjmcp == NULL) {
3616846Sjmcp logmsg(MSG_ERROR,
3626846Sjmcp gettext("%s: Unable to allocate "
3636846Sjmcp "space to store a driver name\n"),
3646846Sjmcp driver);
3656489Sjmcp free(newdev->access_devname);
3666489Sjmcp free(newdev);
3676846Sjmcp free(devpath);
3686846Sjmcp return (FWFLASH_FAILURE);
3696846Sjmcp }
3706846Sjmcp (void) strlcpy(newdev->drvname, driver,
3716846Sjmcp strlen(driver) + 1);
3726846Sjmcp
3736846Sjmcp if ((newdev->classname = calloc(1, strlen(driver) + 1))
3746846Sjmcp == NULL) {
3756846Sjmcp logmsg(MSG_ERROR,
3766846Sjmcp gettext("%s: Unable to malloc "
3776846Sjmcp "space for a class name\n"),
3786846Sjmcp drivername);
3796846Sjmcp free(newdev->access_devname);
3806846Sjmcp free(newdev->drvname);
3816846Sjmcp free(newdev);
3826846Sjmcp free(devpath);
3836489Sjmcp return (FWFLASH_FAILURE);
3846489Sjmcp }
3856846Sjmcp (void) strlcpy(newdev->classname, driver,
3866846Sjmcp strlen(driver) + 1);
3876489Sjmcp
3886846Sjmcp /*
3896846Sjmcp * Only alloc as much as we truly need, and DON'T forget
3906846Sjmcp * that libnvpair manages the memory for property lookups!
3916846Sjmcp * The same goes for libdevinfo properties.
3926846Sjmcp *
3936846Sjmcp * Also note that we're allocating here before we try to
3946846Sjmcp * ses_open() the target, because if we can't allocate
3956846Sjmcp * sufficient space then we might as well go home.
3966846Sjmcp */
3976846Sjmcp newdev->ident = calloc(1, VIDLEN + PIDLEN + REVLEN + 3);
3986846Sjmcp if (newdev->ident == NULL) {
3996846Sjmcp logmsg(MSG_ERROR,
4006846Sjmcp gettext("%s: Unable to malloc space for"
4016846Sjmcp "SCSI INQUIRY data\n"), driver);
4026846Sjmcp free(newdev->classname);
4036846Sjmcp free(newdev->drvname);
4046846Sjmcp free(newdev->access_devname);
4056846Sjmcp free(newdev);
4066846Sjmcp free(devpath);
4076846Sjmcp return (FWFLASH_FAILURE);
4086846Sjmcp }
4096846Sjmcp
4106846Sjmcp if ((ses_target =
4116846Sjmcp ses_open(LIBSES_VERSION, newdev->access_devname))
4126489Sjmcp == NULL) {
4136846Sjmcp logmsg(MSG_INFO,
4146846Sjmcp gettext("%s: Unable to open device %s\n"),
4156846Sjmcp driver, newdev->access_devname);
4166846Sjmcp free(newdev->ident);
4176846Sjmcp free(newdev->classname);
4186489Sjmcp free(newdev->access_devname);
4196489Sjmcp free(newdev->drvname);
4206489Sjmcp free(newdev);
4216846Sjmcp free(devpath);
4226846Sjmcp continue;
4236489Sjmcp }
4246846Sjmcp snapshot = ses_snap_hold(ses_target);
4256846Sjmcp rootnodep = ses_root_node(snapshot);
4266489Sjmcp
4276736Ssuha /*
4286846Sjmcp * If the node has no properties, or the INQUIRY properties
4296846Sjmcp * don't exist, this device does not comply with SES2 so we
4306846Sjmcp * won't touch it.
4316736Ssuha */
4326846Sjmcp if ((props = ses_node_props(rootnodep)) == NULL) {
4336846Sjmcp free(newdev->ident);
4346846Sjmcp ses_snap_rele(snapshot);
4356846Sjmcp ses_close(ses_target);
4366846Sjmcp free(newdev->classname);
4376489Sjmcp free(newdev->access_devname);
4386489Sjmcp free(newdev->drvname);
4396846Sjmcp free(newdev);
4406846Sjmcp free(devpath);
4416846Sjmcp continue;
4426846Sjmcp }
4436846Sjmcp
4446846Sjmcp if ((nvlist_lookup_string(props, SCSI_PROP_VENDOR,
4456846Sjmcp &newdev->ident->vid) != 0) ||
4466846Sjmcp (nvlist_lookup_string(props, SCSI_PROP_PRODUCT,
4476846Sjmcp &newdev->ident->pid) != 0) ||
4486846Sjmcp (nvlist_lookup_string(props, SCSI_PROP_REVISION,
4496846Sjmcp &newdev->ident->revid) != 0)) {
4506846Sjmcp free(newdev->ident);
4516846Sjmcp ses_snap_rele(snapshot);
4526846Sjmcp ses_close(ses_target);
4536736Ssuha free(newdev->classname);
4546846Sjmcp free(newdev->access_devname);
4556846Sjmcp free(newdev->drvname);
4566708Sjmcp free(newdev);
4576846Sjmcp free(devpath);
4586489Sjmcp continue;
4596489Sjmcp }
4606489Sjmcp
4616846Sjmcp nodep = ses_snap_primary_enclosure(snapshot);
4626846Sjmcp
4636846Sjmcp if ((props = ses_node_props(nodep)) == NULL) {
4646846Sjmcp free(newdev->ident);
4656846Sjmcp ses_snap_rele(snapshot);
4666846Sjmcp ses_close(ses_target);
4676846Sjmcp free(newdev->classname);
4686489Sjmcp free(newdev->access_devname);
4696489Sjmcp free(newdev->drvname);
4706489Sjmcp free(newdev);
4716846Sjmcp free(devpath);
4726489Sjmcp continue;
4736846Sjmcp }
4746846Sjmcp
4756846Sjmcp logmsg(MSG_INFO,
4766846Sjmcp "\nvid: %s\npid: %s\nrevid: %s\n",
4776846Sjmcp newdev->ident->vid,
4786846Sjmcp newdev->ident->pid,
4796846Sjmcp newdev->ident->revid);
4806846Sjmcp
4816846Sjmcp if (nvlist_lookup_string(props, LIBSES_EN_PROP_CSN,
4826846Sjmcp &newdev->addresses[0]) == 0) {
4836846Sjmcp logmsg(MSG_INFO,
4846846Sjmcp "Chassis Serial Number: %s\n",
4856846Sjmcp newdev->addresses[0]);
4868920SPei-Hong.Huang@Sun.COM } else
4878920SPei-Hong.Huang@Sun.COM logmsg(MSG_INFO,
4888920SPei-Hong.Huang@Sun.COM "%s: no chassis-serial-number property "
4898920SPei-Hong.Huang@Sun.COM "for device %s\n",
4908920SPei-Hong.Huang@Sun.COM driver, newdev->access_devname);
4916489Sjmcp
4926489Sjmcp
4937317SJames.McPherson@Sun.COM rv = di_prop_lookup_strings(DDI_DEV_T_ANY,
4947317SJames.McPherson@Sun.COM thisnode, "target-port", &newdev->addresses[1]);
4957317SJames.McPherson@Sun.COM if (rv < 0) {
4966846Sjmcp logmsg(MSG_INFO,
4976846Sjmcp "%s: no target-port property "
4986846Sjmcp "for device %s\n",
4996846Sjmcp driver, newdev->access_devname);
5006846Sjmcp } else
5016846Sjmcp logmsg(MSG_INFO,
5026846Sjmcp "target-port property: %s\n",
5036846Sjmcp newdev->addresses[1]);
5046846Sjmcp
5056846Sjmcp
5066489Sjmcp newdev->index = idx;
5076489Sjmcp ++idx;
5086489Sjmcp newdev->plugin = self;
5096489Sjmcp
5106846Sjmcp ses_snap_rele(snapshot);
5116489Sjmcp TAILQ_INSERT_TAIL(fw_devices, newdev, nextdev);
5126489Sjmcp }
5136489Sjmcp
5146489Sjmcp
5156489Sjmcp if (fwflash_debug != 0) {
5166489Sjmcp struct devicelist *tempdev;
5176489Sjmcp
5186489Sjmcp TAILQ_FOREACH(tempdev, fw_devices, nextdev) {
5196846Sjmcp logmsg(MSG_INFO, "%s:fw_identify:\n",
5206846Sjmcp driver);
5216846Sjmcp logmsg(MSG_INFO,
5226846Sjmcp "\ttempdev @ 0x%lx\n"
5236489Sjmcp "\t\taccess_devname: %s\n"
5246489Sjmcp "\t\tdrvname: %s\tclassname: %s\n"
5256489Sjmcp "\t\tident->vid: %s\n"
5266489Sjmcp "\t\tident->pid: %s\n"
5276489Sjmcp "\t\tident->revid: %s\n"
5286489Sjmcp "\t\tindex: %d\n"
5296489Sjmcp "\t\taddress[0]: %s\n"
5306489Sjmcp "\t\taddress[1]: %s\n"
5316489Sjmcp "\t\tplugin @ 0x%lx\n\n",
5326489Sjmcp &tempdev,
5336489Sjmcp tempdev->access_devname,
5346489Sjmcp tempdev->drvname, newdev->classname,
5356489Sjmcp tempdev->ident->vid,
5366489Sjmcp tempdev->ident->pid,
5376489Sjmcp tempdev->ident->revid,
5386489Sjmcp tempdev->index,
5398920SPei-Hong.Huang@Sun.COM (tempdev->addresses[0] ? tempdev->addresses[0] :
5408920SPei-Hong.Huang@Sun.COM "(not supported)"),
5418920SPei-Hong.Huang@Sun.COM (tempdev->addresses[1] ? tempdev->addresses[1] :
5428920SPei-Hong.Huang@Sun.COM "(not supported)"),
5436846Sjmcp &tempdev->plugin);
5446489Sjmcp }
5456489Sjmcp }
5466489Sjmcp
5476489Sjmcp return (FWFLASH_SUCCESS);
5486489Sjmcp }
5496489Sjmcp
5506489Sjmcp
5516489Sjmcp
5526489Sjmcp int
fw_devinfo(struct devicelist * thisdev)5536489Sjmcp fw_devinfo(struct devicelist *thisdev)
5546489Sjmcp {
5556489Sjmcp
5566489Sjmcp fprintf(stdout, gettext("Device[%d] %s\n Class [%s]\n"),
5576489Sjmcp thisdev->index, thisdev->access_devname, thisdev->classname);
5586489Sjmcp
5596489Sjmcp fprintf(stdout,
5606489Sjmcp gettext("\tVendor : %s\n"
5616489Sjmcp "\tProduct : %s\n"
5626489Sjmcp "\tFirmware revision : %s\n"
5636846Sjmcp "\tChassis Serial Number : %s\n"
5646489Sjmcp "\tTarget-port identifier : %s\n"),
5656489Sjmcp thisdev->ident->vid,
5666489Sjmcp thisdev->ident->pid,
5676489Sjmcp thisdev->ident->revid,
5688920SPei-Hong.Huang@Sun.COM (thisdev->addresses[0] ? thisdev->addresses[0] :
5698920SPei-Hong.Huang@Sun.COM "(not supported)"),
5708920SPei-Hong.Huang@Sun.COM (thisdev->addresses[1] ? thisdev->addresses[1] :
5718920SPei-Hong.Huang@Sun.COM "(not supported)"));
5726489Sjmcp
5736489Sjmcp fprintf(stdout, "\n\n");
5746489Sjmcp
5756489Sjmcp return (FWFLASH_SUCCESS);
5766489Sjmcp }
5776489Sjmcp
5786489Sjmcp
5796489Sjmcp
5806489Sjmcp
5816489Sjmcp
5826489Sjmcp /*ARGSUSED*/
5836489Sjmcp static int
get_status(nvlist_t * props,ucode_status_t * sp)5846489Sjmcp get_status(nvlist_t *props, ucode_status_t *sp)
5856489Sjmcp {
5866489Sjmcp int i;
5876489Sjmcp uint64_t status, astatus;
5886489Sjmcp
5896489Sjmcp if (nvlist_lookup_uint64(props, SES_EN_PROP_UCODE, &status) != 0) {
5906489Sjmcp sp->us_status = -1ULL;
5916489Sjmcp (void) snprintf(sp->us_desc, sizeof (sp->us_desc),
5926489Sjmcp "not supported");
593*9683SXin.Chen@Sun.COM return (FWFLASH_FAILURE);
5946489Sjmcp }
5956489Sjmcp
5966846Sjmcp if (nvlist_lookup_uint64(props, SES_EN_PROP_UCODE_A,
5976846Sjmcp &astatus) != 0) {
5986846Sjmcp logmsg(MSG_ERROR,
5996846Sjmcp gettext("\nError: Unable to retrieve current status\n"));
600*9683SXin.Chen@Sun.COM return (FWFLASH_FAILURE);
6016846Sjmcp }
6026489Sjmcp
6036489Sjmcp for (i = 0; i < NUCODE_STATUS; i++) {
6046489Sjmcp if (ucode_statdesc_table[i].us_value == status)
6056489Sjmcp break;
6066489Sjmcp }
6076489Sjmcp
6086489Sjmcp sp->us_status = status;
6096489Sjmcp
6106489Sjmcp if (i == NUCODE_STATUS) {
6116489Sjmcp (void) snprintf(sp->us_desc, sizeof (sp->us_desc),
6126489Sjmcp "unknown (0x%02x)", (int)status);
613*9683SXin.Chen@Sun.COM sp->us_iserr = sp->us_pending = B_TRUE;
614*9683SXin.Chen@Sun.COM return (FWFLASH_FAILURE);
6156489Sjmcp } else {
6166489Sjmcp /* LINTED */
6176489Sjmcp (void) snprintf(sp->us_desc, sizeof (sp->us_desc),
6186489Sjmcp ucode_statdesc_table[i].us_desc, (int)astatus);
6196489Sjmcp sp->us_iserr = ucode_statdesc_table[i].us_iserr;
6206489Sjmcp sp->us_pending = ucode_statdesc_table[i].us_pending;
6216489Sjmcp }
6226489Sjmcp
623*9683SXin.Chen@Sun.COM return (FWFLASH_SUCCESS);
6246489Sjmcp }
6256489Sjmcp
6266489Sjmcp
627*9683SXin.Chen@Sun.COM static int
print_updated_status(ses_node_t * np,void * arg)6286489Sjmcp print_updated_status(ses_node_t *np, void *arg)
6296489Sjmcp {
6306489Sjmcp ucode_wait_t *uwp = arg;
6316846Sjmcp nvlist_t *props;
6326489Sjmcp ucode_status_t status;
6336489Sjmcp
6346489Sjmcp
6356846Sjmcp if ((props = ses_node_props(np)) == NULL) {
636*9683SXin.Chen@Sun.COM return (FWFLASH_FAILURE);
6376846Sjmcp }
6386489Sjmcp
639*9683SXin.Chen@Sun.COM if (get_status(props, &status) != FWFLASH_SUCCESS)
640*9683SXin.Chen@Sun.COM return (FWFLASH_FAILURE);
6416489Sjmcp
6426489Sjmcp if (status.us_status != uwp->uw_prevstatus)
6436489Sjmcp (void) printf("%30s: %s\n", "status", status.us_desc);
6446846Sjmcp
6456489Sjmcp uwp->uw_prevstatus = status.us_status;
6466489Sjmcp uwp->uw_pending = status.us_pending;
6476489Sjmcp
6486846Sjmcp if (status.us_iserr) {
6496489Sjmcp logmsg(MSG_INFO,
6506846Sjmcp "libses: status.us_iserr: 0x%0x\n",
6516489Sjmcp status.us_iserr);
652*9683SXin.Chen@Sun.COM return (FWFLASH_FAILURE);
653*9683SXin.Chen@Sun.COM }
654*9683SXin.Chen@Sun.COM return (FWFLASH_SUCCESS);
6556489Sjmcp }
6566489Sjmcp
6576489Sjmcp /*ARGSUSED*/
6586846Sjmcp static int
sendimg(ses_node_t * np,void * data)6596489Sjmcp sendimg(ses_node_t *np, void *data)
6606489Sjmcp {
6616489Sjmcp nvlist_t *props;
6626489Sjmcp nvlist_t *arg = data;
6636489Sjmcp char *vendor, *product, *revision, *csn;
6646489Sjmcp char buf[128];
6656489Sjmcp ses_snap_t *newsnap;
6666489Sjmcp int ret;
6676489Sjmcp ucode_status_t statdesc;
6686489Sjmcp ucode_wait_t wait;
6696489Sjmcp uint8_t *imagedata;
6706846Sjmcp uint_t len;
6716846Sjmcp
6726489Sjmcp
6736846Sjmcp /* If we've been called without data, eject */
6746846Sjmcp if (nvlist_lookup_byte_array(arg, SES_CTL_PROP_UCODE_DATA,
6756846Sjmcp &imagedata, &len) != 0) {
6766846Sjmcp return (FWFLASH_FAILURE);
6776846Sjmcp }
6786489Sjmcp
6796846Sjmcp props = ses_node_props(np);
6806846Sjmcp if ((props == NULL) ||
6816846Sjmcp (nvlist_lookup_string(props, SES_EN_PROP_VID, &vendor) != 0) ||
6826846Sjmcp (nvlist_lookup_string(props, SES_EN_PROP_PID, &product) != 0) ||
6836846Sjmcp (nvlist_lookup_string(props, SES_EN_PROP_REV, &revision) != 0) ||
6846846Sjmcp (nvlist_lookup_string(props, LIBSES_EN_PROP_CSN, &csn) != 0)) {
6856846Sjmcp return (FWFLASH_FAILURE);
6866846Sjmcp }
6876489Sjmcp
6886489Sjmcp (void) printf("%30s: %s\n", "vendor", vendor);
6896489Sjmcp (void) printf("%30s: %s\n", "product", product);
6906489Sjmcp (void) printf("%30s: %s\n", "revision", revision);
6916489Sjmcp (void) printf("%30s: %s\n", "serial", csn);
6926489Sjmcp
6936489Sjmcp ret = get_status(props, &statdesc);
6946489Sjmcp (void) printf("%30s: %s\n", "current status", statdesc.us_desc);
695*9683SXin.Chen@Sun.COM if (ret != FWFLASH_SUCCESS) {
6966846Sjmcp return (FWFLASH_FAILURE);
6976489Sjmcp }
6986489Sjmcp
6996489Sjmcp (void) snprintf(buf, sizeof (buf), "downloading %u bytes", len);
7006489Sjmcp (void) printf("\n%30s: ", buf);
7016846Sjmcp
7026846Sjmcp /*
7036846Sjmcp * If the bufferid isn't 2, then the verifier has already
7049560SPei-Hong.Huang@Sun.COM * OK'd the image that the user has provided.
7056846Sjmcp *
7066846Sjmcp * At present the non-"standard" images need to be flashed
7076846Sjmcp * using the scsi WRITE BUFFER command
7086846Sjmcp */
7096846Sjmcp if (verifier->flashbuf != 2)
7106846Sjmcp return (scsi_writebuf());
7116846Sjmcp
7126846Sjmcp
713*9683SXin.Chen@Sun.COM if (ses_node_ctl(np, SES_CTL_OP_DL_UCODE, arg) != FWFLASH_SUCCESS) {
7146489Sjmcp (void) printf("failed!\n");
7156489Sjmcp (void) printf("%s\n", ses_errmsg());
7166846Sjmcp return (FWFLASH_FAILURE);
7176489Sjmcp } else {
7186489Sjmcp (void) printf("ok\n");
7196489Sjmcp }
7206489Sjmcp
7216489Sjmcp wait.uw_prevstatus = -1ULL;
7226489Sjmcp wait.uw_oldnp = np;
7236846Sjmcp
724*9683SXin.Chen@Sun.COM if ((newsnap = ses_snap_new(ses_target)) == NULL) {
7256846Sjmcp logmsg(MSG_ERROR,
7266846Sjmcp "failed to update SES snapshot: %s",
7276846Sjmcp ses_errmsg());
728*9683SXin.Chen@Sun.COM return (FWFLASH_FAILURE);
729*9683SXin.Chen@Sun.COM }
7306489Sjmcp
7316846Sjmcp print_updated_status(ses_snap_primary_enclosure(newsnap),
7326846Sjmcp &wait);
7336846Sjmcp ses_snap_rele(newsnap);
7346489Sjmcp
735*9683SXin.Chen@Sun.COM return (FWFLASH_SUCCESS);
7366489Sjmcp }
7376489Sjmcp
7386846Sjmcp static int
scsi_writebuf()7396846Sjmcp scsi_writebuf()
7406846Sjmcp {
7416846Sjmcp int ret;
7426846Sjmcp int i = 0;
7436846Sjmcp libscsi_action_t *action;
7446846Sjmcp spc3_write_buffer_cdb_t *wb_cdb;
7456846Sjmcp libscsi_hdl_t *handle;
7466846Sjmcp libscsi_target_t *target;
7476846Sjmcp sam4_status_t samstatus;
7486736Ssuha
7496736Ssuha
7506846Sjmcp target = ses_scsi_target(ses_target);
7516846Sjmcp handle = libscsi_get_handle(target);
7526846Sjmcp action = libscsi_action_alloc(handle, SPC3_CMD_WRITE_BUFFER,
7536846Sjmcp LIBSCSI_AF_WRITE|LIBSCSI_AF_RQSENSE,
7546846Sjmcp (void *)verifier->fwimage, (size_t)verifier->imgsize);
7556736Ssuha
7566846Sjmcp wb_cdb = (spc3_write_buffer_cdb_t *)libscsi_action_get_cdb(action);
757*9683SXin.Chen@Sun.COM
7586846Sjmcp wb_cdb->wbc_mode = SPC3_WB_MODE_DATA;
7596846Sjmcp wb_cdb->wbc_bufferid = verifier->flashbuf;
760*9683SXin.Chen@Sun.COM
761*9683SXin.Chen@Sun.COM wb_cdb->wbc_buffer_offset[0] = 0;
762*9683SXin.Chen@Sun.COM wb_cdb->wbc_buffer_offset[1] = 0;
763*9683SXin.Chen@Sun.COM wb_cdb->wbc_buffer_offset[2] = 0;
764*9683SXin.Chen@Sun.COM
765*9683SXin.Chen@Sun.COM wb_cdb->wbc_parameter_list_len[0] =
766*9683SXin.Chen@Sun.COM (verifier->imgsize & 0xff0000) >> 16;
767*9683SXin.Chen@Sun.COM wb_cdb->wbc_parameter_list_len[1] = (verifier->imgsize & 0xff00) >> 8;
768*9683SXin.Chen@Sun.COM wb_cdb->wbc_parameter_list_len[2] = (verifier->imgsize & 0xff);
7696846Sjmcp
7706846Sjmcp ret = libscsi_exec(action, target);
7716846Sjmcp samstatus = libscsi_action_get_status(action);
7726736Ssuha
7736736Ssuha logmsg(MSG_INFO,
7746846Sjmcp "\nscsi_writebuffer: ret 0x%0x, samstatus 0x%0x\n",
7756846Sjmcp ret, samstatus);
7766736Ssuha
777*9683SXin.Chen@Sun.COM if ((ret != FWFLASH_SUCCESS) || samstatus != SAM4_STATUS_GOOD) {
7786846Sjmcp libscsi_action_free(action);
779*9683SXin.Chen@Sun.COM return (FWFLASH_FAILURE);
7806846Sjmcp } else {
7816846Sjmcp (void) printf("ok\n");
7826736Ssuha }
7836736Ssuha
7846846Sjmcp for (i = 0; i < NSAM4_STATUS; i++) {
7856846Sjmcp if (sam4_status[i].status == samstatus) {
7866846Sjmcp (void) printf("%s\n", (sam4_status[i].message));
7876846Sjmcp break;
7886846Sjmcp }
7896736Ssuha }
7906736Ssuha
7916846Sjmcp if (i == NSAM4_STATUS)
7926846Sjmcp (void) printf("Status: UNKNOWN\n");
7936736Ssuha
7946846Sjmcp if (samstatus == SAM4_STATUS_GOOD) {
7956846Sjmcp return (FWFLASH_SUCCESS);
7966736Ssuha }
7976736Ssuha
7986846Sjmcp return (FWFLASH_FAILURE);
7996489Sjmcp }
800