#include <libnvpair.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <scsi/libscsi.h>
#include <sys/scsi/scsi_types.h>
#include <libintl.h>
#include <fwflash/fwflash.h>
#include <sys/debug.h>
#include <umem.h>
typedef struct sam4_statdesc {
int sam_status;
char *sam_message;
} sam4_statdesc_t;
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" },
{ SAM4_STATUS_TASK_SET_FULL,
"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]))
#define FW_SD_FREE_DEVPATH(devpath) { \
di_devfs_path_free((devpath)); \
}
#define FW_SD_FREE_DEVICELIST(thisdev, devpath) { \
free((thisdev)); \
FW_SD_FREE_DEVPATH((devpath)) \
}
#define FW_SD_FREE_DRV_NAME(thisdev, devpath) { \
free((thisdev)->drvname); \
FW_SD_FREE_DEVICELIST((thisdev), (devpath)) \
}
#define FW_SD_FREE_CLS_NAME(thisdev, devpath) { \
free((thisdev)->classname); \
FW_SD_FREE_DRV_NAME((thisdev), (devpath)) \
}
#define FW_SD_FREE_ACC_NAME(thisdev, devpath) { \
free((thisdev)->access_devname); \
FW_SD_FREE_CLS_NAME(thisdev, devpath) \
}
#define FW_SD_FREE_ADDR(thisdev, devpath) { \
free((thisdev)->addresses[0]); \
FW_SD_FREE_ACC_NAME(thisdev, devpath) \
}
#define FW_SD_FREE_IDENT(thisdev, devpath) { \
free((thisdev)->ident); \
FW_SD_FREE_ADDR((thisdev), (devpath)) \
}
#define FW_SD_FREE_IDENT_VID(thisdev, devpath) { \
free((thisdev)->ident->vid); \
FW_SD_FREE_IDENT((thisdev), (devpath)) \
}
#define FW_SD_FREE_IDENT_PID(thisdev, devpath) { \
free((thisdev)->ident->pid); \
FW_SD_FREE_IDENT_VID((thisdev), (devpath)) \
}
#define FW_SD_FREE_IDENT_ALL(thisdev, devpath) { \
free((thisdev)->ident->revid); \
FW_SD_FREE_IDENT_PID((thisdev), (devpath)) \
}
#define FW_SD_PARTIAL_WRITE_SIZE (64 * 1024)
char drivername[] = "sd\0";
int plugin_version = FWPLUGIN_VERSION_2;
extern di_node_t rootnode;
extern struct fw_plugin *self;
extern struct vrfyplugin *verifier;
extern int fwflash_debug;
static char *sdfw_devprefix = "/devices";
static char *sdfw_find_link(di_node_t bnode, char *acc_devname);
static int sdfw_link_cb(di_devlink_t devlink, void *arg);
static int sdfw_idtfy_custmz(struct devicelist *device, char *sp);
int
fw_readfw(struct devicelist *flashdev, char *filename)
{
logmsg(MSG_INFO,
"%s: not writing firmware for device %s to file %s\n",
flashdev->drvname, flashdev->access_devname, filename);
logmsg(MSG_ERROR,
gettext("\n\nReading of firmware images from %s-attached "
"devices is not supported\n\n"),
flashdev->drvname);
return (FWFLASH_SUCCESS);
}
static int
sdfw_read_descriptor(struct devicelist *flashdev, libscsi_hdl_t *hdl,
libscsi_target_t *targ, uint8_t *align)
{
spc3_read_buffer_cdb_t *rb_cdb;
size_t nwritten;
libscsi_action_t *action = NULL;
uint8_t descbuf[4];
sam4_status_t samstatus;
VERIFY3P(hdl, !=, NULL);
VERIFY3P(targ, !=, NULL);
VERIFY3P(align, !=, NULL);
if ((action = libscsi_action_alloc(hdl, SPC3_CMD_READ_BUFFER,
LIBSCSI_AF_READ, descbuf, sizeof (descbuf))) == NULL) {
logmsg(MSG_ERROR, gettext("%s: failed to alloc scsi action: "
"%s\n"),
flashdev->drvname, libscsi_errmsg(hdl));
return (FWFLASH_FAILURE);
}
rb_cdb = (spc3_read_buffer_cdb_t *)libscsi_action_get_cdb(action);
rb_cdb->rbc_mode = SPC3_RB_MODE_DESCRIPTOR;
rb_cdb->rbc_bufferid = 0;
rb_cdb->rbc_allocation_len[0] = 0;
rb_cdb->rbc_allocation_len[1] = 0;
rb_cdb->rbc_allocation_len[2] = sizeof (descbuf);
if (libscsi_exec(action, targ) != 0) {
logmsg(MSG_ERROR, gettext("%s: failed to execute SCSI buffer "
"data read: %s\n"),
flashdev->drvname, libscsi_errmsg(hdl));
libscsi_action_free(action);
return (FWFLASH_FAILURE);
}
if ((samstatus = libscsi_action_get_status(action)) !=
SAM4_STATUS_GOOD) {
int i;
for (i = 0; i < NSAM4_STATUS; i++) {
if (samstatus == sam4_status[i].sam_status) {
logmsg(MSG_ERROR, gettext("%s: SCSI buffer "
"data read failed: %s\n"),
flashdev->drvname,
sam4_status[i].sam_message);
libscsi_action_free(action);
return (FWFLASH_FAILURE);
}
}
logmsg(MSG_ERROR, gettext("%s: SCSI buffer data read failed: "
"unknown error: %d\n"), flashdev->drvname, samstatus);
libscsi_action_free(action);
return (FWFLASH_FAILURE);
}
if (libscsi_action_get_buffer(action, NULL, NULL, &nwritten) != 0) {
logmsg(MSG_ERROR, gettext("%s: failed to get actual data "
"size: %s\n"),
flashdev->drvname, libscsi_errmsg(hdl));
libscsi_action_free(action);
return (FWFLASH_FAILURE);
}
libscsi_action_free(action);
if (nwritten != sizeof (descbuf)) {
logmsg(MSG_ERROR, gettext("%s: received a short read from the "
"SCSI READ BUFFER command, expected %u bytes, read %zu\n"),
flashdev->drvname, sizeof (descbuf), nwritten);
return (FWFLASH_FAILURE);
}
if (descbuf[0] == 0 && descbuf[1] == 0 && descbuf[2] == 0 &&
descbuf[3] == 0) {
logmsg(MSG_ERROR, gettext("%s: devices %s does not support "
"firmware upgrade\n"), verifier->vendor,
flashdev->access_devname);
return (FWFLASH_FAILURE);
}
*align = descbuf[0];
return (FWFLASH_SUCCESS);
}
static int
sdfw_write(struct devicelist *flashdev, libscsi_hdl_t *handle,
libscsi_target_t *target, size_t len, size_t off, void *buf)
{
sam4_status_t samstatus;
libscsi_action_t *action = NULL;
spc3_write_buffer_cdb_t *wb_cdb;
logmsg(MSG_INFO, "%s: writing %u bytes of image %s at offset %zu from "
"address %p\n", flashdev->drvname, len, verifier->imgfile, off,
buf);
logmsg(MSG_INFO, "%s: writing to buffer id %u\n",
flashdev->drvname, verifier->flashbuf);
VERIFY3P(flashdev, !=, NULL);
VERIFY3P(handle, !=, NULL);
VERIFY3P(target, !=, NULL);
VERIFY3P(buf, !=, NULL);
VERIFY3U(len, >, 0);
VERIFY3U(off + len, <=, verifier->imgsize);
action = libscsi_action_alloc(handle, SPC3_CMD_WRITE_BUFFER,
LIBSCSI_AF_WRITE | LIBSCSI_AF_RQSENSE | LIBSCSI_AF_ISOLATE, buf,
len);
if (action == NULL) {
logmsg(MSG_ERROR, gettext("%s: failed to alloc scsi action: "
"%s\n"), flashdev->drvname, libscsi_errmsg(handle));
goto err;
}
wb_cdb = (spc3_write_buffer_cdb_t *)libscsi_action_get_cdb(action);
wb_cdb->wbc_mode = SPC3_WB_MODE_DL_UCODE_OFFS_SAVE;
wb_cdb->wbc_buffer_offset[0] = (off >> 16) & 0xff;
wb_cdb->wbc_buffer_offset[1] = (off >> 8) & 0xff;
wb_cdb->wbc_buffer_offset[2] = off & 0xff;
wb_cdb->wbc_bufferid = verifier->flashbuf;
wb_cdb->wbc_parameter_list_len[0] = (len >> 16) & 0xff;
wb_cdb->wbc_parameter_list_len[1] = (len >> 8) & 0xff;
wb_cdb->wbc_parameter_list_len[2] = len & 0xff;
logmsg(MSG_INFO, "%s: spc3_write_buffer_cdb_t opcode: %u\n",
flashdev->drvname, wb_cdb->wbc_opcode);
if (libscsi_exec(action, target) != 0) {
logmsg(MSG_ERROR, gettext("%s: failed to execute SCSI WRITE "
"BUFFER: %s\n"),
flashdev->drvname, libscsi_errmsg(handle));
goto err;
}
if ((samstatus = libscsi_action_get_status(action)) ==
SAM4_STATUS_CHECK_CONDITION) {
uint64_t asc = 0, ascq = 0, key = 0;
const char *code, *keystr;
if (libscsi_action_parse_sense(action, &key, &asc, &ascq,
NULL) != 0) {
logmsg(MSG_ERROR, gettext("%s: failed to write "
"firmware. Received CHECK_CONDITION that cannot be "
"parsed.\n"),
flashdev->drvname);
goto err;
}
code = libscsi_sense_code_name(asc, ascq);
keystr = libscsi_sense_key_name(key);
logmsg(MSG_ERROR, gettext("%s: failed to write firmware: "
"received sense key %" PRIu64 " (%s) additional sense code "
"0x%" PRIx64 "/0x%" PRIx64 " (%s)\n"), flashdev->drvname,
key, keystr != NULL ? keystr : "<unknown>",
asc, ascq, code != NULL ? code : "<unknown>");
goto err;
} else if (samstatus != SAM4_STATUS_GOOD) {
int i;
logmsg(MSG_ERROR, gettext("%s: SCSI buffer data write failed:"),
flashdev->drvname);
for (i = 0; i < NSAM4_STATUS; i++) {
if (samstatus == sam4_status[i].sam_status) {
logmsg(MSG_ERROR, gettext("%s\n"),
sam4_status[i].sam_message);
goto err;
}
}
logmsg(MSG_ERROR, gettext("unknown error: %d\n"), samstatus);
goto err;
} else {
logmsg(MSG_INFO, "%s: received STATUS GOOD\n",
flashdev->drvname);
}
libscsi_action_free(action);
return (FWFLASH_SUCCESS);
err:
if (action != NULL)
libscsi_action_free(action);
return (FWFLASH_FAILURE);
}
int
fw_writefw(struct devicelist *flashdev)
{
libscsi_hdl_t *handle;
libscsi_target_t *target;
libscsi_errno_t serr;
size_t maxxfer, nwrite;
uint8_t align;
int ret = FWFLASH_FAILURE;
if ((verifier == NULL) || (verifier->imgsize == 0) ||
(verifier->fwimage == NULL)) {
logmsg(MSG_ERROR,
gettext("%s: Firmware image has not been verified\n"),
flashdev->drvname);
return (FWFLASH_FAILURE);
}
if ((handle = libscsi_init(LIBSCSI_VERSION, &serr)) == NULL) {
logmsg(MSG_ERROR, gettext("%s: failed to initialize libscsi\n"),
flashdev->drvname);
return (FWFLASH_FAILURE);
}
if ((target = libscsi_open(handle, NULL, flashdev->access_devname)) ==
NULL) {
logmsg(MSG_ERROR,
gettext("%s: unable to open device %s\n"),
flashdev->drvname, flashdev->access_devname);
libscsi_fini(handle);
return (FWFLASH_FAILURE);
}
if (libscsi_max_transfer(target, &maxxfer) != 0) {
logmsg(MSG_ERROR, gettext("%s: failed to determine device "
"maximum transfer size: %s\n"), flashdev->drvname,
libscsi_errmsg(handle));
goto err;
}
if (sdfw_read_descriptor(flashdev, handle, target, &align) !=
FWFLASH_SUCCESS) {
goto err;
}
if (maxxfer < verifier->imgsize) {
logmsg(MSG_INFO, "%s: Maximum transfer is %zu, required "
"alignment is 2^%u\n", flashdev->drvname, maxxfer, align);
if (FW_SD_PARTIAL_WRITE_SIZE > maxxfer) {
logmsg(MSG_ERROR, gettext("%s: cannot write firmware "
"image: HBA enforces a maximum transfer size of "
"%zu bytes, but the default partial transfer size "
"is %u bytes\n"), flashdev->drvname, maxxfer,
FW_SD_PARTIAL_WRITE_SIZE);
goto err;
}
maxxfer = FW_SD_PARTIAL_WRITE_SIZE;
if (ffsll(maxxfer) < align || align == 0xff) {
logmsg(MSG_ERROR, gettext("%s: cannot write firmware "
"image: device requires partial writes aligned "
"to an unsupported value\n"), flashdev->drvname);
goto err;
}
logmsg(MSG_INFO, "%s: final transfer block size is %zu\n",
flashdev->drvname, maxxfer);
}
logmsg(MSG_INFO, "%s: Writing out %u bytes to %s\n", flashdev->drvname,
verifier->imgsize, flashdev->access_devname);
nwrite = 0;
for (;;) {
uintptr_t buf;
size_t towrite = MIN(maxxfer, verifier->imgsize - nwrite);
if (towrite == 0)
break;
buf = (uintptr_t)verifier->fwimage;
buf += nwrite;
if (sdfw_write(flashdev, handle, target, towrite, nwrite,
(void *)buf) != FWFLASH_SUCCESS) {
logmsg(MSG_ERROR, gettext("%s: failed to write to %s "
"successfully: %s\n"), flashdev->drvname,
flashdev->access_devname, libscsi_errmsg(handle));
goto err;
}
nwrite += towrite;
}
logmsg(MSG_ERROR, gettext("Note: For flash based disks "
"(SSD, etc). You may need power off the system to wait a "
"few minutes for supercap to fully discharge, then power "
"on the system again to activate the new firmware\n"));
ret = FWFLASH_SUCCESS;
err:
if (target != NULL)
libscsi_close(handle, target);
if (handle != NULL)
libscsi_fini(handle);
return (ret);
}
int
fw_identify(int start)
{
int idx = start;
int fw_sata_disk = 0;
int *exists;
di_node_t thisnode;
struct devicelist *newdev = NULL;
char *devpath = NULL;
char *driver = NULL;
char *sp_temp;
char *sp_temp_cut;
libscsi_hdl_t *handle;
libscsi_target_t *target;
libscsi_errno_t serr;
if (strcmp(self->drvname, "ssd") == 0) {
driver = self->drvname;
} else
driver = drivername;
thisnode = di_drv_first_node(driver, rootnode);
if (thisnode == DI_NODE_NIL) {
logmsg(MSG_INFO, "No %s nodes in this system\n", driver);
return (FWFLASH_FAILURE);
}
if ((handle = libscsi_init(LIBSCSI_VERSION, &serr)) == NULL) {
logmsg(MSG_ERROR, gettext("%s: failed to initialize "
"libscsi\n"), newdev->drvname);
return (FWFLASH_FAILURE);
}
for (; thisnode != DI_NODE_NIL; thisnode = di_drv_next_node(thisnode)) {
if ((devpath = di_devfs_path(thisnode)) == NULL) {
logmsg(MSG_INFO, "unable to get device path for "
"current node with errno %d\n", errno);
continue;
}
if (di_prop_lookup_ints(DDI_DEV_T_ANY, thisnode,
"removable-media", &exists) > -1) {
logmsg(MSG_INFO,
"%s: not interested in removable media device\n"
"%s\n", driver, devpath);
FW_SD_FREE_DEVPATH(devpath)
continue;
}
if ((newdev = calloc(1, sizeof (struct devicelist))) ==
NULL) {
logmsg(MSG_ERROR,
gettext("%s: identification function unable "
"to allocate space for device entry\n"),
driver);
libscsi_fini(handle);
FW_SD_FREE_DEVPATH(devpath)
return (FWFLASH_FAILURE);
}
if ((newdev->drvname = calloc(1, strlen(driver) + 1)) ==
NULL) {
logmsg(MSG_ERROR,
gettext("%s: Unable to allocate space to store a "
"driver name\n"), driver);
libscsi_fini(handle);
FW_SD_FREE_DEVICELIST(newdev, devpath)
return (FWFLASH_FAILURE);
}
(void) strlcpy(newdev->drvname, driver, strlen(driver) + 1);
if ((newdev->classname = calloc(1, strlen(driver) + 1)) ==
NULL) {
logmsg(MSG_ERROR,
gettext("%s: Unable to allocate space for a class "
"name\n"), drivername);
libscsi_fini(handle);
FW_SD_FREE_DRV_NAME(newdev, devpath)
return (FWFLASH_FAILURE);
}
(void) strlcpy(newdev->classname, driver, strlen(driver) + 1);
if ((newdev->access_devname = calloc(1, MAXPATHLEN)) == NULL) {
logmsg(MSG_ERROR,
gettext("%s: Unable to allocate space for a devfs "
"name\n"), driver);
libscsi_fini(handle);
FW_SD_FREE_CLS_NAME(newdev, devpath)
return (FWFLASH_FAILURE);
}
(void) snprintf(newdev->access_devname, MAXPATHLEN,
"%s%s:c,raw", sdfw_devprefix, devpath);
if ((target = libscsi_open(handle, NULL,
newdev->access_devname)) == NULL) {
(void) snprintf(newdev->access_devname, MAXPATHLEN,
"%s%s:a,raw", sdfw_devprefix, devpath);
if ((target = libscsi_open(handle, NULL,
newdev->access_devname)) == NULL) {
logmsg(MSG_INFO,
"%s: unable to open device %s\n",
newdev->drvname, newdev->access_devname);
FW_SD_FREE_ACC_NAME(newdev, devpath)
continue;
}
}
if ((newdev->addresses[0] = sdfw_find_link(thisnode,
newdev->access_devname)) == NULL) {
libscsi_fini(handle);
FW_SD_FREE_ACC_NAME(newdev, devpath)
return (FWFLASH_FAILURE);
}
if ((newdev->ident = calloc(1, sizeof (struct vpr))) == NULL) {
logmsg(MSG_ERROR,
gettext("%s: Unable to allocate space for SCSI "
"INQUIRY data\n"), driver);
libscsi_fini(handle);
FW_SD_FREE_ADDR(newdev, devpath)
return (FWFLASH_FAILURE);
}
sp_temp = (char *)libscsi_vendor(target);
if (strncmp(sp_temp, "ATA", 3) == 0) {
fw_sata_disk = 1;
} else {
fw_sata_disk = 0;
if ((newdev->ident->vid =
calloc(1, strlen(sp_temp) + 1)) == NULL ||
sp_temp == NULL) {
if (!sp_temp) {
logmsg(MSG_ERROR, gettext("%s: unable "
"to get vendor id of %s\n"),
newdev->drvname,
newdev->access_devname);
} else {
logmsg(MSG_ERROR, gettext("Memory "
"allocation failure\n"));
}
libscsi_close(handle, target);
libscsi_fini(handle);
FW_SD_FREE_IDENT(newdev, devpath)
return (FWFLASH_FAILURE);
}
strlcpy(newdev->ident->vid, sp_temp,
strlen(sp_temp) + 1);
}
sp_temp = (char *)libscsi_product(target);
if (fw_sata_disk) {
sp_temp_cut = strchr(sp_temp, ' ');
if (!sp_temp_cut) {
if (sdfw_idtfy_custmz(newdev, sp_temp)
!= FWFLASH_SUCCESS) {
libscsi_close(handle, target);
libscsi_fini(handle);
FW_SD_FREE_IDENT(newdev, devpath)
return (FWFLASH_FAILURE);
}
} else {
if ((newdev->ident->vid = calloc(1,
(sp_temp_cut - sp_temp + 1))) == NULL) {
logmsg(MSG_ERROR, gettext("%s: unable "
"to get sata vendor id of %s\n"),
newdev->drvname,
newdev->access_devname);
libscsi_close(handle, target);
libscsi_fini(handle);
FW_SD_FREE_IDENT(newdev, devpath)
return (FWFLASH_FAILURE);
}
strlcpy(newdev->ident->vid, sp_temp,
sp_temp_cut - sp_temp + 1);
if ((newdev->ident->pid =
calloc(1, strlen(sp_temp) -
strlen(newdev->ident->vid))) == NULL) {
logmsg(MSG_ERROR, gettext("%s: unable "
"to get sata product id of %s\n"),
newdev->drvname,
newdev->access_devname);
libscsi_close(handle, target);
libscsi_fini(handle);
FW_SD_FREE_IDENT_VID(newdev, devpath)
return (FWFLASH_FAILURE);
}
strlcpy(newdev->ident->pid, sp_temp_cut + 1,
strlen(sp_temp) -
strlen(newdev->ident->vid));
}
} else {
if ((newdev->ident->pid =
calloc(1, strlen(sp_temp) + 1)) == NULL ||
sp_temp == NULL) {
logmsg(MSG_ERROR, gettext("%s: unable to get "
"product id of %s\n"), newdev->drvname,
newdev->access_devname);
FW_SD_FREE_IDENT_VID(newdev, devpath)
libscsi_close(handle, target);
libscsi_fini(handle);
return (FWFLASH_FAILURE);
}
strlcpy(newdev->ident->pid, sp_temp,
strlen(sp_temp) + 1);
}
sp_temp = (char *)libscsi_revision(target);
if ((newdev->ident->revid = calloc(1, strlen(sp_temp) + 1)) ==
NULL || sp_temp == NULL) {
logmsg(MSG_ERROR, gettext("%s: unable to get revision "
"id of %s\n"), newdev->drvname,
newdev->access_devname);
libscsi_close(handle, target);
libscsi_fini(handle);
FW_SD_FREE_IDENT_PID(newdev, devpath)
return (FWFLASH_FAILURE);
}
strlcpy(newdev->ident->revid, sp_temp, strlen(sp_temp) + 1);
libscsi_close(handle, target);
if (di_prop_lookup_strings(DDI_DEV_T_ANY, thisnode,
"inquiry-serial-no", &newdev->addresses[1]) < 0) {
logmsg(MSG_INFO,
"%s: no inquiry-serial-no property for %s\n",
driver, newdev->access_devname);
logmsg(MSG_INFO, "The errno is %d\n", errno);
}
if ((di_prop_lookup_strings(DDI_DEV_T_ANY, thisnode,
"client-guid", &newdev->addresses[2])) < 0) {
logmsg(MSG_INFO,
"%s: no client-guid property "
"for device %s\n",
driver, newdev->access_devname);
if ((di_prop_lookup_strings(DDI_DEV_T_ANY, thisnode,
"guid", &newdev->addresses[2])) < 0) {
logmsg(MSG_INFO,
"%s: no guid property for device %s\n",
driver, newdev->access_devname);
}
} else {
logmsg(MSG_INFO,
"client-guid property: %s\n",
newdev->addresses[2]);
}
newdev->index = idx;
++idx;
newdev->plugin = self;
TAILQ_INSERT_TAIL(fw_devices, newdev, nextdev);
FW_SD_FREE_DEVPATH(devpath)
}
libscsi_fini(handle);
if (idx == start)
return (FWFLASH_FAILURE);
if (fwflash_debug != 0) {
struct devicelist *tempdev;
TAILQ_FOREACH(tempdev, fw_devices, nextdev) {
logmsg(MSG_INFO, "%s:fw_identify:\n",
driver);
logmsg(MSG_INFO,
"\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\taddress[2]: %s\n"
"\t\tplugin @ 0x%lx\n\n",
&tempdev,
tempdev->access_devname,
tempdev->drvname, newdev->classname,
tempdev->ident->vid,
tempdev->ident->pid,
tempdev->ident->revid,
tempdev->index,
tempdev->addresses[0],
(tempdev->addresses[1] ? tempdev->addresses[1] :
"(not supported)"),
(tempdev->addresses[2] ? tempdev->addresses[2] :
"(not supported)"),
&tempdev->plugin);
}
}
return (FWFLASH_SUCCESS);
}
int
fw_devinfo(struct devicelist *thisdev)
{
fprintf(stdout, gettext("Device[%d]\t\t\t%s\n"
" Class [%s]\t\t\t%s\n"),
thisdev->index, thisdev->access_devname,
thisdev->classname, thisdev->addresses[0]);
fprintf(stdout,
gettext(
"\tVendor\t\t\t: %s\n"
"\tProduct\t\t\t: %s\n"
"\tFirmware revision\t: %-s\n"
"\tInquiry Serial Number : %-s\n"
"\tGUID\t\t\t: %s\n"),
thisdev->ident->vid,
thisdev->ident->pid,
thisdev->ident->revid,
(thisdev->addresses[1] ? thisdev->addresses[1] :
"(not supported)"),
(thisdev->addresses[2] ? thisdev->addresses[2] :
"(not supported)"));
fprintf(stdout, "\n\n");
return (FWFLASH_SUCCESS);
}
void
fw_cleanup(struct devicelist *thisdev)
{
free(thisdev->access_devname);
free(thisdev->drvname);
free(thisdev->classname);
free(thisdev->addresses[0]);
thisdev->plugin = NULL;
free(thisdev->ident->vid);
free(thisdev->ident->pid);
free(thisdev->ident->revid);
thisdev->ident = NULL;
}
static int
sdfw_link_cb(di_devlink_t devlink, void *arg)
{
const char *result;
result = di_devlink_path(devlink);
if (result == NULL) {
arg = (void *)"(null)";
} else {
(void) strlcpy(arg, result, strlen(result) + 1);
}
logmsg(MSG_INFO, "\nsdfw_link_cb::linkdata->resultstr = %s\n",
((result != NULL) ? result : "(null)"));
return (DI_WALK_CONTINUE);
}
static char *
sdfw_find_link(di_node_t bnode, char *acc_devname)
{
di_minor_t devminor = DI_MINOR_NIL;
di_devlink_handle_t hdl;
char *cbresult = NULL;
char linkname[] = "^rdsk/\0";
if (bnode == DI_NODE_NIL) {
logmsg(MSG_ERROR,
gettext("sdfw_find_link must be called with non-null "
"di_node_t\n"));
return (NULL);
}
if ((cbresult = calloc(1, MAXPATHLEN)) == NULL) {
logmsg(MSG_ERROR, gettext("unable to allocate space for dev "
"link\n"));
return (NULL);
}
devminor = di_minor_next(bnode, devminor);
errno = 0;
hdl = di_devlink_init(di_devfs_minor_path(devminor), DI_MAKE_LINK);
if (hdl == NULL) {
if (errno == EPERM || errno == EACCES) {
logmsg(MSG_ERROR,
gettext("%s: You must be super-user to use this "
"plugin.\n"), drivername);
} else {
logmsg(MSG_ERROR,
gettext("unable to take devlink snapshot: %s\n"),
strerror(errno));
}
free(cbresult);
return (NULL);
}
errno = 0;
if (di_devlink_walk(hdl, linkname, acc_devname + strlen(sdfw_devprefix),
DI_PRIMARY_LINK, (void *)cbresult, sdfw_link_cb) < 0) {
logmsg(MSG_ERROR,
gettext("Unable to walk devlink snapshot for %s: %s\n"),
acc_devname, strerror(errno));
free(cbresult);
return (NULL);
}
if (di_devlink_fini(&hdl) < 0) {
logmsg(MSG_ERROR,
gettext("Unable to close devlink snapshot: %s\n"),
strerror(errno));
}
logmsg(MSG_INFO, "cbresult: %s\n", cbresult);
return (cbresult);
}
static int
sdfw_idtfy_custmz(struct devicelist *device, char *sp)
{
if (strncmp(sp, "ST", 2) == 0) {
if ((device->ident->vid = strdup("SEAGATE")) == NULL) {
return (FWFLASH_FAILURE);
}
} else if (strncmp(sp, "SSD", 3) == 0) {
if ((device->ident->vid = strdup("INTEL")) == NULL) {
return (FWFLASH_FAILURE);
}
} else {
if ((device->ident->vid = strdup("ATA")) == NULL) {
return (FWFLASH_FAILURE);
}
}
if ((device->ident->pid = calloc(1, strlen(sp) + 1)) == NULL) {
logmsg(MSG_ERROR, gettext("Unable to allocate space for "
"product id\n"));
free(device->ident->vid);
return (FWFLASH_FAILURE);
}
strlcpy(device->ident->pid, sp, strlen(sp) + 1);
return (FWFLASH_SUCCESS);
}