ses.c revision d73e86db323b2684ada2db7e3b2fe57e542703b0
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * CDDL HEADER START
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * The contents of this file are subject to the terms of the
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * Common Development and Distribution License (the "License").
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * You may not use this file except in compliance with the License.
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * See the License for the specific language governing permissions
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * and limitations under the License.
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * When distributing Covered Code, include this CDDL HEADER in each
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * If applicable, add the following below this CDDL HEADER, with the
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * fields enclosed by brackets "[]" replaced with your own identifying
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * information: Portions Copyright [yyyy] [name of copyright owner]
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * CDDL HEADER END
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * Use is subject to license terms.
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp#pragma ident "%Z%%M% %I% %E% SMI"
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * ses (SCSI Generic Device) specific functions.
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp/* useful defines */
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcptypedef struct ucode_statdesc {
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp const char *us_desc;
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp { SES2_DLUCODE_S_INPROGRESS, "in progress", B_TRUE, B_FALSE },
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp { SES2_DLUCODE_S_COMPLETE_NOW, "completed (available)", B_FALSE,
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "completed (need reset or power on)", B_FALSE, B_FALSE },
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp { SES2_DLUCODE_S_COMPLETE_AT_POWERON, "completed (need power on)",
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "internal error (NEED NEW IMAGE BEFORE RESET)",
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "internal error (reset to revert to backup)",
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp (sizeof (ucode_statdesc_table) / sizeof (ucode_statdesc_table[0]))
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcptypedef struct ucode_status {
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcptypedef struct ucode_wait {
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp/* required functions for this plugin */
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcpint fw_readfw(struct devicelist *device, char *filename);
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp/* helper functions */
d73e86db323b2684ada2db7e3b2fe57e542703b0suhastatic int ses_dl_ucode_check(struct devicelist *flashdev);
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcpstatic ses_walk_action_t print_updated_status(ses_node_t *np, void *arg);
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcpstatic int get_status(nvlist_t *props, ucode_status_t *sp);
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcpstatic ses_walk_action_t sendimg(ses_node_t *np, void *data);
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * SES2 does not actually allow us to read a firmware
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * image from an SES device, so we just return success
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * if this is requested, after printing a message.
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "ses: not writing firmware for device %s to file %s\n",
d73e86db323b2684ada2db7e3b2fe57e542703b0suha logmsg(MSG_ERROR, gettext("\n\nSES2 does not support retrieval "
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "of firmware images\n\n"));
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * If we're invoking fw_writefw, then flashdev is a valid,
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * flashable device supporting the SES2 Download Microcode Diagnostic
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * Control page (0x0e).
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * If verifier is null, then we haven't been called following a firmware
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * image verification load operation.
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * *THIS* function uses scsi SEND DIAGNOSTIC/download microcode to
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * achieve the task... if you chase down to the bottom of libses you
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * can see that too.
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "space for device prop list\n"));
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp /* should _not_ happen */
d73e86db323b2684ada2db7e3b2fe57e542703b0suha logmsg(MSG_ERROR, gettext("ses: Firmware image has not "
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "been verified.\n"));
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp fprintf(stdout, "\n"); /* get a fresh line for progress updates */
d73e86db323b2684ada2db7e3b2fe57e542703b0suha logmsg(MSG_ERROR, gettext("ses: Unable to add buffer id "
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "property\n"));
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp if (nvlist_add_byte_array(nvl, SES_CTL_PROP_UCODE_DATA,
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp (uint8_t *)verifier->fwimage, verifier->imgsize) != 0) {
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "%s: Out of memory for property addition\n",
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp ses_open(LIBSES_VERSION, flashdev->access_devname)) == NULL) {
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * We flash via a walker callback function, because it's easier
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * to do it this way when using libses.
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "after the system is rebooted.\n"));
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * The fw_identify() function walks the device
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * tree trying to find devices which this plugin
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * can work with.
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * The parameter "start" gives us the starting index number
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * to give the device when we add it to the fw_devices list.
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp * firstdev is allocated by us and we add space as needed
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp logmsg(MSG_INFO, gettext("No %s nodes in this system\n"),
d73e86db323b2684ada2db7e3b2fe57e542703b0suha logmsg(MSG_ERROR, gettext("ses: Unable to malloc space "
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp /* we've found one, at least */
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp for (; thisnode != DI_NODE_NIL; thisnode = di_drv_next_node(thisnode)) {
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "to allocate space for device entry\n"));
d73e86db323b2684ada2db7e3b2fe57e542703b0suha /* malloc enough for /devices + devpath + ":0" + '\0' */
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp if ((newdev->access_devname = calloc(1, devlength)) == NULL) {
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "space for a devfs name\n"));
d73e86db323b2684ada2db7e3b2fe57e542703b0suha if ((newdev->drvname = calloc(1, strlen(drivername) + 1))
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "space for a driver name\n"));
d73e86db323b2684ada2db7e3b2fe57e542703b0suha if ((newdev->classname = calloc(1, strlen(drivername) + 1))
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "space for a class name\n"));
d73e86db323b2684ada2db7e3b2fe57e542703b0suha * Check for friendly vendor names, and whether this device
d73e86db323b2684ada2db7e3b2fe57e542703b0suha * supports the Download Microcode Control page.
d73e86db323b2684ada2db7e3b2fe57e542703b0suha if ((rv == FWFLASH_FAILURE) || (newdev->ident == NULL))
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "ses: unable to inquire on potentially "
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "flashable device\n%s\n",
d73e86db323b2684ada2db7e3b2fe57e542703b0suha * Look for the target-port property. We use addresses[1]
d73e86db323b2684ada2db7e3b2fe57e542703b0suha * because addresses[0] is already assigned by the inquiry
d73e86db323b2684ada2db7e3b2fe57e542703b0suha * function
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "ses: no target-port property for "
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "device %s\n",
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "\t\taccess_devname: %s\n"
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "\t\tdrvname: %s\tclassname: %s\n"
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "\t\tident->vid: %s\n"
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "\t\tident->pid: %s\n"
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "\t\tident->revid: %s\n"
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "\t\tindex: %d\n"
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "\t\taddress[0]: %s\n"
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "\t\taddress[1]: %s\n"
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "\t\tplugin @ 0x%lx\n\n",
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp fprintf(stdout, gettext("Device[%d] %s\n Class [%s]\n"),
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp thisdev->index, thisdev->access_devname, thisdev->classname);
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "\tProduct : %s\n"
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "\tFirmware revision : %s\n"
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "\tTarget-port identifier : %s\n"),
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp/*ARGSUSED*/
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp if (nvlist_lookup_uint64(props, SES_EN_PROP_UCODE, &status) != 0) {
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "not supported");
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp return (-1);
d73e86db323b2684ada2db7e3b2fe57e542703b0suha verify(nvlist_lookup_uint64(props, SES_EN_PROP_UCODE_A, &astatus) == 0);
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp for (i = 0; i < NUCODE_STATUS; i++) {
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp /* LINTED */
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp return (0);
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp verify(nvlist_lookup_uint64(props, SES_EN_PROP_EID, &id) == 0);
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp verify(nvlist_lookup_uint64(oldprops, SES_EN_PROP_EID, &oldid) == 0);
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "ses: status.us_iserr: 0x%0x\n",
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp/*ARGSUSED*/
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp verify(nvlist_lookup_string(props, SES_EN_PROP_VID, &vendor) == 0);
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp verify(nvlist_lookup_string(props, SES_EN_PROP_PID, &product) == 0);
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp verify(nvlist_lookup_string(props, SES_EN_PROP_REV, &revision) == 0);
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp verify(nvlist_lookup_string(props, LIBSES_EN_PROP_CSN, &csn) == 0);
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp (void) printf("%30s: %s\n", "current status", statdesc.us_desc);
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp if (ret != 0) {
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp verify(nvlist_lookup_byte_array(arg, SES_CTL_PROP_UCODE_DATA,
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp (void) snprintf(buf, sizeof (buf), "downloading %u bytes", len);
5a7763bf3e9db4cfe6cb523b096cb74af71e3793jmcp "failed to update SES snapshot: %s",
d73e86db323b2684ada2db7e3b2fe57e542703b0suha * Simple function to sent a standard SCSI INQUIRY(6) cdb out
d73e86db323b2684ada2db7e3b2fe57e542703b0suha * to thisnode and blat the response back into a struct vpr*
d73e86db323b2684ada2db7e3b2fe57e542703b0suhastatic struct vpr *
d73e86db323b2684ada2db7e3b2fe57e542703b0suha if ((inqcmd = calloc(1, sizeof (struct uscsi_cmd))) == NULL) {
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "for a SCSI INQUIRY(6) command\n"),
d73e86db323b2684ada2db7e3b2fe57e542703b0suha sizeof (struct uscsi_cmd));
d73e86db323b2684ada2db7e3b2fe57e542703b0suha if ((inqvpr = calloc(1, sizeof (struct vpr))) == NULL) {
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "for SCSI INQUIRY(6) response\n"),
d73e86db323b2684ada2db7e3b2fe57e542703b0suha sizeof (struct vpr));
d73e86db323b2684ada2db7e3b2fe57e542703b0suha if ((inqcmd->uscsi_cdb = calloc(1, CDB_GROUP0 * sizeof (caddr_t)))
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "for SCSI INQUIRY(6)\n"),
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "ses: Unable to open device %s: %s\n",
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "for %s identification function.\n"),
d73e86db323b2684ada2db7e3b2fe57e542703b0suha /* just make sure these buffers are clean */
d73e86db323b2684ada2db7e3b2fe57e542703b0suha inqcmd->uscsi_cdblen = CDB_GROUP0; /* a GROUP 0 command */
d73e86db323b2684ada2db7e3b2fe57e542703b0suha inqcmd->uscsi_cdb[1] = 0x00; /* EVPD = Enable Vital Product Data */
d73e86db323b2684ada2db7e3b2fe57e542703b0suha inqcmd->uscsi_cdb[2] = 0x00; /* which pagecode to query? */
d73e86db323b2684ada2db7e3b2fe57e542703b0suha inqcmd->uscsi_cdb[3] = 0x00; /* allocation length, msb */
d73e86db323b2684ada2db7e3b2fe57e542703b0suha inqcmd->uscsi_cdb[4] = INQBUFLEN; /* allocation length, lsb */
d73e86db323b2684ada2db7e3b2fe57e542703b0suha if (rval < 0) {
d73e86db323b2684ada2db7e3b2fe57e542703b0suha /* ioctl failed */
d73e86db323b2684ada2db7e3b2fe57e542703b0suha gettext("ses: Unable to retrieve SCSI INQUIRY(6) data "
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "from device %s: %s\n"),
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "ses inquiry: vid %s ; pid %s ; revid %s\n",
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "ses inquiry: unrecognised device\n");
d73e86db323b2684ada2db7e3b2fe57e542703b0suha * ses_dl_ucode_check() lets us check whether SES2's Download
d73e86db323b2684ada2db7e3b2fe57e542703b0suha * Microcode Control diagnostic and status pages are supported
d73e86db323b2684ada2db7e3b2fe57e542703b0suha * by flashdev.
d73e86db323b2684ada2db7e3b2fe57e542703b0suha int i = 0;
d73e86db323b2684ada2db7e3b2fe57e542703b0suha uchar_t sensebuf[RQBUFLEN]; /* for the request sense data */
d73e86db323b2684ada2db7e3b2fe57e542703b0suha uchar_t pagesup[PCBUFLEN]; /* should be less than 64 pages */
d73e86db323b2684ada2db7e3b2fe57e542703b0suha gettext("ses:ses_dl_ucode_check: Unable to open %s\n"),
d73e86db323b2684ada2db7e3b2fe57e542703b0suha if ((usc = calloc(1, sizeof (struct uscsi_cmd))) == NULL) {
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "microcode download query: %s\n"),
d73e86db323b2684ada2db7e3b2fe57e542703b0suha if ((usc->uscsi_cdb = calloc(1, CDB_GROUP0 * sizeof (caddr_t)))
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "microcode download query: %s\n"),
d73e86db323b2684ada2db7e3b2fe57e542703b0suha usc->uscsi_cdb[2] = 0x00; /* list all Supported diag pages */
d73e86db323b2684ada2db7e3b2fe57e542703b0suha if (rv < 0) {
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "ses: DL uCode checker ioctl error (%d): %s\n",
d73e86db323b2684ada2db7e3b2fe57e542703b0suha /* in SPC4, this is an "n-3" field */
d73e86db323b2684ada2db7e3b2fe57e542703b0suha while (i < limit) {
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "supports the Download Microcode "
d73e86db323b2684ada2db7e3b2fe57e542703b0suha "diagnostic control page\n",