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