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 * We check if this is removable device, in which case 292 * we really aren't interested, so exit stage left 293 */ 294 if (di_prop_lookup_ints(DDI_DEV_T_ANY, thisnode, 295 "removable-media", &exists) > -1) { 296 logmsg(MSG_INFO, 297 "%s: not interested in removable media device\n" 298 "%s\n", driver, devpath); 299 FW_SD_FREE_DEVPATH(devpath) 300 continue; 301 } 302 303 if ((newdev = calloc(1, sizeof (struct devicelist))) 304 == NULL) { 305 logmsg(MSG_ERROR, 306 gettext("%s: identification function unable " 307 "to allocate space for device entry\n"), 308 driver); 309 libscsi_fini(handle); 310 FW_SD_FREE_DEVPATH(devpath) 311 return (FWFLASH_FAILURE); 312 } 313 314 if ((newdev->drvname = calloc(1, strlen(driver) + 1)) 315 == NULL) { 316 logmsg(MSG_ERROR, 317 gettext("%s: Unable to allocate space to store a " 318 "driver name\n"), driver); 319 libscsi_fini(handle); 320 FW_SD_FREE_DEVICELIST(newdev, devpath) 321 return (FWFLASH_FAILURE); 322 } 323 (void) strlcpy(newdev->drvname, driver, strlen(driver) + 1); 324 325 if ((newdev->classname = calloc(1, strlen(driver) + 1)) 326 == NULL) { 327 logmsg(MSG_ERROR, 328 gettext("%s: Unable to allocate space for a class " 329 "name\n"), drivername); 330 libscsi_fini(handle); 331 FW_SD_FREE_DRV_NAME(newdev, devpath) 332 return (FWFLASH_FAILURE); 333 } 334 (void) strlcpy(newdev->classname, driver, strlen(driver) + 1); 335 336 /* Get the access name for current node */ 337 if ((newdev->access_devname = calloc(1, MAXPATHLEN)) == NULL) { 338 logmsg(MSG_ERROR, 339 gettext("%s: Unable to allocate space for a devfs " 340 "name\n"), driver); 341 libscsi_fini(handle); 342 FW_SD_FREE_CLS_NAME(newdev, devpath) 343 return (FWFLASH_FAILURE); 344 } 345 346 /* The slice number may be 2 or 0, we will try 2 first */ 347 (void) snprintf(newdev->access_devname, MAXPATHLEN, 348 "%s%s:c,raw", devprefix, devpath); 349 if ((target = libscsi_open(handle, NULL, 350 newdev->access_devname)) == NULL) { 351 /* try 0 for EFI label */ 352 (void) snprintf(newdev->access_devname, MAXPATHLEN, 353 "%s%s:a,raw", devprefix, devpath); 354 if ((target = libscsi_open(handle, NULL, 355 newdev->access_devname)) == NULL) { 356 logmsg(MSG_INFO, 357 "%s: unable to open device %s\n", 358 newdev->drvname, newdev->access_devname); 359 FW_SD_FREE_ACC_NAME(newdev, devpath) 360 continue; 361 } 362 } 363 364 /* and the /dev/rdsk/ name */ 365 if ((newdev->addresses[0] = find_link(thisnode, 366 newdev->access_devname)) == NULL) { 367 libscsi_fini(handle); 368 FW_SD_FREE_ACC_NAME(newdev, devpath) 369 return (FWFLASH_FAILURE); 370 } 371 372 /* 373 * Only alloc as much as we truly need, and DON'T forget 374 * that libdevinfo manages the memory! 375 */ 376 if ((newdev->ident = calloc(1, sizeof (struct vpr))) == NULL) { 377 logmsg(MSG_ERROR, 378 gettext("%s: Unable to allocate space for SCSI " 379 "INQUIRY data\n"), driver); 380 libscsi_fini(handle); 381 FW_SD_FREE_ADDR(newdev, devpath) 382 return (FWFLASH_FAILURE); 383 } 384 385 /* We don't use new->ident->encap_ident currently */ 386 387 /* Retrive information by using libscsi */ 388 /* Vendor ID */ 389 sp_temp = (char *)libscsi_vendor(target); 390 if (strncmp(sp_temp, "ATA", 3) == 0) { 391 /* We need to do customize the output for SATA disks */ 392 fw_sata_disk = 1; 393 } else { 394 fw_sata_disk = 0; 395 if ((newdev->ident->vid = 396 calloc(1, strlen(sp_temp) + 1)) == NULL || 397 sp_temp == NULL) { 398 if (!sp_temp) { 399 logmsg(MSG_ERROR, gettext("%s: unable " 400 "to get vendor id of %s\n"), 401 newdev->drvname, 402 newdev->access_devname); 403 } else { 404 logmsg(MSG_ERROR, gettext("Memory " 405 "allocation failure\n")); 406 } 407 408 libscsi_close(handle, target); 409 libscsi_fini(handle); 410 FW_SD_FREE_IDENT(newdev, devpath) 411 return (FWFLASH_FAILURE); 412 } 413 strlcpy(newdev->ident->vid, sp_temp, 414 strlen(sp_temp) + 1); 415 } 416 417 /* Product ID */ 418 sp_temp = (char *)libscsi_product(target); 419 if (fw_sata_disk) { 420 sp_temp_cut = strchr(sp_temp, ' '); 421 if (!sp_temp_cut) { 422 /* 423 * There is no SPACE character in the PID field 424 * Customize strings for special SATA disks 425 */ 426 if (sd_idtfy_custmz(newdev, sp_temp) 427 != FWFLASH_SUCCESS) { 428 libscsi_close(handle, target); 429 libscsi_fini(handle); 430 FW_SD_FREE_IDENT(newdev, devpath) 431 return (FWFLASH_FAILURE); 432 } 433 } else { 434 /* The first string is vendor id */ 435 if ((newdev->ident->vid = calloc(1, 436 (sp_temp_cut - sp_temp + 1))) == NULL) { 437 logmsg(MSG_ERROR, gettext("%s: unable " 438 "to get sata vendor id of %s\n"), 439 newdev->drvname, 440 newdev->access_devname); 441 442 libscsi_close(handle, target); 443 libscsi_fini(handle); 444 FW_SD_FREE_IDENT(newdev, devpath) 445 return (FWFLASH_FAILURE); 446 } 447 strlcpy(newdev->ident->vid, sp_temp, 448 sp_temp_cut - sp_temp + 1); 449 450 /* The second string is product id */ 451 if ((newdev->ident->pid = 452 calloc(1, strlen(sp_temp) - 453 strlen(newdev->ident->vid))) == NULL) { 454 logmsg(MSG_ERROR, gettext("%s: unable " 455 "to get sata product id of %s\n"), 456 newdev->drvname, 457 newdev->access_devname); 458 459 libscsi_close(handle, target); 460 libscsi_fini(handle); 461 FW_SD_FREE_IDENT_VID(newdev, devpath) 462 return (FWFLASH_FAILURE); 463 } 464 strlcpy(newdev->ident->pid, sp_temp_cut + 1, 465 strlen(sp_temp) - 466 strlen(newdev->ident->vid)); 467 } 468 } else { 469 if ((newdev->ident->pid = 470 calloc(1, strlen(sp_temp) + 1)) == NULL || 471 sp_temp == NULL) { 472 logmsg(MSG_ERROR, gettext("%s: unable to get " 473 "product id of %s\n"), newdev->drvname, 474 newdev->access_devname); 475 FW_SD_FREE_IDENT_VID(newdev, devpath) 476 libscsi_close(handle, target); 477 libscsi_fini(handle); 478 return (FWFLASH_FAILURE); 479 } 480 strlcpy(newdev->ident->pid, sp_temp, 481 strlen(sp_temp) + 1); 482 } 483 484 /* Revision ID */ 485 sp_temp = (char *)libscsi_revision(target); 486 if ((newdev->ident->revid = calloc(1, strlen(sp_temp) + 1)) 487 == NULL || sp_temp == NULL) { 488 logmsg(MSG_ERROR, gettext("%s: unable to get revision " 489 "id of %s\n"), newdev->drvname, 490 newdev->access_devname); 491 libscsi_close(handle, target); 492 libscsi_fini(handle); 493 FW_SD_FREE_IDENT_PID(newdev, devpath) 494 return (FWFLASH_FAILURE); 495 } 496 strlcpy(newdev->ident->revid, sp_temp, strlen(sp_temp) + 1); 497 498 /* Finish using libscsi */ 499 libscsi_close(handle, target); 500 501 if (di_prop_lookup_strings(DDI_DEV_T_ANY, thisnode, 502 "inquiry-serial-no", &newdev->addresses[1]) < 0) { 503 logmsg(MSG_INFO, 504 "%s: no inquiry-serial-no property for %s\n", 505 driver, newdev->access_devname); 506 logmsg(MSG_INFO, "The errno is %d\n", errno); 507 } 508 509 if ((di_prop_lookup_strings(DDI_DEV_T_ANY, thisnode, 510 "client-guid", &newdev->addresses[2])) < 0) { 511 logmsg(MSG_INFO, 512 "%s: no client-guid property " 513 "for device %s\n", 514 driver, newdev->access_devname); 515 /* try fallback */ 516 if ((di_prop_lookup_strings(DDI_DEV_T_ANY, thisnode, 517 "guid", &newdev->addresses[2])) < 0) { 518 logmsg(MSG_INFO, 519 "%s: no guid property for device %s\n", 520 driver, newdev->access_devname); 521 } 522 } else { 523 logmsg(MSG_INFO, 524 "client-guid property: %s\n", 525 newdev->addresses[2]); 526 } 527 528 newdev->index = idx; 529 ++idx; 530 newdev->plugin = self; 531 532 TAILQ_INSERT_TAIL(fw_devices, newdev, nextdev); 533 FW_SD_FREE_DEVPATH(devpath) 534 } 535 libscsi_fini(handle); 536 537 /* Check if sd targets presented are all unflashable. */ 538 if (idx == start) 539 return (FWFLASH_FAILURE); 540 541 if (fwflash_debug != 0) { 542 struct devicelist *tempdev; 543 544 TAILQ_FOREACH(tempdev, fw_devices, nextdev) { 545 logmsg(MSG_INFO, "%s:fw_identify:\n", 546 driver); 547 logmsg(MSG_INFO, 548 "\ttempdev @ 0x%lx\n" 549 "\t\taccess_devname: %s\n" 550 "\t\tdrvname: %s\tclassname: %s\n" 551 "\t\tident->vid: %s\n" 552 "\t\tident->pid: %s\n" 553 "\t\tident->revid: %s\n" 554 "\t\tindex: %d\n" 555 "\t\taddress[0]: %s\n" 556 "\t\taddress[1]: %s\n" 557 "\t\taddress[2]: %s\n" 558 "\t\tplugin @ 0x%lx\n\n", 559 &tempdev, 560 tempdev->access_devname, 561 tempdev->drvname, newdev->classname, 562 tempdev->ident->vid, 563 tempdev->ident->pid, 564 tempdev->ident->revid, 565 tempdev->index, 566 tempdev->addresses[0], 567 (tempdev->addresses[1] ? tempdev->addresses[1] : 568 "(not supported)"), 569 (tempdev->addresses[2] ? tempdev->addresses[2] : 570 "(not supported)"), 571 &tempdev->plugin); 572 } 573 } 574 return (FWFLASH_SUCCESS); 575 } 576 577 int 578 fw_devinfo(struct devicelist *thisdev) 579 { 580 fprintf(stdout, gettext("Device[%d]\t\t\t%s\n" 581 " Class [%s]\t\t\t%s\n"), 582 thisdev->index, thisdev->access_devname, 583 thisdev->classname, thisdev->addresses[0]); 584 585 fprintf(stdout, 586 gettext( 587 "\tVendor\t\t\t: %s\n" 588 "\tProduct\t\t\t: %s\n" 589 "\tFirmware revision\t: %-s\n" 590 "\tInquiry Serial Number : %-s\n" 591 "\tGUID\t\t\t: %s\n"), 592 thisdev->ident->vid, 593 thisdev->ident->pid, 594 thisdev->ident->revid, 595 (thisdev->addresses[1] ? thisdev->addresses[1] : 596 "(not supported)"), 597 (thisdev->addresses[2] ? thisdev->addresses[2] : 598 "(not supported)")); 599 600 fprintf(stdout, "\n\n"); 601 602 return (FWFLASH_SUCCESS); 603 } 604 605 void 606 fw_cleanup(struct devicelist *thisdev) 607 { 608 /* 609 * Function to clean up all the memory allocated 610 * by this plugin, for thisdev. 611 */ 612 free(thisdev->access_devname); 613 free(thisdev->drvname); 614 free(thisdev->classname); 615 616 /* 617 * Note that we DO NOT free addresses[1,2] because _IF_ 618 * these elements are valid, they are managed by libdevinfo 619 * and we didn't allocate any space for them. 620 */ 621 free(thisdev->addresses[0]); 622 623 /* what this points to is freed in common code */ 624 thisdev->plugin = NULL; 625 626 free(thisdev->ident->vid); 627 free(thisdev->ident->pid); 628 free(thisdev->ident->revid); 629 630 thisdev->ident = NULL; 631 } 632 633 /* 634 * Helper functions 635 */ 636 static int 637 link_cb(di_devlink_t devlink, void *arg) 638 { 639 const char *result; 640 641 result = di_devlink_path(devlink); 642 if (result == NULL) { 643 arg = (void *)"(null)"; 644 } else { 645 (void) strlcpy(arg, result, strlen(result) + 1); 646 } 647 648 logmsg(MSG_INFO, "\nlink_cb::linkdata->resultstr = %s\n", 649 ((result != NULL) ? result : "(null)")); 650 651 return (DI_WALK_CONTINUE); 652 } 653 654 static char * 655 find_link(di_node_t bnode, char *acc_devname) 656 { 657 di_minor_t devminor = DI_MINOR_NIL; 658 di_devlink_handle_t hdl; 659 char *cbresult = NULL; 660 char linkname[] = "^rdsk/\0"; 661 662 if (bnode == DI_NODE_NIL) { 663 logmsg(MSG_ERROR, 664 gettext("find_link must be called with non-null " 665 "di_node_t\n")); 666 return (NULL); 667 } 668 669 if ((cbresult = calloc(1, MAXPATHLEN)) == NULL) { 670 logmsg(MSG_ERROR, gettext("unable to allocate space for dev " 671 "link\n")); 672 return (NULL); 673 } 674 675 devminor = di_minor_next(bnode, devminor); 676 errno = 0; 677 hdl = di_devlink_init(di_devfs_minor_path(devminor), DI_MAKE_LINK); 678 if (hdl == NULL) { 679 if (errno == EPERM || errno == EACCES) { 680 logmsg(MSG_ERROR, 681 gettext("%s: You must be super-user to use this " 682 "plugin.\n"), drivername); 683 } else { 684 logmsg(MSG_ERROR, 685 gettext("unable to take devlink snapshot: %s\n"), 686 strerror(errno)); 687 } 688 free(cbresult); 689 return (NULL); 690 } 691 692 errno = 0; 693 if (di_devlink_walk(hdl, linkname, acc_devname + strlen(devprefix), 694 DI_PRIMARY_LINK, (void *)cbresult, link_cb) < 0) { 695 logmsg(MSG_ERROR, 696 gettext("Unable to walk devlink snapshot for %s: %s\n"), 697 acc_devname, strerror(errno)); 698 free(cbresult); 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 708 logmsg(MSG_INFO, "cbresult: %s\n", cbresult); 709 return (cbresult); 710 } 711 712 static int 713 sd_idtfy_custmz(struct devicelist *device, char *sp) 714 { 715 /* vid customization */ 716 if (strncmp(sp, "ST", 2) == 0) { 717 /* Customize retail Seagate disks */ 718 if ((device->ident->vid = strdup("SEAGATE")) == NULL) { 719 return (FWFLASH_FAILURE); 720 } 721 } else if (strncmp(sp, "SSD", 3) == 0) { 722 /* Customize retail INTEL disks */ 723 if ((device->ident->vid = strdup("INTEL")) == NULL) { 724 return (FWFLASH_FAILURE); 725 } 726 } else { 727 /* disks to do in the furture, fill 'ATA' first */ 728 if ((device->ident->vid = strdup("ATA")) == NULL) { 729 return (FWFLASH_FAILURE); 730 } 731 } 732 733 /* pid customization */ 734 if ((device->ident->pid = calloc(1, strlen(sp) + 1)) == NULL) { 735 logmsg(MSG_ERROR, gettext("Unable to allocate space for " 736 "product id\n")); 737 free(device->ident->vid); 738 return (FWFLASH_FAILURE); 739 } 740 strlcpy(device->ident->pid, sp, strlen(sp) + 1); 741 742 return (FWFLASH_SUCCESS); 743 } 744