xref: /onnv-gate/usr/src/cmd/fwflash/plugins/transport/common/sd.c (revision 10869:a0eba84ac81d)
19683SXin.Chen@Sun.COM /*
29683SXin.Chen@Sun.COM  * CDDL HEADER START
39683SXin.Chen@Sun.COM  *
49683SXin.Chen@Sun.COM  * The contents of this file are subject to the terms of the
59683SXin.Chen@Sun.COM  * Common Development and Distribution License (the "License").
69683SXin.Chen@Sun.COM  * You may not use this file except in compliance with the License.
79683SXin.Chen@Sun.COM  *
89683SXin.Chen@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99683SXin.Chen@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109683SXin.Chen@Sun.COM  * See the License for the specific language governing permissions
119683SXin.Chen@Sun.COM  * and limitations under the License.
129683SXin.Chen@Sun.COM  *
139683SXin.Chen@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149683SXin.Chen@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159683SXin.Chen@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169683SXin.Chen@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179683SXin.Chen@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189683SXin.Chen@Sun.COM  *
199683SXin.Chen@Sun.COM  * CDDL HEADER END
209683SXin.Chen@Sun.COM  */
219683SXin.Chen@Sun.COM /*
229683SXin.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
239683SXin.Chen@Sun.COM  * Use is subject to license terms.
249683SXin.Chen@Sun.COM  */
259683SXin.Chen@Sun.COM 
269683SXin.Chen@Sun.COM /*
279683SXin.Chen@Sun.COM  * sd / ssd (SCSI Direct-attached Device) specific functions.
289683SXin.Chen@Sun.COM  */
299683SXin.Chen@Sun.COM #include <libnvpair.h>
309683SXin.Chen@Sun.COM #include <stdio.h>
319683SXin.Chen@Sun.COM #include <stdlib.h>
329683SXin.Chen@Sun.COM #include <unistd.h>
339683SXin.Chen@Sun.COM #include <sys/types.h>
349683SXin.Chen@Sun.COM #include <sys/sysmacros.h>
359683SXin.Chen@Sun.COM #include <sys/queue.h>
369683SXin.Chen@Sun.COM #include <fcntl.h>
379683SXin.Chen@Sun.COM #include <string.h>
389683SXin.Chen@Sun.COM #include <errno.h>
399683SXin.Chen@Sun.COM #include <scsi/libscsi.h>
409683SXin.Chen@Sun.COM #include <libintl.h> /* for gettext(3c) */
419683SXin.Chen@Sun.COM #include <fwflash/fwflash.h>
429683SXin.Chen@Sun.COM 
439683SXin.Chen@Sun.COM typedef struct sam4_statdesc {
449683SXin.Chen@Sun.COM 	int status;
459683SXin.Chen@Sun.COM 	char *message;
469683SXin.Chen@Sun.COM } sam4_statdesc_t;
479683SXin.Chen@Sun.COM 
489683SXin.Chen@Sun.COM static sam4_statdesc_t sam4_status[] = {
499683SXin.Chen@Sun.COM 	{ SAM4_STATUS_GOOD, "Status: GOOD (success)" },
509683SXin.Chen@Sun.COM 	{ SAM4_STATUS_CHECK_CONDITION, "Status: CHECK CONDITION" },
519683SXin.Chen@Sun.COM 	{ SAM4_STATUS_CONDITION_MET, "Status: CONDITION MET" },
529683SXin.Chen@Sun.COM 	{ SAM4_STATUS_BUSY, "Status: Device is BUSY" },
539683SXin.Chen@Sun.COM 	{ SAM4_STATUS_RESERVATION_CONFLICT, "Status: Device is RESERVED" },
549683SXin.Chen@Sun.COM 	{ SAM4_STATUS_TASK_SET_FULL,
559683SXin.Chen@Sun.COM 	    "Status: TASK SET FULL (insufficient resources in command queue" },
569683SXin.Chen@Sun.COM 	{ SAM4_STATUS_TASK_ABORTED, "Status: TASK ABORTED" },
579683SXin.Chen@Sun.COM 	{ NULL, NULL }
589683SXin.Chen@Sun.COM };
599683SXin.Chen@Sun.COM 
609683SXin.Chen@Sun.COM #define	NSAM4_STATUS	\
619683SXin.Chen@Sun.COM 	(sizeof (sam4_status) / sizeof (sam4_status[0]))
629683SXin.Chen@Sun.COM 
639683SXin.Chen@Sun.COM #define	FW_SD_FREE_DEVPATH(devpath)	{	\
649683SXin.Chen@Sun.COM 		di_devfs_path_free((devpath));	\
659683SXin.Chen@Sun.COM 	}
669683SXin.Chen@Sun.COM #define	FW_SD_FREE_DEVICELIST(thisdev, devpath) {	\
679683SXin.Chen@Sun.COM 		free((thisdev));	\
689683SXin.Chen@Sun.COM 		FW_SD_FREE_DEVPATH((devpath))	\
699683SXin.Chen@Sun.COM 	}
709683SXin.Chen@Sun.COM #define	FW_SD_FREE_DRV_NAME(thisdev, devpath) {	\
719683SXin.Chen@Sun.COM 		free((thisdev)->drvname);	\
729974SXin.Chen@Sun.COM 		FW_SD_FREE_DEVICELIST((thisdev), (devpath))	\
739683SXin.Chen@Sun.COM 	}
749683SXin.Chen@Sun.COM #define	FW_SD_FREE_CLS_NAME(thisdev, devpath) {	\
759683SXin.Chen@Sun.COM 		free((thisdev)->classname);	\
769683SXin.Chen@Sun.COM 		FW_SD_FREE_DRV_NAME((thisdev), (devpath))	\
779683SXin.Chen@Sun.COM 	}
789974SXin.Chen@Sun.COM #define	FW_SD_FREE_ACC_NAME(thisdev, devpath) {	\
799974SXin.Chen@Sun.COM 		free((thisdev)->access_devname);	\
809974SXin.Chen@Sun.COM 		FW_SD_FREE_CLS_NAME(thisdev, devpath)	\
819974SXin.Chen@Sun.COM 	}
829974SXin.Chen@Sun.COM #define	FW_SD_FREE_ADDR(thisdev, devpath) {	\
839974SXin.Chen@Sun.COM 		free((thisdev)->addresses[0]);	\
849974SXin.Chen@Sun.COM 		FW_SD_FREE_ACC_NAME(thisdev, devpath)	\
859974SXin.Chen@Sun.COM 	}
869683SXin.Chen@Sun.COM #define	FW_SD_FREE_IDENT(thisdev, devpath) {	\
879683SXin.Chen@Sun.COM 		free((thisdev)->ident);	\
889974SXin.Chen@Sun.COM 		FW_SD_FREE_ADDR((thisdev), (devpath))	\
899683SXin.Chen@Sun.COM 	}
909683SXin.Chen@Sun.COM #define	FW_SD_FREE_IDENT_VID(thisdev, devpath) {	\
919683SXin.Chen@Sun.COM 		free((thisdev)->ident->vid);	\
929683SXin.Chen@Sun.COM 		FW_SD_FREE_IDENT((thisdev), (devpath))	\
939683SXin.Chen@Sun.COM 	}
949683SXin.Chen@Sun.COM #define	FW_SD_FREE_IDENT_PID(thisdev, devpath) {	\
959683SXin.Chen@Sun.COM 		free((thisdev)->ident->pid);	\
969683SXin.Chen@Sun.COM 		FW_SD_FREE_IDENT_VID((thisdev), (devpath))	\
979683SXin.Chen@Sun.COM 	}
989683SXin.Chen@Sun.COM #define	FW_SD_FREE_IDENT_ALL(thisdev, devpath) {	\
999683SXin.Chen@Sun.COM 		free((thisdev)->ident->revid);	\
1009683SXin.Chen@Sun.COM 		FW_SD_FREE_IDENT_PID((thisdev), (devpath))	\
1019683SXin.Chen@Sun.COM 	}
1029683SXin.Chen@Sun.COM 
1039683SXin.Chen@Sun.COM int errno;
1049683SXin.Chen@Sun.COM char drivername[] = "sd\0";
1059683SXin.Chen@Sun.COM int plugin_version = FWPLUGIN_VERSION_2;
1069683SXin.Chen@Sun.COM 
1079683SXin.Chen@Sun.COM static char *devprefix = "/devices";
1089683SXin.Chen@Sun.COM extern di_node_t rootnode;
1099683SXin.Chen@Sun.COM extern struct fw_plugin *self;
1109683SXin.Chen@Sun.COM extern struct vrfyplugin *verifier;
1119683SXin.Chen@Sun.COM extern int fwflash_debug;
1129683SXin.Chen@Sun.COM 
1139683SXin.Chen@Sun.COM /* required functions for this plugin */
1149683SXin.Chen@Sun.COM int fw_readfw(struct devicelist *device, char *filename);
1159683SXin.Chen@Sun.COM int fw_writefw(struct devicelist *device);
1169683SXin.Chen@Sun.COM int fw_identify(int start);
1179683SXin.Chen@Sun.COM int fw_devinfo(struct devicelist *thisdev);
1189683SXin.Chen@Sun.COM void fw_cleanup(struct devicelist *thisdev);
1199683SXin.Chen@Sun.COM 
1209683SXin.Chen@Sun.COM /* helper functions */
1219974SXin.Chen@Sun.COM static char *find_link(di_node_t bnode, char *acc_devname);
1229683SXin.Chen@Sun.COM static int link_cb(di_devlink_t devlink, void *arg);
1239683SXin.Chen@Sun.COM static int sd_idtfy_custmz(struct devicelist *device, char *sp);
1249683SXin.Chen@Sun.COM 
1259683SXin.Chen@Sun.COM /*
1269683SXin.Chen@Sun.COM  * We don't currently support reading firmware from a disk. If we do eventually
1279683SXin.Chen@Sun.COM  * support it, we would use the scsi READ BUFFER command to do so.
1289683SXin.Chen@Sun.COM  */
1299683SXin.Chen@Sun.COM int
fw_readfw(struct devicelist * flashdev,char * filename)1309683SXin.Chen@Sun.COM fw_readfw(struct devicelist *flashdev, char *filename)
1319683SXin.Chen@Sun.COM {
1329683SXin.Chen@Sun.COM 
1339683SXin.Chen@Sun.COM 	logmsg(MSG_INFO,
1349683SXin.Chen@Sun.COM 	    "%s: not writing firmware for device %s to file %s\n",
1359683SXin.Chen@Sun.COM 	    flashdev->drvname, flashdev->access_devname, filename);
1369683SXin.Chen@Sun.COM 	logmsg(MSG_ERROR,
1379683SXin.Chen@Sun.COM 	    gettext("\n\nReading of firmware images from %s-attached "
1389683SXin.Chen@Sun.COM 	    "devices is not supported\n\n"),
1399683SXin.Chen@Sun.COM 	    flashdev->drvname);
1409683SXin.Chen@Sun.COM 
1419683SXin.Chen@Sun.COM 	return (FWFLASH_SUCCESS);
1429683SXin.Chen@Sun.COM }
1439683SXin.Chen@Sun.COM 
1449683SXin.Chen@Sun.COM int
fw_writefw(struct devicelist * flashdev)1459683SXin.Chen@Sun.COM fw_writefw(struct devicelist *flashdev)
1469683SXin.Chen@Sun.COM {
1479683SXin.Chen@Sun.COM 	int rv;
1489683SXin.Chen@Sun.COM 	int i = 0;
1499683SXin.Chen@Sun.COM 	libscsi_hdl_t	*handle;
1509683SXin.Chen@Sun.COM 	libscsi_target_t *target;
1519683SXin.Chen@Sun.COM 	libscsi_action_t *action;
1529683SXin.Chen@Sun.COM 	libscsi_errno_t serr;
1539683SXin.Chen@Sun.COM 	spc3_write_buffer_cdb_t *wb_cdb;
1549683SXin.Chen@Sun.COM 	sam4_status_t samstatus;
1559683SXin.Chen@Sun.COM 
1569683SXin.Chen@Sun.COM 	if ((verifier == NULL) || (verifier->imgsize == 0) ||
1579683SXin.Chen@Sun.COM 	    (verifier->fwimage == NULL)) {
1589683SXin.Chen@Sun.COM 		/* should _NOT_ happen */
1599683SXin.Chen@Sun.COM 		logmsg(MSG_ERROR,
1609683SXin.Chen@Sun.COM 		    gettext("%s: Firmware image has not been verified\n"),
1619683SXin.Chen@Sun.COM 		    flashdev->drvname);
1629683SXin.Chen@Sun.COM 		return (FWFLASH_FAILURE);
1639683SXin.Chen@Sun.COM 	}
1649683SXin.Chen@Sun.COM 
1659683SXin.Chen@Sun.COM 	if ((handle = libscsi_init(LIBSCSI_VERSION, &serr)) == NULL) {
1669683SXin.Chen@Sun.COM 		logmsg(MSG_ERROR, gettext("%s: failed to initialize libscsi\n"),
1679683SXin.Chen@Sun.COM 		    flashdev->drvname);
1689683SXin.Chen@Sun.COM 		return (FWFLASH_FAILURE);
1699683SXin.Chen@Sun.COM 	}
1709683SXin.Chen@Sun.COM 
1719683SXin.Chen@Sun.COM 	if ((target = libscsi_open(handle, NULL, flashdev->access_devname))
1729683SXin.Chen@Sun.COM 	    == NULL) {
1739683SXin.Chen@Sun.COM 		logmsg(MSG_ERROR,
1749683SXin.Chen@Sun.COM 		    gettext("%s: unable to open device %s\n"),
1759683SXin.Chen@Sun.COM 		    flashdev->drvname, flashdev->access_devname);
1769683SXin.Chen@Sun.COM 		libscsi_fini(handle);
1779683SXin.Chen@Sun.COM 		return (FWFLASH_FAILURE);
1789683SXin.Chen@Sun.COM 	}
1799683SXin.Chen@Sun.COM 
1809683SXin.Chen@Sun.COM 	action = libscsi_action_alloc(handle, SPC3_CMD_WRITE_BUFFER,
1819683SXin.Chen@Sun.COM 	    LIBSCSI_AF_WRITE|LIBSCSI_AF_RQSENSE,
1829683SXin.Chen@Sun.COM 	    (void *)verifier->fwimage, (size_t)verifier->imgsize);
1839683SXin.Chen@Sun.COM 
1849683SXin.Chen@Sun.COM 	wb_cdb = (spc3_write_buffer_cdb_t *)libscsi_action_get_cdb(action);
1859683SXin.Chen@Sun.COM 
1869683SXin.Chen@Sun.COM 	wb_cdb->wbc_mode = SPC3_WB_MODE_DL_UCODE_SAVE;
1879683SXin.Chen@Sun.COM 	wb_cdb->wbc_bufferid = verifier->flashbuf;
1889683SXin.Chen@Sun.COM 
1899683SXin.Chen@Sun.COM 	wb_cdb->wbc_buffer_offset[0] = 0;
1909683SXin.Chen@Sun.COM 	wb_cdb->wbc_buffer_offset[1] = 0;
1919683SXin.Chen@Sun.COM 	wb_cdb->wbc_buffer_offset[2] = 0;
1929683SXin.Chen@Sun.COM 
1939683SXin.Chen@Sun.COM 	wb_cdb->wbc_parameter_list_len[0] =
1949683SXin.Chen@Sun.COM 	    (verifier->imgsize & 0xff0000) >> 16;
1959683SXin.Chen@Sun.COM 	wb_cdb->wbc_parameter_list_len[1] = (verifier->imgsize & 0xff00) >> 8;
1969683SXin.Chen@Sun.COM 	wb_cdb->wbc_parameter_list_len[2] = (verifier->imgsize & 0xff);
1979683SXin.Chen@Sun.COM 
1989683SXin.Chen@Sun.COM 	rv = libscsi_exec(action, target);
1999683SXin.Chen@Sun.COM 	samstatus = libscsi_action_get_status(action);
2009683SXin.Chen@Sun.COM 
2019683SXin.Chen@Sun.COM 	logmsg(MSG_INFO, "\nscsi_writebuffer: ret 0x%0x, samstatus 0x%0x\n",
2029683SXin.Chen@Sun.COM 	    rv, samstatus);
2039683SXin.Chen@Sun.COM 
2049683SXin.Chen@Sun.COM 	libscsi_action_free(action);
2059683SXin.Chen@Sun.COM 	libscsi_close(handle, target);
2069683SXin.Chen@Sun.COM 	libscsi_fini(handle);
2079683SXin.Chen@Sun.COM 
2089683SXin.Chen@Sun.COM 	if (rv != FWFLASH_SUCCESS)
2099683SXin.Chen@Sun.COM 		return (FWFLASH_FAILURE);
2109683SXin.Chen@Sun.COM 
2119683SXin.Chen@Sun.COM 	for (i = 0; i < NSAM4_STATUS; i++) {
2129683SXin.Chen@Sun.COM 		if (sam4_status[i].status == samstatus) {
2139683SXin.Chen@Sun.COM 			logmsg(MSG_ERROR, gettext("RETURN STATUS: %s\n"),
2149683SXin.Chen@Sun.COM 			    (sam4_status[i].message));
2159683SXin.Chen@Sun.COM 			break;
2169683SXin.Chen@Sun.COM 		}
2179683SXin.Chen@Sun.COM 	}
2189683SXin.Chen@Sun.COM 	if (i == NSAM4_STATUS)
2199683SXin.Chen@Sun.COM 		logmsg(MSG_ERROR, gettext("Status UNKNOWN\n"));
2209683SXin.Chen@Sun.COM 
2219683SXin.Chen@Sun.COM 	if (samstatus == SAM4_STATUS_GOOD) {
2229683SXin.Chen@Sun.COM 		logmsg(MSG_ERROR, gettext("Note: For flash based disks "
2239683SXin.Chen@Sun.COM 		    "(SSD, etc). You may need power off the system to wait a "
2249683SXin.Chen@Sun.COM 		    "few minutes for supercap to fully discharge, then power "
2259683SXin.Chen@Sun.COM 		    "on the system again to activate the new firmware\n"));
2269683SXin.Chen@Sun.COM 		return (FWFLASH_SUCCESS);
2279683SXin.Chen@Sun.COM 	}
2289683SXin.Chen@Sun.COM 	return (FWFLASH_FAILURE);
2299683SXin.Chen@Sun.COM }
2309683SXin.Chen@Sun.COM 
2319683SXin.Chen@Sun.COM /*
2329683SXin.Chen@Sun.COM  * The fw_identify() function walks the device
2339683SXin.Chen@Sun.COM  * tree trying to find devices which this plugin
2349683SXin.Chen@Sun.COM  * can work with.
2359683SXin.Chen@Sun.COM  *
2369683SXin.Chen@Sun.COM  * The parameter "start" gives us the starting index number
2379683SXin.Chen@Sun.COM  * to give the device when we add it to the fw_devices list.
2389683SXin.Chen@Sun.COM  *
2399683SXin.Chen@Sun.COM  * firstdev is allocated by us and we add space as needed
2409683SXin.Chen@Sun.COM  *
2419683SXin.Chen@Sun.COM  * When we store the desired information, inquiry-serial-no
2429683SXin.Chen@Sun.COM  * goes in thisdev->addresses[1], and client-guid goes in
2439683SXin.Chen@Sun.COM  * thisdev->addresses[2].
2449683SXin.Chen@Sun.COM  */
2459683SXin.Chen@Sun.COM int
fw_identify(int start)2469683SXin.Chen@Sun.COM fw_identify(int start)
2479683SXin.Chen@Sun.COM {
2489683SXin.Chen@Sun.COM 	int idx = start;
2499683SXin.Chen@Sun.COM 	int fw_sata_disk = 0;
2509683SXin.Chen@Sun.COM 	int *exists;
2519683SXin.Chen@Sun.COM 	di_node_t thisnode;
2529683SXin.Chen@Sun.COM 	struct devicelist *newdev = NULL;
2539683SXin.Chen@Sun.COM 	char *devpath = NULL;
2549683SXin.Chen@Sun.COM 	char *driver = NULL;
2559683SXin.Chen@Sun.COM 	char *sp_temp;
2569683SXin.Chen@Sun.COM 	char *sp_temp_cut;
2579683SXin.Chen@Sun.COM 
2589683SXin.Chen@Sun.COM 	/* We need to inquiry information manually by sending probe command */
2599683SXin.Chen@Sun.COM 	libscsi_hdl_t *handle;
2609683SXin.Chen@Sun.COM 	libscsi_target_t *target;
2619683SXin.Chen@Sun.COM 	libscsi_errno_t serr;
2629683SXin.Chen@Sun.COM 
2639683SXin.Chen@Sun.COM 	/* Just in case we've got an FC-attached device on sparc */
2649683SXin.Chen@Sun.COM 	if (strcmp(self->drvname, "ssd") == 0) {
2659683SXin.Chen@Sun.COM 		driver = self->drvname;
2669683SXin.Chen@Sun.COM 	} else
2679683SXin.Chen@Sun.COM 		driver = drivername;
2689683SXin.Chen@Sun.COM 
2699683SXin.Chen@Sun.COM 	thisnode = di_drv_first_node(driver, rootnode);
2709683SXin.Chen@Sun.COM 
2719683SXin.Chen@Sun.COM 	if (thisnode == DI_NODE_NIL) {
2729683SXin.Chen@Sun.COM 		logmsg(MSG_INFO, "No %s nodes in this system\n", driver);
2739683SXin.Chen@Sun.COM 		return (FWFLASH_FAILURE);
2749683SXin.Chen@Sun.COM 	}
2759683SXin.Chen@Sun.COM 
2769683SXin.Chen@Sun.COM 	if ((handle = libscsi_init(LIBSCSI_VERSION, &serr)) == NULL) {
2779683SXin.Chen@Sun.COM 		logmsg(MSG_ERROR, gettext("%s: failed to initialize "
2789683SXin.Chen@Sun.COM 		    "libscsi\n"), newdev->drvname);
2799683SXin.Chen@Sun.COM 		return (FWFLASH_FAILURE);
2809683SXin.Chen@Sun.COM 	}
2819683SXin.Chen@Sun.COM 
2829683SXin.Chen@Sun.COM 	/* we've found one, at least */
2839683SXin.Chen@Sun.COM 	for (; thisnode != DI_NODE_NIL; thisnode = di_drv_next_node(thisnode)) {
2849974SXin.Chen@Sun.COM 		/* Need to free by di_devfs_path_free */
2859974SXin.Chen@Sun.COM 		if ((devpath = di_devfs_path(thisnode)) == NULL) {
2869974SXin.Chen@Sun.COM 			logmsg(MSG_INFO, "unable to get device path for "
2879974SXin.Chen@Sun.COM 			    "current node with errno %d\n", errno);
2889974SXin.Chen@Sun.COM 			continue;
289*10869SXin.Chen@Sun.COM 		}
2909683SXin.Chen@Sun.COM 		/*
2919683SXin.Chen@Sun.COM 		 * We check if this is removable device, in which case
2929683SXin.Chen@Sun.COM 		 * we really aren't interested, so exit stage left
2939683SXin.Chen@Sun.COM 		 */
2949683SXin.Chen@Sun.COM 		if (di_prop_lookup_ints(DDI_DEV_T_ANY, thisnode,
2959683SXin.Chen@Sun.COM 		    "removable-media", &exists) > -1) {
2969683SXin.Chen@Sun.COM 			logmsg(MSG_INFO,
2979683SXin.Chen@Sun.COM 			    "%s: not interested in removable media device\n"
2989683SXin.Chen@Sun.COM 			    "%s\n", driver, devpath);
2999974SXin.Chen@Sun.COM 			FW_SD_FREE_DEVPATH(devpath)
3009683SXin.Chen@Sun.COM 			continue;
3019683SXin.Chen@Sun.COM 		}
3029683SXin.Chen@Sun.COM 
3039683SXin.Chen@Sun.COM 		if ((newdev = calloc(1, sizeof (struct devicelist)))
3049683SXin.Chen@Sun.COM 		    == NULL) {
3059683SXin.Chen@Sun.COM 			logmsg(MSG_ERROR,
3069683SXin.Chen@Sun.COM 			    gettext("%s: identification function unable "
3079683SXin.Chen@Sun.COM 			    "to allocate space for device entry\n"),
3089683SXin.Chen@Sun.COM 			    driver);
3099683SXin.Chen@Sun.COM 			libscsi_fini(handle);
3109683SXin.Chen@Sun.COM 			FW_SD_FREE_DEVPATH(devpath)
3119683SXin.Chen@Sun.COM 			return (FWFLASH_FAILURE);
3129683SXin.Chen@Sun.COM 		}
3139683SXin.Chen@Sun.COM 
3149683SXin.Chen@Sun.COM 		if ((newdev->drvname = calloc(1, strlen(driver) + 1))
3159683SXin.Chen@Sun.COM 		    == NULL) {
3169683SXin.Chen@Sun.COM 			logmsg(MSG_ERROR,
3179683SXin.Chen@Sun.COM 			    gettext("%s: Unable to allocate space to store a "
3189683SXin.Chen@Sun.COM 			    "driver name\n"), driver);
3199683SXin.Chen@Sun.COM 			libscsi_fini(handle);
3209974SXin.Chen@Sun.COM 			FW_SD_FREE_DEVICELIST(newdev, devpath)
3219683SXin.Chen@Sun.COM 			return (FWFLASH_FAILURE);
3229683SXin.Chen@Sun.COM 		}
3239683SXin.Chen@Sun.COM 		(void) strlcpy(newdev->drvname, driver, strlen(driver) + 1);
3249683SXin.Chen@Sun.COM 
3259683SXin.Chen@Sun.COM 		if ((newdev->classname = calloc(1, strlen(driver) + 1))
3269683SXin.Chen@Sun.COM 		    == NULL) {
3279683SXin.Chen@Sun.COM 			logmsg(MSG_ERROR,
3289683SXin.Chen@Sun.COM 			    gettext("%s: Unable to allocate space for a class "
3299683SXin.Chen@Sun.COM 			    "name\n"), drivername);
3309683SXin.Chen@Sun.COM 			libscsi_fini(handle);
3319683SXin.Chen@Sun.COM 			FW_SD_FREE_DRV_NAME(newdev, devpath)
3329683SXin.Chen@Sun.COM 			return (FWFLASH_FAILURE);
3339683SXin.Chen@Sun.COM 		}
3349683SXin.Chen@Sun.COM 		(void) strlcpy(newdev->classname, driver, strlen(driver) + 1);
3359683SXin.Chen@Sun.COM 
3369974SXin.Chen@Sun.COM 		/* Get the access name for current node */
3379974SXin.Chen@Sun.COM 		if ((newdev->access_devname = calloc(1, MAXPATHLEN)) == NULL) {
3389974SXin.Chen@Sun.COM 			logmsg(MSG_ERROR,
3399974SXin.Chen@Sun.COM 			    gettext("%s: Unable to allocate space for a devfs "
3409974SXin.Chen@Sun.COM 			    "name\n"), driver);
3419974SXin.Chen@Sun.COM 			libscsi_fini(handle);
3429974SXin.Chen@Sun.COM 			FW_SD_FREE_CLS_NAME(newdev, devpath)
3439974SXin.Chen@Sun.COM 			return (FWFLASH_FAILURE);
3449974SXin.Chen@Sun.COM 		}
3459974SXin.Chen@Sun.COM 
3469974SXin.Chen@Sun.COM 		/* The slice number may be 2 or 0, we will try 2 first */
3479974SXin.Chen@Sun.COM 		(void) snprintf(newdev->access_devname, MAXPATHLEN,
3489974SXin.Chen@Sun.COM 		    "%s%s:c,raw", devprefix, devpath);
3499974SXin.Chen@Sun.COM 		if ((target = libscsi_open(handle, NULL,
3509974SXin.Chen@Sun.COM 		    newdev->access_devname)) == NULL) {
3519974SXin.Chen@Sun.COM 			/* try 0 for EFI label */
3529974SXin.Chen@Sun.COM 			(void) snprintf(newdev->access_devname, MAXPATHLEN,
3539974SXin.Chen@Sun.COM 			    "%s%s:a,raw", devprefix, devpath);
3549974SXin.Chen@Sun.COM 			if ((target = libscsi_open(handle, NULL,
3559974SXin.Chen@Sun.COM 			    newdev->access_devname)) == NULL) {
3569974SXin.Chen@Sun.COM 				logmsg(MSG_INFO,
3579974SXin.Chen@Sun.COM 				    "%s: unable to open device %s\n",
3589974SXin.Chen@Sun.COM 				    newdev->drvname, newdev->access_devname);
3599974SXin.Chen@Sun.COM 				FW_SD_FREE_ACC_NAME(newdev, devpath)
3609974SXin.Chen@Sun.COM 				continue;
3619974SXin.Chen@Sun.COM 			}
3629974SXin.Chen@Sun.COM 		}
3639974SXin.Chen@Sun.COM 
3649974SXin.Chen@Sun.COM 		/* and the /dev/rdsk/ name */
3659974SXin.Chen@Sun.COM 		if ((newdev->addresses[0] = find_link(thisnode,
3669974SXin.Chen@Sun.COM 		    newdev->access_devname)) == NULL) {
3679974SXin.Chen@Sun.COM 			libscsi_fini(handle);
3689974SXin.Chen@Sun.COM 			FW_SD_FREE_ACC_NAME(newdev, devpath)
3699974SXin.Chen@Sun.COM 			return (FWFLASH_FAILURE);
3709974SXin.Chen@Sun.COM 		}
3719974SXin.Chen@Sun.COM 
3729683SXin.Chen@Sun.COM 		/*
3739683SXin.Chen@Sun.COM 		 * Only alloc as much as we truly need, and DON'T forget
3749683SXin.Chen@Sun.COM 		 * that libdevinfo manages the memory!
3759683SXin.Chen@Sun.COM 		 */
3769683SXin.Chen@Sun.COM 		if ((newdev->ident = calloc(1, sizeof (struct vpr))) == NULL) {
3779683SXin.Chen@Sun.COM 			logmsg(MSG_ERROR,
3789683SXin.Chen@Sun.COM 			    gettext("%s: Unable to allocate space for SCSI "
3799683SXin.Chen@Sun.COM 			    "INQUIRY data\n"), driver);
3809683SXin.Chen@Sun.COM 			libscsi_fini(handle);
3819974SXin.Chen@Sun.COM 			FW_SD_FREE_ADDR(newdev, devpath)
3829683SXin.Chen@Sun.COM 			return (FWFLASH_FAILURE);
3839683SXin.Chen@Sun.COM 		}
3849683SXin.Chen@Sun.COM 
3859683SXin.Chen@Sun.COM 		/* We don't use new->ident->encap_ident currently */
3869683SXin.Chen@Sun.COM 
3879683SXin.Chen@Sun.COM 		/* Retrive information by using libscsi */
3889683SXin.Chen@Sun.COM 		/* Vendor ID */
3899683SXin.Chen@Sun.COM 		sp_temp = (char *)libscsi_vendor(target);
3909683SXin.Chen@Sun.COM 		if (strncmp(sp_temp, "ATA", 3) == 0) {
3919683SXin.Chen@Sun.COM 			/* We need to do customize the output for SATA disks */
3929683SXin.Chen@Sun.COM 			fw_sata_disk = 1;
3939683SXin.Chen@Sun.COM 		} else {
3949683SXin.Chen@Sun.COM 			fw_sata_disk = 0;
3959683SXin.Chen@Sun.COM 			if ((newdev->ident->vid =
3969683SXin.Chen@Sun.COM 			    calloc(1, strlen(sp_temp) + 1)) == NULL ||
3979683SXin.Chen@Sun.COM 			    sp_temp == NULL) {
3989683SXin.Chen@Sun.COM 				if (!sp_temp) {
3999683SXin.Chen@Sun.COM 					logmsg(MSG_ERROR, gettext("%s: unable "
4009683SXin.Chen@Sun.COM 					    "to get vendor id of %s\n"),
4019683SXin.Chen@Sun.COM 					    newdev->drvname,
4029683SXin.Chen@Sun.COM 					    newdev->access_devname);
4039683SXin.Chen@Sun.COM 				} else {
4049683SXin.Chen@Sun.COM 					logmsg(MSG_ERROR, gettext("Memory "
4059683SXin.Chen@Sun.COM 					    "allocation failure\n"));
4069683SXin.Chen@Sun.COM 				}
4079683SXin.Chen@Sun.COM 
4089683SXin.Chen@Sun.COM 				libscsi_close(handle, target);
4099683SXin.Chen@Sun.COM 				libscsi_fini(handle);
4109683SXin.Chen@Sun.COM 				FW_SD_FREE_IDENT(newdev, devpath)
4119683SXin.Chen@Sun.COM 				return (FWFLASH_FAILURE);
4129683SXin.Chen@Sun.COM 			}
4139683SXin.Chen@Sun.COM 			strlcpy(newdev->ident->vid, sp_temp,
4149683SXin.Chen@Sun.COM 			    strlen(sp_temp) + 1);
4159683SXin.Chen@Sun.COM 		}
4169683SXin.Chen@Sun.COM 
4179683SXin.Chen@Sun.COM 		/* Product ID */
4189683SXin.Chen@Sun.COM 		sp_temp = (char *)libscsi_product(target);
4199683SXin.Chen@Sun.COM 		if (fw_sata_disk) {
4209683SXin.Chen@Sun.COM 			sp_temp_cut = strchr(sp_temp, ' ');
4219683SXin.Chen@Sun.COM 			if (!sp_temp_cut) {
4229974SXin.Chen@Sun.COM 				/*
4239974SXin.Chen@Sun.COM 				 * There is no SPACE character in the PID field
4249974SXin.Chen@Sun.COM 				 * Customize strings for special SATA disks
4259974SXin.Chen@Sun.COM 				 */
4269683SXin.Chen@Sun.COM 				if (sd_idtfy_custmz(newdev, sp_temp)
4279683SXin.Chen@Sun.COM 				    != FWFLASH_SUCCESS) {
4289683SXin.Chen@Sun.COM 					libscsi_close(handle, target);
4299683SXin.Chen@Sun.COM 					libscsi_fini(handle);
4309683SXin.Chen@Sun.COM 					FW_SD_FREE_IDENT(newdev, devpath)
4319683SXin.Chen@Sun.COM 					return (FWFLASH_FAILURE);
4329683SXin.Chen@Sun.COM 				}
4339683SXin.Chen@Sun.COM 			} else {
4349683SXin.Chen@Sun.COM 				/* The first string is vendor id */
4359683SXin.Chen@Sun.COM 				if ((newdev->ident->vid = calloc(1,
4369683SXin.Chen@Sun.COM 				    (sp_temp_cut - sp_temp + 1))) == NULL) {
4379683SXin.Chen@Sun.COM 					logmsg(MSG_ERROR, gettext("%s: unable "
4389683SXin.Chen@Sun.COM 					    "to get sata vendor id of %s\n"),
4399683SXin.Chen@Sun.COM 					    newdev->drvname,
4409683SXin.Chen@Sun.COM 					    newdev->access_devname);
4419683SXin.Chen@Sun.COM 
4429683SXin.Chen@Sun.COM 					libscsi_close(handle, target);
4439683SXin.Chen@Sun.COM 					libscsi_fini(handle);
4449683SXin.Chen@Sun.COM 					FW_SD_FREE_IDENT(newdev, devpath)
4459683SXin.Chen@Sun.COM 					return (FWFLASH_FAILURE);
4469683SXin.Chen@Sun.COM 				}
4479683SXin.Chen@Sun.COM 				strlcpy(newdev->ident->vid, sp_temp,
4489683SXin.Chen@Sun.COM 				    sp_temp_cut - sp_temp + 1);
4499683SXin.Chen@Sun.COM 
4509683SXin.Chen@Sun.COM 				/* The second string is product id */
4519683SXin.Chen@Sun.COM 				if ((newdev->ident->pid =
4529683SXin.Chen@Sun.COM 				    calloc(1, strlen(sp_temp) -
4539683SXin.Chen@Sun.COM 				    strlen(newdev->ident->vid))) == NULL) {
4549683SXin.Chen@Sun.COM 					logmsg(MSG_ERROR, gettext("%s: unable "
4559683SXin.Chen@Sun.COM 					    "to get sata product id of %s\n"),
4569683SXin.Chen@Sun.COM 					    newdev->drvname,
4579683SXin.Chen@Sun.COM 					    newdev->access_devname);
4589683SXin.Chen@Sun.COM 
4599683SXin.Chen@Sun.COM 					libscsi_close(handle, target);
4609683SXin.Chen@Sun.COM 					libscsi_fini(handle);
4619683SXin.Chen@Sun.COM 					FW_SD_FREE_IDENT_VID(newdev, devpath)
4629683SXin.Chen@Sun.COM 					return (FWFLASH_FAILURE);
4639683SXin.Chen@Sun.COM 				}
4649683SXin.Chen@Sun.COM 				strlcpy(newdev->ident->pid, sp_temp_cut + 1,
4659683SXin.Chen@Sun.COM 				    strlen(sp_temp) -
4669683SXin.Chen@Sun.COM 				    strlen(newdev->ident->vid));
4679683SXin.Chen@Sun.COM 			}
4689683SXin.Chen@Sun.COM 		} else {
4699683SXin.Chen@Sun.COM 			if ((newdev->ident->pid =
4709683SXin.Chen@Sun.COM 			    calloc(1, strlen(sp_temp) + 1)) == NULL ||
4719683SXin.Chen@Sun.COM 			    sp_temp == NULL) {
4729683SXin.Chen@Sun.COM 				logmsg(MSG_ERROR, gettext("%s: unable to get "
4739683SXin.Chen@Sun.COM 				    "product id of %s\n"), newdev->drvname,
4749683SXin.Chen@Sun.COM 				    newdev->access_devname);
4759683SXin.Chen@Sun.COM 				FW_SD_FREE_IDENT_VID(newdev, devpath)
4769683SXin.Chen@Sun.COM 				libscsi_close(handle, target);
4779683SXin.Chen@Sun.COM 				libscsi_fini(handle);
4789683SXin.Chen@Sun.COM 				return (FWFLASH_FAILURE);
4799683SXin.Chen@Sun.COM 			}
4809683SXin.Chen@Sun.COM 			strlcpy(newdev->ident->pid, sp_temp,
4819683SXin.Chen@Sun.COM 			    strlen(sp_temp) + 1);
4829683SXin.Chen@Sun.COM 		}
4839683SXin.Chen@Sun.COM 
4849683SXin.Chen@Sun.COM 		/* Revision ID */
4859683SXin.Chen@Sun.COM 		sp_temp = (char *)libscsi_revision(target);
4869683SXin.Chen@Sun.COM 		if ((newdev->ident->revid = calloc(1, strlen(sp_temp) + 1))
4879683SXin.Chen@Sun.COM 		    == NULL || sp_temp == NULL) {
4889683SXin.Chen@Sun.COM 			logmsg(MSG_ERROR, gettext("%s: unable to get revision "
4899683SXin.Chen@Sun.COM 			    "id of %s\n"), newdev->drvname,
4909683SXin.Chen@Sun.COM 			    newdev->access_devname);
4919683SXin.Chen@Sun.COM 			libscsi_close(handle, target);
4929683SXin.Chen@Sun.COM 			libscsi_fini(handle);
4939683SXin.Chen@Sun.COM 			FW_SD_FREE_IDENT_PID(newdev, devpath)
4949683SXin.Chen@Sun.COM 			return (FWFLASH_FAILURE);
4959683SXin.Chen@Sun.COM 		}
4969683SXin.Chen@Sun.COM 		strlcpy(newdev->ident->revid, sp_temp, strlen(sp_temp) + 1);
4979683SXin.Chen@Sun.COM 
4989683SXin.Chen@Sun.COM 		/* Finish using libscsi */
4999683SXin.Chen@Sun.COM 		libscsi_close(handle, target);
5009683SXin.Chen@Sun.COM 
5019683SXin.Chen@Sun.COM 		if (di_prop_lookup_strings(DDI_DEV_T_ANY, thisnode,
5029683SXin.Chen@Sun.COM 		    "inquiry-serial-no", &newdev->addresses[1]) < 0) {
5039683SXin.Chen@Sun.COM 			logmsg(MSG_INFO,
5049683SXin.Chen@Sun.COM 			    "%s: no inquiry-serial-no property for %s\n",
5059683SXin.Chen@Sun.COM 			    driver, newdev->access_devname);
5069683SXin.Chen@Sun.COM 			logmsg(MSG_INFO, "The errno is %d\n", errno);
5079683SXin.Chen@Sun.COM 		}
5089683SXin.Chen@Sun.COM 
5099683SXin.Chen@Sun.COM 		if ((di_prop_lookup_strings(DDI_DEV_T_ANY, thisnode,
5109683SXin.Chen@Sun.COM 		    "client-guid", &newdev->addresses[2])) < 0) {
5119683SXin.Chen@Sun.COM 			logmsg(MSG_INFO,
5129683SXin.Chen@Sun.COM 			    "%s: no client-guid property "
5139683SXin.Chen@Sun.COM 			    "for device %s\n",
5149683SXin.Chen@Sun.COM 			    driver, newdev->access_devname);
5159683SXin.Chen@Sun.COM 			/* try fallback */
5169683SXin.Chen@Sun.COM 			if ((di_prop_lookup_strings(DDI_DEV_T_ANY, thisnode,
5179683SXin.Chen@Sun.COM 			    "guid", &newdev->addresses[2])) < 0) {
5189683SXin.Chen@Sun.COM 				logmsg(MSG_INFO,
5199683SXin.Chen@Sun.COM 				    "%s: no guid property for device %s\n",
5209683SXin.Chen@Sun.COM 				    driver, newdev->access_devname);
5219683SXin.Chen@Sun.COM 			}
5229683SXin.Chen@Sun.COM 		} else {
5239683SXin.Chen@Sun.COM 			logmsg(MSG_INFO,
5249683SXin.Chen@Sun.COM 			    "client-guid property: %s\n",
5259683SXin.Chen@Sun.COM 			    newdev->addresses[2]);
5269683SXin.Chen@Sun.COM 		}
5279683SXin.Chen@Sun.COM 
5289683SXin.Chen@Sun.COM 		newdev->index = idx;
5299683SXin.Chen@Sun.COM 		++idx;
5309683SXin.Chen@Sun.COM 		newdev->plugin = self;
5319683SXin.Chen@Sun.COM 
5329683SXin.Chen@Sun.COM 		TAILQ_INSERT_TAIL(fw_devices, newdev, nextdev);
5339974SXin.Chen@Sun.COM 		FW_SD_FREE_DEVPATH(devpath)
5349683SXin.Chen@Sun.COM 	}
5359683SXin.Chen@Sun.COM 	libscsi_fini(handle);
5369683SXin.Chen@Sun.COM 
5379683SXin.Chen@Sun.COM 	/* Check if sd targets presented are all unflashable. */
5389683SXin.Chen@Sun.COM 	if (idx == start)
5399683SXin.Chen@Sun.COM 		return (FWFLASH_FAILURE);
5409683SXin.Chen@Sun.COM 
5419683SXin.Chen@Sun.COM 	if (fwflash_debug != 0) {
5429683SXin.Chen@Sun.COM 		struct devicelist *tempdev;
5439683SXin.Chen@Sun.COM 
5449683SXin.Chen@Sun.COM 		TAILQ_FOREACH(tempdev, fw_devices, nextdev) {
5459683SXin.Chen@Sun.COM 			logmsg(MSG_INFO, "%s:fw_identify:\n",
5469683SXin.Chen@Sun.COM 			    driver);
5479683SXin.Chen@Sun.COM 			logmsg(MSG_INFO,
5489683SXin.Chen@Sun.COM 			    "\ttempdev @ 0x%lx\n"
5499683SXin.Chen@Sun.COM 			    "\t\taccess_devname: %s\n"
5509683SXin.Chen@Sun.COM 			    "\t\tdrvname: %s\tclassname: %s\n"
5519683SXin.Chen@Sun.COM 			    "\t\tident->vid:   %s\n"
5529683SXin.Chen@Sun.COM 			    "\t\tident->pid:   %s\n"
5539683SXin.Chen@Sun.COM 			    "\t\tident->revid: %s\n"
5549683SXin.Chen@Sun.COM 			    "\t\tindex:	%d\n"
5559683SXin.Chen@Sun.COM 			    "\t\taddress[0]:   %s\n"
5569683SXin.Chen@Sun.COM 			    "\t\taddress[1]:   %s\n"
5579683SXin.Chen@Sun.COM 			    "\t\taddress[2]:   %s\n"
5589683SXin.Chen@Sun.COM 			    "\t\tplugin @ 0x%lx\n\n",
5599683SXin.Chen@Sun.COM 			    &tempdev,
5609683SXin.Chen@Sun.COM 			    tempdev->access_devname,
5619683SXin.Chen@Sun.COM 			    tempdev->drvname, newdev->classname,
5629683SXin.Chen@Sun.COM 			    tempdev->ident->vid,
5639683SXin.Chen@Sun.COM 			    tempdev->ident->pid,
5649683SXin.Chen@Sun.COM 			    tempdev->ident->revid,
5659683SXin.Chen@Sun.COM 			    tempdev->index,
5669683SXin.Chen@Sun.COM 			    tempdev->addresses[0],
5679683SXin.Chen@Sun.COM 			    (tempdev->addresses[1] ? tempdev->addresses[1] :
5689683SXin.Chen@Sun.COM 			    "(not supported)"),
5699683SXin.Chen@Sun.COM 			    (tempdev->addresses[2] ? tempdev->addresses[2] :
5709683SXin.Chen@Sun.COM 			    "(not supported)"),
5719683SXin.Chen@Sun.COM 			    &tempdev->plugin);
5729683SXin.Chen@Sun.COM 		}
5739683SXin.Chen@Sun.COM 	}
5749683SXin.Chen@Sun.COM 	return (FWFLASH_SUCCESS);
5759683SXin.Chen@Sun.COM }
5769683SXin.Chen@Sun.COM 
5779683SXin.Chen@Sun.COM int
fw_devinfo(struct devicelist * thisdev)5789683SXin.Chen@Sun.COM fw_devinfo(struct devicelist *thisdev)
5799683SXin.Chen@Sun.COM {
5809683SXin.Chen@Sun.COM 	fprintf(stdout, gettext("Device[%d]\t\t\t%s\n"
5819683SXin.Chen@Sun.COM 	    "  Class [%s]\t\t\t%s\n"),
5829683SXin.Chen@Sun.COM 	    thisdev->index, thisdev->access_devname,
5839683SXin.Chen@Sun.COM 	    thisdev->classname, thisdev->addresses[0]);
5849683SXin.Chen@Sun.COM 
5859683SXin.Chen@Sun.COM 	fprintf(stdout,
5869683SXin.Chen@Sun.COM 	    gettext(
5879683SXin.Chen@Sun.COM 	    "\tVendor\t\t\t: %s\n"
5889683SXin.Chen@Sun.COM 	    "\tProduct\t\t\t: %s\n"
5899683SXin.Chen@Sun.COM 	    "\tFirmware revision\t: %-s\n"
5909683SXin.Chen@Sun.COM 	    "\tInquiry Serial Number   : %-s\n"
5919683SXin.Chen@Sun.COM 	    "\tGUID\t\t\t: %s\n"),
5929683SXin.Chen@Sun.COM 	    thisdev->ident->vid,
5939683SXin.Chen@Sun.COM 	    thisdev->ident->pid,
5949683SXin.Chen@Sun.COM 	    thisdev->ident->revid,
5959683SXin.Chen@Sun.COM 	    (thisdev->addresses[1] ? thisdev->addresses[1] :
5969683SXin.Chen@Sun.COM 	    "(not supported)"),
5979683SXin.Chen@Sun.COM 	    (thisdev->addresses[2] ? thisdev->addresses[2] :
5989683SXin.Chen@Sun.COM 	    "(not supported)"));
5999683SXin.Chen@Sun.COM 
6009683SXin.Chen@Sun.COM 	fprintf(stdout, "\n\n");
6019683SXin.Chen@Sun.COM 
6029683SXin.Chen@Sun.COM 	return (FWFLASH_SUCCESS);
6039683SXin.Chen@Sun.COM }
6049683SXin.Chen@Sun.COM 
6059683SXin.Chen@Sun.COM void
fw_cleanup(struct devicelist * thisdev)6069683SXin.Chen@Sun.COM fw_cleanup(struct devicelist *thisdev)
6079683SXin.Chen@Sun.COM {
6089683SXin.Chen@Sun.COM 	/*
6099683SXin.Chen@Sun.COM 	 * Function to clean up all the memory allocated
6109683SXin.Chen@Sun.COM 	 * by this plugin, for thisdev.
6119683SXin.Chen@Sun.COM 	 */
6129683SXin.Chen@Sun.COM 	free(thisdev->access_devname);
6139683SXin.Chen@Sun.COM 	free(thisdev->drvname);
6149683SXin.Chen@Sun.COM 	free(thisdev->classname);
6159683SXin.Chen@Sun.COM 
6169683SXin.Chen@Sun.COM 	/*
6179683SXin.Chen@Sun.COM 	 * Note that we DO NOT free addresses[1,2] because _IF_
6189683SXin.Chen@Sun.COM 	 * these elements are valid, they are managed by libdevinfo
6199683SXin.Chen@Sun.COM 	 * and we didn't allocate any space for them.
6209683SXin.Chen@Sun.COM 	 */
6219683SXin.Chen@Sun.COM 	free(thisdev->addresses[0]);
6229683SXin.Chen@Sun.COM 
6239683SXin.Chen@Sun.COM 	/* what this points to is freed in common code */
6249683SXin.Chen@Sun.COM 	thisdev->plugin = NULL;
6259683SXin.Chen@Sun.COM 
6269683SXin.Chen@Sun.COM 	free(thisdev->ident->vid);
6279683SXin.Chen@Sun.COM 	free(thisdev->ident->pid);
6289683SXin.Chen@Sun.COM 	free(thisdev->ident->revid);
6299683SXin.Chen@Sun.COM 
6309683SXin.Chen@Sun.COM 	thisdev->ident = NULL;
6319683SXin.Chen@Sun.COM }
6329683SXin.Chen@Sun.COM 
6339683SXin.Chen@Sun.COM /*
6349683SXin.Chen@Sun.COM  * Helper functions
6359683SXin.Chen@Sun.COM  */
6369683SXin.Chen@Sun.COM static int
link_cb(di_devlink_t devlink,void * arg)6379683SXin.Chen@Sun.COM link_cb(di_devlink_t devlink, void *arg)
6389683SXin.Chen@Sun.COM {
6399683SXin.Chen@Sun.COM 	const char *result;
6409683SXin.Chen@Sun.COM 
6419683SXin.Chen@Sun.COM 	result = di_devlink_path(devlink);
6429683SXin.Chen@Sun.COM 	if (result == NULL) {
6439683SXin.Chen@Sun.COM 		arg = (void *)"(null)";
6449683SXin.Chen@Sun.COM 	} else {
6459683SXin.Chen@Sun.COM 		(void) strlcpy(arg, result, strlen(result) + 1);
6469683SXin.Chen@Sun.COM 	}
6479683SXin.Chen@Sun.COM 
6489683SXin.Chen@Sun.COM 	logmsg(MSG_INFO, "\nlink_cb::linkdata->resultstr = %s\n",
6499683SXin.Chen@Sun.COM 	    ((result != NULL) ? result : "(null)"));
6509683SXin.Chen@Sun.COM 
6519683SXin.Chen@Sun.COM 	return (DI_WALK_CONTINUE);
6529683SXin.Chen@Sun.COM }
6539683SXin.Chen@Sun.COM 
6549683SXin.Chen@Sun.COM static char *
find_link(di_node_t bnode,char * acc_devname)6559974SXin.Chen@Sun.COM find_link(di_node_t bnode, char *acc_devname)
6569683SXin.Chen@Sun.COM {
6579683SXin.Chen@Sun.COM 	di_minor_t devminor = DI_MINOR_NIL;
6589974SXin.Chen@Sun.COM 	di_devlink_handle_t hdl;
6599683SXin.Chen@Sun.COM 	char *cbresult = NULL;
6609683SXin.Chen@Sun.COM 	char linkname[] = "^rdsk/\0";
6619683SXin.Chen@Sun.COM 
6629683SXin.Chen@Sun.COM 	if (bnode == DI_NODE_NIL) {
6639683SXin.Chen@Sun.COM 		logmsg(MSG_ERROR,
6649683SXin.Chen@Sun.COM 		    gettext("find_link must be called with non-null "
6659683SXin.Chen@Sun.COM 		    "di_node_t\n"));
6669683SXin.Chen@Sun.COM 		return (NULL);
6679683SXin.Chen@Sun.COM 	}
6689683SXin.Chen@Sun.COM 
6699974SXin.Chen@Sun.COM 	if ((cbresult = calloc(1, MAXPATHLEN)) == NULL) {
6709683SXin.Chen@Sun.COM 		logmsg(MSG_ERROR, gettext("unable to allocate space for dev "
6719683SXin.Chen@Sun.COM 		    "link\n"));
6729683SXin.Chen@Sun.COM 		return (NULL);
6739683SXin.Chen@Sun.COM 	}
6749683SXin.Chen@Sun.COM 
6759683SXin.Chen@Sun.COM 	devminor = di_minor_next(bnode, devminor);
6769683SXin.Chen@Sun.COM 	errno = 0;
6779683SXin.Chen@Sun.COM 	hdl = di_devlink_init(di_devfs_minor_path(devminor), DI_MAKE_LINK);
6789683SXin.Chen@Sun.COM 	if (hdl == NULL) {
6799683SXin.Chen@Sun.COM 		if (errno == EPERM || errno == EACCES) {
6809683SXin.Chen@Sun.COM 			logmsg(MSG_ERROR,
6819683SXin.Chen@Sun.COM 			    gettext("%s: You must be super-user to use this "
6829683SXin.Chen@Sun.COM 			    "plugin.\n"), drivername);
6839683SXin.Chen@Sun.COM 		} else {
6849683SXin.Chen@Sun.COM 			logmsg(MSG_ERROR,
6859683SXin.Chen@Sun.COM 			    gettext("unable to take devlink snapshot: %s\n"),
6869683SXin.Chen@Sun.COM 			    strerror(errno));
6879683SXin.Chen@Sun.COM 		}
6889974SXin.Chen@Sun.COM 		free(cbresult);
6899683SXin.Chen@Sun.COM 		return (NULL);
6909683SXin.Chen@Sun.COM 	}
6919683SXin.Chen@Sun.COM 
6929683SXin.Chen@Sun.COM 	errno = 0;
6939974SXin.Chen@Sun.COM 	if (di_devlink_walk(hdl, linkname, acc_devname + strlen(devprefix),
6949974SXin.Chen@Sun.COM 	    DI_PRIMARY_LINK, (void *)cbresult, link_cb) < 0) {
6959683SXin.Chen@Sun.COM 		logmsg(MSG_ERROR,
6969683SXin.Chen@Sun.COM 		    gettext("Unable to walk devlink snapshot for %s: %s\n"),
6979974SXin.Chen@Sun.COM 		    acc_devname, strerror(errno));
6989974SXin.Chen@Sun.COM 		free(cbresult);
6999683SXin.Chen@Sun.COM 		return (NULL);
7009683SXin.Chen@Sun.COM 	}
7019683SXin.Chen@Sun.COM 
7029683SXin.Chen@Sun.COM 	if (di_devlink_fini(&hdl) < 0) {
7039683SXin.Chen@Sun.COM 		logmsg(MSG_ERROR,
7049683SXin.Chen@Sun.COM 		    gettext("Unable to close devlink snapshot: %s\n"),
7059683SXin.Chen@Sun.COM 		    strerror(errno));
7069683SXin.Chen@Sun.COM 	}
7079683SXin.Chen@Sun.COM 
7089683SXin.Chen@Sun.COM 	logmsg(MSG_INFO, "cbresult: %s\n", cbresult);
7099683SXin.Chen@Sun.COM 	return (cbresult);
7109683SXin.Chen@Sun.COM }
7119683SXin.Chen@Sun.COM 
7129683SXin.Chen@Sun.COM static int
sd_idtfy_custmz(struct devicelist * device,char * sp)7139683SXin.Chen@Sun.COM sd_idtfy_custmz(struct devicelist *device, char *sp)
7149683SXin.Chen@Sun.COM {
7159683SXin.Chen@Sun.COM 	/* vid customization */
7169683SXin.Chen@Sun.COM 	if (strncmp(sp, "ST", 2) == 0) {
7179683SXin.Chen@Sun.COM 		/* Customize retail Seagate disks */
7189683SXin.Chen@Sun.COM 		if ((device->ident->vid = strdup("SEAGATE")) == NULL) {
7199683SXin.Chen@Sun.COM 			return (FWFLASH_FAILURE);
7209683SXin.Chen@Sun.COM 		}
7219683SXin.Chen@Sun.COM 	} else if (strncmp(sp, "SSD", 3) == 0) {
7229683SXin.Chen@Sun.COM 		/* Customize retail INTEL disks */
7239683SXin.Chen@Sun.COM 		if ((device->ident->vid = strdup("INTEL")) == NULL) {
7249683SXin.Chen@Sun.COM 			return (FWFLASH_FAILURE);
7259683SXin.Chen@Sun.COM 		}
7269683SXin.Chen@Sun.COM 	} else {
7279683SXin.Chen@Sun.COM 		/* disks to do in the furture, fill 'ATA' first */
7289683SXin.Chen@Sun.COM 		if ((device->ident->vid = strdup("ATA")) == NULL) {
7299683SXin.Chen@Sun.COM 			return (FWFLASH_FAILURE);
7309683SXin.Chen@Sun.COM 		}
7319683SXin.Chen@Sun.COM 	}
7329683SXin.Chen@Sun.COM 
7339683SXin.Chen@Sun.COM 	/* pid customization */
7349683SXin.Chen@Sun.COM 	if ((device->ident->pid = calloc(1, strlen(sp) + 1)) == NULL) {
7359683SXin.Chen@Sun.COM 		logmsg(MSG_ERROR, gettext("Unable to allocate space for "
7369683SXin.Chen@Sun.COM 		    "product id\n"));
7379683SXin.Chen@Sun.COM 		free(device->ident->vid);
7389683SXin.Chen@Sun.COM 		return (FWFLASH_FAILURE);
7399683SXin.Chen@Sun.COM 	}
7409683SXin.Chen@Sun.COM 	strlcpy(device->ident->pid, sp, strlen(sp) + 1);
7419683SXin.Chen@Sun.COM 
7429683SXin.Chen@Sun.COM 	return (FWFLASH_SUCCESS);
7439683SXin.Chen@Sun.COM }
744