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
fcal_update(unsigned int verbose,char * file)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
findversion(int index,uchar_t * version)298 findversion(int index, uchar_t *version)
299 /*ARGSUSED*/
300 {
301 int fd = 0, 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
feprom_program(uchar_t * source_address,uchar_t * dest_address,volatile socal_reg_t * regs)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
write_feprom(uchar_t * source_address,uchar_t * dest_address,volatile socal_reg_t * regs)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
feprom_erase(volatile uchar_t * dest_address,volatile socal_reg_t * regs)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
usec_delay(int s)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
getsbuslist(void)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
getbootdev(unsigned int verbose)594 getbootdev(unsigned int verbose)
595 {
596 char *df = "df /";
597 FILE *ptr;
598 char *p = NULL, *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
feprom_read(uchar_t * source_address,uchar_t * dest_address,int offset,int size,volatile socal_reg_t * regs)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
load_file(char * file,caddr_t prom,volatile socal_reg_t * regs)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
warn(void)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
getsocpath(char * devpath,int * devcnt)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
loadsocpath(const char * pathname,int * devcnt)915 loadsocpath(const char *pathname, int *devcnt)
916 {
917 int ret = 0;
918 int len;
919 int len_tmp;
920 char *sp = NULL;
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