/*
* $Id: cfggsc.c,v 1.1 2001/04/15 11:12:37 ant Exp $
* Copyright (c) 1997 by Matthew Jacob
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; version 2.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* The author may be reached via electronic communications at
*
* mjacob@feral.com
*
* or, via United States Postal Address
*
* Matthew Jacob
* 1831 Castro Street
* San Francisco, CA, 94131
*/
#include <stdio.h>
#include <sys/scsi.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/devinfo.h>
#include <sys/device.h>
#include <sys/cfgodm.h>
#include <cf.h>
#include <sys/cfgdb.h>
#include <fcntl.h>
#include <sys/sysconfig.h>
#include <sys/errno.h>
#include <sys/device.h>
#include <sys/mode.h>
#include "gscdds.h"
extern mid_t loadext(char *, int, int);
static int verbose;
static struct gsc_ddsinfo ddsinfo;
int main(int a, char **v);
static void check_add_sockets(dev_t, int, char *, char *);
static int has_driver_get_vpd(char *, int, char *);
#define MKNOD_MODE S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
#define vprintf if (verbose) printf
static void
err_exit(char exitcode)
{
odm_close_class(CuDv_CLASS);
odm_close_class(PdDv_CLASS);
odm_terminate();
exit(exitcode);
}
int
main(int a, char **v)
{
extern char *optarg;
char sstring[256], bufname[256], conns[NAMESIZE], *ptr, *lname;
struct Class *cprp, *cusdev, *predev;
struct CuDvDr dpr, *dprp;
struct CuDv parobj, cusobj, hdobj, *xprp;
struct PdDv preobj;
struct CuAt *attrobj;
int rc, c, errflg, ipl_phase, unit, munit, howmany, lun, domake;
dev_t ctl;
long major;
int *mlist;
mid_t kmid;
struct cfg_dd dd;
lname = NULL;
errflg = 0;
ipl_phase = RUNTIME_CFG;
(void) memset((void *) &ddsinfo, 0, sizeof ddsinfo);
while ((c = getopt(a, v, "l:12v")) != EOF) {
switch (c) {
case 'l':
if (lname != NULL)
errflg++;
lname = optarg;
break;
case 'v':
verbose++;
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)
exit (E_ARGS);
if (lname == NULL)
exit(E_LNAME);
if (odm_initialize() == -1) {
return (E_ODMINIT);
}
/* lock the database */
if (odm_lock("/etc/objrepos/config_lock",0) == -1)
err_exit(E_ODMLOCK);
/* open customized devices object class */
if ((int)(cusdev = odm_open_class(CuDv_CLASS)) == -1)
err_exit(E_ODMOPEN);
/* search for customized object with this logical name */
sprintf(sstring, "name = '%s'", lname);
rc = (int) odm_get_first(cusdev, sstring, &cusobj);
if (rc == 0) {
/* No CuDv object with this name */
err_exit(E_NOCuDv);
} else if (rc == -1) {
/* ODM failure */
err_exit(E_ODMGET);
}
/* open predefined devices object class */
if ((int)(predev = odm_open_class(PdDv_CLASS)) == -1)
err_exit(E_ODMOPEN);
/* get predefined device object for this logical name */
sprintf(sstring, "uniquetype = '%s'", cusobj.PdDvLn_Lvalue);
rc = (int)odm_get_first(predev, sstring, &preobj);
if (rc == 0) {
/* No PdDv object for this device */
err_exit(E_NOPdDv);
} else if (rc == -1) {
/* ODM failure */
err_exit(E_ODMGET);
}
/* close predefined device object class */
if (odm_close_class(predev) == -1)
err_exit(E_ODMCLOSE);
if (ipl_phase != RUNTIME_CFG)
setleds(preobj.led);
/*
* Now, if the device is already configured, we're
* pretty much done.
*/
if (cusobj.status == AVAILABLE) {
/* close customized device object class */
if (odm_close_class(cusdev) == -1)
err_exit(E_ODMCLOSE);
odm_terminate();
return(E_OK);
}
if (cusobj.status != DEFINED) {
vprintf("bad state: %d\n", cusobj.status);
err_exit(E_DEVSTATE);
}
/* get the device's parent object */
sprintf(sstring, "name = '%s'", cusobj.parent);
rc = (int) odm_get_first(cusdev, sstring, &parobj);
if (rc == 0) {
/* Parent device not in CuDv */
err_exit(E_NOCuDvPARENT);
} else if (rc == -1) {
/* ODM failure */
err_exit(E_ODMGET);
}
/* Parent MUST be available to continue */
if (parobj.status != AVAILABLE)
err_exit(E_PARENTSTATE);
/* make sure that no other devices are configured */
/* at this location */
sprintf(sstring, "parent = '%s' AND location='%s' AND status=%d",
cusobj.parent, cusobj.location, AVAILABLE);
rc = (int) odm_get_first(cusdev, sstring, &cusobj);
if (rc == -1) {
/* odm failure */
err_exit(E_ODMGET);
} else if (rc) {
/* Error: device config'd at this location */
err_exit(E_AVAILCONNECT);
}
memcpy(conns, cusobj.location, NAMESIZE);
vprintf("now fool with luns: location is %s\n", conns);
ptr = conns;
while (*ptr && ptr < &conns[NAMESIZE])
ptr++;
ptr--;
if (ptr < &conns[1]) {
err_exit(E_BADATTR);
}
lun = *ptr - '0';
vprintf("I see lun %d\n", lun);
if (lun < 0 || lun >= 8)
err_exit(E_INVCONNECT);
ddsinfo.lun = lun;
/*
* Generate Target
*/
if (ptr[-1] == ',') {
*(--ptr) = 0;
} else {
*ptr = 0;
}
while (ptr > conns && *ptr != '-')
ptr--;
if (*ptr == '-')
ptr++;
ddsinfo.target = strtol(ptr, (char **) NULL, 0);
vprintf("I see tgt %d ptr = %d\n", ddsinfo.target, ptr - conns);
/*
* Generate dev_t for adapter
*/
cprp = odm_open_class(CuDvDr_CLASS) ;
sprintf(sstring, "value3 = %s", cusobj.parent);
rc = (int) odm_get_obj(cprp, sstring, &dpr, TRUE);
if (rc == 0) {
err_exit(E_NOCuDvPARENT);
} else if (rc == -1) {
err_exit(E_ODMGET);
}
ddsinfo.busid = (dev_t) makedev(atoi(dpr.value1), atoi(dpr.value2));
vprintf("I see %d.%d for connecting adapter\n",
major(ddsinfo.busid), minor(ddsinfo.busid));
/*
* Get unit number out of logical name
*/
ptr = lname;
ptr += strlen(preobj.prefix);
unit = atoi(ptr);
vprintf("I see %d as unit\n", unit);
/*
* Okay, now that we have the pertinent information that we'll
* need (adapter dev_t, device type, target, lbits, shareable,
* unit number), we can look into actually loading/configuring the
* current driver.
*/
(void) sprintf(bufname, "/dev/%s", lname);
/*
* Get or generate major number..
*/
if ((major = (long) genmajor(preobj.DvDr)) == -1) {
odm_terminate();
return (E_MAJORNO);
}
vprintf("major is %d\n", major);
/*
* Let's see if this is the first time through. If it's
* the first time through, getminor will return NULL
* or won't have any minors in the list.
*/
mlist = getminor(major, &howmany, preobj.DvDr);
vprintf("getminor: %x and howmany %d for %s\n", mlist, howmany,
preobj.DvDr);
domake = 1;
if (mlist != NULL && howmany != 0) {
/*
* We have a list of minors already.
* See if we already have the minor
* we want defined.
*/
for (c = 0; c < howmany; c++) {
if (mlist[c] == unit) {
vprintf("unit %d already has minor\n", unit);
domake = 0;
break;
}
}
}
if (domake) {
(void) unlink(bufname);
/*
* Now create the minor number that will match the unit number.
* We really don't care whether genminor succeeds, since
* we've alreay unlinked the device node.
*/
mlist = genminor(preobj.DvDr, major, unit, 1, 1, 1);
if (mlist == (long *) NULL) {
err_exit(E_MINORNO);
}
vprintf("making %s as %d.%d with minor returned as %d\n",
bufname, major, unit, *mlist);
if (mknod(bufname, MKNOD_MODE, makedev(major, unit))) {
err_exit(E_MKSPECIAL);
}
} else {
(void) mknod(bufname, MKNOD_MODE, makedev(major, unit));
}
/*
* Load the driver....
*/
kmid = loadext(preobj.DvDr, TRUE, FALSE);
if (!kmid) {
err_exit(E_LOADEXT);
}
/*
* And configure the driver...
*/
dd.kmid = kmid;
dd.devno = makedev(major, unit);
dd.cmd = CFG_INIT;
dd.ddsptr = (caddr_t) &ddsinfo;
dd.ddslen = sizeof (ddsinfo);
if (sysconfig(SYS_CFGDD, &dd, sizeof (dd)) == CONF_FAIL) {
int saverr = errno;
/*
* Unload driver...
*/
(void) loadext(preobj.DvDr, FALSE, FALSE);
switch(saverr) {
case ENODEV:
err_exit(E_WRONGDEVICE);
/* NOTREACHED */
break;
case EBUSY:
err_exit(E_AVAILCONNECT);
/* NOTREACHED */
break;
case EINVAL:
default:
err_exit(E_CFGINIT);
/* NOTREACHED */
break;
}
}
/* now mark the device as available */
cusobj.status = AVAILABLE;
if (odm_change_obj(CuDv_CLASS, &cusobj) == -1) {
/*
* Unconfigure driver (for this instance)...
*/
dd.kmid = 0;
dd.ddsptr = (caddr_t) NULL;
dd.ddslen = (int ) 0;
dd.cmd = CFG_TERM;
(void) sysconfig(SYS_CFGDD, &dd, sizeof (dd));
/*
* Unload driver...
*/
(void) loadext(preobj.DvDr, FALSE, FALSE);
err_exit (E_ODMUPDATE);
}
(void) odm_terminate();
return (E_OK);
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-indent-level: 4
* c-brace-imaginary-offset: 0
* c-brace-offset: -4
* c-argdecl-indent: 4
* c-label-offset: -4
* c-continued-statement-offset: 4
* c-continued-brace-offset: 0
* End:
*/