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

756 lines
23 KiB
C

static char sccsid[] = "@(#)17 1.2 src/bos/usr/lib/methods/common/cfgcommo.c, cfgmethods, bos411, 9428A410j 2/17/94 15:00:44";
/*
* COMPONENT_NAME: CFGMETHODS
*
* FUNCTIONS: err_exit
* err_undo1
* err_undo2
* err_undo3
* main
*
* ORIGINS: 27
*
*
* (C) COPYRIGHT International Business Machines Corp. 1993
* 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.
*/
/*
* cfgcommo.c - Generic Configure Method Code
* (used for CDLI kernel module device drivers)
*
* interface:
* cfgXXX -l <logical_name> [-<1|2>] [-D]
*
*/
/* header files needed for compilation */
#include <stdio.h>
#include <sys/types.h>
#include <sys/cfgdb.h>
#include <sys/cfgodm.h>
#include <cf.h>
#include <sys/sysconfig.h>
#include <sys/sysmacros.h>
#include <sys/device.h>
#include <sys/ndd.h>
/* Local header files */
#include "cfgdebug.h"
#include "cfg_ndd.h"
/* external functions */
extern int conferrno; /* Config (getattr) Error Number */
/* global variables */
int Dflag; /* flag for defining children */
/* main function code */
main(argc, argv, envp)
int argc;
char *argv[];
char *envp[];
{
extern int optind; /* for getopt function */
extern char *optarg; /* for getopt function */
struct cfg_kmod cfg_k; /* sysconfig command structure */
char *logical_name; /* logical name to configure */
char sstring[256]; /* search criteria pointer */
char conflist[1024]; /* busresolve() configured devices */
char not_resolved[1024]; /* busresolve() not resolved devices */
char vpd[VPDSIZE]; /* vpd data */
ndd_cfg_odm_t dev_obj; /* struc for odm pointers for subroutines */
struct Class *cusvpd; /* customized vpd class ptr */
struct CuDv dmyobj; /* temp customized device object storage */
struct CuVPD vpdobj; /* customized vpd object */
struct CuAt *cusattobj; /* device customized attribute storage */
int dev_kmid; /* device drivers cfg_k.kmid value */
char addl_dvdr[128]; /* name of additional driver */
int how_many; /* storage for getattr command */
ndd_config_t ndd_config; /* devices cfg init struct */
int inst_num; /* instance number of device */
int l_dds; /* length of user defined dds */
ushort devid; /* Device id - used at run-time */
int ipl_phase; /* ipl phase: 0=run,1=phase1,2=phase2 */
int slot; /* slot of adapters */
int rc; /* return codes go here */
int errflg,c; /* used in parsing parameters */
/***** */
/***** Parse Parameters */
/***** */
ipl_phase = RUNTIME_CFG;
errflg = 0;
logical_name = NULL;
Dflag = FALSE;
while ((c = getopt(argc,argv,"l:12D")) != EOF) {
switch (c) {
case 'l':
if (logical_name != NULL)
errflg++;
logical_name = optarg;
break;
case 'D':
if (Dflag != FALSE)
errflg++;
Dflag = TRUE;
break;
case '1':
if (ipl_phase != RUNTIME_CFG)
errflg++;
ipl_phase = PHASE1;
break;
case '2':
if (ipl_phase != RUNTIME_CFG)
errflg++;
ipl_phase = PHASE2;
break;
default:
errflg++;
}
}
if (errflg) {
/* error parsing parameters */
DEBUG_0("cfgcommo: command line error\n");
exit(E_ARGS);
}
/***** */
/***** Validate Parameters */
/***** */
/* logical name must be specified */
if (logical_name == NULL) {
DEBUG_0("cfgcommo: logical name must be specified\n");
exit(E_LNAME);
}
DEBUG_1 ("cfgcommo: Configuring device: %s\n",logical_name)
/* start up odm */
if (odm_initialize() == -1) {
/* initialization failed */
DEBUG_0("cfgcommo: odm_initialize() failed\n")
exit(E_ODMINIT);
}
DEBUG_0 ("cfgcommo: ODM initialized\n")
/* open customized devices object class */
if ((int)(dev_obj.cusdev = odm_open_class(CuDv_CLASS)) == -1) {
DEBUG_0("cfgcommo: open class CuDv failed\n");
err_exit(E_ODMOPEN);
}
/* search for customized object with this logical name */
sprintf(sstring, "name = '%s'", logical_name);
rc = (int)odm_get_first(dev_obj.cusdev,sstring,&dev_obj.cusobj);
if (rc==0) {
/* No CuDv object with this name */
DEBUG_1("cfgcommo: failed to find CuDv object for %s\n", logical_name);
err_exit(E_NOCuDv);
}
else if (rc==-1) {
/* ODM failure */
DEBUG_0("cfgcommo: ODM failure getting CuDv object");
err_exit(E_ODMGET);
}
/* open predefined devices object class */
if ((int)(dev_obj.predev = odm_open_class(PdDv_CLASS)) == -1) {
DEBUG_0("cfgcommo: open class PdDv failed\n");
err_exit(E_ODMOPEN);
}
/* get predefined device object for this logical name */
sprintf(sstring, "uniquetype = '%s'", dev_obj.cusobj.PdDvLn_Lvalue);
rc = (int)odm_get_first(dev_obj.predev, sstring, &dev_obj.preobj);
if (rc==0) {
/* No PdDv object for this device */
DEBUG_0("cfgcommo: failed to find PdDv object for this device\n");
err_exit(E_NOPdDv);
}
else if (rc==-1) {
/* ODM failure */
DEBUG_0("cfgcommo: ODM failure getting PdDv object");
err_exit(E_ODMGET);
}
/****************************************************************
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)
setleds(dev_obj.preobj.led);
/****************************************************************
Open databases and verify parent device
****************************************************************/
/* open predefined attributes object class */
if ((int)(dev_obj.preatt = odm_open_class(PdAt_CLASS)) == -1) {
DEBUG_0("cfgcommo: open class PdAt failed\n");
err_exit(E_ODMOPEN);
}
/* open customized attributes object class */
if ((int)(dev_obj.cusatt = odm_open_class(CuAt_CLASS)) == -1) {
DEBUG_0("cfgcommo: open class CuAt failed\n");
err_exit(E_ODMOPEN);
}
/******************************************************************
At this point, there is a CuDv entry for this device which means
the State is either DEFINED or AVAILABLE.
******************************************************************/
/* get the device's parent object */
sprintf(sstring, "name = '%s'", dev_obj.cusobj.parent);
rc = (int)odm_get_first(dev_obj.cusdev,sstring,&dev_obj.parobj);
DEBUG_2("cfgcommo: name of parent device = %s,rc=%d\n",dev_obj.cusobj.parent,rc);
if (rc==0)
{
/* Parent device not in CuDv */
DEBUG_0("cfgcommo: no parent CuDv object\n");
err_exit(E_NOCuDvPARENT);
}
else if (rc==-1)
{
/* ODM failure */
DEBUG_0("cfgcommo: ODM failure getting parent CuDv object\n")
err_exit(E_ODMGET);
}
/******************************************************************
Check to see if the device is already configured (AVAILABLE).
We actually go about the business of configuring the device
only if the device is not configured yet. Configuring the
device in this case refers to the process of checking parent
and sibling status, checking for attribute consistency, build-
ing a DDS, loading the driver, etc...
******************************************************************/
if (dev_obj.cusobj.status == 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.
*******************************************************/
if (dev_obj.parobj.status != AVAILABLE)
{
DEBUG_0("cfgcommo: parent is not AVAILABLE")
err_exit(E_PARENTSTATE);
}
/*******************************************************
Check to see if any device is selected for this parent
at this location.
*******************************************************/
/* make sure that no other devices are configured */
/* at this location (This includes the following */
/* states: AVAILABLE, STOPPED, DIAGNOSE) */
sprintf(sstring, "parent = '%s' AND connwhere = '%s' AND status != %d",
dev_obj.cusobj.parent, dev_obj.cusobj.connwhere, DEFINED);
rc = (int)odm_get_first(dev_obj.cusdev,sstring,&dmyobj);
if (rc == -1)
{
/* odm failure */
err_exit(E_ODMGET);
}
else if (rc)
{
/* Error: device config'd at this location */
DEBUG_0("cfgcommo: device already AVAILABLE at this connection\n")
err_exit(E_AVAILCONNECT);
}
/***************************************************
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 (!strcmp(dev_obj.preobj.subclass,"mca"))
{
if (ipl_phase == RUNTIME_CFG)
{
DEBUG_0("cfgcommo: checking adapter for slot and bus resources\n")
/* Make sure card is in specified slot */
slot = atoi(dev_obj.cusobj.connwhere);
devid = (ushort) strtol(dev_obj.preobj.devid,(char **) NULL,0);
sprintf (sstring,"/dev/%s",dev_obj.cusobj.parent);
rc = chkslot(sstring,slot,devid);
if (rc != 0) {
DEBUG_2("cfgcommo: card %s not found in slot %d\n",
logical_name,slot);
err_exit(rc);
}
/*
* Get the bus that this device is connected to.
* (searches hierarchy until bus is found.
* then returns object information for bus )
*/
rc = Get_Parent_Bus(dev_obj.cusdev, dev_obj.cusobj.parent, &dmyobj) ;
if (rc == 0)
{
/* Invoke Bus Resolve */
rc = busresolve(logical_name,(int)0,conflist,
not_resolved, dmyobj.name);
if (rc != 0)
{
DEBUG_0("cfgcommo: bus resources could not be resolved\n")
err_exit(rc);
}
}
else if (rc == E_PARENT)
{
DEBUG_0("cfgcommo: device not on bus\n")
}
else
{
DEBUG_0("cfgcommo: ODM err getting parent bus\n")
err_exit(rc) ;
}
} /* end of ipl phase check */
} /* end of device is adapter (subclass = mca) */
/***************************************************
If device has a device driver, then need to load driver,
build DDS and pass to driver.
Then, a device dependent routine is called for
downloading microcode.
If device has an additional driver, it will
then be loaded.
***************************************************/
dev_kmid = 0; /* initialize values */
DEBUG_1("cfgcommo: checking for DvDr entry, DvDr=%s\n",dev_obj.preobj.DvDr);
if (strcmp(dev_obj.preobj.DvDr, "") != 0)
{
/* get instance number for this device */
inst_num = geninst(dev_obj.preobj.DvDr,logical_name);
if (inst_num == -1) {
DEBUG_0("cfgcommo: error getting instance number\n")
err_exit(E_INSTNUM);
}
DEBUG_1("cfgcommo: instance number = %d\n",inst_num);
DEBUG_0("cfgcommo: load a device driver\n")
/* call loadext to load the device driver */
if ((cfg_k.kmid = loadext(dev_obj.preobj.DvDr, TRUE, FALSE))
== NULL)
{
/* error loading device driver */
DEBUG_1("cfgcommo: error loading driver %s\n", dev_obj.preobj.DvDr)
err_exit(E_LOADEXT);
}
dev_kmid = cfg_k.kmid;
DEBUG_1("cfgcommo: kernel module id = %x\n",dev_kmid)
ndd_config.seq_number = inst_num;
ndd_config.dds = (char * ) NULL;
cfg_k.mdiptr = (char *) &ndd_config;
cfg_k.mdilen = sizeof (struct ndd_config);
/* build the DDS */
DEBUG_0("cfgcommo: Calling build_dds()\n")
rc = build_dds(logical_name, &dev_obj,
&ndd_config.dds,
&l_dds );
if (rc) {
/* error building dds */
DEBUG_1("cfgcommo: error building dds, rc=%d\n",rc)
err_undo1(dev_obj.preobj.DvDr);
if ( rc < 0 || rc > 255)
rc = E_DDS;
err_exit(rc);
}
DEBUG_0("cfgcommo: Returned from build_dds()\n")
/* call sysconfig to pass DDS to driver */
DEBUG_0("cfgcommo: Pass DDS to driver via sysconfig()\n")
cfg_k.cmd = CFG_INIT;
if (sysconfig(SYS_CFGKMOD, &cfg_k, sizeof(struct cfg_kmod )) == -1) {
/* error configuring device */
DEBUG_0("cfgcommo: error configuring device\n")
err_undo1(dev_obj.preobj.DvDr);
err_exit(E_CFGINIT);
}
/* download microcode if necessary */
DEBUG_0("cfgcommo: Calling download_microcode()\n")
ndd_config.seq_number = inst_num;
ndd_config.ucode = (char * ) NULL;
cfg_k.mdiptr = (char *) &ndd_config;
cfg_k.mdilen = sizeof (struct ndd_config);
rc = download_microcode(logical_name, &dev_obj, &cfg_k);
if (rc) {
/* error downloading microcode */
DEBUG_1("cfgcommo: error downloading microcode, rc=%d\n",rc)
err_undo2(cfg_k.kmid,inst_num);
err_undo1(dev_obj.preobj.DvDr);
if ( rc < 0 || rc > 255)
rc = E_UCODE;
err_exit(rc);
}
DEBUG_0("cfgcommo: Returned from download_microcode()\n")
/***************************************************
If device has an additional driver, then need to
call the specified configure method for that driver
to load and configure the driver
Attribute addl_dvdr is the method to run
***************************************************/
strcpy ( addl_dvdr, NULL ); /* initialize values */
cusattobj = getattr( logical_name, "addl_dvdr", FALSE,&how_many );
if (cusattobj != NULL) {
strcpy ( addl_dvdr, cusattobj->value);
}
else {
/* NOTE: error to be indicated here */
/* only if attribute is there but could */
/* not be read */
if ( conferrno != E_NOPdOBJ ) {
/* error getting addl dvdr name */
DEBUG_0("cfgcommo: error getting addl dvdr name\n")
err_undo2(dev_kmid,inst_num);
err_undo1(dev_obj.preobj.DvDr);
err_exit(E_ODMGET);
}
}
if (strcmp(addl_dvdr, "") != 0)
{
/* call specified method with parameter "ADDL_CFG"
* to configure the additional driver
*/
sprintf( sstring, " %d %s %d ",
ADDL_CFG, logical_name, inst_num);
DEBUG_2("cfgcommo: calling %s %s\n",addl_dvdr, sstring)
if(odm_run_method(addl_dvdr,sstring,NULL,NULL)){
fprintf(stderr,"cfgcommo: can't run %s\n",
addl_dvdr);
err_undo2(dev_kmid,inst_num);
err_undo1(dev_obj.preobj.DvDr);
err_exit(E_ODMRUNMETHOD);
}
} /* end if (device has an additional driver) then ... */
} /* end if (device has a driver) then ... */
/* call device specific routine to for any special work */
DEBUG_0("cfgcommo: Calling device specific hook()\n")
rc = device_specific(logical_name, &dev_obj, dev_kmid);
if (rc != 0) {
/* error in device specific */
DEBUG_0("cfgcommo: error in device specific\n");
/* need to find a E_ error to return here to cover users */
err_exit(rc);
}
DEBUG_0("cfgcommo: Returned from specific_work()\n");
/* if device has VPD data then go get it */
if (dev_obj.preobj.has_vpd == TRUE) {
/* get VPD for this device */
memset( vpd, 0, sizeof(vpd) );
DEBUG_0("cfgcommo: Calling query_vpd()\n")
ndd_config.seq_number = inst_num;
cfg_k.mdiptr = (char *) &ndd_config;
cfg_k.mdilen = sizeof (struct ndd_config);
rc = query_vpd(logical_name, &dev_obj, &cfg_k, vpd);
if (rc) {
/* failed to get VPD */
DEBUG_1("cfgcommo: error getting VPD, rc=%d\n",rc)
err_undo3(dev_obj.preobj.DvDr, dev_kmid, inst_num);
if ( rc < 0 || rc > 255)
rc = E_VPD;
err_exit(rc);
}
DEBUG_0("cfgcommo: Returned from query_vpd()\n")
/* open customized vpd object class */
if ((int)(cusvpd = odm_open_class(CuVPD_CLASS)) == -1) {
DEBUG_0("cfgcommo: open class CuVPD failed");
err_undo3(dev_obj.preobj.DvDr, dev_kmid, inst_num);
err_exit(E_ODMOPEN);
}
/* search for customized vpd object with this logical name */
sprintf(sstring, "name = '%s' and vpd_type = '%d'",
logical_name,HW_VPD);
rc = (int)odm_get_first(cusvpd,sstring,&vpdobj);
if (rc==-1) {
/* ODM failure */
DEBUG_0("cfgcommo: ODM failure getting CuVPD object");
err_undo3(dev_obj.preobj.DvDr, dev_kmid, inst_num);
err_exit(E_ODMGET);
}
if (rc==0) {
/* need to add vpd object */
DEBUG_0("cfgcommo: Adding new VPD object\n");
strcpy(vpdobj.name,logical_name);
vpdobj.vpd_type = HW_VPD;
memcpy(vpdobj.vpd,vpd,sizeof(vpd));
if (odm_add_obj(cusvpd,&vpdobj) == -1) {
DEBUG_0("cfgcommo: ODM failure adding CuVPD object")
err_undo3(dev_obj.preobj.DvDr, dev_kmid, inst_num);
err_exit(E_ODMADD);
}
DEBUG_0("cfgcommo: Successfully added new VPD object\n");
} else {
/* see if vpd object needs to be updated */
if (memcmp(vpdobj.vpd,vpd,sizeof(vpd))) {
DEBUG_0("cfgcommo: Updating VPD object\n");
memcpy(vpdobj.vpd,vpd,sizeof(vpd));
if (odm_change_obj(cusvpd,&vpdobj) == -1) {
DEBUG_0("cfgcommo: ODM failure updating CuVPD object")
err_undo3(dev_obj.preobj.DvDr, dev_kmid, inst_num);
err_exit(E_ODMUPDATE);
}
DEBUG_0("cfgcommo: Successfully updated VPD object\n");
}
}
/* close customized vpd object class */
if (odm_close_class(CuVPD_CLASS) == -1) {
DEBUG_0("cfgcommo: error closing CuVPD object class\n");
err_undo3(dev_obj.preobj.DvDr, dev_kmid, inst_num);
err_exit(E_ODMCLOSE);
}
} /* end if (device has vpd) then ... */
/*
* Update customized device object. Set current
* status to AVAILABLE and reset change status to
* SAME only if it was MISSING
*/
dev_obj.cusobj.status = AVAILABLE;
if (dev_obj.cusobj.chgstatus == MISSING)
{
dev_obj.cusobj.chgstatus = SAME ;
}
if (odm_change_obj(dev_obj.cusdev, &dev_obj.cusobj) == -1)
{
/* ODM failure */
DEBUG_0("cfgcommo: ODM failure updating CuDv object\n");
err_exit(E_ODMUPDATE);
}
} /* end if (device is not AVAILABLE) then ... */
/* call device specific routine to detect/manage child devices */
DEBUG_0("cfgcommo: Calling define_children()\n");
if (define_children(logical_name, &dev_obj, ipl_phase) != 0) {
/* error defining children */
DEBUG_0("cfgcommo: error defining children\n");
err_exit(E_FINDCHILD);
}
DEBUG_0("cfgcommo: Returned from define_children()\n")
/* close predefined device object class */
if (odm_close_class(dev_obj.predev) == -1) {
DEBUG_0("cfgcommo: close object class PdDv failed");
err_exit(E_ODMCLOSE);
}
/* close customized device object class */
if (odm_close_class(dev_obj.cusdev) == -1) {
DEBUG_0("cfgcommo: error closing CuDv object class\n");
err_exit(E_ODMCLOSE);
}
/* close PdAt object class */
if (odm_close_class(dev_obj.preatt) == -1) {
DEBUG_0("cfgcommo: error closing PdAt object class\n");
err_exit(E_ODMCLOSE);
}
/* close customized att object class */
if (odm_close_class(dev_obj.cusatt) == -1) {
DEBUG_0("cfgcommo: error closing CuAt object class\n");
err_exit(E_ODMCLOSE);
}
odm_terminate();
exit(0);
}
/*
* NAME: err_exit
*
* FUNCTION: Closes any open object classes and terminates ODM. Used to
* back out on an error.
*
* EXECUTION ENVIRONMENT:
*
* 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.
*
* NOTES:
*
* void
* err_exit( exitcode )
* exitcode = The error exit code.
*
* RETURNS:
* None
*/
err_exit(exitcode)
char 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);
}
/*
* NAME: err_undo1
*
* FUNCTION: Unloads the device's device driver. Used to back out on an
* error.
*
* EXECUTION ENVIRONMENT:
*
* 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.
*
* NOTES:
*
* void
* err_undo1( DvDr )
* DvDr = pointer to device driver name.
*
* RETURNS:
* None
*/
err_undo1(DvDr)
char *DvDr; /* pointer to device driver name */
{
/* unload driver */
if (loadext(DvDr,FALSE,FALSE) == NULL) {
DEBUG_0("cfgcommo: error unloading driver\n");
}
return;
}
/*
* NAME: err_undo2
*
* FUNCTION: Terminates the device. Used to back out on an error.
*
* EXECUTION ENVIRONMENT:
*
* 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.
*
* NOTES:
*
* void
* err_undo2( kmid ,inst_num_2 )
* kmid = The device's kernel module id from load function.
* inst_num_2 = The device's instance number
*
* RETURNS:
* None
*/
err_undo2(kmid,inst_num_2)
mid_t kmid; /* The device's kmid */
int inst_num_2; /* The device's instance number */
{
struct cfg_kmod cfg_k; /* sysconfig command structure */
ndd_config_t ndd_config; /* devices cfg init struct */
/* terminate device */
cfg_k.kmid = kmid;
cfg_k.cmd = CFG_TERM;
ndd_config.seq_number = inst_num_2;
cfg_k.mdiptr = (char *) &ndd_config;
cfg_k.mdilen = sizeof (struct ndd_config);
if (sysconfig(SYS_CFGKMOD,&cfg_k,sizeof(struct cfg_kmod)) == -1) {
DEBUG_0("cfgcommo: error unconfiguring device\n");
}
return;
}
/*
* NAME: err_undo3
*
* FUNCTION: Terminates the device and unloads the driver, if the device has
* a driver. If the device does not have a driver, it simply
* returns. This routine is used to back out on errors that
* occur while processing VPD.
*
* EXECUTION ENVIRONMENT:
*
* 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.
*
* NOTES:
*
* void
* err_undo3( DvDr , kmid, inst_num_3 )
* DvDr = pointer to device driver name.
* kmid = The device's kernel module id from load function.
* inst_num_3 = instance number of device
*
* RETURNS:
* None
*/
err_undo3(DvDr, kmid, inst_num_3)
char *DvDr; /* pointer to device driver name */
mid_t kmid; /* the device's kmid */
int inst_num_3; /* instance number in undo3 routine */
{
odm_close_class(CuVPD_CLASS); /* make sure CuVPD is closed */
if (strcmp(DvDr, "") != 0) { /* If device has a driver then ... */
err_undo2(kmid,inst_num_3); /* terminate device */
err_undo1(DvDr); /* unload device driver */
}
return;
}