829 lines
18 KiB
C
829 lines
18 KiB
C
static char sccsid[] = "@(#)27 1.2 src/bos/usr/lib/methods/common/cfgboot_tools.c, cfgmethods, bos41J, 9523A_all 95/06/05 18:00:01";
|
|
/*
|
|
* COMPONENT_NAME: (CFGMETHODS) cfgboot_tools.c - RSPC config/boot routines
|
|
*
|
|
* FUNCTIONS: get_resid_index
|
|
* get_bootdev_odm_name
|
|
* mk_nv_list
|
|
* get_bootparms
|
|
* get_odm_name
|
|
* mk_nv_name
|
|
* get_smallest_bax
|
|
* pciquery
|
|
* iplcb_get
|
|
*
|
|
* ORIGINS: 27
|
|
*
|
|
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
|
|
* combined with the aggregated modules for this product)
|
|
* SOURCE MATERIALS
|
|
* (C) COPYRIGHT International Business Machines Corp. 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 <sys/types.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <sys/mdio.h>
|
|
#include <sys/iplcb.h>
|
|
#include <sys/rosinfo.h>
|
|
#include <odmi.h>
|
|
#include <sys/cfgdb.h>
|
|
#include <sys/cfgodm.h>
|
|
#include <cf.h>
|
|
#include <cfgresid.h>
|
|
|
|
int get_resid_index(struct CuDv *, struct PdDv *, CFG_DEVICE *,int);
|
|
int get_bootdev_odm_name(char *, char *);
|
|
int mk_nv_list(struct CuDv *, struct PdDv *, char *);
|
|
int get_bootparms(struct CuDv *, struct PdDv *, char *);
|
|
static int get_odm_name(char *, struct CuDv *);
|
|
static int mk_nv_name(struct CuDv *, struct PdDv *, CFG_DEVICE *, int, char *);
|
|
static ulong get_smallest_bax(int);
|
|
static int pciquery(int, char *, ulong *);
|
|
static int iplcb_get(void *, int, int, int);
|
|
|
|
|
|
|
|
/*
|
|
* get_resid_index: Matches an ODM device with corresponding device
|
|
* entry in resid data. Returns index into residual
|
|
* data device array. If no match is found, returns -1.
|
|
*/
|
|
int
|
|
get_resid_index(cudv,pddv,devp,num)
|
|
struct CuDv *cudv;
|
|
struct PdDv *pddv;
|
|
CFG_DEVICE *devp;
|
|
int num;
|
|
|
|
{
|
|
int rc;
|
|
int i;
|
|
int j;
|
|
struct CuDv pcudv;
|
|
struct CuAt cuat;
|
|
struct PdAt pdat;
|
|
char sstr[128];
|
|
int pci_busnum;
|
|
int devfunc;
|
|
ulong ioaddr;
|
|
int cnt;
|
|
CFG_iopack_t *iopkt;
|
|
char pnp[8];
|
|
ulong serial;
|
|
|
|
|
|
if (!strcmp(pddv->subclass,"pci")) {
|
|
/* Its a PCI device */
|
|
|
|
#ifdef BOOT_DEBUG
|
|
fprintf(stderr, "Its a PCI device\n");
|
|
#endif
|
|
/* Get CuDv for parent bus */
|
|
sprintf(sstr,"name=%s",cudv->parent);
|
|
rc = (int)odm_get_first(CuDv_CLASS,sstr,&pcudv);
|
|
if (rc == 0 || rc == -1)
|
|
return(-1);
|
|
|
|
/* Get PCI bus number attribute for parent bus */
|
|
sprintf(sstr,"name=%s AND attribute=bus_number",pcudv.name);
|
|
rc = (int)odm_get_first(CuAt_CLASS,sstr,&cuat);
|
|
if (rc == -1) {
|
|
return(-1);
|
|
}
|
|
else if (rc != 0) {
|
|
pci_busnum = (int)strtoul(cuat.value, (char **)NULL, 0);
|
|
}
|
|
else {
|
|
sprintf(sstr,"uniquetype=%s AND attribute=bus_number",
|
|
pcudv.PdDvLn_Lvalue);
|
|
rc = (int)odm_get_first(PdAt_CLASS,sstr,&pdat);
|
|
if (rc == 0 || rc == -1)
|
|
return(-1);
|
|
pci_busnum = (int)strtoul(pdat.deflt, (char **)NULL, 0);
|
|
}
|
|
|
|
|
|
devfunc = (int)strtoul(cudv->connwhere, (char **)NULL, 10);
|
|
|
|
#ifdef BOOT_DEBUG
|
|
fprintf(stderr, "\tPCI bus number = %x\n\tDevFunc number = %x\n",pci_busnum,devfunc);
|
|
#endif
|
|
|
|
/* A PCI device is matched using PCI bus number and DevFunc */
|
|
for (i=0; i<num; i++) {
|
|
if ((devp[i].deviceid.busid == PCI_DEVICE) &&
|
|
(devp[i].busaccess.pciaccess.busnumber
|
|
== pci_busnum) &&
|
|
(devp[i].busaccess.pciaccess.devfuncnumber
|
|
== devfunc)) {
|
|
/* Found matching resid entry */
|
|
return(i);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
else if (!strcmp(pddv->subclass,"isa")) {
|
|
/* Its an ISA device */
|
|
|
|
#ifdef BOOT_DEBUG
|
|
fprintf(stderr, "Its an ISA device\n");
|
|
#endif
|
|
/* Get an I/O attribute for adapter */
|
|
sprintf(sstr,"name=%s AND type LIKE O*",cudv->name);
|
|
rc = (int)odm_get_first(CuAt_CLASS,sstr,&cuat);
|
|
if (rc == -1) {
|
|
return(-1);
|
|
}
|
|
else if (rc != 0) {
|
|
ioaddr = strtoul(cuat.value, (char **)NULL, 0);
|
|
}
|
|
else {
|
|
sprintf(sstr,"uniquetype=%s AND type LIKE O*",
|
|
cudv->PdDvLn_Lvalue);
|
|
rc = (int)odm_get_first(PdAt_CLASS,sstr,&pdat);
|
|
if (rc == 0 || rc == -1)
|
|
return(-1);
|
|
ioaddr = strtoul(pdat.deflt, (char **)NULL, 0);
|
|
}
|
|
|
|
#ifdef BOOT_DEBUG
|
|
fprintf(stderr, "\tI/O address = %x\n",ioaddr);
|
|
#endif
|
|
|
|
/* An ISA device is matched using I/O address */
|
|
for (i=0; i<num; i++) {
|
|
if ((devp[i].deviceid.busid == ISA_DEVICE) &&
|
|
!(devp[i].deviceid.flags & INTEGRATED) &&
|
|
(!strcmp(devp[i].pnpid,pddv->devid))) {
|
|
|
|
#ifdef BOOT_DEBUG
|
|
fprintf(stderr, "\tFound matching PNP number\n");
|
|
#endif
|
|
|
|
/* Get I/O packets from resid data */
|
|
rc = get_io_packets(i, 'a', &cnt, &iopkt);
|
|
if (rc)
|
|
return(-1);
|
|
|
|
for (j=0; j<cnt; j++) {
|
|
if (iopkt[j].min == ioaddr) {
|
|
/* Found matching resid entry */
|
|
return(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (!strcmp(pddv->subclass,"isa_sio")) {
|
|
/* Its an integrated ISA device */
|
|
|
|
#ifdef BOOT_DEBUG
|
|
fprintf(stderr, "Its an integrated ISA device\n");
|
|
#endif
|
|
|
|
strncpy(pnp,cudv->connwhere,7);
|
|
pnp[7] = '\0';
|
|
serial = strtoul(&(cudv->connwhere[7]), (char **)NULL, 16);
|
|
|
|
#ifdef BOOT_DEBUG
|
|
fprintf(stderr,"\tPNP number = %s\n",pnp);
|
|
fprintf(stderr,"\tSerial number = %x\n",serial);
|
|
#endif
|
|
|
|
/* Integrated ISA devices are matched on PNP and serial nums */
|
|
for (i=0; i<num; i++) {
|
|
if ((devp[i].deviceid.busid == ISA_DEVICE) &&
|
|
(devp[i].deviceid.flags & INTEGRATED) &&
|
|
(devp[i].deviceid.serialnum == serial) &&
|
|
(!strcmp(devp[i].pnpid,pnp))) {
|
|
/* Found matching resid entry */
|
|
return(i);
|
|
}
|
|
}
|
|
}
|
|
#ifdef BOOT_DEBUG
|
|
fprintf(stderr, "Its an unsupported device type: {%s}\n",pddv->uniquetype);
|
|
#endif
|
|
|
|
return(-1);
|
|
}
|
|
|
|
|
|
/*
|
|
* get_bootdev_odm_name: Finds ODM device corresponding to device
|
|
* identified by fw-boot-device
|
|
*/
|
|
int
|
|
get_bootdev_odm_name(bootlist,bootname)
|
|
char *bootlist;
|
|
char *bootname;
|
|
{
|
|
char *p;
|
|
char *dev_id;
|
|
char *end_list;
|
|
struct CuDv cudv;
|
|
int rc;
|
|
|
|
|
|
/* bootlist is a fw-boot-device style device identifier. This */
|
|
/* consists of a sequence of individual device identifiers that */
|
|
/* identify all devices in path from bus to end boot device. */
|
|
|
|
#ifdef BOOT_DEBUG
|
|
fprintf(stderr, "fw-boot-device=%s\n",bootlist);
|
|
#endif
|
|
|
|
/* Process each individual device in list */
|
|
end_list = bootlist + strlen(bootlist);
|
|
p = bootlist;
|
|
while(p != end_list) {
|
|
/* Skip initial 'slash' character */
|
|
p++;
|
|
|
|
/* Set up pointer to current device identifier */
|
|
dev_id = p;
|
|
|
|
/* Find start of next device identifier */
|
|
while (*p != '/' && *p != '\0') p++;
|
|
|
|
/* NULL terminate current device identifier */
|
|
*p = '\0';
|
|
|
|
/* Convert device identifier to a CuDv object */
|
|
rc = get_odm_name(dev_id,&cudv);
|
|
if (rc)
|
|
return(rc);
|
|
}
|
|
|
|
/* Found CuDv for boot device */
|
|
strcpy(bootname,cudv.name);
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* get_odm_name: Finds ODM device which is a child of "cudv" and
|
|
* identified by substring from fw-boot-device
|
|
*/
|
|
static int
|
|
get_odm_name(dev_id, cudv)
|
|
char *dev_id;
|
|
struct CuDv *cudv;
|
|
{
|
|
char *type;
|
|
char *addr;
|
|
char *parms;
|
|
char *p;
|
|
int rc;
|
|
char sstr[256];
|
|
CFG_DEVICE *dp;
|
|
int num;
|
|
CFG_pci_descriptor_t *pci;
|
|
int i;
|
|
int busnum;
|
|
int cnt;
|
|
int devnum;
|
|
int func;
|
|
int sid;
|
|
int lun;
|
|
int connection;
|
|
ulong ioaddr;
|
|
struct CuDv *cudvlist;
|
|
struct listinfo cudv_info;
|
|
struct CuAt *cuat;
|
|
int j;
|
|
ulong tst_ioaddr;
|
|
ulong min_io;
|
|
|
|
|
|
#ifdef BOOT_DEBUG
|
|
fprintf(stderr, "\tDevice string=%s\n",dev_id);
|
|
#endif
|
|
|
|
/* Assume format of device identifier to be type@addr:parms */
|
|
/* or just type@addr. */
|
|
/* Parse into three pieces */
|
|
type = dev_id;
|
|
for (p=type; *p!='@'; p++); /* Skip to '@' character */
|
|
*p = '\0';
|
|
|
|
addr = p + 1;
|
|
for (p=type; *p!=':' && *p!='\0'; p++); /* Skip to ':' character */
|
|
if (*p == ':') {
|
|
*p = '\0';
|
|
p++;
|
|
}
|
|
parms = p; /* Points to '\0' if no parms */
|
|
|
|
|
|
/* Now start decoding */
|
|
|
|
if (!strcmp(type,"pci")) {
|
|
|
|
/* PCI system bus */
|
|
|
|
ioaddr = strtoul(addr, (char **)NULL, 16);
|
|
|
|
/* Get resid device table */
|
|
if (get_resid_dev(&num, &dp) != 0) {
|
|
return(-1);
|
|
}
|
|
|
|
/* Look for top level PCI bus */
|
|
for (i=0; i<num; i++) {
|
|
if ((dp[i].deviceid.busid == PROCESSOR_DEVICE) &&
|
|
(dp[i].deviceid.basetype == Bridge_Controller) &&
|
|
(dp[i].deviceid.subtype == PCI_Bridge)) {
|
|
|
|
/* Found PCI bus, see if it has right address */
|
|
min_io = get_smallest_bax(i);
|
|
if (ioaddr != min_io)
|
|
continue;
|
|
|
|
/* Found correct PCI bus, get PCI bus number */
|
|
get_pci_descriptor(i,'a', &cnt, &pci);
|
|
busnum = pci->busnum;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Get CuDv for the PCI bus */
|
|
sprintf(sstr,"parent=sysplanar0 AND connwhere=4.%d AND status=1",busnum);
|
|
rc = (int)odm_get_first(CuDv_CLASS,sstr,cudv);
|
|
if (rc == 0 || rc == -1) {
|
|
return(-1);
|
|
}
|
|
} /* End PCI system bus */
|
|
|
|
else if (!strncmp(type,"pci",3)) {
|
|
|
|
/* PCI device */
|
|
|
|
/* Parse addr for device number and function number */
|
|
/* addr will point to device number string, p to function */
|
|
for (p=addr; *p!=','; p++); /* Skip to ',' character */
|
|
*p = '\0';
|
|
p++;
|
|
|
|
/* Get numeric values for device and function numbers */
|
|
devnum = strtoul(addr, (char **)NULL, 16);
|
|
func = strtoul(p, (char **)NULL, 16);
|
|
|
|
/* Get CuDv for the PCI device */
|
|
sprintf(sstr,"parent=%s AND connwhere=%d AND status=1",cudv->name,8*devnum+func);
|
|
rc = (int)odm_get_first(CuDv_CLASS,sstr,cudv);
|
|
if (rc == 0 || rc == -1) {
|
|
return(-1);
|
|
}
|
|
} /* End PCI device */
|
|
|
|
else if (!strcmp(type,"harddisk")
|
|
|| !strcmp(type,"tape")
|
|
|| !strcmp(type,"cdrom")
|
|
|| !strcmp(type,"floppy")) {
|
|
|
|
/* Disk, tape, CDROM, or floppy */
|
|
|
|
/* If the addr string has a ',' then device is SCSI */
|
|
for (p=addr; *p!=',' && *p!='\0'; p++);
|
|
if (*p == ',') {
|
|
|
|
/* Its SCSI format with ID and LUN */
|
|
*p = '\0';
|
|
p++;
|
|
sid = strtoul(addr, (char **)NULL, 16);
|
|
lun = strtoul(p, (char **)NULL, 16);
|
|
|
|
/* Set up ODM search arg for the SCSI device */
|
|
sprintf(sstr,"parent=%s AND connwhere=%d,%d AND status=1",cudv->name,sid,lun);
|
|
} /* End SCSI device */
|
|
|
|
else {
|
|
/* Its IDE or floppy */
|
|
connection = strtoul(addr, (char **)NULL, 16);
|
|
|
|
/* Set up ODM search arg for the device */
|
|
sprintf(sstr,"parent=%s AND connwhere=%d AND status=1",cudv->name,connection);
|
|
}
|
|
|
|
/* Get CuDv for the device */
|
|
rc = (int)odm_get_first(CuDv_CLASS,sstr,cudv);
|
|
if (rc == 0 || rc == -1) {
|
|
return(-1);
|
|
}
|
|
} /* End disk, tape, CDROM, or floppy */
|
|
|
|
else {
|
|
/* ISA device */
|
|
|
|
/* addr string is the I/O address */
|
|
ioaddr = strtoul(addr, (char **)NULL, 16);
|
|
|
|
/* Get all children of the ISA bus */
|
|
sprintf(sstr,"parent=%s AND status=1",cudv->name);
|
|
cudvlist = odm_get_list(CuDv_CLASS,sstr,&cudv_info,16,1);
|
|
if (cudvlist == NULL || (int)cudvlist == -1) {
|
|
return(-1);
|
|
}
|
|
|
|
/* Get attributes for each device, look for matching I/O addr */
|
|
for (i=0; i<cudv_info.num; i++) {
|
|
cuat = getattr(cudvlist[i].name, NULL, TRUE, &cnt);
|
|
for (j=0; j<cnt; j++) {
|
|
if (cuat[j].type[0] == 'O') {
|
|
tst_ioaddr = strtoul(cuat[j].value, (char **)NULL, 0);
|
|
if (ioaddr == tst_ioaddr) {
|
|
/* Found device */
|
|
*cudv = cudvlist[i];
|
|
free(cuat);
|
|
odm_free_list(cudvlist,&cudv_info);
|
|
return(0);
|
|
}
|
|
}
|
|
}
|
|
free(cuat);
|
|
}
|
|
|
|
odm_free_list(cudvlist,&cudv_info);
|
|
return(-1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
int
|
|
mk_nv_list(c_ptr,p_ptr,p)
|
|
struct CuDv *c_ptr;
|
|
struct PdDv *p_ptr;
|
|
char *p;
|
|
{
|
|
CFG_DEVICE *devp;
|
|
int num;
|
|
struct CuDv *cudv_p;
|
|
struct CuDv cudv;
|
|
struct PdDv *pddv_p;
|
|
struct PdDv pddv;
|
|
char sstr[128];
|
|
char n[256];
|
|
char tmp[512];
|
|
int rc;
|
|
|
|
|
|
/* Initialize returned string to a NULL string in case of error */
|
|
*p = '\0';
|
|
|
|
/* get the number of devices and the device info from resid data */
|
|
rc = get_resid_dev(&num, &devp); /* libcfg function */
|
|
if (rc)
|
|
return(-1);
|
|
|
|
cudv_p = c_ptr;
|
|
pddv_p = p_ptr;
|
|
while(cudv_p) {
|
|
|
|
/* Make portion of name corresponding to CuDv object */
|
|
rc = mk_nv_name(cudv_p,pddv_p,devp,num,n);
|
|
if (rc)
|
|
return(rc);
|
|
|
|
/* Insert name in front of string to be returned */
|
|
strcpy(tmp,p);
|
|
strcpy(p,n);
|
|
strcat(p,tmp);
|
|
|
|
/* If not to system bus, then process next parent */
|
|
if (strncmp(cudv_p->PdDvLn_Lvalue,"bus/sys/",8)) {
|
|
/* Get parent CuDv and PdDv */
|
|
sprintf(sstr,"name=%s", cudv_p->parent);
|
|
rc = (int)odm_get_first(CuDv_CLASS,sstr,&cudv);
|
|
if (rc==0) {
|
|
/* failed to get an object */
|
|
return(E_NOCuDv);
|
|
}
|
|
else if (rc==-1) {
|
|
/* ODM error */
|
|
return(E_ODMGET);
|
|
}
|
|
|
|
cudv_p = &cudv;
|
|
|
|
sprintf(sstr,"uniquetype=%s", cudv_p->PdDvLn_Lvalue);
|
|
rc = (int)odm_get_first(PdDv_CLASS,sstr,&pddv);
|
|
if (rc==0) {
|
|
/* failed to get an object */
|
|
return(E_NOPdDv);
|
|
}
|
|
else if (rc==-1) {
|
|
/* ODM error */
|
|
return(E_ODMGET);
|
|
}
|
|
|
|
pddv_p = &pddv;
|
|
}
|
|
|
|
else {
|
|
/* Processed all devices up to and including top bus */
|
|
cudv_p = NULL; /* Set ptr to NULL for exit */
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
static int
|
|
mk_nv_name(cudv, pddv, devp, num, n)
|
|
struct CuDv *cudv;
|
|
struct PdDv *pddv;
|
|
CFG_DEVICE *devp;
|
|
int num;
|
|
char *n;
|
|
|
|
{
|
|
int i;
|
|
CFG_pci_descriptor_t *pci;
|
|
ulong min_io;
|
|
int busnum;
|
|
int cnt;
|
|
ulong devid;
|
|
ulong v_id;
|
|
ulong d_id;
|
|
ulong devfunc;
|
|
CFG_iopack_t *iopkt;
|
|
int index;
|
|
int rc;
|
|
|
|
|
|
if (!strncmp(pddv->uniquetype,"bus/sys/",8)) {
|
|
/* Top level bus...assume PCI bus */
|
|
|
|
/* Get PCI bus number from connwhere */
|
|
busnum = (uchar)strtoul(strchr(cudv->connwhere,'.')+1,NULL,10);
|
|
|
|
/* Find PCI bus in resid data by matching PCI bus number */
|
|
for (i=0; i<num; i++) {
|
|
if ((devp[i].deviceid.busid == PROCESSOR_DEVICE) &&
|
|
(devp[i].deviceid.basetype == Bridge_Controller) &&
|
|
(devp[i].deviceid.subtype == PCI_Bridge)) {
|
|
/* Check PCI bus num in bridge descriptor */
|
|
get_pci_descriptor(i,'a', &cnt, &pci);
|
|
if (pci->busnum == busnum) {
|
|
/* Found correct device entry */
|
|
/* Get addr translation descriptors */
|
|
min_io = get_smallest_bax(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
sprintf(n,"/pci@%x",min_io);
|
|
}
|
|
|
|
else if (!strcmp(pddv->subclass,"pci")) {
|
|
|
|
/* Its a PCI device */
|
|
devfunc = strtoul(cudv->connwhere,NULL,10);
|
|
devid = strtoul(pddv->devid, (char **)NULL, 0);
|
|
if (devid == 0) {
|
|
/* devid in PdDv may be NULL for ISA bridges */
|
|
/* So read bytes from PCI cfg space */
|
|
rc = pciquery(devfunc,cudv->parent,&devid);
|
|
if (rc == -1)
|
|
return(-1);
|
|
}
|
|
|
|
v_id = ((devid & 0x00FF0000)>>8) | ((devid & 0xFF000000)>>24);
|
|
d_id = ((devid & 0x0000FF00)>>8) | ((devid & 0x000000FF)<<8);
|
|
|
|
sprintf(n,"/pci%x,%x@%x,%x",v_id,d_id,devfunc/8,devfunc&0x7);
|
|
}
|
|
|
|
else if (!strcmp(pddv->subclass,"isa") ||
|
|
!strcmp(pddv->subclass,"isa_sio")) {
|
|
|
|
/* Its an ISA device */
|
|
index = get_resid_index(cudv,pddv,devp,num);
|
|
if (index == -1)
|
|
return(-1);
|
|
|
|
/* Get I/O packets from resid data */
|
|
rc = get_io_packets(index, 'a', &cnt, &iopkt);
|
|
if (rc)
|
|
return(-1);
|
|
|
|
sprintf(n,"/%s@%x",devp[index].pnpid,iopkt[0].min);
|
|
}
|
|
|
|
else if (!strcmp(pddv->subclass,"scsi") ||
|
|
!strcmp(pddv->subclass,"ide")) {
|
|
if (!strcmp(pddv->class,"disk")) {
|
|
sprintf(n,"/harddisk@%s",cudv->connwhere);
|
|
}
|
|
|
|
else if (!strcmp(pddv->class,"cdrom")) {
|
|
sprintf(n,"/cdrom@%s",cudv->connwhere);
|
|
}
|
|
|
|
else if (!strcmp(pddv->class,"tape")) {
|
|
sprintf(n,"/tape@%s",cudv->connwhere);
|
|
}
|
|
}
|
|
|
|
else if (!strcmp(pddv->class,"diskette")) {
|
|
sprintf(n,"/floppy@%s",cudv->connwhere);
|
|
}
|
|
|
|
else {
|
|
/* Not a possible boot device */
|
|
return(-1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* get_smallest_bax: Gets address translation descriptors from residual
|
|
* data for the device whose index in the residual
|
|
* data device table is "index". It returns the smallest
|
|
* system address for which there is an I/O mapping. If
|
|
* there are no I/O mapping, then it returns the smallest
|
|
* system address for which there is a bus memory mapping.
|
|
*/
|
|
static ulong
|
|
get_smallest_bax(index)
|
|
int index;
|
|
{
|
|
int rc;
|
|
int num;
|
|
int i;
|
|
CFG_bax_descriptor_t *ptr;
|
|
unsigned long long min_io;
|
|
unsigned long long min_mem;
|
|
|
|
|
|
min_io = min_mem = -1;
|
|
|
|
/* Get all vendor packets for bus */
|
|
if (get_bax_descriptor(index, 'a', &num, &ptr) != 0)
|
|
return(-1);
|
|
|
|
/* Look for smallest I/O address translation descriptor */
|
|
for (i=0; i<num; i++) {
|
|
if (ptr->conv == 2) {
|
|
if (ptr->sys < min_io)
|
|
min_io = ptr->sys;
|
|
}
|
|
else if (ptr->conv == 1) {
|
|
if (ptr->sys < min_mem)
|
|
min_mem = ptr->sys;
|
|
}
|
|
ptr++;
|
|
}
|
|
|
|
if (min_io == -1)
|
|
return(min_mem);
|
|
|
|
return(min_io);
|
|
}
|
|
|
|
static int
|
|
pciquery(devfunc,bus,devid)
|
|
int devfunc;
|
|
char *bus;
|
|
ulong *devid;
|
|
{
|
|
int rc;
|
|
MACH_DD_IO mddRecord;
|
|
int fd;
|
|
char devbus[32];
|
|
|
|
|
|
/* build mdd record */
|
|
mddRecord.md_size = 1;
|
|
mddRecord.md_incr = MV_WORD;
|
|
mddRecord.md_addr = 0;
|
|
mddRecord.md_sla = devfunc;
|
|
mddRecord.md_data = (uchar*)devid;
|
|
|
|
sprintf(devbus,"/dev/%s",bus);
|
|
if ((fd = open(devbus, O_RDWR, 0)) < 0) {
|
|
return(-1);
|
|
}
|
|
|
|
rc = ioctl(fd, MIOPCFGET, &mddRecord);
|
|
close(fd);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
/*
|
|
* get_bootparms: Determines if device identified by 'cudv' is the boot
|
|
* device. If it is, the parameters at the end of the
|
|
* fw-boot-device NVRAM variable are returned in 'parms'.
|
|
* If it is not the boot device, a NULL string is returned
|
|
* in 'parms'.
|
|
*/
|
|
int
|
|
get_bootparms(cudv, pddv, parms)
|
|
struct CuDv *cudv;
|
|
struct PdDv *pddv;
|
|
char *parms;
|
|
{
|
|
IPL_DIRECTORY iplcb_dir; /* IPL control block directory */
|
|
IPL_INFO iplcb_info; /* IPL control blk info section */
|
|
char bl[2048];
|
|
char test_bl[2048];
|
|
char *p1;
|
|
int rc;
|
|
int num;
|
|
CFG_DEVICE *devp;
|
|
|
|
|
|
*parms = '\0';
|
|
|
|
/* Get directory section of IPL control block */
|
|
/* it starts at offset of 128 into IPL control block */
|
|
if (iplcb_get(&iplcb_dir,128,sizeof(iplcb_dir),MIOIPLCB)) {
|
|
return(-1);
|
|
}
|
|
|
|
/* Get iplinfo structure. */
|
|
if (iplcb_get(&iplcb_info,iplcb_dir.ipl_info_offset,
|
|
sizeof(iplcb_info), MIOIPLCB)) {
|
|
return(-1);
|
|
}
|
|
|
|
strcpy(bl, &(iplcb_info.previpl_device[3]));
|
|
|
|
#ifdef BOOT_DEBUG
|
|
fprintf(stderr,"boot device string from IPL CB: '%s'\n",bl);
|
|
#endif
|
|
|
|
/* Find last device in boot device string */
|
|
p1 = &bl[strlen(bl)-1];
|
|
while(*p1 != '/') p1--;
|
|
|
|
/* Now find parameters, if any, and replace ':' with NULL */
|
|
while(*p1 != ':' && *p1 != '\0') p1++;
|
|
if (*p1 == ':') {
|
|
*p1 = '\0';
|
|
p1++;
|
|
}
|
|
/* p1 now points to parm string or '\0' */
|
|
|
|
rc = get_resid_dev(&num, &devp);
|
|
if (rc)
|
|
return(-1);
|
|
|
|
rc = mk_nv_list(cudv, pddv, test_bl);
|
|
if (rc)
|
|
return(-1);
|
|
|
|
if (!strcmp(bl,test_bl))
|
|
strcpy(parms,p1);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* iplcb_get: Read in section of the IPL control block. The directory
|
|
* section starts at offset 128.
|
|
*/
|
|
static int
|
|
iplcb_get(dest, address, num_bytes, iocall)
|
|
void *dest;
|
|
int address;
|
|
int num_bytes;
|
|
int iocall;
|
|
{
|
|
int fd; /* file descriptor */
|
|
MACH_DD_IO mdd;
|
|
|
|
|
|
if ((fd = open("/dev/nvram",0)) < 0) {
|
|
return(-1);
|
|
}
|
|
|
|
mdd.md_addr = (long)address;
|
|
mdd.md_data = dest;
|
|
mdd.md_size = (long)num_bytes;
|
|
mdd.md_incr = MV_BYTE;
|
|
|
|
if (ioctl(fd,iocall,&mdd)) {
|
|
return(-1);
|
|
}
|
|
|
|
close(fd);
|
|
return(0);
|
|
}
|