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 /* 28 * I18N message number ranges 29 * This file: 4500 - 4999 30 * Shared common messages: 1 - 1999 31 */ 32 33 #include <fcntl.h> 34 #include <limits.h> 35 #include <setjmp.h> 36 #include <signal.h> 37 #include <siginfo.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <strings.h> 42 #include <unistd.h> 43 #include <ctype.h> 44 #include <dirent.h> 45 #include <sys/exec.h> 46 #include <sys/exechdr.h> 47 #include <sys/mman.h> 48 #include <sys/stat.h> 49 #include <sys/types.h> 50 #include <sys/fibre-channel/fcio.h> 51 #include <sys/socalreg.h> 52 /* 53 * The following define is not to 54 * include sys/fc4/fcal_linkapp.h 55 * file from sys/socalio.h, since it 56 * has same structure defines as in 57 * sys/fibre-channel/fcio.h. 58 */ 59 #define _SYS_FC4_FCAL_LINKAPP_H 60 #include <sys/socalio.h> 61 #include <sys/time.h> 62 #include <nl_types.h> 63 #include <errno.h> 64 #include <stgcom.h> 65 #include <gfc.h> 66 #include <l_common.h> 67 #include "luxadm.h" 68 69 /* Defines */ 70 #define FEPROM_SIZE 256*1024 71 #define FEPROM_MAX_PROGRAM 25 72 #define FEPROM_MAX_ERASE 1000 73 #define FEPROM_READ_MEMORY 0x00 74 #define FEPROM_ERASE 0x20 75 #define FEPROM_ERASE_VERIFY 0xa0 76 #define FEPROM_PROGRAM 0x40 77 #define FEPROM_PROGRAM_VERIFY 0xc0 78 #define FEPROM_RESET 0xff 79 #define HBA_MAX 128 80 81 #define FOUND 0 82 #define NOT_FOUND 1 83 #define PROM_SIZ 0x20010 84 85 #define MAX_RETRIES 3 86 #define MAX_WAIT_TIME 30 87 88 /* 89 * The next define is to work around a problem with sbusmem driver not 90 * able to round up mmap() requests that are not around page boundaries. 91 */ 92 #define PROM_SIZ_ROUNDED 0x22000 93 #define SAMPLE_SIZ 0x100 94 95 #define REG_OFFSET 0x20000 96 97 #define FEPROM_WWN_OFFSET 0x3fe00 98 99 #define FEPROM_SUN_WWN 0x50200200 100 101 /* 102 * We'll leave this on leadville, as the onboard 103 * isn't allowed to be zapped by luxadm 104 */ 105 106 #define ONBOARD_SOCAL "SUNW,socal@d" 107 108 #define SOCAL_STR "SUNW,socal" 109 #define SOCAL_STR_LEN 10 110 111 112 static uchar_t buffer[FEPROM_SIZE]; 113 114 static char sbus_list[HBA_MAX][PATH_MAX]; 115 static char sbussoc_list[HBA_MAX][PATH_MAX]; 116 static char bootpath[PATH_MAX]; 117 static char version[MAXNAMELEN]; 118 119 static uint_t getsbuslist(void); 120 static int load_file(char *, caddr_t, volatile socal_reg_t *); 121 static void usec_delay(int); 122 static void getbootdev(unsigned int); 123 static void getsocpath(char *, int *); 124 static int loadsocpath(const char *, int *); 125 static int warn(void); 126 static int findversion(int, uchar_t *); 127 static int write_feprom(uchar_t *, uchar_t *, volatile socal_reg_t *); 128 static int feprom_erase(volatile uchar_t *, volatile socal_reg_t *); 129 130 static struct exec exec; 131 132 int 133 fcal_update(unsigned int verbose, char *file) 134 /*ARGSUSED*/ 135 { 136 int fd, strfound = 0, retval = 0; 137 int fbuf_idx, fd1, bytes_read; 138 caddr_t addr; 139 uint_t i; 140 uint_t fflag = 0; 141 uint_t vflag = 0; 142 uint_t numslots; 143 volatile socal_reg_t *regs; 144 char *slotname, socal[MAXNAMELEN]; 145 char fbuf[BUFSIZ]; 146 147 if (!file) 148 vflag++; 149 else { 150 fflag++; 151 if ((fd1 = open(file, O_RDONLY)) == -1) { 152 (void) fprintf(stderr, 153 MSGSTR(4500, 154 "Error: open() failed on file " 155 "%s\n"), file); 156 return (1); 157 } 158 /* 159 * We will just make a check to see if it the file 160 * has the "SUNW,socal" strings in it 161 * We cannot use strstr() here because we are operating on 162 * binary data and so is very likely to have embedded NULLs 163 */ 164 while (!strfound && ((bytes_read = read(fd1, 165 fbuf, BUFSIZ)) > 0)) { 166 for (fbuf_idx = 0; fbuf_idx < bytes_read; 167 fbuf_idx++) { 168 /* First check for the SUNW,socal string */ 169 if (strncmp((fbuf + fbuf_idx), SOCAL_STR, 170 SOCAL_STR_LEN) == 0) { 171 strfound = 1; 172 break; 173 } 174 175 } 176 } 177 (void) close(fd1); 178 179 if (!strfound) { 180 (void) fprintf(stderr, 181 MSGSTR(4501, 182 "Error: %s is not a " 183 "FC100/S Fcode file\n"), file); 184 return (1); 185 } 186 } 187 188 /* 189 * Get count of, and names of SBus slots using the SBus memory 190 * interface. 191 */ 192 (void) getbootdev(verbose); 193 if (getenv("_LUX_D_DEBUG") != NULL) { 194 (void) fprintf(stdout, " Bootpath: %s\n", bootpath); 195 } 196 197 numslots = getsbuslist(); 198 (void) fprintf(stdout, 199 MSGSTR(4503, "\n Found Path to %d FC100/S Cards\n"), numslots); 200 201 for (i = 0; i < numslots; i++) { 202 203 /* 204 * Open SBus memory for this slot. 205 */ 206 slotname = &sbus_list[i][0]; 207 if (fflag && (strcmp(slotname, bootpath) == 0)) { 208 (void) fprintf(stderr, 209 MSGSTR(4504, " Ignoring %s (bootpath)\n"), slotname); 210 continue; 211 } 212 213 (void) sprintf(socal, "%s:0", &sbussoc_list[i][0]); 214 215 if ((fd = open(socal, O_RDWR)) < 0) { 216 (void) sprintf(socal, "%s:1", &sbussoc_list[i][0]); 217 if ((fd = open(socal, O_RDWR)) < 0) { 218 (void) fprintf(stderr, 219 MSGSTR(4505, "Could not open %s\n"), 220 &sbussoc_list[i][0]); 221 (void) fprintf(stderr, 222 MSGSTR(4506, "Ignoring %s\n"), 223 &sbussoc_list[i][0]); 224 retval++; 225 continue; 226 } 227 } 228 229 (void) close(fd); 230 231 if (verbose) { 232 (void) fprintf(stdout, "\n "); 233 (void) fprintf(stdout, 234 MSGSTR(85, "Opening %s\n"), slotname); 235 } 236 237 fd = open(slotname, O_RDWR); 238 239 if (fd < 0) { 240 perror(MSGSTR(4507, "open of slotname")); 241 retval++; 242 continue; 243 } 244 245 /* 246 * Mmap that SBus memory into my memory space. 247 */ 248 addr = mmap((caddr_t)0, PROM_SIZ_ROUNDED, PROT_READ|PROT_WRITE, 249 MAP_SHARED, fd, 0); 250 251 if (addr == MAP_FAILED) { 252 perror(MSGSTR(46, "mmap")); 253 (void) close(fd); 254 retval++; 255 continue; 256 } 257 258 if ((int)addr == -1) { 259 perror(MSGSTR(46, "mmap")); 260 (void) close(fd); 261 retval++; 262 continue; 263 } 264 265 regs = (socal_reg_t *)((int)addr + REG_OFFSET); 266 267 (void) fprintf(stdout, 268 MSGSTR(4508, "\n Device: %s\n"), 269 &sbussoc_list[i][0]); 270 /* 271 * Load the New FCode 272 */ 273 if (fflag) { 274 if (!warn()) 275 retval += load_file(file, addr, regs); 276 } else if (vflag) { 277 if (findversion(i, (uchar_t *)&version[0]) == FOUND) { 278 (void) fprintf(stdout, 279 MSGSTR(4509, 280 " Detected FC100/S Version: %s\n"), version); 281 } 282 } 283 284 if (munmap(addr, PROM_SIZ) == -1) { 285 perror(MSGSTR(4510, "munmap")); 286 retval++; 287 } 288 289 (void) close(fd); 290 291 } 292 (void) fprintf(stdout, " "); 293 (void) fprintf(stdout, MSGSTR(125, "Complete\n")); 294 return (retval); 295 } 296 297 static int 298 findversion(int index, uchar_t *version) 299 /*ARGSUSED*/ 300 { 301 int fd, ntries; 302 struct socal_fm_version *buffer; 303 char socal[MAXNAMELEN]; 304 char fp[MAXNAMELEN]; 305 char prom_ver[100]; 306 char mcode_ver[100]; 307 uint_t dev_type; 308 fcio_t fcio; 309 char fw_rev[FC_FW_REV_SIZE + 1]; 310 311 312 if ((dev_type = g_get_path_type(&sbussoc_list[index][0])) == 0) { 313 return (L_INVALID_PATH); 314 } 315 316 317 if (dev_type & FC4_FCA_MASK) { 318 P_DPRINTF("findversion: found an FC4 path\n"); 319 (void) sprintf(socal, "%s:0", &sbussoc_list[index][0]); 320 if ((fd = open(socal, O_RDWR)) < 0) { 321 (void) sprintf(socal, "%s:1", &sbussoc_list[index][0]); 322 if ((fd = open(socal, O_RDWR)) < 0) { 323 (void) fprintf(stderr, 324 MSGSTR(4511, "Could not open %s\n"), 325 &sbussoc_list[index][0]); 326 (void) close(fd); 327 return (NOT_FOUND); 328 } 329 } 330 if ((buffer = (struct socal_fm_version *)malloc( 331 sizeof (struct socal_fm_version))) == NULL) { 332 (void) fprintf(stderr, MSGSTR(10, 333 " Error: Unable to allocate memory.")); 334 (void) fprintf(stderr, "\n"); 335 (void) close(fd); 336 return (NOT_FOUND); 337 } 338 339 buffer->fcode_ver = (char *)version; 340 buffer->mcode_ver = mcode_ver; 341 buffer->prom_ver = prom_ver; 342 buffer->fcode_ver_len = MAXNAMELEN - 1; 343 buffer->mcode_ver_len = 100; 344 buffer->prom_ver_len = 100; 345 346 if (ioctl(fd, FCIO_FCODE_MCODE_VERSION, buffer) < 0) { 347 (void) fprintf(stderr, MSGSTR(4512, 348 "fcal_s_download: could not get" 349 " fcode version.\n")); 350 (void) close(fd); 351 (void) free(buffer); 352 return (NOT_FOUND); 353 } 354 version[buffer->fcode_ver_len] = '\0'; 355 free(buffer); 356 357 } else if (dev_type & FC_FCA_MASK) { 358 /* 359 * Get the fcode and prom's fw version 360 * using new ioctls. Currently, we pass 361 * only the fcode version to the calling function 362 * and ignore the FW version (using the existing 363 * implementation). The function definition 364 * might be changed in future to pass both the 365 * fcode and FW revisions to the calling function, if 366 * needed by the calling function. 367 */ 368 P_DPRINTF("findversion: found an FC path\n"); 369 (void) sprintf(fp, "%s/fp@0,0:devctl", 370 &sbussoc_list[index][0]); 371 if ((fd = open(fp, O_RDWR)) < 0) { 372 (void) sprintf(fp, "%s/fp@1,0:devctl", 373 &sbussoc_list[index][0]); 374 if ((fd = open(fp, O_RDWR)) < 0) { 375 (void) fprintf(stderr, 376 MSGSTR(4511, "Could not open %s\n"), 377 &sbussoc_list[index][0]); 378 (void) close(fd); 379 return (NOT_FOUND); 380 } 381 } 382 /* Get the fcode version */ 383 bzero(version, sizeof (version)); 384 fcio.fcio_cmd = FCIO_GET_FCODE_REV; 385 /* Information read operation */ 386 fcio.fcio_xfer = FCIO_XFER_READ; 387 fcio.fcio_obuf = (caddr_t)version; 388 fcio.fcio_olen = MAXNAMELEN; 389 390 for (ntries = 0; ntries < MAX_RETRIES; ntries++) { 391 if (ioctl(fd, FCIO_CMD, &fcio) != 0) { 392 if ((errno == EAGAIN) && 393 (ntries+1 < MAX_RETRIES)) { 394 /* wait 30 secs */ 395 (void) sleep(MAX_WAIT_TIME); 396 continue; 397 } 398 I_DPRINTF("ioctl FCIO_GET_FCODE_REV failed.\n" 399 "Error: %s\n", strerror(errno)); 400 (void) close(fd); 401 return (L_FCIO_GET_FCODE_REV_FAIL); 402 } 403 break; 404 } 405 version[MAXNAMELEN-1] = '\0'; 406 407 /* Get the FW revision */ 408 bzero(fw_rev, sizeof (fw_rev)); 409 fcio.fcio_cmd = FCIO_GET_FW_REV; 410 /* Information read operation */ 411 fcio.fcio_xfer = FCIO_XFER_READ; 412 fcio.fcio_obuf = (caddr_t)fw_rev; 413 fcio.fcio_olen = FC_FW_REV_SIZE; 414 for (ntries = 0; ntries < MAX_RETRIES; ntries++) { 415 if (ioctl(fd, FCIO_CMD, &fcio) != 0) { 416 if ((errno == EAGAIN) && 417 (ntries+1 < MAX_RETRIES)) { 418 /* wait 30 secs */ 419 (void) sleep(MAX_WAIT_TIME); 420 continue; 421 } 422 I_DPRINTF(" FCIO_GET_FW_REV ioctl failed.\n" 423 " Error: %s\n", strerror(errno)); 424 (void) close(fd); 425 return (L_FCIO_GET_FW_REV_FAIL); 426 } 427 break; 428 } 429 } 430 431 (void) close(fd); 432 return (FOUND); 433 } 434 /* 435 * program an FEprom with data from 'source_address'. 436 * program the FEprom with zeroes, 437 * erase it, 438 * program it with the real data. 439 */ 440 static int 441 feprom_program(uchar_t *source_address, uchar_t *dest_address, 442 volatile socal_reg_t *regs) 443 { 444 int i; 445 446 (void) fprintf(stdout, MSGSTR(4513, "Filling with zeroes...\n")); 447 if (!write_feprom((uchar_t *)0, dest_address, regs)) { 448 (void) fprintf(stderr, 449 MSGSTR(4514, "FEprom at 0x%x: zero fill failed\n"), 450 (int)dest_address); 451 return (0); 452 } 453 454 (void) fprintf(stdout, MSGSTR(4515, "Erasing...\n")); 455 for (i = 0; i < FEPROM_MAX_ERASE; i++) { 456 if (feprom_erase(dest_address, regs)) 457 break; 458 } 459 460 if (i >= FEPROM_MAX_ERASE) { 461 (void) fprintf(stderr, 462 MSGSTR(4516, "FEprom at 0x%x: failed to erase\n"), 463 (int)dest_address); 464 return (0); 465 } else if (i > 0) { 466 if (i == 1) { 467 (void) fprintf(stderr, MSGSTR(4517, 468 "FEprom erased after %d attempt\n"), i); 469 } else { 470 (void) fprintf(stderr, MSGSTR(4518, 471 "FEprom erased after %d attempts\n"), i); 472 } 473 } 474 475 (void) fprintf(stdout, MSGSTR(4519, "Programming...\n")); 476 if (!(write_feprom(source_address, dest_address, regs))) { 477 (void) fprintf(stderr, 478 MSGSTR(4520, "FEprom at 0x%x: write failed\n"), 479 (int)dest_address); 480 return (0); 481 } 482 483 /* select the zeroth bank at end so we can read it */ 484 regs->socal_cr.w &= ~(0x30000); 485 (void) fprintf(stdout, MSGSTR(4521, "Programming done\n")); 486 return (1); 487 } 488 489 /* 490 * program an FEprom one byte at a time using hot electron injection. 491 */ 492 static int 493 write_feprom(uchar_t *source_address, uchar_t *dest_address, 494 volatile socal_reg_t *regs) 495 { 496 int pulse, i; 497 uchar_t *s = source_address; 498 volatile uchar_t *d; 499 500 for (i = 0; i < FEPROM_SIZE; i++, s++) { 501 502 if ((i & 0xffff) == 0) { 503 (void) fprintf(stdout, 504 MSGSTR(4522, "selecting bank %d\n"), i>>16); 505 regs->socal_cr.w &= ~(0x30000); 506 regs->socal_cr.w |= i & 0x30000; 507 } 508 509 d = dest_address + (i & 0xffff); 510 511 for (pulse = 0; pulse < FEPROM_MAX_PROGRAM; pulse++) { 512 *d = FEPROM_PROGRAM; 513 *d = source_address ? *s : 0; 514 usec_delay(50); 515 *d = FEPROM_PROGRAM_VERIFY; 516 usec_delay(30); 517 if (*d == (source_address ? *s : 0)) 518 break; 519 } 520 521 if (pulse >= FEPROM_MAX_PROGRAM) { 522 *dest_address = FEPROM_RESET; 523 return (0); 524 } 525 } 526 527 *dest_address = FEPROM_RESET; 528 return (1); 529 } 530 531 /* 532 * erase an FEprom using Fowler-Nordheim tunneling. 533 */ 534 static int 535 feprom_erase(volatile uchar_t *dest_address, volatile socal_reg_t *regs) 536 { 537 int i; 538 volatile uchar_t *d = dest_address; 539 540 *d = FEPROM_ERASE; 541 usec_delay(50); 542 *d = FEPROM_ERASE; 543 544 usec_delay(10000); /* wait 10ms while FEprom erases */ 545 546 for (i = 0; i < FEPROM_SIZE; i++) { 547 548 if ((i & 0xffff) == 0) { 549 regs->socal_cr.w &= ~(0x30000); 550 regs->socal_cr.w |= i & 0x30000; 551 } 552 553 d = dest_address + (i & 0xffff); 554 555 *d = FEPROM_ERASE_VERIFY; 556 usec_delay(50); 557 if (*d != 0xff) { 558 *dest_address = FEPROM_RESET; 559 return (0); 560 } 561 } 562 *dest_address = FEPROM_RESET; 563 return (1); 564 } 565 566 static void 567 usec_delay(int s) 568 { 569 hrtime_t now, then; 570 571 now = gethrtime(); 572 then = now + s*1000; 573 do { 574 now = gethrtime(); 575 } while (now < then); 576 } 577 578 static uint_t 579 getsbuslist(void) 580 { 581 int devcnt = 0; 582 char devpath[PATH_MAX]; 583 584 /* We're searching the /devices directory, so... */ 585 (void) strcpy(devpath, "/devices"); 586 587 /* get the directory entries under /devices for socal sbusmem */ 588 (void) getsocpath(devpath, (int *)&devcnt); 589 590 return (devcnt); 591 } 592 593 static void 594 getbootdev(unsigned int verbose) 595 { 596 char *df = "df /"; 597 FILE *ptr; 598 char *p, *p1; 599 char bootdev[PATH_MAX]; 600 char buf[BUFSIZ]; 601 int foundroot = 0; 602 603 604 if ((ptr = popen(df, "r")) != NULL) { 605 while (fgets(buf, BUFSIZ, ptr) != NULL) { 606 if (p = strstr(buf, "/dev/dsk/")) { 607 (void) memset((char *)&bootdev[0], 0, 608 PATH_MAX); 609 p1 = p; 610 while (*p1 != '\0') { 611 if (!isalnum(*p1) && (*p1 != '/')) 612 *p1 = ' '; 613 p1++; 614 } 615 (void) sscanf(p, "%s", bootdev); 616 foundroot = 1; 617 } 618 } 619 if (!foundroot) { 620 if (verbose) 621 (void) fprintf(stderr, MSGSTR(44, 622 "root is not on a local disk!\n")); 623 (void) memset((char *)&bootpath[0], 0, PATH_MAX); 624 return; 625 } 626 (void) pclose(ptr); 627 if (bootdev[0]) { 628 char *ls; 629 char *p1; 630 char *p2 = NULL; 631 char *sbusmem = "/sbusmem@"; 632 char *slot = ",0:slot"; 633 634 ls = (char *)malloc(PATH_MAX); 635 (void) memset((char *)ls, 0, PATH_MAX); 636 (void) strcpy(ls, "ls -l "); 637 (void) strcat(ls, bootdev); 638 if ((ptr = popen(ls, "r")) != NULL) { 639 while (fgets(buf, BUFSIZ, ptr) != NULL) { 640 if (p = strstr(buf, "/devices")) { 641 if (p1 = strstr(buf, "sbus")) { 642 while (*p1 != '/') 643 p1++; 644 p2 = strstr(p1, "@"); 645 ++p2; 646 *p1 = '\0'; 647 } else { 648 if (p1 = strstr(buf, 649 SOCAL_STR)) { 650 p2 = strstr(p1, "@"); 651 ++p2; 652 --p1; 653 *p1 = '\0'; 654 } 655 } 656 } 657 } 658 (void) pclose(ptr); 659 } 660 (void) memset((char *)&bootdev[0], 0, PATH_MAX); 661 (void) sscanf(p, "%s", bootdev); 662 (void) memset((char *)&bootpath[0], 0, PATH_MAX); 663 (void) strcat(bootpath, bootdev); 664 (void) strcat(bootpath, sbusmem); 665 if (p2) { 666 (void) strncat(bootpath, p2, 1); 667 (void) strcat(bootpath, slot); 668 (void) strncat(bootpath, p2, 1); 669 } 670 } 671 } 672 } 673 674 /* 675 * This function reads "size" bytes from the FC100/S PROM. 676 * source_address: PROM address 677 * dest_address: local memeory 678 * offset: Location in PROM to start reading from. 679 */ 680 static void 681 feprom_read(uchar_t *source_address, uchar_t *dest_address, 682 int offset, int size, volatile socal_reg_t *regs) 683 { 684 uchar_t *s = source_address; 685 uchar_t *d = dest_address; 686 int i = offset; 687 688 if (getenv("_LUX_D_DEBUG") != NULL) { 689 (void) fprintf(stdout, 690 " feprom_read: selecting bank %d\n", 691 (i&0xf0000)>>16); 692 if (size <= 8) { 693 (void) fprintf(stdout, " Data read: "); 694 } 695 } 696 regs->socal_cr.w = i & 0xf0000; 697 s = source_address + (i & 0xffff); 698 *s = FEPROM_READ_MEMORY; 699 usec_delay(6); 700 for (; s < source_address + (i & 0xffff) + size; d++, s++) { 701 *d = *s; 702 if ((getenv("_LUX_D_DEBUG") != NULL) && 703 (size <= 8)) { 704 (void) fprintf(stdout, "0x%x ", *d); 705 } 706 } 707 if ((getenv("_LUX_D_DEBUG") != NULL) && 708 (size <= 8)) { 709 (void) fprintf(stdout, "\n From offset: 0x%x\n", 710 offset); 711 } 712 } 713 714 715 static int 716 load_file(char *file, caddr_t prom, volatile socal_reg_t *regs) 717 { 718 uint_t wwn_d8, wwn_lo; 719 uint_t wwn_hi; 720 int ffd = open(file, 0); 721 722 wwn_hi = FEPROM_SUN_WWN; 723 724 if (ffd < 0) { 725 perror(MSGSTR(4524, "open of file")); 726 exit(1); 727 } 728 (void) fprintf(stdout, MSGSTR(4525, "Loading FCode: %s\n"), file); 729 730 if (read(ffd, &exec, sizeof (exec)) != sizeof (exec)) { 731 perror(MSGSTR(4526, "read exec")); 732 exit(1); 733 } 734 735 if (exec.a_trsize || exec.a_drsize) { 736 (void) fprintf(stderr, 737 MSGSTR(4527, "%s: is relocatable\n"), file); 738 exit(1); 739 } 740 741 if (exec.a_data || exec.a_bss) { 742 (void) fprintf(stderr, 743 MSGSTR(4528, "%s: has data or bss\n"), file); 744 exit(1); 745 } 746 747 if (exec.a_machtype != M_SPARC) { 748 (void) fprintf(stderr, 749 MSGSTR(4529, "%s: not for SPARC\n"), file); 750 exit(1); 751 } 752 753 (void) fprintf(stdout, MSGSTR(4530, 754 "Loading 0x%x bytes from %s at offset 0x%x\n"), 755 (int)exec.a_text, file, 0); 756 757 if (read(ffd, &buffer, exec.a_text) != exec.a_text) { 758 perror(MSGSTR(4531, "read")); 759 exit(1); 760 } 761 762 (void) close(ffd); 763 764 feprom_read((uchar_t *)prom, (uchar_t *)&wwn_d8, 765 FEPROM_WWN_OFFSET, 4, regs); 766 feprom_read((uchar_t *)prom, (uchar_t *)&wwn_lo, 767 FEPROM_WWN_OFFSET + 4, 4, regs); 768 wwn_hi |= wwn_d8 & 0x0f; /* only last digit is interesting */ 769 if (getenv("_LUX_D_DEBUG") != NULL) { 770 (void) fprintf(stdout, 771 " load_file: Writing WWN hi:0x%x lo:0x%x " 772 "to the FC100/S PROM\n", wwn_hi, wwn_lo); 773 } 774 /* put wwn into buffer location */ 775 bcopy((const void *)&wwn_hi, 776 (void *)&buffer[FEPROM_WWN_OFFSET], 777 sizeof (wwn_hi)); 778 bcopy((const void *)&wwn_lo, 779 (void *)&buffer[FEPROM_WWN_OFFSET + 4], 780 sizeof (wwn_lo)); 781 bcopy((const void *)&wwn_hi, 782 (void *)&buffer[FEPROM_WWN_OFFSET + 8], 783 sizeof (wwn_hi)); 784 bcopy((const void *)&wwn_lo, 785 (void *)&buffer[FEPROM_WWN_OFFSET + 0xc], 786 sizeof (wwn_lo)); 787 788 if (feprom_program((uchar_t *)buffer, (uchar_t *)prom, regs) == 0) { 789 /* here 0 means failure */ 790 return (1); 791 } 792 793 return (0); 794 } 795 796 static int 797 warn(void) 798 { 799 char input[1024]; 800 801 input[0] = '\0'; 802 803 (void) fprintf(stderr, MSGSTR(4532, 804 "\nWARNING!! This program will update the FCode in this FC100/S Sbus Card.\n")); 805 (void) fprintf(stderr, MSGSTR(4533, 806 "This may take a few (5) minutes. Please be patient.\n")); 807 808 loop1: 809 (void) fprintf(stderr, MSGSTR(4534, 810 "Do you wish to continue ? (y/n) ")); 811 812 (void) gets(input); 813 814 if ((strcmp(input, MSGSTR(4535, "y")) == 0) || 815 (strcmp(input, MSGSTR(40, "yes")) == 0)) { 816 return (FOUND); 817 } else if ((strcmp(input, MSGSTR(4536, "n")) == 0) || 818 (strcmp(input, MSGSTR(45, "no")) == 0)) { 819 (void) fprintf(stderr, MSGSTR(4537, "Not Downloading FCode\n")); 820 return (NOT_FOUND); 821 } else { 822 (void) fprintf(stderr, MSGSTR(4538, "Invalid input\n")); 823 goto loop1; 824 } 825 } 826 827 828 /* 829 * getsocpath(): 830 * Searches the /devices directory recursively returning all soc_name 831 * entries in sbussoc_list (global). This excludes port entries and 832 * onboard socal (which leaves only directory entries with 833 * soc_name included). devcnt is updated to reflect number of soc_name 834 * devices found. 835 */ 836 837 static void 838 getsocpath(char *devpath, int *devcnt) 839 { 840 struct stat statbuf; 841 struct dirent *dirp; 842 DIR *dp; 843 char *ptr; 844 845 if (lstat(devpath, &statbuf) < 0) { 846 (void) fprintf(stderr, 847 MSGSTR(4539, "Error: %s lstat() error\n"), devpath); 848 exit(1); 849 } 850 851 if (S_ISDIR(statbuf.st_mode) == 0) 852 /* 853 * not a directory so 854 * we don't care about it - return 855 */ 856 return; 857 858 else { 859 if (strstr(devpath, ONBOARD_SOCAL)) 860 return; 861 862 if (strstr(devpath, SOCAL_STR)) { 863 /* It's a keeper - call the load function */ 864 if ((loadsocpath(devpath, devcnt)) < 0) { 865 (void) fprintf(stderr, 866 MSGSTR(4540, "Error: Cannot set device list\n"), 867 devpath); 868 exit(1); 869 } 870 /* 871 * if socal directory - return, 872 * nothing else to see here 873 */ 874 return; 875 } 876 } 877 878 /* 879 * It's a directory. Call ourself to 880 * traverse the path(s) 881 */ 882 883 ptr = devpath + strlen(devpath); 884 *ptr++ = '/'; 885 *ptr = 0; 886 887 /* Forget the /devices/pseudo/ directory */ 888 if (strcmp(devpath, "/devices/pseudo/") == 0) 889 return; 890 891 if ((dp = opendir(devpath)) == NULL) { 892 (void) fprintf(stderr, 893 MSGSTR(4541, "Error: %s Can't read directory\n"), devpath); 894 exit(1); 895 } 896 897 while ((dirp = readdir(dp)) != NULL) { 898 899 if (strcmp(dirp->d_name, ".") == 0 || 900 strcmp(dirp->d_name, "..") == 0) 901 continue; 902 903 (void) strcpy(ptr, dirp->d_name); /* append name */ 904 getsocpath(devpath, devcnt); 905 } 906 907 if (closedir(dp) < 0) { 908 (void) fprintf(stderr, 909 MSGSTR(4542, "Error: %s Can't close directory\n"), devpath); 910 exit(1); 911 } 912 } 913 914 static int 915 loadsocpath(const char *pathname, int *devcnt) 916 { 917 int ret = 0; 918 int len; 919 int len_tmp; 920 char *sp; 921 char *sp_tmp; 922 char buffer[PATH_MAX]; 923 924 925 /* 926 * Okay we found a device, now let's load it in to sbussoc_list 927 * and load the sbusmem file into sbus_list 928 */ 929 930 if (pathname != NULL && *devcnt < HBA_MAX) { 931 (void) strcpy(sbussoc_list[*devcnt], pathname); 932 if (sp_tmp = strstr(sbussoc_list[*devcnt], SOCAL_STR)) { 933 sp = sp_tmp; 934 /* len_tmp will be len of "SUNW,socal@" */ 935 len_tmp = SOCAL_STR_LEN + 1; 936 } 937 len = strlen(sbussoc_list[*devcnt]) - strlen(sp); 938 (void) strncpy(buffer, sbussoc_list[*devcnt], len); 939 buffer[len] = '\0'; 940 sp += len_tmp; 941 (void) sprintf(sbus_list[*devcnt], "%ssbusmem@%c,0:slot%c", 942 buffer, sp[0], sp[0]); 943 *devcnt += 1; 944 } 945 else 946 ret = -1; 947 return (ret); 948 } 949