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