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 /* 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 (void) strlcpy(newdev->addresses[0], 490 "(not supported)", 17); 491 } 492 493 494 rv = di_prop_lookup_strings(DDI_DEV_T_ANY, 495 thisnode, "target-port", &newdev->addresses[1]); 496 if (rv < 0) { 497 logmsg(MSG_INFO, 498 "%s: no target-port property " 499 "for device %s\n", 500 driver, newdev->access_devname); 501 (void) strlcpy(newdev->addresses[1], 502 "(not supported)", 17); 503 } else 504 logmsg(MSG_INFO, 505 "target-port property: %s\n", 506 newdev->addresses[1]); 507 508 509 newdev->index = idx; 510 ++idx; 511 newdev->plugin = self; 512 513 ses_snap_rele(snapshot); 514 TAILQ_INSERT_TAIL(fw_devices, newdev, nextdev); 515 } 516 517 518 if (fwflash_debug != 0) { 519 struct devicelist *tempdev; 520 521 TAILQ_FOREACH(tempdev, fw_devices, nextdev) { 522 logmsg(MSG_INFO, "%s:fw_identify:\n", 523 driver); 524 logmsg(MSG_INFO, 525 "\ttempdev @ 0x%lx\n" 526 "\t\taccess_devname: %s\n" 527 "\t\tdrvname: %s\tclassname: %s\n" 528 "\t\tident->vid: %s\n" 529 "\t\tident->pid: %s\n" 530 "\t\tident->revid: %s\n" 531 "\t\tindex: %d\n" 532 "\t\taddress[0]: %s\n" 533 "\t\taddress[1]: %s\n" 534 "\t\tplugin @ 0x%lx\n\n", 535 &tempdev, 536 tempdev->access_devname, 537 tempdev->drvname, newdev->classname, 538 tempdev->ident->vid, 539 tempdev->ident->pid, 540 tempdev->ident->revid, 541 tempdev->index, 542 tempdev->addresses[0], 543 tempdev->addresses[1], 544 &tempdev->plugin); 545 } 546 } 547 548 return (FWFLASH_SUCCESS); 549 } 550 551 552 553 int 554 fw_devinfo(struct devicelist *thisdev) 555 { 556 557 558 fprintf(stdout, gettext("Device[%d] %s\n Class [%s]\n"), 559 thisdev->index, thisdev->access_devname, thisdev->classname); 560 561 fprintf(stdout, 562 gettext("\tVendor : %s\n" 563 "\tProduct : %s\n" 564 "\tFirmware revision : %s\n" 565 "\tChassis Serial Number : %s\n" 566 "\tTarget-port identifier : %s\n"), 567 thisdev->ident->vid, 568 thisdev->ident->pid, 569 thisdev->ident->revid, 570 thisdev->addresses[0], 571 thisdev->addresses[1]); 572 573 fprintf(stdout, "\n\n"); 574 575 return (FWFLASH_SUCCESS); 576 } 577 578 579 580 581 582 /*ARGSUSED*/ 583 static int 584 get_status(nvlist_t *props, ucode_status_t *sp) 585 { 586 int i; 587 uint64_t status, astatus; 588 589 if (nvlist_lookup_uint64(props, SES_EN_PROP_UCODE, &status) != 0) { 590 sp->us_status = -1ULL; 591 (void) snprintf(sp->us_desc, sizeof (sp->us_desc), 592 "not supported"); 593 internalstatus = FWFLASH_FAILURE; 594 return (-1); 595 } 596 597 if (nvlist_lookup_uint64(props, SES_EN_PROP_UCODE_A, 598 &astatus) != 0) { 599 logmsg(MSG_ERROR, 600 gettext("\nError: Unable to retrieve current status\n")); 601 internalstatus = FWFLASH_FAILURE; 602 return (-1); 603 } 604 605 for (i = 0; i < NUCODE_STATUS; i++) { 606 if (ucode_statdesc_table[i].us_value == status) 607 break; 608 } 609 610 sp->us_status = status; 611 612 if (i == NUCODE_STATUS) { 613 (void) snprintf(sp->us_desc, sizeof (sp->us_desc), 614 "unknown (0x%02x)", (int)status); 615 sp->us_iserr = sp->us_pending = B_FALSE; 616 } else { 617 /* LINTED */ 618 (void) snprintf(sp->us_desc, sizeof (sp->us_desc), 619 ucode_statdesc_table[i].us_desc, (int)astatus); 620 sp->us_iserr = ucode_statdesc_table[i].us_iserr; 621 sp->us_pending = ucode_statdesc_table[i].us_pending; 622 } 623 624 return (0); 625 } 626 627 628 static void 629 print_updated_status(ses_node_t *np, void *arg) 630 { 631 ucode_wait_t *uwp = arg; 632 nvlist_t *props; 633 ucode_status_t status; 634 635 636 if ((props = ses_node_props(np)) == NULL) { 637 internalstatus = FWFLASH_FAILURE; 638 return; 639 } 640 641 if (get_status(props, &status) != 0) 642 /* internalstatus is already set to FWFLASH_FAILURE */ 643 return; 644 645 if (status.us_status != uwp->uw_prevstatus) 646 (void) printf("%30s: %s\n", "status", status.us_desc); 647 648 uwp->uw_prevstatus = status.us_status; 649 uwp->uw_pending = status.us_pending; 650 651 if (status.us_iserr) { 652 logmsg(MSG_INFO, 653 "libses: status.us_iserr: 0x%0x\n", 654 status.us_iserr); 655 internalstatus = FWFLASH_FAILURE; 656 } else 657 internalstatus = FWFLASH_SUCCESS; 658 659 } 660 661 /*ARGSUSED*/ 662 static int 663 sendimg(ses_node_t *np, void *data) 664 { 665 nvlist_t *props; 666 nvlist_t *arg = data; 667 char *vendor, *product, *revision, *csn; 668 char buf[128]; 669 ses_snap_t *newsnap; 670 int ret; 671 ucode_status_t statdesc; 672 ucode_wait_t wait; 673 uint8_t *imagedata; 674 uint_t len; 675 676 677 /* If we've been called without data, eject */ 678 if (nvlist_lookup_byte_array(arg, SES_CTL_PROP_UCODE_DATA, 679 &imagedata, &len) != 0) { 680 return (FWFLASH_FAILURE); 681 } 682 683 props = ses_node_props(np); 684 if ((props == NULL) || 685 (nvlist_lookup_string(props, SES_EN_PROP_VID, &vendor) != 0) || 686 (nvlist_lookup_string(props, SES_EN_PROP_PID, &product) != 0) || 687 (nvlist_lookup_string(props, SES_EN_PROP_REV, &revision) != 0) || 688 (nvlist_lookup_string(props, LIBSES_EN_PROP_CSN, &csn) != 0)) { 689 return (FWFLASH_FAILURE); 690 } 691 692 (void) printf("%30s: %s\n", "vendor", vendor); 693 (void) printf("%30s: %s\n", "product", product); 694 (void) printf("%30s: %s\n", "revision", revision); 695 (void) printf("%30s: %s\n", "serial", csn); 696 697 ret = get_status(props, &statdesc); 698 (void) printf("%30s: %s\n", "current status", statdesc.us_desc); 699 if (ret != 0) { 700 return (FWFLASH_FAILURE); 701 } 702 703 (void) snprintf(buf, sizeof (buf), "downloading %u bytes", len); 704 (void) printf("\n%30s: ", buf); 705 706 /* 707 * If the bufferid isn't 2, then the verifier has already 708 * OK'd the image that the user has provided. That means 709 * we've got manufacturing_mode = 1 from the command line. 710 * 711 * At present the non-"standard" images need to be flashed 712 * using the scsi WRITE BUFFER command 713 */ 714 if (verifier->flashbuf != 2) 715 return (scsi_writebuf()); 716 717 718 if (ses_node_ctl(np, SES_CTL_OP_DL_UCODE, arg) != 0) { 719 (void) printf("failed!\n"); 720 (void) printf("%s\n", ses_errmsg()); 721 return (FWFLASH_FAILURE); 722 } else { 723 (void) printf("ok\n"); 724 } 725 726 wait.uw_prevstatus = -1ULL; 727 wait.uw_oldnp = np; 728 729 if ((newsnap = ses_snap_new(ses_target)) == NULL) 730 logmsg(MSG_ERROR, 731 "failed to update SES snapshot: %s", 732 ses_errmsg()); 733 734 print_updated_status(ses_snap_primary_enclosure(newsnap), 735 &wait); 736 ses_snap_rele(newsnap); 737 738 return (internalstatus); 739 } 740 741 static int 742 scsi_writebuf() 743 { 744 int ret; 745 int i = 0; 746 libscsi_action_t *action; 747 spc3_write_buffer_cdb_t *wb_cdb; 748 libscsi_hdl_t *handle; 749 libscsi_target_t *target; 750 sam4_status_t samstatus; 751 752 753 target = ses_scsi_target(ses_target); 754 handle = libscsi_get_handle(target); 755 action = libscsi_action_alloc(handle, SPC3_CMD_WRITE_BUFFER, 756 LIBSCSI_AF_WRITE|LIBSCSI_AF_RQSENSE, 757 (void *)verifier->fwimage, (size_t)verifier->imgsize); 758 759 wb_cdb = (spc3_write_buffer_cdb_t *)libscsi_action_get_cdb(action); 760 wb_cdb->wbc_mode = SPC3_WB_MODE_DATA; 761 wb_cdb->wbc_bufferid = verifier->flashbuf; 762 SCSI_WRITE24(&wb_cdb->wbc_buffer_offset, 0); 763 SCSI_WRITE24(&wb_cdb->wbc_parameter_list_len, verifier->imgsize); 764 765 ret = libscsi_exec(action, target); 766 samstatus = libscsi_action_get_status(action); 767 768 logmsg(MSG_INFO, 769 "\nscsi_writebuffer: ret 0x%0x, samstatus 0x%0x\n", 770 ret, samstatus); 771 772 if ((ret != 0) || samstatus != 0) { 773 libscsi_action_free(action); 774 return (ret); 775 } else { 776 (void) printf("ok\n"); 777 } 778 779 for (i = 0; i < NSAM4_STATUS; i++) { 780 if (sam4_status[i].status == samstatus) { 781 (void) printf("%s\n", (sam4_status[i].message)); 782 break; 783 } 784 } 785 786 if (i == NSAM4_STATUS) 787 (void) printf("Status: UNKNOWN\n"); 788 789 if (samstatus == SAM4_STATUS_GOOD) { 790 internalstatus = FWFLASH_SUCCESS; 791 return (FWFLASH_SUCCESS); 792 } 793 794 return (FWFLASH_FAILURE); 795 } 796