ses.c revision c4800545504378963d9f2eeb253f06899664f9f6
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* ses (SCSI Generic Device) specific functions.
*/
#include <assert.h>
#include <libnvpair.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sysmacros.h>
#include <fcntl.h>
#include <string.h>
#include <strings.h>
#include <libintl.h> /* for gettext(3c) */
#define VIDLEN 0x08
#define PIDLEN 0x10
#define REVLEN 0x04
#define SASADDRLEN 0x10
#define PCBUFLEN 0x40
#define RQBUFLEN 0xfe
#define STATBUFLEN 0xfe
#define INQBUFLEN 0x80
/* useful defines */
#define UCODE_CHECK_STATUS 0
#define UCODE_CHECK_SUPPORTED 1
typedef struct ucode_statdesc {
const char *us_desc;
static ucode_statdesc_t ucode_statdesc_table[] = {
B_FALSE },
{ SES2_DLUCODE_S_COMPLETE_AT_POWERON, "completed (need power on)",
{ SES2_DLUCODE_S_PAGE_ERR, "page error (offset %d)",
{ SES2_DLUCODE_S_IMAGE_ERR, "invalid image",
{ SES2_DLUCODE_S_TIMEOUT, "download timeout",
"internal error (NEED NEW IMAGE BEFORE RESET)",
"internal error (reset to revert to backup)",
};
#define NUCODE_STATUS \
(sizeof (ucode_statdesc_table) / sizeof (ucode_statdesc_table[0]))
typedef struct ucode_status {
char us_desc[128];
typedef struct ucode_wait {
} ucode_wait_t;
typedef struct sam4_statdesc {
int status;
char *message;
static sam4_statdesc_t sam4_status[] = {
{ SAM4_STATUS_GOOD, "Status: GOOD (success)" },
{ SAM4_STATUS_CHECK_CONDITION, "Status: CHECK CONDITION" },
{ SAM4_STATUS_CONDITION_MET, "Status: CONDITION MET" },
{ SAM4_STATUS_BUSY, "Status: Device is BUSY" },
{ SAM4_STATUS_RESERVATION_CONFLICT, "Status: Device is RESERVED" },
"Status: TASK SET FULL (insufficient resources in command queue" },
{ SAM4_STATUS_TASK_ABORTED, "Status: TASK ABORTED" },
};
#define NSAM4_STATUS \
(sizeof (sam4_status) / sizeof (sam4_status[0]))
char drivername[] = "ses\0";
static char *devprefix = "/devices";
static char *sessuffix = ":0";
static char *sgensuffix = ":ses";
static ses_target_t *ses_target;
static int internalstatus;
extern int errno;
extern struct vrfyplugin *verifier;
extern int fwflash_debug;
/* required functions for this plugin */
int fw_identify(int start);
/* helper functions */
static int scsi_writebuf();
/*
* We don't currently support reading firmware from a SAS
* expander. If we do eventually support it, we would use
* the scsi READ BUFFER command to do so.
*/
int
{
"%s: not writing firmware for device %s to file %s\n",
gettext("\n\nReading of firmware images from %s-attached "
"devices is not supported\n\n"),
return (FWFLASH_SUCCESS);
}
/*
* If we're invoking fw_writefw, then flashdev is a valid,
* flashable device supporting the SES2 Download Microcode Diagnostic
* Control page (0x0e).
*
* If verifier is null, then we haven't been called following a firmware
* image verification load operation.
*
* *THIS* function uses scsi SEND DIAGNOSTIC/download microcode to
* achieve the task... if you chase down to the bottom of libses you
* can see that too.
*/
int
{
int rv;
/* should _not_ happen */
gettext("%s: Firmware image has not "
"been verified.\n"),
return (FWFLASH_FAILURE);
}
SES_DLUCODE_M_WITH_OFFS) != 0) {
gettext("%s: Unable to allocate "
"space for device prop list\n"),
return (FWFLASH_FAILURE);
}
gettext("%s: Unable to add buffer id "
"property, hence unable to flash device\n"),
goto cancel;
}
"%s: Out of memory for property addition\n",
goto cancel;
}
if ((ses_target =
gettext("%s: Unable to open flashable device %s\n"),
goto cancel;
}
gettext("%s: Unable to locate primary enclosure for "
"device %s\n"),
} else {
if (rv == FWFLASH_SUCCESS) {
gettext("%s: Done. New image will be active "
"after the system is rebooted.\n\n"),
} else {
"%s: unable to flash image %s to device %s\n\n",
}
}
return (internalstatus);
}
/*
* The fw_identify() function walks the device
* tree trying to find devices which this plugin
* can work with.
*
* The parameter "start" gives us the starting index number
* to give the device when we add it to the fw_devices list.
*
* firstdev is allocated by us and we add space as needed
*/
int
fw_identify(int start)
{
int rv = FWFLASH_FAILURE;
struct devicelist *newdev;
char *devpath;
char *devsuffix;
char *driver;
int devlength = 0;
} else {
driver = drivername;
}
if (thisnode == DI_NODE_NIL) {
driver);
return (rv);
}
gettext("%s: Unable to allocate space "
"for a device node\n"),
driver);
return (rv);
}
/* we've found one, at least */
== NULL) {
gettext("%s: identification function unable "
"to allocate space for device entry\n"),
driver);
return (rv);
}
/* calloc enough for /devices + devpath + devsuffix + '\0' */
gettext("%s: Unable to allocate "
"space for a devfs name\n"),
driver);
return (FWFLASH_FAILURE);
}
== NULL) {
gettext("%s: Unable to allocate "
"space to store a driver name\n"),
driver);
return (FWFLASH_FAILURE);
}
== NULL) {
gettext("%s: Unable to malloc "
"space for a class name\n"),
return (FWFLASH_FAILURE);
}
/*
* Only alloc as much as we truly need, and DON'T forget
* that libnvpair manages the memory for property lookups!
* The same goes for libdevinfo properties.
*
* Also note that we're allocating here before we try to
* ses_open() the target, because if we can't allocate
* sufficient space then we might as well go home.
*/
gettext("%s: Unable to malloc space for"
"SCSI INQUIRY data\n"), driver);
return (FWFLASH_FAILURE);
}
if ((ses_target =
== NULL) {
gettext("%s: Unable to open device %s\n"),
continue;
}
/*
* If the node has no properties, or the INQUIRY properties
* don't exist, this device does not comply with SES2 so we
* won't touch it.
*/
continue;
}
continue;
}
continue;
}
"\nvid: %s\npid: %s\nrevid: %s\n",
"Chassis Serial Number: %s\n",
} else {
"(not supported)", 17);
}
thisnode, "target-port",
"%s: no target-port property "
"for device %s\n",
"(not supported)", 17);
} else
"target-port property: %s\n",
++idx;
}
if (fwflash_debug != 0) {
struct devicelist *tempdev;
driver);
"\ttempdev @ 0x%lx\n"
"\t\taccess_devname: %s\n"
"\t\tdrvname: %s\tclassname: %s\n"
"\t\tident->vid: %s\n"
"\t\tident->pid: %s\n"
"\t\tident->revid: %s\n"
"\t\tindex: %d\n"
"\t\taddress[0]: %s\n"
"\t\taddress[1]: %s\n"
"\t\tplugin @ 0x%lx\n\n",
&tempdev,
}
}
return (FWFLASH_SUCCESS);
}
int
{
gettext("\tVendor : %s\n"
"\tProduct : %s\n"
"\tFirmware revision : %s\n"
"\tChassis Serial Number : %s\n"
"\tTarget-port identifier : %s\n"),
return (FWFLASH_SUCCESS);
}
/*ARGSUSED*/
static int
{
int i;
"not supported");
return (-1);
}
&astatus) != 0) {
gettext("\nError: Unable to retrieve current status\n"));
return (-1);
}
for (i = 0; i < NUCODE_STATUS; i++) {
break;
}
if (i == NUCODE_STATUS) {
"unknown (0x%02x)", (int)status);
} else {
/* LINTED */
}
return (0);
}
static void
{
return;
}
/* internalstatus is already set to FWFLASH_FAILURE */
return;
"libses: status.us_iserr: 0x%0x\n",
} else
}
/*ARGSUSED*/
static int
{
char buf[128];
int ret;
/* If we've been called without data, eject */
return (FWFLASH_FAILURE);
}
return (FWFLASH_FAILURE);
}
if (ret != 0) {
return (FWFLASH_FAILURE);
}
/*
* If the bufferid isn't 2, then the verifier has already
* OK'd the image that the user has provided. That means
* we've got manufacturing_mode = 1 from the command line.
*
* At present the non-"standard" images need to be flashed
* using the scsi WRITE BUFFER command
*/
return (scsi_writebuf());
(void) printf("failed!\n");
return (FWFLASH_FAILURE);
} else {
(void) printf("ok\n");
}
"failed to update SES snapshot: %s",
ses_errmsg());
&wait);
return (internalstatus);
}
static int
{
int ret;
int i = 0;
"\nscsi_writebuffer: ret 0x%0x, samstatus 0x%0x\n",
return (ret);
} else {
(void) printf("ok\n");
}
for (i = 0; i < NSAM4_STATUS; i++) {
break;
}
}
if (i == NSAM4_STATUS)
(void) printf("Status: UNKNOWN\n");
if (samstatus == SAM4_STATUS_GOOD) {
return (FWFLASH_SUCCESS);
}
return (FWFLASH_FAILURE);
}