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 * ses (SCSI Generic Device) specific functions. 28 */ 29 30 #include <libnvpair.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <sys/types.h> 35 #include <sys/sysmacros.h> 36 #include <sys/queue.h> 37 #include <fcntl.h> 38 #include <string.h> 39 #include <scsi/libscsi.h> 40 #include <scsi/libses.h> 41 #include <libintl.h> /* for gettext(3c) */ 42 #include <fwflash/fwflash.h> 43 44 45 #define VIDLEN 0x08 46 #define PIDLEN 0x10 47 #define REVLEN 0x04 48 #define SASADDRLEN 0x10 49 #define PCBUFLEN 0x40 50 #define RQBUFLEN 0xfe 51 #define STATBUFLEN 0xfe 52 #define INQBUFLEN 0x80 53 54 /* useful defines */ 55 #define UCODE_CHECK_STATUS 0 56 #define UCODE_CHECK_SUPPORTED 1 57 58 typedef struct ucode_statdesc { 59 uint64_t us_value; 60 const char *us_desc; 61 boolean_t us_pending; 62 boolean_t us_iserr; 63 } ucode_statdesc_t; 64 65 static ucode_statdesc_t ucode_statdesc_table[] = { 66 { SES2_DLUCODE_S_NOP, "none", B_FALSE, B_FALSE }, 67 { SES2_DLUCODE_S_INPROGRESS, "in progress", B_TRUE, B_FALSE }, 68 { SES2_DLUCODE_S_SAVING, "saved", B_TRUE, B_FALSE }, 69 { SES2_DLUCODE_S_COMPLETE_NOW, "completed (available)", B_FALSE, 70 B_FALSE }, 71 { SES2_DLUCODE_S_COMPLETE_AT_RESET, 72 "completed (need reset or power on)", B_FALSE, B_FALSE }, 73 { SES2_DLUCODE_S_COMPLETE_AT_POWERON, "completed (need power on)", 74 B_FALSE, B_FALSE }, 75 { SES2_DLUCODE_S_PAGE_ERR, "page error (offset %d)", 76 B_FALSE, B_TRUE }, 77 { SES2_DLUCODE_S_IMAGE_ERR, "invalid image", 78 B_FALSE, B_TRUE }, 79 { SES2_DLUCODE_S_TIMEOUT, "download timeout", 80 B_FALSE, B_TRUE }, 81 { SES2_DLUCODE_S_INTERNAL_NEEDIMAGE, 82 "internal error (NEED NEW IMAGE BEFORE RESET)", 83 B_FALSE, B_TRUE }, 84 { SES2_DLUCODE_S_INTERNAL_SAFE, 85 "internal error (reset to revert to backup)", 86 B_FALSE, B_TRUE }, 87 }; 88 89 #define NUCODE_STATUS \ 90 (sizeof (ucode_statdesc_table) / sizeof (ucode_statdesc_table[0])) 91 92 typedef struct ucode_status { 93 uint64_t us_status; 94 boolean_t us_iserr; 95 boolean_t us_pending; 96 char us_desc[128]; 97 } ucode_status_t; 98 99 typedef struct ucode_wait { 100 uint64_t uw_prevstatus; 101 boolean_t uw_pending; 102 ses_node_t *uw_oldnp; 103 } ucode_wait_t; 104 105 106 typedef struct sam4_statdesc { 107 int status; 108 char *message; 109 } sam4_statdesc_t; 110 111 112 static sam4_statdesc_t sam4_status[] = { 113 { SAM4_STATUS_GOOD, "Status: GOOD (success)" }, 114 { SAM4_STATUS_CHECK_CONDITION, "Status: CHECK CONDITION" }, 115 { SAM4_STATUS_CONDITION_MET, "Status: CONDITION MET" }, 116 { SAM4_STATUS_BUSY, "Status: Device is BUSY" }, 117 { SAM4_STATUS_RESERVATION_CONFLICT, "Status: Device is RESERVED" }, 118 { SAM4_STATUS_TASK_SET_FULL, 119 "Status: TASK SET FULL (insufficient resources in command queue" }, 120 { SAM4_STATUS_TASK_ABORTED, "Status: TASK ABORTED" }, 121 { NULL, NULL } 122 }; 123 124 #define NSAM4_STATUS \ 125 (sizeof (sam4_status) / sizeof (sam4_status[0])) 126 127 128 129 char drivername[] = "ses\0"; 130 static char *devprefix = "/devices"; 131 static char *sessuffix = ":0"; 132 static char *sgensuffix = ":ses"; 133 134 135 static ses_target_t *ses_target; 136 static int internalstatus; 137 138 extern di_node_t rootnode; 139 extern int errno; 140 extern struct fw_plugin *self; 141 extern struct vrfyplugin *verifier; 142 extern int fwflash_debug; 143 144 145 /* required functions for this plugin */ 146 int fw_readfw(struct devicelist *device, char *filename); 147 int fw_writefw(struct devicelist *device); 148 int fw_identify(int start); 149 int fw_devinfo(struct devicelist *thisdev); 150 151 152 /* helper functions */ 153 static void print_updated_status(ses_node_t *np, void *arg); 154 static int get_status(nvlist_t *props, ucode_status_t *sp); 155 static int sendimg(ses_node_t *np, void *data); 156 static int scsi_writebuf(); 157 158 /* 159 * We don't currently support reading firmware from a SAS 160 * expander. If we do eventually support it, we would use 161 * the scsi READ BUFFER command to do so. 162 */ 163 int 164 fw_readfw(struct devicelist *flashdev, char *filename) 165 { 166 167 logmsg(MSG_INFO, 168 "%s: not writing firmware for device %s to file %s\n", 169 flashdev->drvname, flashdev->access_devname, filename); 170 logmsg(MSG_ERROR, 171 gettext("\n\nReading of firmware images from %s-attached " 172 "devices is not supported\n\n"), 173 flashdev->drvname); 174 175 return (FWFLASH_SUCCESS); 176 } 177 178 179 /* 180 * If we're invoking fw_writefw, then flashdev is a valid, 181 * flashable device supporting the SES2 Download Microcode Diagnostic 182 * Control page (0x0e). 183 * 184 * If verifier is null, then we haven't been called following a firmware 185 * image verification load operation. 186 * 187 * *THIS* function uses scsi SEND DIAGNOSTIC/download microcode to 188 * achieve the task... if you chase down to the bottom of libses you 189 * can see that too. 190 */ 191 int 192 fw_writefw(struct devicelist *flashdev) 193 { 194 int rv; 195 nvlist_t *nvl; 196 ses_snap_t *snapshot; 197 ses_node_t *targetnode; 198 199 if ((verifier == NULL) || (verifier->imgsize == 0) || 200 (verifier->fwimage == NULL)) { 201 /* should _not_ happen */ 202 logmsg(MSG_ERROR, 203 gettext("%s: Firmware image has not " 204 "been verified.\n"), 205 flashdev->drvname); 206 return (FWFLASH_FAILURE); 207 } 208 209 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 210 nvlist_add_uint64(nvl, SES_CTL_PROP_UCODE_MODE, 211 SES_DLUCODE_M_WITH_OFFS) != 0) { 212 logmsg(MSG_ERROR, 213 gettext("%s: Unable to allocate " 214 "space for device prop list\n"), 215 flashdev->drvname); 216 return (FWFLASH_FAILURE); 217 } 218 219 fprintf(stdout, "\n"); /* get a fresh line for progress updates */ 220 221 if (nvlist_add_uint64(nvl, SES_CTL_PROP_UCODE_BUFID, 222 verifier->flashbuf) != 0) { 223 logmsg(MSG_ERROR, 224 gettext("%s: Unable to add buffer id " 225 "property, hence unable to flash device\n"), 226 flashdev->drvname); 227 goto cancel; 228 } 229 230 if (nvlist_add_byte_array(nvl, SES_CTL_PROP_UCODE_DATA, 231 (uint8_t *)verifier->fwimage, verifier->imgsize) != 0) { 232 logmsg(MSG_ERROR, 233 "%s: Out of memory for property addition\n", 234 flashdev->drvname); 235 goto cancel; 236 } 237 238 if ((ses_target = 239 ses_open(LIBSES_VERSION, flashdev->access_devname)) == NULL) { 240 logmsg(MSG_ERROR, 241 gettext("%s: Unable to open flashable device %s\n"), 242 flashdev->drvname, flashdev->access_devname); 243 goto cancel; 244 } 245 246 snapshot = ses_snap_hold(ses_target); 247 internalstatus = FWFLASH_FAILURE; 248 249 if ((targetnode = ses_snap_primary_enclosure(snapshot)) == NULL) { 250 logmsg(MSG_ERROR, 251 gettext("%s: Unable to locate primary enclosure for " 252 "device %s\n"), 253 flashdev->access_devname); 254 } else { 255 rv = sendimg(targetnode, nvl); 256 if (rv == FWFLASH_SUCCESS) { 257 logmsg(MSG_ERROR, 258 gettext("%s: Done. New image will be active " 259 "after the system is rebooted.\n\n"), 260 flashdev->drvname); 261 } else { 262 logmsg(MSG_INFO, 263 "%s: unable to flash image %s to device %s\n\n", 264 flashdev->drvname, verifier->imgfile, 265 flashdev->access_devname); 266 } 267 } 268 269 ses_snap_rele(snapshot); 270 ses_close(ses_target); 271 cancel: 272 nvlist_free(nvl); 273 274 return (internalstatus); 275 } 276 277 278 /* 279 * The fw_identify() function walks the device 280 * tree trying to find devices which this plugin 281 * can work with. 282 * 283 * The parameter "start" gives us the starting index number 284 * to give the device when we add it to the fw_devices list. 285 * 286 * firstdev is allocated by us and we add space as needed 287 */ 288 int 289 fw_identify(int start) 290 { 291 292 int rv = FWFLASH_FAILURE; 293 di_node_t thisnode; 294 struct devicelist *newdev; 295 char *devpath; 296 char *devsuffix; 297 char *driver; 298 int idx = start; 299 size_t devlength = 0; 300 nvlist_t *props; 301 ses_snap_t *snapshot; 302 ses_node_t *rootnodep, *nodep; 303 304 305 if (strcmp(self->drvname, "sgen") == 0) { 306 devsuffix = sgensuffix; 307 driver = self->drvname; 308 } else { 309 devsuffix = sessuffix; 310 driver = drivername; 311 } 312 313 thisnode = di_drv_first_node(driver, rootnode); 314 315 if (thisnode == DI_NODE_NIL) { 316 logmsg(MSG_INFO, gettext("No %s nodes in this system\n"), 317 driver); 318 return (FWFLASH_FAILURE); 319 } 320 321 if ((devpath = calloc(1, MAXPATHLEN + 1)) == NULL) { 322 logmsg(MSG_ERROR, 323 gettext("%s: Unable to allocate space " 324 "for a device node\n"), 325 driver); 326 return (FWFLASH_FAILURE); 327 } 328 329 /* we've found one, at least */ 330 331 for (; thisnode != DI_NODE_NIL; thisnode = di_drv_next_node(thisnode)) { 332 333 devpath = di_devfs_path(thisnode); 334 335 if ((newdev = calloc(1, sizeof (struct devicelist))) 336 == NULL) { 337 logmsg(MSG_ERROR, 338 gettext("%s: identification function unable " 339 "to allocate space for device entry\n"), 340 driver); 341 free(devpath); 342 return (FWFLASH_FAILURE); 343 } 344 345 /* calloc enough for /devices + devpath + devsuffix + '\0' */ 346 devlength = strlen(devpath) + strlen(devprefix) + 347 strlen(devsuffix) + 2; 348 349 if ((newdev->access_devname = calloc(1, devlength)) == NULL) { 350 logmsg(MSG_ERROR, 351 gettext("%s: Unable to allocate " 352 "space for a devfs name\n"), 353 driver); 354 free(devpath); 355 free(newdev); 356 return (FWFLASH_FAILURE); 357 } 358 snprintf(newdev->access_devname, devlength, 359 "%s%s%s", devprefix, devpath, devsuffix); 360 361 if ((newdev->drvname = calloc(1, strlen(driver) + 1)) 362 == NULL) { 363 logmsg(MSG_ERROR, 364 gettext("%s: Unable to allocate " 365 "space to store a driver name\n"), 366 driver); 367 free(newdev->access_devname); 368 free(newdev); 369 free(devpath); 370 return (FWFLASH_FAILURE); 371 } 372 (void) strlcpy(newdev->drvname, driver, 373 strlen(driver) + 1); 374 375 if ((newdev->classname = calloc(1, strlen(driver) + 1)) 376 == NULL) { 377 logmsg(MSG_ERROR, 378 gettext("%s: Unable to malloc " 379 "space for a class name\n"), 380 drivername); 381 free(newdev->access_devname); 382 free(newdev->drvname); 383 free(newdev); 384 free(devpath); 385 return (FWFLASH_FAILURE); 386 } 387 (void) strlcpy(newdev->classname, driver, 388 strlen(driver) + 1); 389 390 /* 391 * Only alloc as much as we truly need, and DON'T forget 392 * that libnvpair manages the memory for property lookups! 393 * The same goes for libdevinfo properties. 394 * 395 * Also note that we're allocating here before we try to 396 * ses_open() the target, because if we can't allocate 397 * sufficient space then we might as well go home. 398 */ 399 newdev->ident = calloc(1, VIDLEN + PIDLEN + REVLEN + 3); 400 if (newdev->ident == NULL) { 401 logmsg(MSG_ERROR, 402 gettext("%s: Unable to malloc space for" 403 "SCSI INQUIRY data\n"), driver); 404 free(newdev->classname); 405 free(newdev->drvname); 406 free(newdev->access_devname); 407 free(newdev); 408 free(devpath); 409 return (FWFLASH_FAILURE); 410 } 411 412 if ((ses_target = 413 ses_open(LIBSES_VERSION, newdev->access_devname)) 414 == NULL) { 415 logmsg(MSG_INFO, 416 gettext("%s: Unable to open device %s\n"), 417 driver, newdev->access_devname); 418 free(newdev->ident); 419 free(newdev->classname); 420 free(newdev->access_devname); 421 free(newdev->drvname); 422 free(newdev); 423 free(devpath); 424 continue; 425 } 426 snapshot = ses_snap_hold(ses_target); 427 rootnodep = ses_root_node(snapshot); 428 429 /* 430 * If the node has no properties, or the INQUIRY properties 431 * don't exist, this device does not comply with SES2 so we 432 * won't touch it. 433 */ 434 if ((props = ses_node_props(rootnodep)) == NULL) { 435 free(newdev->ident); 436 ses_snap_rele(snapshot); 437 ses_close(ses_target); 438 free(newdev->classname); 439 free(newdev->access_devname); 440 free(newdev->drvname); 441 free(newdev); 442 free(devpath); 443 continue; 444 } 445 446 if ((nvlist_lookup_string(props, SCSI_PROP_VENDOR, 447 &newdev->ident->vid) != 0) || 448 (nvlist_lookup_string(props, SCSI_PROP_PRODUCT, 449 &newdev->ident->pid) != 0) || 450 (nvlist_lookup_string(props, SCSI_PROP_REVISION, 451 &newdev->ident->revid) != 0)) { 452 free(newdev->ident); 453 ses_snap_rele(snapshot); 454 ses_close(ses_target); 455 free(newdev->classname); 456 free(newdev->access_devname); 457 free(newdev->drvname); 458 free(newdev); 459 free(devpath); 460 continue; 461 } 462 463 nodep = ses_snap_primary_enclosure(snapshot); 464 465 if ((props = ses_node_props(nodep)) == NULL) { 466 free(newdev->ident); 467 ses_snap_rele(snapshot); 468 ses_close(ses_target); 469 free(newdev->classname); 470 free(newdev->access_devname); 471 free(newdev->drvname); 472 free(newdev); 473 free(devpath); 474 continue; 475 } 476 477 logmsg(MSG_INFO, 478 "\nvid: %s\npid: %s\nrevid: %s\n", 479 newdev->ident->vid, 480 newdev->ident->pid, 481 newdev->ident->revid); 482 483 if (nvlist_lookup_string(props, LIBSES_EN_PROP_CSN, 484 &newdev->addresses[0]) == 0) { 485 logmsg(MSG_INFO, 486 "Chassis Serial Number: %s\n", 487 newdev->addresses[0]); 488 } else 489 logmsg(MSG_INFO, 490 "%s: no chassis-serial-number property " 491 "for device %s\n", 492 driver, newdev->access_devname); 493 494 495 rv = di_prop_lookup_strings(DDI_DEV_T_ANY, 496 thisnode, "target-port", &newdev->addresses[1]); 497 if (rv < 0) { 498 logmsg(MSG_INFO, 499 "%s: no target-port property " 500 "for device %s\n", 501 driver, newdev->access_devname); 502 } else 503 logmsg(MSG_INFO, 504 "target-port property: %s\n", 505 newdev->addresses[1]); 506 507 508 newdev->index = idx; 509 ++idx; 510 newdev->plugin = self; 511 512 ses_snap_rele(snapshot); 513 TAILQ_INSERT_TAIL(fw_devices, newdev, nextdev); 514 } 515 516 517 if (fwflash_debug != 0) { 518 struct devicelist *tempdev; 519 520 TAILQ_FOREACH(tempdev, fw_devices, nextdev) { 521 logmsg(MSG_INFO, "%s:fw_identify:\n", 522 driver); 523 logmsg(MSG_INFO, 524 "\ttempdev @ 0x%lx\n" 525 "\t\taccess_devname: %s\n" 526 "\t\tdrvname: %s\tclassname: %s\n" 527 "\t\tident->vid: %s\n" 528 "\t\tident->pid: %s\n" 529 "\t\tident->revid: %s\n" 530 "\t\tindex: %d\n" 531 "\t\taddress[0]: %s\n" 532 "\t\taddress[1]: %s\n" 533 "\t\tplugin @ 0x%lx\n\n", 534 &tempdev, 535 tempdev->access_devname, 536 tempdev->drvname, newdev->classname, 537 tempdev->ident->vid, 538 tempdev->ident->pid, 539 tempdev->ident->revid, 540 tempdev->index, 541 (tempdev->addresses[0] ? tempdev->addresses[0] : 542 "(not supported)"), 543 (tempdev->addresses[1] ? tempdev->addresses[1] : 544 "(not supported)"), 545 &tempdev->plugin); 546 } 547 } 548 549 return (FWFLASH_SUCCESS); 550 } 551 552 553 554 int 555 fw_devinfo(struct devicelist *thisdev) 556 { 557 558 559 fprintf(stdout, gettext("Device[%d] %s\n Class [%s]\n"), 560 thisdev->index, thisdev->access_devname, thisdev->classname); 561 562 fprintf(stdout, 563 gettext("\tVendor : %s\n" 564 "\tProduct : %s\n" 565 "\tFirmware revision : %s\n" 566 "\tChassis Serial Number : %s\n" 567 "\tTarget-port identifier : %s\n"), 568 thisdev->ident->vid, 569 thisdev->ident->pid, 570 thisdev->ident->revid, 571 (thisdev->addresses[0] ? thisdev->addresses[0] : 572 "(not supported)"), 573 (thisdev->addresses[1] ? thisdev->addresses[1] : 574 "(not supported)")); 575 576 fprintf(stdout, "\n\n"); 577 578 return (FWFLASH_SUCCESS); 579 } 580 581 582 583 584 585 /*ARGSUSED*/ 586 static int 587 get_status(nvlist_t *props, ucode_status_t *sp) 588 { 589 int i; 590 uint64_t status, astatus; 591 592 if (nvlist_lookup_uint64(props, SES_EN_PROP_UCODE, &status) != 0) { 593 sp->us_status = -1ULL; 594 (void) snprintf(sp->us_desc, sizeof (sp->us_desc), 595 "not supported"); 596 internalstatus = FWFLASH_FAILURE; 597 return (-1); 598 } 599 600 if (nvlist_lookup_uint64(props, SES_EN_PROP_UCODE_A, 601 &astatus) != 0) { 602 logmsg(MSG_ERROR, 603 gettext("\nError: Unable to retrieve current status\n")); 604 internalstatus = FWFLASH_FAILURE; 605 return (-1); 606 } 607 608 for (i = 0; i < NUCODE_STATUS; i++) { 609 if (ucode_statdesc_table[i].us_value == status) 610 break; 611 } 612 613 sp->us_status = status; 614 615 if (i == NUCODE_STATUS) { 616 (void) snprintf(sp->us_desc, sizeof (sp->us_desc), 617 "unknown (0x%02x)", (int)status); 618 sp->us_iserr = sp->us_pending = B_FALSE; 619 } else { 620 /* LINTED */ 621 (void) snprintf(sp->us_desc, sizeof (sp->us_desc), 622 ucode_statdesc_table[i].us_desc, (int)astatus); 623 sp->us_iserr = ucode_statdesc_table[i].us_iserr; 624 sp->us_pending = ucode_statdesc_table[i].us_pending; 625 } 626 627 return (0); 628 } 629 630 631 static void 632 print_updated_status(ses_node_t *np, void *arg) 633 { 634 ucode_wait_t *uwp = arg; 635 nvlist_t *props; 636 ucode_status_t status; 637 638 639 if ((props = ses_node_props(np)) == NULL) { 640 internalstatus = FWFLASH_FAILURE; 641 return; 642 } 643 644 if (get_status(props, &status) != 0) 645 /* internalstatus is already set to FWFLASH_FAILURE */ 646 return; 647 648 if (status.us_status != uwp->uw_prevstatus) 649 (void) printf("%30s: %s\n", "status", status.us_desc); 650 651 uwp->uw_prevstatus = status.us_status; 652 uwp->uw_pending = status.us_pending; 653 654 if (status.us_iserr) { 655 logmsg(MSG_INFO, 656 "libses: status.us_iserr: 0x%0x\n", 657 status.us_iserr); 658 internalstatus = FWFLASH_FAILURE; 659 } else 660 internalstatus = FWFLASH_SUCCESS; 661 662 } 663 664 /*ARGSUSED*/ 665 static int 666 sendimg(ses_node_t *np, void *data) 667 { 668 nvlist_t *props; 669 nvlist_t *arg = data; 670 char *vendor, *product, *revision, *csn; 671 char buf[128]; 672 ses_snap_t *newsnap; 673 int ret; 674 ucode_status_t statdesc; 675 ucode_wait_t wait; 676 uint8_t *imagedata; 677 uint_t len; 678 679 680 /* If we've been called without data, eject */ 681 if (nvlist_lookup_byte_array(arg, SES_CTL_PROP_UCODE_DATA, 682 &imagedata, &len) != 0) { 683 return (FWFLASH_FAILURE); 684 } 685 686 props = ses_node_props(np); 687 if ((props == NULL) || 688 (nvlist_lookup_string(props, SES_EN_PROP_VID, &vendor) != 0) || 689 (nvlist_lookup_string(props, SES_EN_PROP_PID, &product) != 0) || 690 (nvlist_lookup_string(props, SES_EN_PROP_REV, &revision) != 0) || 691 (nvlist_lookup_string(props, LIBSES_EN_PROP_CSN, &csn) != 0)) { 692 return (FWFLASH_FAILURE); 693 } 694 695 (void) printf("%30s: %s\n", "vendor", vendor); 696 (void) printf("%30s: %s\n", "product", product); 697 (void) printf("%30s: %s\n", "revision", revision); 698 (void) printf("%30s: %s\n", "serial", csn); 699 700 ret = get_status(props, &statdesc); 701 (void) printf("%30s: %s\n", "current status", statdesc.us_desc); 702 if (ret != 0) { 703 return (FWFLASH_FAILURE); 704 } 705 706 (void) snprintf(buf, sizeof (buf), "downloading %u bytes", len); 707 (void) printf("\n%30s: ", buf); 708 709 /* 710 * If the bufferid isn't 2, then the verifier has already 711 * OK'd the image that the user has provided. That means 712 * we've got manufacturing_mode = 1 from the command line. 713 * 714 * At present the non-"standard" images need to be flashed 715 * using the scsi WRITE BUFFER command 716 */ 717 if (verifier->flashbuf != 2) 718 return (scsi_writebuf()); 719 720 721 if (ses_node_ctl(np, SES_CTL_OP_DL_UCODE, arg) != 0) { 722 (void) printf("failed!\n"); 723 (void) printf("%s\n", ses_errmsg()); 724 return (FWFLASH_FAILURE); 725 } else { 726 (void) printf("ok\n"); 727 } 728 729 wait.uw_prevstatus = -1ULL; 730 wait.uw_oldnp = np; 731 732 if ((newsnap = ses_snap_new(ses_target)) == NULL) 733 logmsg(MSG_ERROR, 734 "failed to update SES snapshot: %s", 735 ses_errmsg()); 736 737 print_updated_status(ses_snap_primary_enclosure(newsnap), 738 &wait); 739 ses_snap_rele(newsnap); 740 741 return (internalstatus); 742 } 743 744 static int 745 scsi_writebuf() 746 { 747 int ret; 748 int i = 0; 749 libscsi_action_t *action; 750 spc3_write_buffer_cdb_t *wb_cdb; 751 libscsi_hdl_t *handle; 752 libscsi_target_t *target; 753 sam4_status_t samstatus; 754 755 756 target = ses_scsi_target(ses_target); 757 handle = libscsi_get_handle(target); 758 action = libscsi_action_alloc(handle, SPC3_CMD_WRITE_BUFFER, 759 LIBSCSI_AF_WRITE|LIBSCSI_AF_RQSENSE, 760 (void *)verifier->fwimage, (size_t)verifier->imgsize); 761 762 wb_cdb = (spc3_write_buffer_cdb_t *)libscsi_action_get_cdb(action); 763 wb_cdb->wbc_mode = SPC3_WB_MODE_DATA; 764 wb_cdb->wbc_bufferid = verifier->flashbuf; 765 SCSI_WRITE24(&wb_cdb->wbc_buffer_offset, 0); 766 SCSI_WRITE24(&wb_cdb->wbc_parameter_list_len, verifier->imgsize); 767 768 ret = libscsi_exec(action, target); 769 samstatus = libscsi_action_get_status(action); 770 771 logmsg(MSG_INFO, 772 "\nscsi_writebuffer: ret 0x%0x, samstatus 0x%0x\n", 773 ret, samstatus); 774 775 if ((ret != 0) || samstatus != 0) { 776 libscsi_action_free(action); 777 return (ret); 778 } else { 779 (void) printf("ok\n"); 780 } 781 782 for (i = 0; i < NSAM4_STATUS; i++) { 783 if (sam4_status[i].status == samstatus) { 784 (void) printf("%s\n", (sam4_status[i].message)); 785 break; 786 } 787 } 788 789 if (i == NSAM4_STATUS) 790 (void) printf("Status: UNKNOWN\n"); 791 792 if (samstatus == SAM4_STATUS_GOOD) { 793 internalstatus = FWFLASH_SUCCESS; 794 return (FWFLASH_SUCCESS); 795 } 796 797 return (FWFLASH_FAILURE); 798 } 799