1*d65b419eSXinChen /* 2*d65b419eSXinChen * CDDL HEADER START 3*d65b419eSXinChen * 4*d65b419eSXinChen * The contents of this file are subject to the terms of the 5*d65b419eSXinChen * Common Development and Distribution License (the "License"). 6*d65b419eSXinChen * You may not use this file except in compliance with the License. 7*d65b419eSXinChen * 8*d65b419eSXinChen * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*d65b419eSXinChen * or http://www.opensolaris.org/os/licensing. 10*d65b419eSXinChen * See the License for the specific language governing permissions 11*d65b419eSXinChen * and limitations under the License. 12*d65b419eSXinChen * 13*d65b419eSXinChen * When distributing Covered Code, include this CDDL HEADER in each 14*d65b419eSXinChen * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*d65b419eSXinChen * If applicable, add the following below this CDDL HEADER, with the 16*d65b419eSXinChen * fields enclosed by brackets "[]" replaced with your own identifying 17*d65b419eSXinChen * information: Portions Copyright [yyyy] [name of copyright owner] 18*d65b419eSXinChen * 19*d65b419eSXinChen * CDDL HEADER END 20*d65b419eSXinChen */ 21*d65b419eSXinChen /* 22*d65b419eSXinChen * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*d65b419eSXinChen * Use is subject to license terms. 24*d65b419eSXinChen */ 25*d65b419eSXinChen 26*d65b419eSXinChen /* 27*d65b419eSXinChen * sd / ssd (SCSI Direct-attached Device) specific functions. 28*d65b419eSXinChen */ 29*d65b419eSXinChen #include <libnvpair.h> 30*d65b419eSXinChen #include <stdio.h> 31*d65b419eSXinChen #include <stdlib.h> 32*d65b419eSXinChen #include <unistd.h> 33*d65b419eSXinChen #include <sys/types.h> 34*d65b419eSXinChen #include <sys/sysmacros.h> 35*d65b419eSXinChen #include <sys/queue.h> 36*d65b419eSXinChen #include <fcntl.h> 37*d65b419eSXinChen #include <string.h> 38*d65b419eSXinChen #include <errno.h> 39*d65b419eSXinChen #include <scsi/libscsi.h> 40*d65b419eSXinChen #include <libintl.h> /* for gettext(3c) */ 41*d65b419eSXinChen #include <fwflash/fwflash.h> 42*d65b419eSXinChen 43*d65b419eSXinChen typedef struct sam4_statdesc { 44*d65b419eSXinChen int status; 45*d65b419eSXinChen char *message; 46*d65b419eSXinChen } sam4_statdesc_t; 47*d65b419eSXinChen 48*d65b419eSXinChen static sam4_statdesc_t sam4_status[] = { 49*d65b419eSXinChen { SAM4_STATUS_GOOD, "Status: GOOD (success)" }, 50*d65b419eSXinChen { SAM4_STATUS_CHECK_CONDITION, "Status: CHECK CONDITION" }, 51*d65b419eSXinChen { SAM4_STATUS_CONDITION_MET, "Status: CONDITION MET" }, 52*d65b419eSXinChen { SAM4_STATUS_BUSY, "Status: Device is BUSY" }, 53*d65b419eSXinChen { SAM4_STATUS_RESERVATION_CONFLICT, "Status: Device is RESERVED" }, 54*d65b419eSXinChen { SAM4_STATUS_TASK_SET_FULL, 55*d65b419eSXinChen "Status: TASK SET FULL (insufficient resources in command queue" }, 56*d65b419eSXinChen { SAM4_STATUS_TASK_ABORTED, "Status: TASK ABORTED" }, 57*d65b419eSXinChen { NULL, NULL } 58*d65b419eSXinChen }; 59*d65b419eSXinChen 60*d65b419eSXinChen #define NSAM4_STATUS \ 61*d65b419eSXinChen (sizeof (sam4_status) / sizeof (sam4_status[0])) 62*d65b419eSXinChen 63*d65b419eSXinChen #define FW_SD_FREE_DEVPATH(devpath) { \ 64*d65b419eSXinChen di_devfs_path_free((devpath)); \ 65*d65b419eSXinChen } 66*d65b419eSXinChen #define FW_SD_FREE_DEVICELIST(thisdev, devpath) { \ 67*d65b419eSXinChen free((thisdev)); \ 68*d65b419eSXinChen FW_SD_FREE_DEVPATH((devpath)) \ 69*d65b419eSXinChen } 70*d65b419eSXinChen #define FW_SD_FREE_ACC_NAME(thisdev, devpath) { \ 71*d65b419eSXinChen free((thisdev)->access_devname); \ 72*d65b419eSXinChen FW_SD_FREE_DEVICELIST(thisdev, devpath) \ 73*d65b419eSXinChen } 74*d65b419eSXinChen #define FW_SD_FREE_DRV_NAME(thisdev, devpath) { \ 75*d65b419eSXinChen free((thisdev)->drvname); \ 76*d65b419eSXinChen FW_SD_FREE_ACC_NAME((thisdev), (devpath)) \ 77*d65b419eSXinChen } 78*d65b419eSXinChen #define FW_SD_FREE_CLS_NAME(thisdev, devpath) { \ 79*d65b419eSXinChen free((thisdev)->classname); \ 80*d65b419eSXinChen FW_SD_FREE_DRV_NAME((thisdev), (devpath)) \ 81*d65b419eSXinChen } 82*d65b419eSXinChen #define FW_SD_FREE_IDENT(thisdev, devpath) { \ 83*d65b419eSXinChen free((thisdev)->ident); \ 84*d65b419eSXinChen FW_SD_FREE_CLS_NAME((thisdev), (devpath)) \ 85*d65b419eSXinChen } 86*d65b419eSXinChen #define FW_SD_FREE_IDENT_VID(thisdev, devpath) { \ 87*d65b419eSXinChen free((thisdev)->ident->vid); \ 88*d65b419eSXinChen FW_SD_FREE_IDENT((thisdev), (devpath)) \ 89*d65b419eSXinChen } 90*d65b419eSXinChen #define FW_SD_FREE_IDENT_PID(thisdev, devpath) { \ 91*d65b419eSXinChen free((thisdev)->ident->pid); \ 92*d65b419eSXinChen FW_SD_FREE_IDENT_VID((thisdev), (devpath)) \ 93*d65b419eSXinChen } 94*d65b419eSXinChen #define FW_SD_FREE_IDENT_ALL(thisdev, devpath) { \ 95*d65b419eSXinChen free((thisdev)->ident->revid); \ 96*d65b419eSXinChen FW_SD_FREE_IDENT_PID((thisdev), (devpath)) \ 97*d65b419eSXinChen } 98*d65b419eSXinChen 99*d65b419eSXinChen int errno; 100*d65b419eSXinChen char drivername[] = "sd\0"; 101*d65b419eSXinChen int plugin_version = FWPLUGIN_VERSION_2; 102*d65b419eSXinChen 103*d65b419eSXinChen static char *devprefix = "/devices"; 104*d65b419eSXinChen extern di_node_t rootnode; 105*d65b419eSXinChen extern struct fw_plugin *self; 106*d65b419eSXinChen extern struct vrfyplugin *verifier; 107*d65b419eSXinChen extern int fwflash_debug; 108*d65b419eSXinChen 109*d65b419eSXinChen /* required functions for this plugin */ 110*d65b419eSXinChen int fw_readfw(struct devicelist *device, char *filename); 111*d65b419eSXinChen int fw_writefw(struct devicelist *device); 112*d65b419eSXinChen int fw_identify(int start); 113*d65b419eSXinChen int fw_devinfo(struct devicelist *thisdev); 114*d65b419eSXinChen void fw_cleanup(struct devicelist *thisdev); 115*d65b419eSXinChen 116*d65b419eSXinChen /* helper functions */ 117*d65b419eSXinChen static char *find_link(di_node_t bnode); 118*d65b419eSXinChen static int link_cb(di_devlink_t devlink, void *arg); 119*d65b419eSXinChen static int sd_idtfy_custmz(struct devicelist *device, char *sp); 120*d65b419eSXinChen 121*d65b419eSXinChen /* 122*d65b419eSXinChen * We don't currently support reading firmware from a disk. If we do eventually 123*d65b419eSXinChen * support it, we would use the scsi READ BUFFER command to do so. 124*d65b419eSXinChen */ 125*d65b419eSXinChen int 126*d65b419eSXinChen fw_readfw(struct devicelist *flashdev, char *filename) 127*d65b419eSXinChen { 128*d65b419eSXinChen 129*d65b419eSXinChen logmsg(MSG_INFO, 130*d65b419eSXinChen "%s: not writing firmware for device %s to file %s\n", 131*d65b419eSXinChen flashdev->drvname, flashdev->access_devname, filename); 132*d65b419eSXinChen logmsg(MSG_ERROR, 133*d65b419eSXinChen gettext("\n\nReading of firmware images from %s-attached " 134*d65b419eSXinChen "devices is not supported\n\n"), 135*d65b419eSXinChen flashdev->drvname); 136*d65b419eSXinChen 137*d65b419eSXinChen return (FWFLASH_SUCCESS); 138*d65b419eSXinChen } 139*d65b419eSXinChen 140*d65b419eSXinChen int 141*d65b419eSXinChen fw_writefw(struct devicelist *flashdev) 142*d65b419eSXinChen { 143*d65b419eSXinChen int rv; 144*d65b419eSXinChen int i = 0; 145*d65b419eSXinChen libscsi_hdl_t *handle; 146*d65b419eSXinChen libscsi_target_t *target; 147*d65b419eSXinChen libscsi_action_t *action; 148*d65b419eSXinChen libscsi_errno_t serr; 149*d65b419eSXinChen spc3_write_buffer_cdb_t *wb_cdb; 150*d65b419eSXinChen sam4_status_t samstatus; 151*d65b419eSXinChen 152*d65b419eSXinChen if ((verifier == NULL) || (verifier->imgsize == 0) || 153*d65b419eSXinChen (verifier->fwimage == NULL)) { 154*d65b419eSXinChen /* should _NOT_ happen */ 155*d65b419eSXinChen logmsg(MSG_ERROR, 156*d65b419eSXinChen gettext("%s: Firmware image has not been verified\n"), 157*d65b419eSXinChen flashdev->drvname); 158*d65b419eSXinChen return (FWFLASH_FAILURE); 159*d65b419eSXinChen } 160*d65b419eSXinChen 161*d65b419eSXinChen if ((handle = libscsi_init(LIBSCSI_VERSION, &serr)) == NULL) { 162*d65b419eSXinChen logmsg(MSG_ERROR, gettext("%s: failed to initialize libscsi\n"), 163*d65b419eSXinChen flashdev->drvname); 164*d65b419eSXinChen return (FWFLASH_FAILURE); 165*d65b419eSXinChen } 166*d65b419eSXinChen 167*d65b419eSXinChen if ((target = libscsi_open(handle, NULL, flashdev->access_devname)) 168*d65b419eSXinChen == NULL) { 169*d65b419eSXinChen logmsg(MSG_ERROR, 170*d65b419eSXinChen gettext("%s: unable to open device %s\n"), 171*d65b419eSXinChen flashdev->drvname, flashdev->access_devname); 172*d65b419eSXinChen libscsi_fini(handle); 173*d65b419eSXinChen return (FWFLASH_FAILURE); 174*d65b419eSXinChen } 175*d65b419eSXinChen 176*d65b419eSXinChen action = libscsi_action_alloc(handle, SPC3_CMD_WRITE_BUFFER, 177*d65b419eSXinChen LIBSCSI_AF_WRITE|LIBSCSI_AF_RQSENSE, 178*d65b419eSXinChen (void *)verifier->fwimage, (size_t)verifier->imgsize); 179*d65b419eSXinChen 180*d65b419eSXinChen wb_cdb = (spc3_write_buffer_cdb_t *)libscsi_action_get_cdb(action); 181*d65b419eSXinChen 182*d65b419eSXinChen wb_cdb->wbc_mode = SPC3_WB_MODE_DL_UCODE_SAVE; 183*d65b419eSXinChen wb_cdb->wbc_bufferid = verifier->flashbuf; 184*d65b419eSXinChen 185*d65b419eSXinChen wb_cdb->wbc_buffer_offset[0] = 0; 186*d65b419eSXinChen wb_cdb->wbc_buffer_offset[1] = 0; 187*d65b419eSXinChen wb_cdb->wbc_buffer_offset[2] = 0; 188*d65b419eSXinChen 189*d65b419eSXinChen wb_cdb->wbc_parameter_list_len[0] = 190*d65b419eSXinChen (verifier->imgsize & 0xff0000) >> 16; 191*d65b419eSXinChen wb_cdb->wbc_parameter_list_len[1] = (verifier->imgsize & 0xff00) >> 8; 192*d65b419eSXinChen wb_cdb->wbc_parameter_list_len[2] = (verifier->imgsize & 0xff); 193*d65b419eSXinChen 194*d65b419eSXinChen rv = libscsi_exec(action, target); 195*d65b419eSXinChen samstatus = libscsi_action_get_status(action); 196*d65b419eSXinChen 197*d65b419eSXinChen logmsg(MSG_INFO, "\nscsi_writebuffer: ret 0x%0x, samstatus 0x%0x\n", 198*d65b419eSXinChen rv, samstatus); 199*d65b419eSXinChen 200*d65b419eSXinChen libscsi_action_free(action); 201*d65b419eSXinChen libscsi_close(handle, target); 202*d65b419eSXinChen libscsi_fini(handle); 203*d65b419eSXinChen 204*d65b419eSXinChen if (rv != FWFLASH_SUCCESS) 205*d65b419eSXinChen return (FWFLASH_FAILURE); 206*d65b419eSXinChen 207*d65b419eSXinChen for (i = 0; i < NSAM4_STATUS; i++) { 208*d65b419eSXinChen if (sam4_status[i].status == samstatus) { 209*d65b419eSXinChen logmsg(MSG_ERROR, gettext("RETURN STATUS: %s\n"), 210*d65b419eSXinChen (sam4_status[i].message)); 211*d65b419eSXinChen break; 212*d65b419eSXinChen } 213*d65b419eSXinChen } 214*d65b419eSXinChen if (i == NSAM4_STATUS) 215*d65b419eSXinChen logmsg(MSG_ERROR, gettext("Status UNKNOWN\n")); 216*d65b419eSXinChen 217*d65b419eSXinChen if (samstatus == SAM4_STATUS_GOOD) { 218*d65b419eSXinChen logmsg(MSG_ERROR, gettext("Note: For flash based disks " 219*d65b419eSXinChen "(SSD, etc). You may need power off the system to wait a " 220*d65b419eSXinChen "few minutes for supercap to fully discharge, then power " 221*d65b419eSXinChen "on the system again to activate the new firmware\n")); 222*d65b419eSXinChen return (FWFLASH_SUCCESS); 223*d65b419eSXinChen } 224*d65b419eSXinChen return (FWFLASH_FAILURE); 225*d65b419eSXinChen } 226*d65b419eSXinChen 227*d65b419eSXinChen /* 228*d65b419eSXinChen * The fw_identify() function walks the device 229*d65b419eSXinChen * tree trying to find devices which this plugin 230*d65b419eSXinChen * can work with. 231*d65b419eSXinChen * 232*d65b419eSXinChen * The parameter "start" gives us the starting index number 233*d65b419eSXinChen * to give the device when we add it to the fw_devices list. 234*d65b419eSXinChen * 235*d65b419eSXinChen * firstdev is allocated by us and we add space as needed 236*d65b419eSXinChen * 237*d65b419eSXinChen * When we store the desired information, inquiry-serial-no 238*d65b419eSXinChen * goes in thisdev->addresses[1], and client-guid goes in 239*d65b419eSXinChen * thisdev->addresses[2]. 240*d65b419eSXinChen */ 241*d65b419eSXinChen int 242*d65b419eSXinChen fw_identify(int start) 243*d65b419eSXinChen { 244*d65b419eSXinChen int idx = start; 245*d65b419eSXinChen int fw_sata_disk = 0; 246*d65b419eSXinChen int *exists; 247*d65b419eSXinChen di_node_t thisnode; 248*d65b419eSXinChen struct devicelist *newdev = NULL; 249*d65b419eSXinChen char *devpath = NULL; 250*d65b419eSXinChen char *driver = NULL; 251*d65b419eSXinChen char *sp_temp; 252*d65b419eSXinChen char *sp_temp_cut; 253*d65b419eSXinChen 254*d65b419eSXinChen /* We need to inquiry information manually by sending probe command */ 255*d65b419eSXinChen libscsi_hdl_t *handle; 256*d65b419eSXinChen libscsi_target_t *target; 257*d65b419eSXinChen libscsi_errno_t serr; 258*d65b419eSXinChen 259*d65b419eSXinChen /* Just in case we've got an FC-attached device on sparc */ 260*d65b419eSXinChen if (strcmp(self->drvname, "ssd") == 0) { 261*d65b419eSXinChen driver = self->drvname; 262*d65b419eSXinChen } else 263*d65b419eSXinChen driver = drivername; 264*d65b419eSXinChen 265*d65b419eSXinChen thisnode = di_drv_first_node(driver, rootnode); 266*d65b419eSXinChen 267*d65b419eSXinChen if (thisnode == DI_NODE_NIL) { 268*d65b419eSXinChen logmsg(MSG_INFO, "No %s nodes in this system\n", driver); 269*d65b419eSXinChen return (FWFLASH_FAILURE); 270*d65b419eSXinChen } 271*d65b419eSXinChen 272*d65b419eSXinChen if ((devpath = calloc(1, MAXPATHLEN + 1)) == NULL) { 273*d65b419eSXinChen logmsg(MSG_ERROR, 274*d65b419eSXinChen gettext("%s: Unable to allocate space for a device node\n"), 275*d65b419eSXinChen driver); 276*d65b419eSXinChen return (FWFLASH_FAILURE); 277*d65b419eSXinChen } 278*d65b419eSXinChen 279*d65b419eSXinChen if ((handle = libscsi_init(LIBSCSI_VERSION, &serr)) == NULL) { 280*d65b419eSXinChen logmsg(MSG_ERROR, gettext("%s: failed to initialize " 281*d65b419eSXinChen "libscsi\n"), newdev->drvname); 282*d65b419eSXinChen FW_SD_FREE_DEVPATH(devpath) 283*d65b419eSXinChen return (FWFLASH_FAILURE); 284*d65b419eSXinChen } 285*d65b419eSXinChen 286*d65b419eSXinChen /* we've found one, at least */ 287*d65b419eSXinChen for (; thisnode != DI_NODE_NIL; thisnode = di_drv_next_node(thisnode)) { 288*d65b419eSXinChen devpath = di_devfs_path(thisnode); 289*d65b419eSXinChen /* 290*d65b419eSXinChen * We check if this is removable device, in which case 291*d65b419eSXinChen * we really aren't interested, so exit stage left 292*d65b419eSXinChen */ 293*d65b419eSXinChen if (di_prop_lookup_ints(DDI_DEV_T_ANY, thisnode, 294*d65b419eSXinChen "removable-media", &exists) > -1) { 295*d65b419eSXinChen logmsg(MSG_INFO, 296*d65b419eSXinChen "%s: not interested in removable media device\n" 297*d65b419eSXinChen "%s\n", driver, devpath); 298*d65b419eSXinChen continue; 299*d65b419eSXinChen } 300*d65b419eSXinChen 301*d65b419eSXinChen if ((newdev = calloc(1, sizeof (struct devicelist))) 302*d65b419eSXinChen == NULL) { 303*d65b419eSXinChen logmsg(MSG_ERROR, 304*d65b419eSXinChen gettext("%s: identification function unable " 305*d65b419eSXinChen "to allocate space for device entry\n"), 306*d65b419eSXinChen driver); 307*d65b419eSXinChen libscsi_fini(handle); 308*d65b419eSXinChen FW_SD_FREE_DEVPATH(devpath) 309*d65b419eSXinChen return (FWFLASH_FAILURE); 310*d65b419eSXinChen } 311*d65b419eSXinChen 312*d65b419eSXinChen if ((newdev->access_devname = calloc(1, MAXPATHLEN)) == NULL) { 313*d65b419eSXinChen logmsg(MSG_ERROR, 314*d65b419eSXinChen gettext("%s: Unable to allocate space for a devfs " 315*d65b419eSXinChen "name\n"), driver); 316*d65b419eSXinChen libscsi_fini(handle); 317*d65b419eSXinChen FW_SD_FREE_DEVICELIST(newdev, devpath) 318*d65b419eSXinChen return (FWFLASH_FAILURE); 319*d65b419eSXinChen } 320*d65b419eSXinChen 321*d65b419eSXinChen /* save the /devices name */ 322*d65b419eSXinChen (void) snprintf(newdev->access_devname, MAXPATHLEN, 323*d65b419eSXinChen "%s%s:c,raw", devprefix, devpath); 324*d65b419eSXinChen 325*d65b419eSXinChen /* and the /dev/rdsk/ name */ 326*d65b419eSXinChen newdev->addresses[0] = calloc(1, MAXPATHLEN); 327*d65b419eSXinChen if (newdev->addresses[0]) 328*d65b419eSXinChen newdev->addresses[0] = find_link(thisnode); 329*d65b419eSXinChen if (newdev->addresses[0] == NULL) { 330*d65b419eSXinChen libscsi_fini(handle); 331*d65b419eSXinChen FW_SD_FREE_DEVICELIST(newdev, devpath) 332*d65b419eSXinChen return (FWFLASH_FAILURE); 333*d65b419eSXinChen } 334*d65b419eSXinChen 335*d65b419eSXinChen if ((newdev->drvname = calloc(1, strlen(driver) + 1)) 336*d65b419eSXinChen == NULL) { 337*d65b419eSXinChen logmsg(MSG_ERROR, 338*d65b419eSXinChen gettext("%s: Unable to allocate space to store a " 339*d65b419eSXinChen "driver name\n"), driver); 340*d65b419eSXinChen libscsi_fini(handle); 341*d65b419eSXinChen FW_SD_FREE_ACC_NAME(newdev, devpath) 342*d65b419eSXinChen return (FWFLASH_FAILURE); 343*d65b419eSXinChen } 344*d65b419eSXinChen (void) strlcpy(newdev->drvname, driver, strlen(driver) + 1); 345*d65b419eSXinChen 346*d65b419eSXinChen if ((newdev->classname = calloc(1, strlen(driver) + 1)) 347*d65b419eSXinChen == NULL) { 348*d65b419eSXinChen logmsg(MSG_ERROR, 349*d65b419eSXinChen gettext("%s: Unable to allocate space for a class " 350*d65b419eSXinChen "name\n"), drivername); 351*d65b419eSXinChen libscsi_fini(handle); 352*d65b419eSXinChen FW_SD_FREE_DRV_NAME(newdev, devpath) 353*d65b419eSXinChen return (FWFLASH_FAILURE); 354*d65b419eSXinChen } 355*d65b419eSXinChen (void) strlcpy(newdev->classname, driver, strlen(driver) + 1); 356*d65b419eSXinChen 357*d65b419eSXinChen /* 358*d65b419eSXinChen * Only alloc as much as we truly need, and DON'T forget 359*d65b419eSXinChen * that libdevinfo manages the memory! 360*d65b419eSXinChen */ 361*d65b419eSXinChen if ((newdev->ident = calloc(1, sizeof (struct vpr))) == NULL) { 362*d65b419eSXinChen logmsg(MSG_ERROR, 363*d65b419eSXinChen gettext("%s: Unable to allocate space for SCSI " 364*d65b419eSXinChen "INQUIRY data\n"), driver); 365*d65b419eSXinChen libscsi_fini(handle); 366*d65b419eSXinChen FW_SD_FREE_CLS_NAME(newdev, devpath) 367*d65b419eSXinChen return (FWFLASH_FAILURE); 368*d65b419eSXinChen } 369*d65b419eSXinChen 370*d65b419eSXinChen /* We don't use new->ident->encap_ident currently */ 371*d65b419eSXinChen 372*d65b419eSXinChen /* Retrive information by using libscsi */ 373*d65b419eSXinChen if ((target = libscsi_open(handle, NULL, 374*d65b419eSXinChen newdev->access_devname)) == NULL) { 375*d65b419eSXinChen logmsg(MSG_INFO, "%s: unable to open device %s\n", 376*d65b419eSXinChen newdev->drvname, newdev->access_devname); 377*d65b419eSXinChen FW_SD_FREE_IDENT(newdev, devpath) 378*d65b419eSXinChen continue; 379*d65b419eSXinChen } 380*d65b419eSXinChen 381*d65b419eSXinChen /* Vendor ID */ 382*d65b419eSXinChen sp_temp = (char *)libscsi_vendor(target); 383*d65b419eSXinChen if (strncmp(sp_temp, "ATA", 3) == 0) { 384*d65b419eSXinChen /* We need to do customize the output for SATA disks */ 385*d65b419eSXinChen fw_sata_disk = 1; 386*d65b419eSXinChen } else { 387*d65b419eSXinChen fw_sata_disk = 0; 388*d65b419eSXinChen if ((newdev->ident->vid = 389*d65b419eSXinChen calloc(1, strlen(sp_temp) + 1)) == NULL || 390*d65b419eSXinChen sp_temp == NULL) { 391*d65b419eSXinChen if (!sp_temp) { 392*d65b419eSXinChen logmsg(MSG_ERROR, gettext("%s: unable " 393*d65b419eSXinChen "to get vendor id of %s\n"), 394*d65b419eSXinChen newdev->drvname, 395*d65b419eSXinChen newdev->access_devname); 396*d65b419eSXinChen } else { 397*d65b419eSXinChen logmsg(MSG_ERROR, gettext("Memory " 398*d65b419eSXinChen "allocation failure\n")); 399*d65b419eSXinChen } 400*d65b419eSXinChen 401*d65b419eSXinChen libscsi_close(handle, target); 402*d65b419eSXinChen libscsi_fini(handle); 403*d65b419eSXinChen FW_SD_FREE_IDENT(newdev, devpath) 404*d65b419eSXinChen return (FWFLASH_FAILURE); 405*d65b419eSXinChen } 406*d65b419eSXinChen strlcpy(newdev->ident->vid, sp_temp, 407*d65b419eSXinChen strlen(sp_temp) + 1); 408*d65b419eSXinChen } 409*d65b419eSXinChen 410*d65b419eSXinChen /* Product ID */ 411*d65b419eSXinChen sp_temp = (char *)libscsi_product(target); 412*d65b419eSXinChen if (fw_sata_disk) { 413*d65b419eSXinChen sp_temp_cut = strchr(sp_temp, ' '); 414*d65b419eSXinChen if (!sp_temp_cut) { 415*d65b419eSXinChen /* Customize strings for special SATA disks */ 416*d65b419eSXinChen if (sd_idtfy_custmz(newdev, sp_temp) 417*d65b419eSXinChen != FWFLASH_SUCCESS) { 418*d65b419eSXinChen libscsi_close(handle, target); 419*d65b419eSXinChen libscsi_fini(handle); 420*d65b419eSXinChen FW_SD_FREE_IDENT(newdev, devpath) 421*d65b419eSXinChen return (FWFLASH_FAILURE); 422*d65b419eSXinChen } 423*d65b419eSXinChen } else { 424*d65b419eSXinChen /* The first string is vendor id */ 425*d65b419eSXinChen if ((newdev->ident->vid = calloc(1, 426*d65b419eSXinChen (sp_temp_cut - sp_temp + 1))) == NULL) { 427*d65b419eSXinChen logmsg(MSG_ERROR, gettext("%s: unable " 428*d65b419eSXinChen "to get sata vendor id of %s\n"), 429*d65b419eSXinChen newdev->drvname, 430*d65b419eSXinChen newdev->access_devname); 431*d65b419eSXinChen 432*d65b419eSXinChen libscsi_close(handle, target); 433*d65b419eSXinChen libscsi_fini(handle); 434*d65b419eSXinChen FW_SD_FREE_IDENT(newdev, devpath) 435*d65b419eSXinChen return (FWFLASH_FAILURE); 436*d65b419eSXinChen } 437*d65b419eSXinChen strlcpy(newdev->ident->vid, sp_temp, 438*d65b419eSXinChen sp_temp_cut - sp_temp + 1); 439*d65b419eSXinChen 440*d65b419eSXinChen /* The second string is product id */ 441*d65b419eSXinChen if ((newdev->ident->pid = 442*d65b419eSXinChen calloc(1, strlen(sp_temp) - 443*d65b419eSXinChen strlen(newdev->ident->vid))) == NULL) { 444*d65b419eSXinChen logmsg(MSG_ERROR, gettext("%s: unable " 445*d65b419eSXinChen "to get sata product id of %s\n"), 446*d65b419eSXinChen newdev->drvname, 447*d65b419eSXinChen newdev->access_devname); 448*d65b419eSXinChen 449*d65b419eSXinChen libscsi_close(handle, target); 450*d65b419eSXinChen libscsi_fini(handle); 451*d65b419eSXinChen FW_SD_FREE_IDENT_VID(newdev, devpath) 452*d65b419eSXinChen return (FWFLASH_FAILURE); 453*d65b419eSXinChen } 454*d65b419eSXinChen strlcpy(newdev->ident->pid, sp_temp_cut + 1, 455*d65b419eSXinChen strlen(sp_temp) - 456*d65b419eSXinChen strlen(newdev->ident->vid)); 457*d65b419eSXinChen } 458*d65b419eSXinChen } else { 459*d65b419eSXinChen if ((newdev->ident->pid = 460*d65b419eSXinChen calloc(1, strlen(sp_temp) + 1)) == NULL || 461*d65b419eSXinChen sp_temp == NULL) { 462*d65b419eSXinChen logmsg(MSG_ERROR, gettext("%s: unable to get " 463*d65b419eSXinChen "product id of %s\n"), newdev->drvname, 464*d65b419eSXinChen newdev->access_devname); 465*d65b419eSXinChen FW_SD_FREE_IDENT_VID(newdev, devpath) 466*d65b419eSXinChen libscsi_close(handle, target); 467*d65b419eSXinChen libscsi_fini(handle); 468*d65b419eSXinChen return (FWFLASH_FAILURE); 469*d65b419eSXinChen } 470*d65b419eSXinChen strlcpy(newdev->ident->pid, sp_temp, 471*d65b419eSXinChen strlen(sp_temp) + 1); 472*d65b419eSXinChen } 473*d65b419eSXinChen 474*d65b419eSXinChen /* Revision ID */ 475*d65b419eSXinChen sp_temp = (char *)libscsi_revision(target); 476*d65b419eSXinChen if ((newdev->ident->revid = calloc(1, strlen(sp_temp) + 1)) 477*d65b419eSXinChen == NULL || sp_temp == NULL) { 478*d65b419eSXinChen logmsg(MSG_ERROR, gettext("%s: unable to get revision " 479*d65b419eSXinChen "id of %s\n"), newdev->drvname, 480*d65b419eSXinChen newdev->access_devname); 481*d65b419eSXinChen libscsi_close(handle, target); 482*d65b419eSXinChen libscsi_fini(handle); 483*d65b419eSXinChen FW_SD_FREE_IDENT_PID(newdev, devpath) 484*d65b419eSXinChen return (FWFLASH_FAILURE); 485*d65b419eSXinChen } 486*d65b419eSXinChen strlcpy(newdev->ident->revid, sp_temp, strlen(sp_temp) + 1); 487*d65b419eSXinChen 488*d65b419eSXinChen /* Finish using libscsi */ 489*d65b419eSXinChen libscsi_close(handle, target); 490*d65b419eSXinChen 491*d65b419eSXinChen if (di_prop_lookup_strings(DDI_DEV_T_ANY, thisnode, 492*d65b419eSXinChen "inquiry-serial-no", &newdev->addresses[1]) < 0) { 493*d65b419eSXinChen logmsg(MSG_INFO, 494*d65b419eSXinChen "%s: no inquiry-serial-no property for %s\n", 495*d65b419eSXinChen driver, newdev->access_devname); 496*d65b419eSXinChen logmsg(MSG_INFO, "The errno is %d\n", errno); 497*d65b419eSXinChen } 498*d65b419eSXinChen 499*d65b419eSXinChen if ((di_prop_lookup_strings(DDI_DEV_T_ANY, thisnode, 500*d65b419eSXinChen "client-guid", &newdev->addresses[2])) < 0) { 501*d65b419eSXinChen logmsg(MSG_INFO, 502*d65b419eSXinChen "%s: no client-guid property " 503*d65b419eSXinChen "for device %s\n", 504*d65b419eSXinChen driver, newdev->access_devname); 505*d65b419eSXinChen /* try fallback */ 506*d65b419eSXinChen if ((di_prop_lookup_strings(DDI_DEV_T_ANY, thisnode, 507*d65b419eSXinChen "guid", &newdev->addresses[2])) < 0) { 508*d65b419eSXinChen logmsg(MSG_INFO, 509*d65b419eSXinChen "%s: no guid property for device %s\n", 510*d65b419eSXinChen driver, newdev->access_devname); 511*d65b419eSXinChen } 512*d65b419eSXinChen } else { 513*d65b419eSXinChen logmsg(MSG_INFO, 514*d65b419eSXinChen "client-guid property: %s\n", 515*d65b419eSXinChen newdev->addresses[2]); 516*d65b419eSXinChen } 517*d65b419eSXinChen 518*d65b419eSXinChen newdev->index = idx; 519*d65b419eSXinChen ++idx; 520*d65b419eSXinChen newdev->plugin = self; 521*d65b419eSXinChen 522*d65b419eSXinChen TAILQ_INSERT_TAIL(fw_devices, newdev, nextdev); 523*d65b419eSXinChen } 524*d65b419eSXinChen libscsi_fini(handle); 525*d65b419eSXinChen FW_SD_FREE_DEVPATH(devpath) 526*d65b419eSXinChen 527*d65b419eSXinChen /* Check if sd targets presented are all unflashable. */ 528*d65b419eSXinChen if (idx == start) 529*d65b419eSXinChen return (FWFLASH_FAILURE); 530*d65b419eSXinChen 531*d65b419eSXinChen if (fwflash_debug != 0) { 532*d65b419eSXinChen struct devicelist *tempdev; 533*d65b419eSXinChen 534*d65b419eSXinChen TAILQ_FOREACH(tempdev, fw_devices, nextdev) { 535*d65b419eSXinChen logmsg(MSG_INFO, "%s:fw_identify:\n", 536*d65b419eSXinChen driver); 537*d65b419eSXinChen logmsg(MSG_INFO, 538*d65b419eSXinChen "\ttempdev @ 0x%lx\n" 539*d65b419eSXinChen "\t\taccess_devname: %s\n" 540*d65b419eSXinChen "\t\tdrvname: %s\tclassname: %s\n" 541*d65b419eSXinChen "\t\tident->vid: %s\n" 542*d65b419eSXinChen "\t\tident->pid: %s\n" 543*d65b419eSXinChen "\t\tident->revid: %s\n" 544*d65b419eSXinChen "\t\tindex: %d\n" 545*d65b419eSXinChen "\t\taddress[0]: %s\n" 546*d65b419eSXinChen "\t\taddress[1]: %s\n" 547*d65b419eSXinChen "\t\taddress[2]: %s\n" 548*d65b419eSXinChen "\t\tplugin @ 0x%lx\n\n", 549*d65b419eSXinChen &tempdev, 550*d65b419eSXinChen tempdev->access_devname, 551*d65b419eSXinChen tempdev->drvname, newdev->classname, 552*d65b419eSXinChen tempdev->ident->vid, 553*d65b419eSXinChen tempdev->ident->pid, 554*d65b419eSXinChen tempdev->ident->revid, 555*d65b419eSXinChen tempdev->index, 556*d65b419eSXinChen tempdev->addresses[0], 557*d65b419eSXinChen (tempdev->addresses[1] ? tempdev->addresses[1] : 558*d65b419eSXinChen "(not supported)"), 559*d65b419eSXinChen (tempdev->addresses[2] ? tempdev->addresses[2] : 560*d65b419eSXinChen "(not supported)"), 561*d65b419eSXinChen &tempdev->plugin); 562*d65b419eSXinChen } 563*d65b419eSXinChen } 564*d65b419eSXinChen return (FWFLASH_SUCCESS); 565*d65b419eSXinChen } 566*d65b419eSXinChen 567*d65b419eSXinChen int 568*d65b419eSXinChen fw_devinfo(struct devicelist *thisdev) 569*d65b419eSXinChen { 570*d65b419eSXinChen fprintf(stdout, gettext("Device[%d]\t\t\t%s\n" 571*d65b419eSXinChen " Class [%s]\t\t\t%s\n"), 572*d65b419eSXinChen thisdev->index, thisdev->access_devname, 573*d65b419eSXinChen thisdev->classname, thisdev->addresses[0]); 574*d65b419eSXinChen 575*d65b419eSXinChen fprintf(stdout, 576*d65b419eSXinChen gettext( 577*d65b419eSXinChen "\tVendor\t\t\t: %s\n" 578*d65b419eSXinChen "\tProduct\t\t\t: %s\n" 579*d65b419eSXinChen "\tFirmware revision\t: %-s\n" 580*d65b419eSXinChen "\tInquiry Serial Number : %-s\n" 581*d65b419eSXinChen "\tGUID\t\t\t: %s\n"), 582*d65b419eSXinChen thisdev->ident->vid, 583*d65b419eSXinChen thisdev->ident->pid, 584*d65b419eSXinChen thisdev->ident->revid, 585*d65b419eSXinChen (thisdev->addresses[1] ? thisdev->addresses[1] : 586*d65b419eSXinChen "(not supported)"), 587*d65b419eSXinChen (thisdev->addresses[2] ? thisdev->addresses[2] : 588*d65b419eSXinChen "(not supported)")); 589*d65b419eSXinChen 590*d65b419eSXinChen fprintf(stdout, "\n\n"); 591*d65b419eSXinChen 592*d65b419eSXinChen return (FWFLASH_SUCCESS); 593*d65b419eSXinChen } 594*d65b419eSXinChen 595*d65b419eSXinChen void 596*d65b419eSXinChen fw_cleanup(struct devicelist *thisdev) 597*d65b419eSXinChen { 598*d65b419eSXinChen /* 599*d65b419eSXinChen * Function to clean up all the memory allocated 600*d65b419eSXinChen * by this plugin, for thisdev. 601*d65b419eSXinChen */ 602*d65b419eSXinChen free(thisdev->access_devname); 603*d65b419eSXinChen free(thisdev->drvname); 604*d65b419eSXinChen free(thisdev->classname); 605*d65b419eSXinChen 606*d65b419eSXinChen /* 607*d65b419eSXinChen * Note that we DO NOT free addresses[1,2] because _IF_ 608*d65b419eSXinChen * these elements are valid, they are managed by libdevinfo 609*d65b419eSXinChen * and we didn't allocate any space for them. 610*d65b419eSXinChen */ 611*d65b419eSXinChen free(thisdev->addresses[0]); 612*d65b419eSXinChen 613*d65b419eSXinChen /* what this points to is freed in common code */ 614*d65b419eSXinChen thisdev->plugin = NULL; 615*d65b419eSXinChen 616*d65b419eSXinChen free(thisdev->ident->vid); 617*d65b419eSXinChen free(thisdev->ident->pid); 618*d65b419eSXinChen free(thisdev->ident->revid); 619*d65b419eSXinChen 620*d65b419eSXinChen thisdev->ident = NULL; 621*d65b419eSXinChen } 622*d65b419eSXinChen 623*d65b419eSXinChen /* 624*d65b419eSXinChen * Helper functions 625*d65b419eSXinChen */ 626*d65b419eSXinChen static int 627*d65b419eSXinChen link_cb(di_devlink_t devlink, void *arg) 628*d65b419eSXinChen { 629*d65b419eSXinChen const char *result; 630*d65b419eSXinChen 631*d65b419eSXinChen result = di_devlink_path(devlink); 632*d65b419eSXinChen if (result == NULL) { 633*d65b419eSXinChen arg = (void *)"(null)"; 634*d65b419eSXinChen } else { 635*d65b419eSXinChen (void) strlcpy(arg, result, strlen(result) + 1); 636*d65b419eSXinChen } 637*d65b419eSXinChen 638*d65b419eSXinChen logmsg(MSG_INFO, "\nlink_cb::linkdata->resultstr = %s\n", 639*d65b419eSXinChen ((result != NULL) ? result : "(null)")); 640*d65b419eSXinChen 641*d65b419eSXinChen return (DI_WALK_CONTINUE); 642*d65b419eSXinChen } 643*d65b419eSXinChen 644*d65b419eSXinChen static char * 645*d65b419eSXinChen find_link(di_node_t bnode) 646*d65b419eSXinChen { 647*d65b419eSXinChen di_minor_t devminor = DI_MINOR_NIL; 648*d65b419eSXinChen di_devlink_handle_t hdl; 649*d65b419eSXinChen char *devfspath = NULL; 650*d65b419eSXinChen char *minorpath = NULL; 651*d65b419eSXinChen char *cbresult = NULL; 652*d65b419eSXinChen char linkname[] = "^rdsk/\0"; 653*d65b419eSXinChen 654*d65b419eSXinChen devfspath = di_devfs_path(bnode); 655*d65b419eSXinChen if (bnode == DI_NODE_NIL) { 656*d65b419eSXinChen logmsg(MSG_ERROR, 657*d65b419eSXinChen gettext("find_link must be called with non-null " 658*d65b419eSXinChen "di_node_t\n")); 659*d65b419eSXinChen FW_SD_FREE_DEVPATH(devfspath) 660*d65b419eSXinChen return (NULL); 661*d65b419eSXinChen } 662*d65b419eSXinChen 663*d65b419eSXinChen logmsg(MSG_INFO, "find_link: devfspath %s\n", devfspath); 664*d65b419eSXinChen 665*d65b419eSXinChen if (((cbresult = calloc(1, MAXPATHLEN)) == NULL) || 666*d65b419eSXinChen ((minorpath = calloc(1, MAXPATHLEN)) == NULL)) { 667*d65b419eSXinChen logmsg(MSG_ERROR, gettext("unable to allocate space for dev " 668*d65b419eSXinChen "link\n")); 669*d65b419eSXinChen FW_SD_FREE_DEVPATH(devfspath) 670*d65b419eSXinChen return (NULL); 671*d65b419eSXinChen } 672*d65b419eSXinChen 673*d65b419eSXinChen devminor = di_minor_next(bnode, devminor); 674*d65b419eSXinChen errno = 0; 675*d65b419eSXinChen hdl = di_devlink_init(di_devfs_minor_path(devminor), DI_MAKE_LINK); 676*d65b419eSXinChen if (hdl == NULL) { 677*d65b419eSXinChen if (errno == EPERM || errno == EACCES) { 678*d65b419eSXinChen logmsg(MSG_ERROR, 679*d65b419eSXinChen gettext("%s: You must be super-user to use this " 680*d65b419eSXinChen "plugin.\n"), drivername); 681*d65b419eSXinChen } else { 682*d65b419eSXinChen logmsg(MSG_ERROR, 683*d65b419eSXinChen gettext("unable to take devlink snapshot: %s\n"), 684*d65b419eSXinChen strerror(errno)); 685*d65b419eSXinChen } 686*d65b419eSXinChen FW_SD_FREE_DEVPATH(devfspath) 687*d65b419eSXinChen return (NULL); 688*d65b419eSXinChen } 689*d65b419eSXinChen 690*d65b419eSXinChen (void) snprintf(minorpath, MAXPATHLEN, "%s:c,raw", devfspath); 691*d65b419eSXinChen 692*d65b419eSXinChen errno = 0; 693*d65b419eSXinChen if (di_devlink_walk(hdl, linkname, minorpath, DI_PRIMARY_LINK, 694*d65b419eSXinChen (void *)cbresult, link_cb) < 0) { 695*d65b419eSXinChen logmsg(MSG_ERROR, 696*d65b419eSXinChen gettext("Unable to walk devlink snapshot for %s: %s\n"), 697*d65b419eSXinChen minorpath, strerror(errno)); 698*d65b419eSXinChen FW_SD_FREE_DEVPATH(devfspath) 699*d65b419eSXinChen return (NULL); 700*d65b419eSXinChen } 701*d65b419eSXinChen 702*d65b419eSXinChen if (di_devlink_fini(&hdl) < 0) { 703*d65b419eSXinChen logmsg(MSG_ERROR, 704*d65b419eSXinChen gettext("Unable to close devlink snapshot: %s\n"), 705*d65b419eSXinChen strerror(errno)); 706*d65b419eSXinChen } 707*d65b419eSXinChen free(minorpath); /* don't need this now */ 708*d65b419eSXinChen FW_SD_FREE_DEVPATH(devfspath) 709*d65b419eSXinChen 710*d65b419eSXinChen logmsg(MSG_INFO, "cbresult: %s\n", cbresult); 711*d65b419eSXinChen return (cbresult); 712*d65b419eSXinChen } 713*d65b419eSXinChen 714*d65b419eSXinChen static int 715*d65b419eSXinChen sd_idtfy_custmz(struct devicelist *device, char *sp) 716*d65b419eSXinChen { 717*d65b419eSXinChen /* vid customization */ 718*d65b419eSXinChen if (strncmp(sp, "ST", 2) == 0) { 719*d65b419eSXinChen /* Customize retail Seagate disks */ 720*d65b419eSXinChen if ((device->ident->vid = strdup("SEAGATE")) == NULL) { 721*d65b419eSXinChen return (FWFLASH_FAILURE); 722*d65b419eSXinChen } 723*d65b419eSXinChen } else if (strncmp(sp, "SSD", 3) == 0) { 724*d65b419eSXinChen /* Customize retail INTEL disks */ 725*d65b419eSXinChen if ((device->ident->vid = strdup("INTEL")) == NULL) { 726*d65b419eSXinChen return (FWFLASH_FAILURE); 727*d65b419eSXinChen } 728*d65b419eSXinChen } else { 729*d65b419eSXinChen /* disks to do in the furture, fill 'ATA' first */ 730*d65b419eSXinChen if ((device->ident->vid = strdup("ATA")) == NULL) { 731*d65b419eSXinChen return (FWFLASH_FAILURE); 732*d65b419eSXinChen } 733*d65b419eSXinChen } 734*d65b419eSXinChen 735*d65b419eSXinChen /* pid customization */ 736*d65b419eSXinChen if ((device->ident->pid = calloc(1, strlen(sp) + 1)) == NULL) { 737*d65b419eSXinChen logmsg(MSG_ERROR, gettext("Unable to allocate space for " 738*d65b419eSXinChen "product id\n")); 739*d65b419eSXinChen free(device->ident->vid); 740*d65b419eSXinChen return (FWFLASH_FAILURE); 741*d65b419eSXinChen } 742*d65b419eSXinChen strlcpy(device->ident->pid, sp, strlen(sp) + 1); 743*d65b419eSXinChen 744*d65b419eSXinChen return (FWFLASH_SUCCESS); 745*d65b419eSXinChen } 746