Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

701 lines
28 KiB
C

#ifndef lint
static char sccsid[] = "@(#)06 1.14 src/bos/usr/lib/methods/cfgasync/cfgasync.c, cfgtty, bos41J, 9520A_all 4/27/95 12:49:36";
#endif
/*
* COMPONENT_NAME: (CFGTTY) Async Adapter Configure Method for streams based driver
*
* FUNCTIONS: main, err_exit, err_undo1, err_undo2
*
* ORIGINS: 27, 83
*
*/
/*
* (C) COPYRIGHT International Business Machines Corp. 1989, 1994
* All Rights Reserved
* Licensed Materials - Property of IBM
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*/
/*
* LEVEL 1, 5 Years Bull Confidential Information
*/
#include <stdio.h> /* standard I/O */
#include <stdlib.h> /* standard C library */
#include <sys/types.h> /* standard typedef */
#include <cf.h> /* error messages */
#include <errno.h> /* standard error numbers */
#include <sys/cfgdb.h> /* config #define */
#include <sys/sysmacros.h>
#include <sys/sysconfig.h>
#include <sys/device.h>
#include <sys/cfgodm.h> /* config structures */
#include <sys/str_tty.h>
#include "cfgdebug.h"
#include "ttycfg.h"
#define TTYDBG_MODULE "ttydbg"
/*
* ==============================================================================
* defines and strutures
* ==============================================================================
*/
#define BUS_CONNKEY "mca"
/*
* ==============================================================================
* External functions declarations
* ==============================================================================
*/
extern mid_t loadext();
/*
* =============================================================================
* Global variable for rsadapdds : trueslot (real slot number for STD I/O)
* =============================================================================
*/
int trueslot;
/*
* =============================================================================
* LOCAL UTILITY ROUTINES
* =============================================================================
*/
/*
* -----------------------------------------------------------------------------
* ERR_EXIT
* -----------------------------------------------------------------------------
*
* Closes any open object classes and terminates ODM.
* Used to back out on an error.
*
* This routine is to be used only within this file.
* The device specific routines for the various device
* specific config methods must not call this function.
*
* Return code: None
* -----------------------------------------------------------------------------
*/
static void err_exit(exitcode)
int exitcode;
{
/* Close any open object class */
odm_close_class(CuDv_CLASS);
odm_close_class(PdDv_CLASS);
odm_close_class(CuAt_CLASS);
odm_close_class(PdAt_CLASS);
/* Terminate the ODM */
odm_terminate();
exit(exitcode);
} /* End static void err_exit(...) */
/*
* -----------------------------------------------------------------------------
* ERR_UNDO1
* -----------------------------------------------------------------------------
*
* Unloads the device's device driver. Used to back out on
* an error.
*
* This routine is to be used only within this file. The device
* specific routines for the various device specific config methods
* must not call this function.
*
* Return code: None
* -----------------------------------------------------------------------------
*/
static void err_undo1(DvDr)
char *DvDr; /* pointer to device driver name */
{
/* unload driver */
if (loadext(DvDr, FALSE, FALSE) == (mid_t)NULL) {
DEBUG_0("cfgasync: error unloading driver\n");
};
} /* End static void err_undo1(...) */
/*
* -----------------------------------------------------------------------------
* ERR_UNDO2
* -----------------------------------------------------------------------------
*
* Terminates the device. Used to back out on an error.
*
* This routine is to be used only within this file. The device
* specific routines for the various device specific config methods
* must not call this function.
*
* Return code: None
* -----------------------------------------------------------------------------
*/
static void err_undo2(DvDr, cfgPtr)
char *DvDr; /* pointer to device driver name */
struct cfg_dd * cfgPtr;
{
/* terminate device */
cfgPtr->cmd = CFG_TERM;
if (sysconfig(SYS_CFGDD, cfgPtr, sizeof(*cfgPtr)) == -1) {
DEBUG_0("cfgasync: error unconfiguring device\n");
};
err_undo1(DvDr);
} /* End static void err_undo2(...) */
/*
* -----------------------------------------------------------------------------
* LOAD_CFGTTYDBG
* -----------------------------------------------------------------------------
*
* loads the module ttydbg for dump and debug.
*
* Return code: 0 on succcess, E_LOADEXT or E_SYSCONFIG otherwise
* -----------------------------------------------------------------------------
*/
load_ttydbg()
{
struct cfg_kmod cfg;
int error = 0;
/* initialization */
cfg.kmid = loadext(TTYDBG_MODULE,FALSE,TRUE);
if (cfg.kmid == (mid_t)NULL) { /* not yet loaded */
if ((cfg.kmid = loadext(TTYDBG_MODULE,TRUE,TRUE)) == (mid_t)NULL) {
DEBUG_2("load_ttydbg: loadext of %s failed with errno %d\n",
TTYDBG_MODULE, errno);
error = E_LOADEXT;
}
else {
/***** SYS_CFGKMOD *****/
cfg.mdiptr = (caddr_t)NULL;
cfg.mdilen = 0;
cfg.cmd = CFG_INIT;
/* call sysconfig() to config the driver */
if (sysconfig(SYS_CFGKMOD, &cfg, sizeof(cfg)) == CONF_FAIL) {
DEBUG_2("load_ttydbg: sysconfig of %s failed with errno %d\n",
TTYDBG_MODULE, errno);
err_undo1(TTYDBG_MODULE);
error = E_SYSCONFIG;
}
}
}
return(error);
} /* End of load_ttydbg() function */
/*
* =============================================================================
* MAIN
* =============================================================================
*
* This process is executed to "configure" an adapter device in streams environment.
*
* This process is invoked when an adapter device instance is to be
* "configured". The invokation will be made by a high level
* configuration command or by the configuration manager at IPL.
*
* Interface: cfgasync -l <logical_name> <phase>
*
* Return code: Exits with 0 on success, ODM error code otherwise.
* =============================================================================
*/
main(argc, argv, envp)
int argc;
char *argv[];
char *envp[];
{
extern int Get_Parent_Bus(); /* Searches up for bus */
extern int chkslot(); /* cardid is in desired slot? */
extern int rsadapdds(); /* build RS adapter DDS */
extern int lionadapdds(); /* build LION adapter DDS */
extern int define_children(); /* Define children */
char * logical_name; /* logical name to configure */
char sstring[256]; /* search criteria pointer */
char hw_vpd[VPDSIZE]; /* vpd for parent adapter */
char conf_list[1024]; /* busresolve() configured devices */
char not_res_list[1024]; /* busresolve() not resolved devices */
long majorno; /* major number */
int return_code; /* return code */
int current_opt, option_error; /* used in parsing parameters */
int ipl_phase; /* ipl phase */
int slot; /* slot of adapter */
ushort devid; /* device identifier */
struct cfg_dd cfg; /* sysconfig command structure for dd */
/* ODM structures declarations */
struct Class * cus_dev_class; /* customized devices class ptr */
struct Class * pre_dev_class; /* predefined devices class ptr */
struct Class * cus_vpd_class; /* customized vpd class ptr */
struct CuDv cus_dev; /* customized device object storage */
struct PdDv pre_dev; /* predefined device object storage */
struct CuDv par_cus_dev; /* customized device object storage */
struct CuVPD vpd_dev; /* customized vpd object storage */
struct CuDv dmy_dev; /* customized device object storage */
/* ============================== */
/* set up initial variable values */
/* ============================== */
ipl_phase = RUNTIME_CFG;
option_error = 0;
logical_name = NULL;
/* ================ */
/* Parse Parameters */
/* ================ */
while ((current_opt = getopt(argc,argv,"l:12")) != EOF) {
switch (current_opt) {
case 'l':
if (logical_name != NULL) {
option_error++;
};
logical_name = optarg;
break;
case '1':
if (ipl_phase != RUNTIME_CFG) {
option_error++;
};
ipl_phase = PHASE1;
break;
case '2':
if (ipl_phase != RUNTIME_CFG) {
option_error++;
};
ipl_phase = PHASE2;
break;
default:
option_error++;
}
}
if (option_error) {
/* error parsing parameters */
DEBUG_0("cfgasync: command line error\n");
exit(E_ARGS);
};
/* =========================================================== */
/* Check command-line parameters for validity */
/* For config methods this includes making sure that a logical */
/* name was specified, and that both phase flags were not set. */
/* The customized devices object class must also be searched */
/* to see if the logical name is valid. */
/* =========================================================== */
if (logical_name == NULL) {
DEBUG_0("cfgasync: no logical name\n");
exit(E_LNAME);
};
/* start up odm */
if (odm_initialize() == -1) {
DEBUG_0("cfgasync: bad odm initialization\n");
exit(E_ODMINIT);
};
/* open customized devices object class (CuDv) */
if ((int)(cus_dev_class = odm_open_class(CuDv_CLASS)) == -1) {
DEBUG_0("cfgasync: CuDv open class error\n");
err_exit(E_ODMOPEN);
};
/* ================================================= */
/* Get the Customized Devices Object for this device */
/* ================================================= */
sprintf(sstring, "name = '%s'", logical_name);
return_code = (int)odm_get_obj(cus_dev_class, sstring, &cus_dev, ODM_FIRST);
switch (return_code) {
case 0: /* odm objects not found */
DEBUG_1 ("cfgasync: CuDv %s found no objects.\n",sstring);
err_exit (E_NOCuDv);
break; /* To avoid bug if err_exit is suppressed */
case -1: /* odm error occurred */
DEBUG_1 ("cfgasync: get_obj failed, %s.\n", sstring);
err_exit (E_ODMGET);
break; /* To avoid bug if err_exit is suppressed */
default: /* odm object found ==> That's OK */
DEBUG_1 ("cfgasync: CuDv %s found objects.\n",sstring);
} /* End switch (return_code) */
/* ================================================================= */
/* Get the predefined object for this device. This object is located */
/* searching the predefined devices object class based on the unique */
/* type link descriptor in the customized device. */
/* ================================================================= */
/* open predefined devices object class (PdDv) */
if ((int)(pre_dev_class = odm_open_class(PdDv_CLASS)) == -1) {
DEBUG_0("cfgasync: PdDv open class error\n");
err_exit (E_ODMOPEN);
};
/* search Predefined devices for object with this unique type */
sprintf(sstring, "uniquetype = '%s'", cus_dev.PdDvLn_Lvalue);
return_code = (int)odm_get_obj(pre_dev_class, sstring, &pre_dev, ODM_FIRST);
switch (return_code) {
case 0: /* odm objects not found */
DEBUG_1 ("cfgasync: PdDv crit=%s found no objects.\n",sstring);
err_exit (E_NOPdDv);
break; /* To avoid bug if err_exit is suppressed */
case -1: /* odm error occurred */
DEBUG_1 ("cfgasync: get_obj failed, crit=%s.\n",sstring);
err_exit (E_ODMGET);
break; /* To avoid bug if err_exit is suppressed */
default: /* odm object found ==> That's OK */
DEBUG_1 ("cfgasync: PdDv uniquetype = %s found objects.\n",
cus_dev.PdDvLn_Lvalue);
} /* End switch (return_code) */
/* ============================================================ */
/* If this device is being configured during an ipl phase, then */
/* display this device's LED value on the system LEDs. */
/* ============================================================ */
if (ipl_phase != RUNTIME_CFG) {
/* display LED value */
setleds(pre_dev.led);
};
/* ============================================================ */
/* Check to see if the device is already configured. */
/* We actually go about the business of configuring the device */
/* only if the device is not configured yet i.e. DEFINED. */
/* ============================================================ */
if (cus_dev.status == (short) DEFINED) {
/* ==================================================== */
/* The device is not available to the system yet. Now */
/* check to make sure that the device's relations will */
/* allow it to be configured. In particular, make sure */
/* that the parent is configured (AVAILABLE), and that */
/* no other devices are configured at the same location. */
/* Get the device's parent object */
/* ==================================================== */
sprintf(sstring, "name = '%s'", cus_dev.parent);
return_code = (int)odm_get_obj(cus_dev_class,sstring,&par_cus_dev,ODM_FIRST);
switch (return_code) {
case 0: /* odm objects not found */
DEBUG_1 ("cfgasync: CuDv %s found no objects.\n",
sstring);
err_exit (E_NOCuDvPARENT);
break; /* To avoid bug if err_exit is suppressed */
case -1: /* odm error occurred */
DEBUG_1 ("cfgasync: get_obj failed, %s.\n",
sstring);
err_exit (E_ODMGET);
break; /* To avoid bug if err_exit is suppressed */
default : /* odm object found ==> That's OK */
DEBUG_1 ("cfgasync: CuDv %s found objects.\n",
sstring);
} /* End switch (return_code) */
if (par_cus_dev.status != (short) AVAILABLE) {
DEBUG_1 ("cfgasync: parent %s is not AVAILABLE\n",
cus_dev.parent);
err_exit (E_PARENTSTATE);
};
/* trueslot = SIO slot for config native I/O
* used by rsadapdds
*/
trueslot = (atoi(par_cus_dev.connwhere) -1) & 0x0f;
/* Make sure that no devices are config'd at this location */
sprintf(sstring,
"parent = '%s' AND connwhere = '%s' AND status = %d",
cus_dev.parent, cus_dev.connwhere, AVAILABLE);
return_code = (int)odm_get_obj(cus_dev_class, sstring, &dmy_dev, ODM_FIRST);
switch (return_code) {
case 0: /* odm objects not found ==> That's OK */
DEBUG_1 ("cfgasync: No CuDv %s configured at this location.\n",
sstring);
break;
case -1: /* odm error occurred */
DEBUG_1 ("cfgasync: get_obj %s failed\n", sstring);
err_exit (E_ODMGET);
break; /* To avoid bug if err_exit is suppressed */
default: /* Error: device configured at this location */
DEBUG_1("cfgasync: %s : Device is configured at this location\n",
sstring);
err_exit (E_AVAILCONNECT);
} /* End switch (return_code) */
/* ================================================== */
/* If the device is an adapter being configured at */
/* RUN TIME, then we must resolve any bus attribute */
/* conflicts before configuring device to the driver. */
/* ================================================== */
if (ipl_phase == RUNTIME_CFG) {
/* Make sure card is in specified slot */
/* This test is done only if the adapter is directly */
/* connected on bus. Its subclass must match */
/* bus connkey */
if (!strcmp(pre_dev.subclass, BUS_CONNKEY)) {
slot = atoi(cus_dev.connwhere);
devid = (ushort) strtol(pre_dev.devid, (char **)NULL, 0);
sprintf(sstring,"/dev/%s", cus_dev.parent);
return_code = chkslot(sstring, slot, devid);
if (return_code != 0) {
DEBUG_2("cfgasync: card %s not found in slot %d\n",
logical_name, slot);
err_exit(return_code);
};
};
/* Get the bus that this device is connected to */
return_code = Get_Parent_Bus(cus_dev_class, cus_dev.parent, &dmy_dev);
switch (return_code) {
case 0:
/* Invoke Bus Resolve */
return_code = busresolve(logical_name, (int)0, conf_list,
not_res_list, dmy_dev.name);
if (return_code != 0) {
DEBUG_0("cfgasync: bus resources could not be resolved\n");
err_exit(return_code);
}
else {
DEBUG_1("cfgasync: busresolve OK on bus '%s'\n", dmy_dev.name);
}
break;
case E_PARENT:
DEBUG_1("cfgasync: No bus found in the hierarchy above %s\n",
logical_name);
err_exit(return_code);
break;
default:
DEBUG_0("cfgasync: ODM error getting parent bus\n");
err_exit(return_code);
} /* End switch (return_code) */
}; /* End if (ipl_phase == RUNTIME_CFG) */
return_code = load_ttydbg();
if (return_code) {
DEBUG_1("load_ttydbg failed with %d\n", return_code);
}
/* ===================================================== */
/* Load and configuration of the driver for this adapter */
/* No minor is generated for adapter. Only major */
/* is used by sysconfig routine */
/* ===================================================== */
/* An associated driver is needed */
if (!strcmp(pre_dev.DvDr, "")) {
DEBUG_0("cfgasync: No associated driver is found\n");
err_exit(E_LNAME);
};
/* CFG.KMID */
DEBUG_1("cfgasync: Trying to load %s driver\n", pre_dev.DvDr);
if ((cfg.kmid = loadext(pre_dev.DvDr, TRUE, FALSE)) == NULL) {
/* error loading device driver */
DEBUG_1("cfgasync: loadext failed with errno = %d\n", errno);
err_exit(E_LOADEXT);
};
if ((majorno = genmajor(pre_dev.DvDr)) == (long) -1) {
/* error allocating major number */
err_undo1 (pre_dev.DvDr);
err_exit(E_MAJORNO);
};
/* CFG.DEVNO */
/* minor is meaningless for adapters */
cfg.devno = makedev(majorno, 0);
DEBUG_1("cfgasync: devno = %x\n", cfg.devno);
/* CFG.DDSPTR and CFG.DDSLEN */
/* Build the DDS */
if (!strcmp(pre_dev.DvDr, RS_DRIVER)) {
DEBUG_0("cfgasync: Trying to build DDS\n");
if (return_code = rsadapdds(&cus_dev, &cfg.ddsptr, &cfg.ddslen)) {
/* error building dds */
DEBUG_1("cfgasync: error building dds for %s\n", logical_name);
err_undo1(pre_dev.DvDr);
err_exit (return_code);
};
}
else if (!strcmp(pre_dev.DvDr, LION_DRIVER)) {
DEBUG_0("cfgasync: Trying to build DDS\n");
if (return_code = lionadapdds(&cus_dev, &cfg.ddsptr, &cfg.ddslen)) {
/* error building dds */
DEBUG_1("cfgasync: error building dds for %s\n", logical_name);
err_undo1(pre_dev.DvDr);
err_exit (return_code);
};
}
else {
/* Unsupported driver */
DEBUG_1("cfgasync: driver %s isn't supported for this configure method.\n",
pre_dev.DvDr);
err_undo1(pre_dev.DvDr);
err_exit(E_INVATTR);
}
/* CFG.CMD */
cfg.cmd = CFG_INIT;
DEBUG_1("cfgasync: Trying to configure %s driver\n", pre_dev.DvDr);
DEBUG_1("cfgasync: cfg.kmid = 0x%x\n", cfg.kmid);
DEBUG_1("cfgasync: cfg.devno = 0x%x\n", cfg.devno);
DEBUG_1("cfgasync: cfg.cmd = 0x%x\n", cfg.cmd);
DEBUG_1("cfgasync: cfg.ddsptr = 0x%x\n", cfg.ddsptr);
DEBUG_1("cfgasync: cfg.ddslen = 0x%x\n", cfg.ddslen);
if (sysconfig(SYS_CFGDD, &cfg, sizeof(struct cfg_dd)) == -1) {
/* error configuring driver */
DEBUG_1("cfgasync: errno = %d",errno);
err_undo1(pre_dev.DvDr);
err_exit(E_CFGINIT);
};
DEBUG_0("cfgasync: Initialize Complete\n");
/* ======================================================= */
/* chk_lion */
/* This call is used to correct some bugs in 64 ports card.*/
/* ========================================================*/
if (!strcmp(pre_dev.DvDr, LION_DRIVER)) {
if (return_code = chk_lion(&cus_dev, cfg.kmid, cfg.devno)) {
/* failed check */
DEBUG_1("cfgasync: chk_lion error for %s",
cus_dev.name);
err_undo2(pre_dev.DvDr, &cfg);
err_exit(return_code);
};
};
/* ======================================================= */
/* get the vpd data */
/* ========================================================*/
DEBUG_0("cfgasync: entering query_vpd()\n")
if (pre_dev.has_vpd == TRUE) {
memset(hw_vpd, 0, sizeof(hw_vpd));
if (return_code = query_vpd(&cus_dev, hw_vpd)) {
/* failed to get VPD */
DEBUG_1("cfgasync: error getting VPD for %s",
cus_dev.name);
err_undo2(pre_dev.DvDr, &cfg);
err_exit(return_code);
};
DEBUG_0("cfgasync: Returned from query_vpd()\n")
/* open customized vpd object class */
if ((int)(cus_vpd_class = odm_open_class(CuVPD_CLASS)) == -1) {
err_undo2(pre_dev.DvDr, &cfg);
err_exit(E_ODMOPEN);
};
sprintf(sstring,"name = '%s' AND vpd_type = %d", cus_dev.name, HW_VPD);
return_code = (int)odm_get_obj(cus_vpd_class, sstring, &vpd_dev, ODM_FIRST);
switch (return_code) {
case 0: /* odm objects not found */
DEBUG_1("cfgasync: CuVPD %s found no objects.\n",sstring);
/* Need to add vpd object */
DEBUG_0("cfgasync: Adding new VPD object\n");
strcpy(vpd_dev.name, logical_name);
vpd_dev.vpd_type = HW_VPD;
memcpy(vpd_dev.vpd, hw_vpd, sizeof(hw_vpd));
if (odm_add_obj(cus_vpd_class, &vpd_dev) == -1) {
DEBUG_1("cfgasync: ODM failure adding CuVPD object: %s\n",
vpd_dev.name);
/* No return code is tested for this odm_close_class */
/* because the first error is the interesting one */
odm_close_class(CuVPD_CLASS);
err_undo2(pre_dev.DvDr, &cfg);
err_exit(E_ODMADD);
};
DEBUG_1("cfgasync: Successfully added new VPD object: %s\n",
vpd_dev.name);
break; /* To avoid bug if err_exit is suppressed */
case -1: /* odm error occurred */
DEBUG_1("cfgasync: get_obj failed, CuVPD %s.\n",sstring);
/* No return code is tested for this odm_close_class */
/* because the first error is the interesting one */
odm_close_class(CuVPD_CLASS);
err_undo2(pre_dev.DvDr, &cfg);
err_exit(E_ODMGET);
break; /* To avoid bug if err_exit is suppressed */
default: /*odm objects found */
DEBUG_1("cfgasync: CuVPD %s found objects.\n",sstring);
/* If vpd object needs to be updated */
if (memcmp(hw_vpd, vpd_dev.vpd ,sizeof(hw_vpd))) {
/* Store Hardware VPD in object */
memcpy (vpd_dev.vpd, hw_vpd, sizeof(hw_vpd));
if ((odm_change_obj(cus_vpd_class, &vpd_dev)) < 0) {
DEBUG_1("cfgasync: update CuVPD for %s failed", vpd_dev.name);
/* No return code is tested for this odm_close_class */
/* because the first error is the interesting one */
odm_close_class(CuVPD_CLASS);
err_undo2(pre_dev.DvDr, &cfg);
err_exit(E_ODMUPDATE);
};
};
} /* End switch (return_code) */
if (odm_close_class(cus_vpd_class) < 0) {
err_undo2(pre_dev.DvDr, &cfg);
err_exit(E_ODMCLOSE);
};
}; /* End if (pre_dev.has_vpd == TRUE) */
/* ====================================================== */
/* Update the customized object to reflect the device's */
/* current status. The device status field should be */
/* changed to AVAILABLE. */
/* ====================================================== */
cus_dev.status = (short) AVAILABLE;
if (cus_dev.chgstatus == MISSING) {
cus_dev.chgstatus = SAME ;
};
if ((return_code = odm_change_obj(cus_dev_class, &cus_dev)) < 0) {
/* change object failed */
DEBUG_1 ("cfgasync: update %s failed.\n", logical_name);
err_exit (E_ODMUPDATE);
};
}; /* End if (cus_dev.status == (short) DEFINED) */
/* call device specific routine to detect/manage child devices */
if (define_children(logical_name, ipl_phase)) {
/* error defining children */
DEBUG_0("cfgasync: error defining children\n");
err_exit(E_FINDCHILD);
}
DEBUG_0("cfgasync: Returned from define_children()\n")
/* close object classes */
if (odm_close_class(pre_dev_class) < 0) {
err_exit (E_ODMCLOSE);
};
if (odm_close_class(cus_dev_class) < 0) {
err_exit (E_ODMCLOSE);
};
/* ====================================================== */
/* Config method is finished at this point. Terminate the */
/* ODM, and exit with a good return code. */
/* ====================================================== */
odm_terminate();
return(E_OK);
} /* End main(...) */