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