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