/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* I18N message number ranges
* This file: 4500 - 4999
* Shared common messages: 1 - 1999
*/
#include <fcntl.h>
#include <limits.h>
#include <setjmp.h>
#include <signal.h>
#include <siginfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <ctype.h>
#include <dirent.h>
#include <sys/socalreg.h>
/*
* The following define is not to
* include sys/fc4/fcal_linkapp.h
* has same structure defines as in
*/
#define _SYS_FC4_FCAL_LINKAPP_H
#include <nl_types.h>
#include <errno.h>
#include <stgcom.h>
#include <gfc.h>
#include <l_common.h>
#include "luxadm.h"
/* Defines */
#define FOUND 0
/*
* The next define is to work around a problem with sbusmem driver not
* able to round up mmap() requests that are not around page boundaries.
*/
/*
* We'll leave this on leadville, as the onboard
* isn't allowed to be zapped by luxadm
*/
static uint_t getsbuslist(void);
static void usec_delay(int);
static void getbootdev(unsigned int);
static void getsocpath(char *, int *);
static int loadsocpath(const char *, int *);
static int warn(void);
static int findversion(int, uchar_t *);
int
/*ARGSUSED*/
{
uint_t i;
if (!file)
vflag++;
else {
fflag++;
MSGSTR(4500,
"Error: open() failed on file "
"%s\n"), file);
return (1);
}
/*
* We will just make a check to see if it the file
* has the "SUNW,socal" strings in it
* We cannot use strstr() here because we are operating on
* binary data and so is very likely to have embedded NULLs
*/
fbuf_idx++) {
/* First check for the SUNW,socal string */
SOCAL_STR_LEN) == 0) {
strfound = 1;
break;
}
}
}
if (!strfound) {
MSGSTR(4501,
"Error: %s is not a "
"FC100/S Fcode file\n"), file);
return (1);
}
}
/*
* Get count of, and names of SBus slots using the SBus memory
* interface.
*/
(void) getbootdev(verbose);
}
numslots = getsbuslist();
for (i = 0; i < numslots; i++) {
/*
* Open SBus memory for this slot.
*/
continue;
}
&sbussoc_list[i][0]);
&sbussoc_list[i][0]);
retval++;
continue;
}
}
if (verbose) {
}
if (fd < 0) {
retval++;
continue;
}
/*
* Mmap that SBus memory into my memory space.
*/
MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) {
retval++;
continue;
}
if ((int)addr == -1) {
retval++;
continue;
}
&sbussoc_list[i][0]);
/*
* Load the New FCode
*/
if (fflag) {
if (!warn())
} else if (vflag) {
MSGSTR(4509,
" Detected FC100/S Version: %s\n"), version);
}
}
retval++;
}
}
return (retval);
}
static int
/*ARGSUSED*/
{
return (L_INVALID_PATH);
}
if (dev_type & FC4_FCA_MASK) {
P_DPRINTF("findversion: found an FC4 path\n");
&sbussoc_list[index][0]);
return (NOT_FOUND);
}
}
sizeof (struct socal_fm_version))) == NULL) {
" Error: Unable to allocate memory."));
return (NOT_FOUND);
}
"fcal_s_download: could not get"
" fcode version.\n"));
return (NOT_FOUND);
}
} else if (dev_type & FC_FCA_MASK) {
/*
* Get the fcode and prom's fw version
* using new ioctls. Currently, we pass
* only the fcode version to the calling function
* and ignore the FW version (using the existing
* implementation). The function definition
* might be changed in future to pass both the
* fcode and FW revisions to the calling function, if
* needed by the calling function.
*/
P_DPRINTF("findversion: found an FC path\n");
&sbussoc_list[index][0]);
&sbussoc_list[index][0]);
&sbussoc_list[index][0]);
return (NOT_FOUND);
}
}
/* Get the fcode version */
/* Information read operation */
/* wait 30 secs */
(void) sleep(MAX_WAIT_TIME);
continue;
}
I_DPRINTF("ioctl FCIO_GET_FCODE_REV failed.\n"
return (L_FCIO_GET_FCODE_REV_FAIL);
}
break;
}
/* Get the FW revision */
/* Information read operation */
/* wait 30 secs */
(void) sleep(MAX_WAIT_TIME);
continue;
}
I_DPRINTF(" FCIO_GET_FW_REV ioctl failed.\n"
return (L_FCIO_GET_FW_REV_FAIL);
}
break;
}
}
return (FOUND);
}
/*
* program an FEprom with data from 'source_address'.
* program the FEprom with zeroes,
* erase it,
* program it with the real data.
*/
static int
volatile socal_reg_t *regs)
{
int i;
(int)dest_address);
return (0);
}
for (i = 0; i < FEPROM_MAX_ERASE; i++) {
break;
}
if (i >= FEPROM_MAX_ERASE) {
(int)dest_address);
return (0);
} else if (i > 0) {
if (i == 1) {
"FEprom erased after %d attempt\n"), i);
} else {
"FEprom erased after %d attempts\n"), i);
}
}
(int)dest_address);
return (0);
}
/* select the zeroth bank at end so we can read it */
return (1);
}
/*
* program an FEprom one byte at a time using hot electron injection.
*/
static int
volatile socal_reg_t *regs)
{
int pulse, i;
uchar_t *s = source_address;
volatile uchar_t *d;
for (i = 0; i < FEPROM_SIZE; i++, s++) {
if ((i & 0xffff) == 0) {
}
d = dest_address + (i & 0xffff);
*d = FEPROM_PROGRAM;
*d = source_address ? *s : 0;
usec_delay(50);
*d = FEPROM_PROGRAM_VERIFY;
usec_delay(30);
if (*d == (source_address ? *s : 0))
break;
}
if (pulse >= FEPROM_MAX_PROGRAM) {
return (0);
}
}
return (1);
}
/*
* erase an FEprom using Fowler-Nordheim tunneling.
*/
static int
{
int i;
volatile uchar_t *d = dest_address;
*d = FEPROM_ERASE;
usec_delay(50);
*d = FEPROM_ERASE;
for (i = 0; i < FEPROM_SIZE; i++) {
if ((i & 0xffff) == 0) {
}
d = dest_address + (i & 0xffff);
*d = FEPROM_ERASE_VERIFY;
usec_delay(50);
if (*d != 0xff) {
return (0);
}
}
return (1);
}
static void
usec_delay(int s)
{
do {
}
static uint_t
getsbuslist(void)
{
int devcnt = 0;
/* We're searching the /devices directory, so... */
/* get the directory entries under /devices for socal sbusmem */
return (devcnt);
}
static void
{
char *p, *p1;
int foundroot = 0;
PATH_MAX);
p1 = p;
while (*p1 != '\0') {
*p1 = ' ';
p1++;
}
foundroot = 1;
}
}
if (!foundroot) {
if (verbose)
"root is not on a local disk!\n"));
return;
}
if (bootdev[0]) {
char *ls;
char *p1;
while (*p1 != '/')
p1++;
++p2;
*p1 = '\0';
} else {
SOCAL_STR)) {
++p2;
--p1;
*p1 = '\0';
}
}
}
}
}
if (p2) {
}
}
}
}
/*
* This function reads "size" bytes from the FC100/S PROM.
* source_address: PROM address
* dest_address: local memeory
* offset: Location in PROM to start reading from.
*/
static void
{
uchar_t *s = source_address;
uchar_t *d = dest_address;
int i = offset;
" feprom_read: selecting bank %d\n",
(i&0xf0000)>>16);
if (size <= 8) {
}
}
s = source_address + (i & 0xffff);
*s = FEPROM_READ_MEMORY;
usec_delay(6);
*d = *s;
(size <= 8)) {
}
}
(size <= 8)) {
offset);
}
}
static int
{
if (ffd < 0) {
exit(1);
}
exit(1);
}
exit(1);
}
exit(1);
}
exit(1);
}
"Loading 0x%x bytes from %s at offset 0x%x\n"),
exit(1);
}
" load_file: Writing WWN hi:0x%x lo:0x%x "
}
/* put wwn into buffer location */
(void *)&buffer[FEPROM_WWN_OFFSET],
sizeof (wwn_hi));
sizeof (wwn_lo));
sizeof (wwn_hi));
sizeof (wwn_lo));
/* here 0 means failure */
return (1);
}
return (0);
}
static int
warn(void)
{
input[0] = '\0';
"\nWARNING!! This program will update the FCode in this FC100/S Sbus Card.\n"));
"This may take a few (5) minutes. Please be patient.\n"));
"Do you wish to continue ? (y/n) "));
return (FOUND);
return (NOT_FOUND);
} else {
goto loop1;
}
}
/*
* getsocpath():
* Searches the /devices directory recursively returning all soc_name
* entries in sbussoc_list (global). This excludes port entries and
* onboard socal (which leaves only directory entries with
* soc_name included). devcnt is updated to reflect number of soc_name
* devices found.
*/
static void
{
char *ptr;
exit(1);
}
/*
* not a directory so
* we don't care about it - return
*/
return;
else {
return;
/* It's a keeper - call the load function */
devpath);
exit(1);
}
/*
* if socal directory - return,
* nothing else to see here
*/
return;
}
}
/*
* It's a directory. Call ourself to
* traverse the path(s)
*/
*ptr++ = '/';
*ptr = 0;
return;
exit(1);
}
continue;
}
exit(1);
}
}
static int
{
int ret = 0;
int len;
int len_tmp;
char *sp;
char *sp_tmp;
/*
* Okay we found a device, now let's load it in to sbussoc_list
* and load the sbusmem file into sbus_list
*/
/* len_tmp will be len of "SUNW,socal@" */
}
*devcnt += 1;
}
else
ret = -1;
return (ret);
}