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

605 lines
15 KiB
C

static char sccsid[] = "@(#)94 1.19.1.8 src/bos/usr/lib/methods/cfgbus/bcm.c, cmdbuscf, bos411, 9436C411a 9/8/94 08:35:34";
/*
* COMPONENT_NAME: (CMDBUSCF) Main Bus Configuration module
*
* FUNCTIONS: bus_config_method
* main
* mk_sp_file
* set_busid
* get_iplcb
* setup_bimw_attr
* chk_ccm
* open_classes
* close_classes
*
*
* ORIGINS: 27
*
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
* combined with the aggregated modules for this product)
* SOURCE MATERIALS
*
* (C) COPYRIGHT International Business Machines Corp. 1989,1994
* All Rights Reserved
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*/
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/cfgdb.h>
#include <sys/cfgodm.h>
#include <cf.h>
#include <sys/mode.h>
#include <sys/mdio.h>
#include <sys/iocc.h>
#include <sys/systemcfg.h>
#include <sys/iplcb.h>
#include "bcm.h"
struct Class *predev; /* predefined devices class ptr */
struct Class *cusdev; /* customized devices class ptr */
struct Class *preatt; /* predefined attributes class ptr */
struct Class *cusatt; /* customized attributes class ptr */
extern char *optarg;
int allpkg = 0 ;
main(argc, argv)
int argc;
char **argv;
{
int i, c, rc;
int phase = 0;
char *busname = NULL;
/* check if environment variable set to install all packages */
if ( !strcmp(getenv("DEV_PKGNAME"),"ALL") )
allpkg = 1;
while (EOF != (c = getopt(argc, argv, "12dl:"))) {
switch (c) {
case '1':
phase = PHASE1;
break;
case '2':
phase = PHASE2;
break;
case 'd':
prntflag = TRUE;
trace_file = fopen( "BUS.out", "w" );
break;
case 'l':
busname = optarg;
break;
default :
exit(E_ARGS);
break;
}
}
/* Initialize the ODM */
if (odm_initialize() == -1)
exit(E_ODMINIT);
/* Open object classes and keep open for multiple accesses */
rc = open_classes();
if (rc == 0)
rc = bus_config_method(phase, busname);
/* Close all object classes */
(void)close_classes();
/* Terminate the ODM */
odm_terminate();
exit( rc );
}
int
bus_config_method(phase, busname)
int phase;
char *busname;
{
int rc;
char conf_list[2000], not_res_list[2000];
struct CuDv cudv;
char bus_devname[100];
unsigned short card_table[CARD_TABLE_SIZE];
char sstr[80]; /* ODM search string */
/* Set the bus device's LED value */
if (phase)
setleds(BUS_CONFIG_METHOD);
/* Get the bus's CuDv object */
sprintf(sstr, "name=%s", busname);
rc = (int)odm_get_first(CuDv_CLASS, sstr, &cudv);
if (rc == -1)
return(E_ODMGET); /* ODM failure */
else if (rc == 0)
return(E_NOCuDv); /* No CuDv for the bus */
/* Set up bus's /dev name for later use */
sprintf(bus_devname,"/dev/%s", busname);
/* Only perform bus config operations if bus is DEFINED */
if (cudv.status == DEFINED) {
/*
* Make the special file for the bus. Remember that
* the Bus Id is the same as the connwhere.
*/
if (!mk_sp_file(bus_devname, (int)(cudv.location[3] - '0')))
return(E_MKSPECIAL); /* Couldn't make special files */
/* Try to set the busid attribute. Abort if it fails. */
if ((rc = set_busid(&cudv)) != 0)
return(rc) ;
/*
* Set up the bus_iocc_mem attribute value to have the
* correct setting for IOCC or XIO machines.
*/
if ((rc = setup_bimw_attr(busname, bus_devname)) != 0)
return(rc) ;
/* set the bus status to available */
cudv.status = AVAILABLE;
if ((int)odm_change_obj(CuDv_CLASS, &cudv) == -1)
return(E_ODMUPDATE);
}
/* Always walk bus to discover child adapters */
busquery( card_table, CARD_TABLE_SIZE, bus_devname, phase);
/* Restore bus device's LED value since busquery will change LEDs */
if (phase)
setleds(BUS_CONFIG_METHOD);
/* Match up devices with CuDv objects in data base */
if (rc = sync_bus(busname, phase, card_table, CARD_TABLE_SIZE))
return(rc);
/* check if CCM device present and reserve CCM attrs if needed */
if (rc = chk_ccm(busname))
return(rc);
/* Resolve bus resources */
rc = busresolve(NULL, phase, conf_list, not_res_list, busname);
if (rc)
return (rc);
/* Print the list of adapters that were successfully resolved and
* are to be configured to standard out.
*/
fprintf(stdout, "%s\n", conf_list);
return(0);
} /* END bus_config_method */
/*
* NAME : setup_bimw_attr()
* FUNCTION : Sets the bimw attribute value to 0x0 on XIO machines
* and 0x10 on IOCC machines. It identifies the amount of
* bus memory to reserve starting at the address of 0xfffff0.
* On IOCC machines the address range 0xfffff0-0xffffff must
* be reserved due to an IOCC problem. If the bimw attribute
* is set to 0x0, no memory will be reserved.
* INPUTS :
* busname : bus being configured
* devname : bus's special file name
*
* RETURNS : 0 => successfully updated CuAt.
* other => error code indicating failure (capable of being
* returned by the caller).
*/
int
setup_bimw_attr(char *busname, char *devname)
{
struct CuAt *cuat;
int cucnt;
char xio_value[] = "0x0";
char iocc_value[] = "0x10";
int fd;
MACH_DD_IO mddRecord;
ulong cfgreg;
/* Get the width attribute */
if ((cuat = getattr(busname, "bimw", 0, &cucnt)) == NULL) {
return(E_NOATTR);
}
if (__power_pc()) {
/* treat like XIO */
strcpy(cuat->value, xio_value);
}
else /* __power_rs() */ {
/* Check to see if it's XIO or IOCC */
if ((fd = open(devname, O_RDWR)) == -1)
return(E_OPEN);
mddRecord.md_size = 1;
mddRecord.md_incr = MV_WORD;
mddRecord.md_data = (uchar *)&cfgreg;
mddRecord.md_addr = IO_IOCC + 0x10;
if (ioctl(fd, MIOCCGET, &mddRecord) == -1) {
close(fd);
return(E_DEVACCESS);
}
close(fd);
if (cfgreg & XIOBIT)
/* Its XIO */
strcpy(cuat->value, xio_value);
else
/* Its IOCC */
strcpy(cuat->value, iocc_value);
}
putattr(cuat);
return (0);
} /* END setup_bus_iocc_mem_attr() */
/*
* NAME : mk_sp_file
* FUNCTION : generates the special file for the bus. It selects
* the minor number based on the bus number passed in
* (see below for more information).
* INPUTS :
* Fname : file name to be created.
* BusNum : 1 byte bus number
* NOTES :
* Note that the minor number is tied to the bus
* number as follows (this relationship is also
* documented in sys/io/machdd/md.c for bos325 and
* src/bos/kernel/io/machdd/md.c for bos410) :
*
* BUS_NUM MINOR_NUMBER
* '0' 0
* '1' 16
* '2' 32
* '3' 48
* RETURNS : FALSE => could not create special file
* TRUE => successfully created special file.
*/
int
mk_sp_file(Fname, bus_num)
char *Fname; /* name of special file to create (include /dev/) */
int bus_num; /* bus number */
{
int rc; /* return code returned by this routine. */
int mode; /* file mode mask used to create file. */
dev_t devno; /* device number to use when creating file*/
int minor; /* device minor number */
/* Compute device minor number and device number */
minor = (bus_num << 4) & 0xf0;
devno = (dev_t)(0x030000 | minor);
/* Make the bus special file */
mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP ;
rc = unlink(Fname) ;
rc = (mknod(Fname, mode, devno) == 0) ;
return(rc) ;
}
/*
* NAME : set_busid
* FUNCTION : Sets the "bus_id" attribute in CuAt to indicate
* the correct busid for the bus being configured.
* INPUTS :
* cudv : the CuDv object of the bus being configured.
*
* RETURNS : 0 => successfully set "bus_id" attribute.
* other => error code indicating failure (capable of being
* returned by the caller.
*/
int
set_busid(cudv)
struct CuDv *cudv; /* CuDv obj for bus being configured */
{
char sstr[128];
struct CuAt *cuat;
struct PdAt pdat;
int i, rc, offset, cnt;
uint loc_offset;
ulong cuat_busid, bus_id;
IPL_DIRECTORY iplcb_dir; /* IPL control block directory */
struct buc_info buc; /* IPL cntrl block buc info section */
ulong buid;
/* Get buid */
if (__power_rs())
buid = 0x20 | ( cudv->location[3] - '0' );
else { /* Power PC */
/*
* Read in the IPL Control Block directory
* and get offset to first info buc section
*/
rc = get_iplcb((char *)&iplcb_dir, 128,
sizeof(iplcb_dir), MIOIPLCB);
if (rc) return(rc);
offset = iplcb_dir.buc_info_offset;
/*
* Read in the first info buc section of the IPL
* Control Block so we can get number of structs
* for our loop counter, i
*/
rc = get_iplcb((char *)&buc, offset, sizeof(buc), MIOIPLCB);
if (rc) return(rc);
/*
* Loop through buc array structures to find the BUID value
*/
for (i = buc.num_of_structs; i--; offset += buc.struct_size) {
/* Read each info buc section of the IPLCB */
rc = get_iplcb((char *)&buc, offset,
sizeof(buc), MIOIPLCB);
if (rc) return(rc);
/* Find buc entry for IOCC with location == busnum */
if (buc.IOCC_flag) {
/* Then this array struct is for an IOCC */
/*
* An early version of IPL ROS does not build
* the struct with location field - check for
* that by comparing location field offset
* against struct size. If early version then
* only one IOCC BUC entry, so just use it.
*/
loc_offset = (uint)buc.location - (uint)&buc;
if (loc_offset < buc.struct_size) {
/* Entry has valid location field */
if (cudv->location[3] == buc.location[2]) {
/* This is entry containing BUID */
buid =
(ulong)buc.buid_data[0].buid_value;
break;
}
}
else {
/* IPL ROS early version */
/* This is only IOCC BUC struct */
buid = (ulong)buc.buid_data[0].buid_value;
break;
}
}
} /* end for */
/* if did not find a buc that matched, can't continue */
if ( i < 0 )
return (E_DEVACCESS);
} /* else if POWER PC */
/* And after all that we can form the BUS ID */
bus_id = 0x80000000 | (buid << 20);
if (prntflag) fprintf(trace_file, "bus id = %x\n",bus_id);
/* Check bus_id in CuAt, redefine it if required */
cuat = getattr(cudv->name, "bus_id", FALSE, &cnt);
if (cuat == NULL)
return(E_NOATTR);
/* See if current busid is correct */
cuat_busid = strtoul(cuat->value, (char **)NULL, 0);
if (cuat_busid == bus_id)
/* The bus_id is already correct */
return (0);
/* Need to set busid to correct value */
sprintf(cuat->value, "0x%x", bus_id);
putattr(cuat) ;
return (0);
} /* END set_busid */
/*
* NAME: get_iplcb
*
* FUNCTION: Reads "num_bytes" bytes from the IPL control block.
* Bytes are read from the offset into the IPL
* control block and stored at address "dest".
*
* RETURNS: error code. 0 means no error.
*/
int
get_iplcb(dest, offset, num_bytes, ioctl_type)
char *dest;
int offset;
int num_bytes;
int ioctl_type;
{
int fd; /* file descriptor */
MACH_DD_IO mdd;
if ((fd = open("/dev/nvram", O_RDONLY)) == -1)
return(E_DEVACCESS);
mdd.md_addr = offset;
mdd.md_data = dest;
mdd.md_size = num_bytes;
mdd.md_incr = MV_BYTE;
if (ioctl(fd, ioctl_type, &mdd) == -1) {
close(fd);
return(E_DEVACCESS);
}
close(fd);
return(0);
}
/*
* NAME: chk_ccm
*
* FUNCTION: Checks if the FRS_Add_MCA_Device routine has
* ran and added a special predefined attribute and
* CuAt attribute. If so, CuAt entries are added
* to reserve bus memory. If CuAt entries
* are present without the "frs"
* attribute, then delete the attributes, as they should not
* be used to reserve bus memory.
*
* RETURNS: error code. 0 means no error.
*/
int
chk_ccm ( busname )
char *busname;
{
struct CuAt cuat;
struct CuDv cudv;
struct PdAt *pdatptr; /* ptr to list of PdAt objects */
struct listinfo db_list; /* list info of PdAt objects */
char criteria[MAX_CRITELEM_LEN];
int rc;
int i;
int reserve_mem;
/* get list of PdAt frs attributes */
pdatptr = odm_get_list(PdAt_CLASS,
"uniquetype like adapter/mca/* and attribute=frs",
&db_list, 2, 1);
if ( (int)pdatptr == -1) {
return(E_ODMGET);
}
reserve_mem=FALSE;
/* loop through objects found in PdAt */
for (i=0; i< db_list.num; i++) {
/* get the corresponding CuDv */
sprintf(criteria,"PdDvLn=%s",pdatptr[i].uniquetype);
rc = (int)odm_get_first(CuDv_CLASS, criteria, &cudv);
if (rc == -1) {
return (E_ODMGET);
}
if (rc != 0) {
/* check if CuAt frs attribute present */
sprintf(criteria,"name=%s and attribute=frs",
cudv.name);
rc = (int)odm_get_first(CuAt_CLASS, criteria,
&cuat);
if (rc == -1) {
return (E_ODMGET);
}
if (rc == 0) { /* CuAt frs attribute not present */
/* reserve bus memory */
reserve_mem=TRUE;
break;
}
}
}
if (reserve_mem) {
/* build CuAt to add */
strcpy(cuat.name, busname);
strcpy(cuat.attribute, "rcrw1");
strcpy(cuat.value, "0x4000");
strcpy(cuat.type, "W");
strcpy(cuat.generic, "");
strcpy(cuat.rep, "nl");
cuat.nls_index = 0;
/* add 3 attributes for the CCM bus memory */
rc = putattr(&cuat);
strcpy(cuat.attribute, "rcrw2");
strcpy(cuat.value, "0x100000");
putattr(&cuat);
strcpy(cuat.attribute, "rcrw3");
strcpy(cuat.value, "0x2000");
putattr(&cuat);
}
else {
/* delete the CCM bus memory objects */
sprintf(criteria,"name=%s and attribute like rcrw*", busname);
odm_rm_obj(CuAt_CLASS,criteria);
}
return(0);
}
/*
* NAME: open_classes
*
* FUNCTION: Opens the four object classes: PdDv, CuDv, PdAt, CuAt.
* They are kept open for multiple accesses.
*
* RETURNS: error code. 0 means no error.
*/
int
open_classes ( void )
{
/* open predefined devices object class */
if ((int)(predev = odm_open_class(PdDv_CLASS)) == -1)
return(E_ODMOPEN);
/* open customized devices object class */
if ((int)(cusdev = odm_open_class(CuDv_CLASS)) == -1)
return(E_ODMOPEN);
/* open predefined attribute object class */
if ((int)(preatt = odm_open_class(PdAt_CLASS)) == -1)
return(E_ODMOPEN);
/* open customized attribute object class */
if ((int)(cusatt = odm_open_class(CuAt_CLASS)) == -1)
return(E_ODMOPEN);
return(0);
}
/*
* NAME: close_classes
*
* FUNCTION: Closes the four object classes: PdDv, CuDv, PdAt, CuAt.
*
* RETURNS: error code. 0 means no error.
*/
int
close_classes ( void )
{
odm_close_class(CuAt_CLASS);
odm_close_class(PdAt_CLASS);
odm_close_class(CuDv_CLASS);
odm_close_class(PdDv_CLASS);
return(0);
}