/*- * (C) COPYRIGHT Daniel K. Forrest (forrest@ssec.wisc.edu) * All Rights Reserved * * THIS CODE IS NOT PUBLIC DOMAIN. * * You may modify it for your own personal use, but you cannot * distribute the modified code in any form (executable or source * code) and it may not be used as part of any commercial product. * It is supplied "as is" without warranty of any kind. * -*/ /*- * * FUNCTION: Configure method for a RIC Adapter Port * * INTERFACE: cfgcdr100 -l [-<1|2>] * -*/ /* * header files needed for compilation */ #include #include #include #include #include #include #include #include #include #include /* * Local header files */ #include "debug.h" #include "cdr100.h" /* * external functions */ extern long genmajor(); /* * main function code */ main(argc, argv, envp) int argc; char *argv[]; char *envp[]; { struct cfg_dd cfg; /* sysconfig command structure */ char *logical_name;/* logical name to configure */ char sstring[256];/* search criteria pointer */ struct Class *cusdev; /* customized devices class ptr */ struct Class *predev; /* predefined devices class ptr */ struct CuDv cusobj; /* customized device object storage */ struct PdDv preobj; /* predefined device object storage */ struct CuDv parobj; /* customized device object storage */ struct CuDv dmyobj; /* customized device object storage */ int majorno; /* major number assigned to device */ int minorno; /* minor number assigned to device */ long *minor_list; /* list returned by getminor */ int how_many; /* number of minors in list */ int ipl_phase; /* ipl phase: 0=run,1=phase1,2=phase2 */ int rc; /* return codes go here */ int errflg; /* used in parsing parameters */ int c; /* used in parsing parameters */ extern int optind; /* for getopt function */ extern char *optarg; /* for getopt function */ /* * Parse Parameters */ ipl_phase = RUNTIME_CFG; errflg = 0; logical_name = NULL; while ((c = getopt(argc, argv, "l:12")) != EOF) { switch (c) { case 'l': if (logical_name != NULL) errflg++; logical_name = optarg; 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("cfgcdr100: command line error\n"); exit(E_ARGS); } /* * Validate Parameters */ /* * logical name must be specified */ if (logical_name == NULL) { DEBUG_0("cfgcdr100: logical name must be specified\n"); exit(E_LNAME); } DEBUG_1("Configuring device: %s\n", logical_name); /* * start up odm */ if (odm_initialize() == -1) { /* initialization failed */ DEBUG_0("cfgcdr100: odm_initialize() failed\n"); exit(E_ODMINIT); } /* * lock the database */ if (odm_lock("/etc/objrepos/config_lock", 0) == -1) { DEBUG_0("cfgcdr100: odm_lock() failed\n"); err_exit(E_ODMLOCK); } DEBUG_0("ODM initialized and locked\n"); /* * open customized devices object class */ if ((int) (cusdev = odm_open_class(CuDv_CLASS)) == -1) { DEBUG_0("cfgcdr100: 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(cusdev, sstring, &cusobj); if (rc == 0) { /* No CuDv object with this name */ DEBUG_1("cfgcdr100: failed to find CuDv object for %s\n", logical_name); err_exit(E_NOCuDv); } else if (rc == -1) { /* ODM failure */ DEBUG_0("cfgcdr100: ODM failure getting CuDv object"); err_exit(E_ODMGET); } /* * open predefined devices object class */ if ((int) (predev = odm_open_class(PdDv_CLASS)) == -1) { DEBUG_0("cfgcdr100: open class PdDv failed\n"); 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 */ DEBUG_0("cfgcdr100: failed to find PdDv object for this device\n"); err_exit(E_NOPdDv); } else if (rc == -1) { /* ODM failure */ DEBUG_0("cfgcdr100: ODM failure getting PdDv object"); err_exit(E_ODMGET); } /* * close predefined device object class */ if (odm_close_class(predev) == -1) { DEBUG_0("cfgcdr100: close object class PdDv failed"); err_exit(E_ODMCLOSE); } /* * 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(preobj.led); /* * 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, * building a DDS, loading the driver, etc... */ if (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. */ /* * 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 */ DEBUG_0("cfgcdr100: no parent CuDv object\n"); err_exit(E_NOCuDvPARENT); } else if (rc == -1) { /* ODM failure */ DEBUG_0("cfgcdr100: ODM failure getting parent CuDv object\n"); err_exit(E_ODMGET); } if (parobj.status != AVAILABLE) { DEBUG_0("cfgcdr100: parent is not AVAILABLE"); err_exit(E_PARENTSTATE); } /* * make sure that no other devices are configured at this location */ sprintf(sstring, "parent = '%s' AND connwhere = '%s' AND status = %d", cusobj.parent, cusobj.connwhere, AVAILABLE); rc = (int) odm_get_first(cusdev, sstring, &dmyobj); if (rc == -1) { /* odm failure */ err_exit(E_ODMGET); } else if (rc) { /* device config'd at this location */ DEBUG_0("cfgcdr100: device already AVAILABLE at this connection\n"); err_exit(E_AVAILCONNECT); } /* * Load device driver, get major number, and call device dependent * routines to get minor number, make special files, and build DDS. This * code then passes the DDS to the driver. */ /* * call loadext to load the device driver */ if ((cfg.kmid = loadext(preobj.DvDr, TRUE, FALSE)) == NULL) { /* * error loading device driver */ DEBUG_1("cfgcdr100: error loading driver %s\n", preobj.DvDr); err_exit(E_LOADEXT); } /* * get major number */ DEBUG_0("cfgcdr100: Calling genmajor()\n"); if ((majorno = genmajor(preobj.DvDr)) == -1) { DEBUG_0("cfgcdr100: error generating major number"); err_undo(preobj.DvDr); err_exit(E_MAJORNO); } DEBUG_1("cfgcdr100: Returned major number: %d\n", majorno); /* * get minor number */ DEBUG_0("cfgcdr100: Calling getminor()\n"); minor_list = getminor(majorno, &how_many, logical_name); if (minor_list == NULL || how_many == 0) { DEBUG_0("cfgcdr100: Calling generate_minor()\n"); rc = generate_minor(logical_name, majorno, &minorno); if (rc) { DEBUG_1("cfgcdr100: error generating minor number, rc=%d\n", rc); /* * First make sure any minors that might have been assigned are * cleaned up */ reldevno(logical_name, TRUE); err_undo(preobj.DvDr); if (rc < 0 || rc > 255) rc = E_MINORNO; err_exit(rc); } DEBUG_0("cfgcdr100: Returned from generate_minor()\n"); } else minorno = *minor_list; DEBUG_1("cfgcdr100: minor number: %d\n", minorno); /* * create devno for this device */ cfg.devno = makedev(majorno, minorno); /* * make special files */ DEBUG_0("cfgcdr100: Calling make_special_files()\n"); rc = make_special_files(logical_name, cfg.devno); if (rc) { /* error making special files */ DEBUG_1("cfgcdr100: error making special file(s), rc=%d\n", rc); err_undo(preobj.DvDr); if (rc < 0 || rc > 255) rc = E_MKSPECIAL; err_exit(rc); } DEBUG_0("cfgcdr100: Returned from make_special_files()\n"); /* * build the DDS */ DEBUG_0("cfgcdr100: Calling build_dds()\n"); rc = build_dds(logical_name, &cfg.ddsptr, &cfg.ddslen); if (rc) { /* error building dds */ DEBUG_1("cfgcdr100: error building dds, rc=%d\n", rc); err_undo(preobj.DvDr); if (rc < 0 || rc > 255) rc = E_DDS; err_exit(rc); } DEBUG_0("cfgcdr100: Returned from build_dds()\n"); /* * call sysconfig to pass DDS to driver */ DEBUG_0("cfgcdr100: Pass DDS to driver via sysconfig()\n"); cfg.cmd = CFG_INIT; if (sysconfig(SYS_CFGDD, &cfg, sizeof(struct cfg_dd)) == -1) { /* * error configuring device */ DEBUG_0("cfgcdr100: error configuring device\n"); err_undo(preobj.DvDr); err_exit(E_CFGINIT); } /* * update customized device object with a change operation */ cusobj.status = AVAILABLE; if (odm_change_obj(cusdev, &cusobj) == -1) { /* ODM failure */ DEBUG_0("cfgcdr100: ODM failure updating CuDv object\n"); err_exit(E_ODMUPDATE); } } /* end if (device is not AVAILABLE) */ /* * close customized device object class */ if (odm_close_class(cusdev) == -1) { DEBUG_0("cfgcdr100: error closing CuDv 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. * * NOTES: * * 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); /* * Terminate the ODM */ odm_terminate(); exit(exitcode); } /*- * NAME: err_undo * * FUNCTION: Unloads the device's device driver. Used to back out on an * error. * * err_undo( DvDr ) * DvDr = pointer to device driver name. * * RETURNS: * None -*/ err_undo(DvDr) char *DvDr; /* pointer to device driver name */ { /* * unload driver */ if (loadext(DvDr, FALSE, FALSE) == NULL) { DEBUG_0("cfgcdr100: error unloading driver\n"); } return; } /*- * NAME: err_undo2 * * FUNCTION: Terminates the device. Used to back out on an error. * * * err_undo2( devno ) * devno = The device's devno. * * RETURNS: * None -*/ err_undo2(devno) dev_t devno; /* The device's devno */ { struct cfg_dd cfg; /* sysconfig command structure */ /* * terminate device */ cfg.devno = devno; cfg.kmid = (mid_t) 0; cfg.ddsptr = (caddr_t) NULL; cfg.ddslen = (int) 0; cfg.cmd = CFG_TERM; if (sysconfig(SYS_CFGDD, &cfg, sizeof(struct cfg_dd)) == -1) { DEBUG_0("cfgdevice: error unconfiguring device\n"); } return; } /*- * NAME: build_dds * * FUNCTION: Builds the DDS (Defined Data Structure) for the * Realtime Interface Co-Processor Portmaster adapter * * RETURNS: 0 - success * >0 - failure * -*/ int build_dds(lognam, addr, len) char *lognam; /* logical name of device */ uchar **addr; /* receiving pointer for DDS address */ int *len; /* receiving variable for DDS length */ { int rc; /* return code */ int scsi_id; /* work variable */ char sstring[512];/* working string */ struct CuDv cudvport; /* object class record */ struct CuDv cudvadap; /* object class record */ struct CuDvDr cudvdradap; /* object class record */ int majorno; /* major number assigned to adapter */ int minorno; /* minor number assigned to adapter */ struct cdr100_dds *dds; /* pointer to DDS structure */ dds = (struct cdr100_dds *) malloc(sizeof(struct cdr100_dds)); if (dds == NULL) return (E_MALLOC); /* report allocation error */ /* * Driver requires dds be cleared: */ memset(dds, 0, sizeof(struct cdr100_dds)); sprintf(sstring, "name = '%s'", lognam); if ((rc = (int) odm_get_obj(CuDv_CLASS, sstring, &cudvport, ODM_FIRST)) == 0) return (E_NOCuDv); else if (rc == -1) return (E_ODMGET); /* * fill in resource name fields */ strcpy(dds->dev_name, lognam); /* * scan field to extract port number */ if (sscanf(cudvport.connwhere, "%1d", &scsi_id) != 1) return (E_INVCONNECT); dds->scsi_id = scsi_id; dds->lun_id = 0; DEBUG_1("SCSI ID IS %d\n", dds->scsi_id); /* * read the parent adapter object */ sprintf(sstring, "name = '%s'", cudvport.parent); if ((rc = (int) odm_get_obj(CuDv_CLASS, sstring, &cudvadap, ODM_FIRST)) == 0) return (E_NOCuDv); else if (rc == -1) return (E_ODMGET); /* * read the parent device driver object */ sprintf(sstring, "resource = 'devno' AND value3 = '%s'", cudvport.parent); if ((rc = (int) odm_get_obj(CuDvDr_CLASS, sstring, &cudvdradap, ODM_FIRST)) == 0) return (E_NOCuDv); else if (rc == -1) return (E_ODMGET); /* * scan fields to extract device number */ if (sscanf(cudvdradap.value1, "%d", &majorno) != 1) return (E_MAJORNO); if (sscanf(cudvdradap.value2, "%d", &minorno) != 1) return (E_MINORNO); dds->adapter_devno = makedev(majorno, minorno); DEBUG_3("DEVNO IS %08x (%d,%d)\n", dds->adapter_devno, majorno, minorno); *addr = (caddr_t) (dds); /* output the DDS address and length */ *len = sizeof(struct cdr100_dds); return (E_OK); } /*- * NAME: generate_minor * * FUNCTION: Routine for generating the device minor number * * RETURNS: * minor number success * E_MINORNO on failure -*/ int generate_minor(lname, majno, minorno) char *lname; /* logical device name */ long majno; /* device major number */ long *minorno; /* device minor number */ { long *minorptr; /* * use genminor() to create and reserve the minor numbers used by this * device. */ minorptr = genminor(lname, majno, -1, 1, 1, 1); if (minorptr == (long *) NULL) /* * error generating minor number */ return (E_MINORNO); *minorno = *minorptr; return (E_OK); } /*- * NAME: make_special_file * * FUNCTION: Creates, or alters a special file as required * * * NOTES: * make_special_file(suffix,devno) * * suffix = suffix part of the special file name. For most cases * this will be the device logical name. For devices with * more than one special file, this routine will be called * one time for each special file needed, passing the file * name required for the special file. * * If the special file already exists, then the major/minor numbers * are checked. If they are incorrect, the old file is deleted, and * a new one created. If the numbers were correct, no action is * taken, and 0 is returned. * * RETURNS: 0 For success, errno for failure. -*/ int make_special_files(suffix, devno) char *suffix; /* suffix for special file name */ dev_t devno; /* major and minor numbers */ { long cflags; /* create flag / mode & type */ struct stat buf; char spfilename[128]; if (devno < 0 || *suffix == '\0') return (E_MKSPECIAL); /* error in parameters */ cflags = S_IFBLK | S_IRUSR | S_IRGRP | S_IROTH; sprintf(spfilename, "/dev/%s", suffix); /* file name =/dev/[suffix] */ if (stat(spfilename, &buf)) { /* stat failed */ if (errno != ENOENT) { /* error if file exists */ DEBUG_0("stat failed\n"); return (E_MKSPECIAL); } } else { /* stat succeeded */ if (buf.st_rdev == devno) /* major/minor #s are same, */ return (0); /* leave special file alone */ if (unlink(spfilename)) { /* unlink special file name */ DEBUG_0("unlink failed\n"); return (E_MKSPECIAL); } } if (mknod(spfilename, cflags, devno)) { DEBUG_0("mknod failed\n"); return (E_MKSPECIAL); } cflags = S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH; sprintf(spfilename, "/dev/r%s", suffix); /* file name =/dev/r[suffix] */ if (stat(spfilename, &buf)) { /* stat failed */ if (errno != ENOENT) { /* error if file exists */ DEBUG_0("stat failed\n"); return (E_MKSPECIAL); } } else { /* stat succeeded */ if (buf.st_rdev == devno) /* major/minor #s are same, */ return (0); /* leave special file alone */ if (unlink(spfilename)) { /* unlink special file name */ DEBUG_0("unlink failed\n"); return (E_MKSPECIAL); } } if (mknod(spfilename, cflags, devno)) { DEBUG_0("mknod failed\n"); return (E_MKSPECIAL); } return (0); }