Imported Upstream version 2.5.0
[debian/amanda] / contrib / gsc / cfggsc.c
1 /*
2  * $Id: cfggsc.c,v 1.1 2001/04/15 11:12:37 ant Exp $
3  * Copyright (c) 1997 by Matthew Jacob
4  *
5  *      This software is free software; you can redistribute it and/or
6  *      modify it under the terms of the GNU Library General Public
7  *      License as published by the Free Software Foundation; version 2.
8  *
9  *      This software is distributed in the hope that it will be useful,
10  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *      Library General Public License for more details.
13  *
14  *      You should have received a copy of the GNU Library General Public
15  *      License along with this software; if not, write to the Free
16  *      Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  *      The author may be reached via electronic communications at
19  *
20  *              mjacob@feral.com
21  *
22  *      or, via United States Postal Address
23  *
24  *              Matthew Jacob
25  *              1831 Castro Street
26  *              San Francisco, CA, 94131
27  */
28
29
30 #include <stdio.h>
31 #include <sys/scsi.h>
32 #include <sys/types.h>
33 #include <sys/errno.h>
34 #include <sys/ioctl.h>
35 #include <sys/devinfo.h>
36 #include <sys/device.h>
37 #include <sys/cfgodm.h>
38 #include <cf.h>
39 #include <sys/cfgdb.h>
40 #include <fcntl.h>
41 #include <sys/sysconfig.h>
42 #include <sys/errno.h>
43 #include <sys/device.h>
44 #include <sys/mode.h>
45
46 #include "gscdds.h"
47
48 extern mid_t loadext(char *, int, int);
49
50 static int verbose;
51 static struct gsc_ddsinfo ddsinfo;
52
53 int main(int a, char **v);
54 static void check_add_sockets(dev_t, int, char *, char *);
55 static int has_driver_get_vpd(char *, int, char *);
56
57 #define MKNOD_MODE S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
58
59 #define vprintf if (verbose) printf
60
61
62 static void
63 err_exit(char exitcode)
64 {
65     odm_close_class(CuDv_CLASS);
66     odm_close_class(PdDv_CLASS);
67     odm_terminate();
68     exit(exitcode);
69 }
70
71 int
72 main(int a, char **v)
73 {
74     extern char *optarg;
75     char sstring[256], bufname[256], conns[NAMESIZE], *ptr, *lname;
76     struct Class *cprp, *cusdev, *predev;
77     struct CuDvDr dpr, *dprp;
78     struct CuDv parobj, cusobj, hdobj, *xprp;
79     struct PdDv preobj;
80     struct CuAt *attrobj;
81     int rc, c, errflg, ipl_phase, unit, munit, howmany, lun, domake;
82     dev_t ctl;
83     long major;
84     int *mlist;
85     mid_t kmid;
86     struct cfg_dd dd;
87
88     lname = NULL;
89     errflg = 0;
90     ipl_phase = RUNTIME_CFG;
91     (void) memset((void *) &ddsinfo, 0, sizeof ddsinfo);
92
93     while ((c = getopt(a, v, "l:12v")) != EOF) {
94         switch (c) {
95         case 'l':
96             if (lname != NULL)
97                 errflg++;
98             lname = optarg;
99             break;
100         case 'v':
101             verbose++;
102             break;
103         case '1':
104             if (ipl_phase != RUNTIME_CFG)
105                 errflg++;
106             ipl_phase = PHASE1;
107             break;
108         case '2':
109             if (ipl_phase != RUNTIME_CFG)
110                 errflg++;
111             ipl_phase = PHASE2;
112             break;
113         default:
114             errflg++;
115         }
116     }
117     if (errflg)
118         exit (E_ARGS);
119     if (lname == NULL)
120         exit(E_LNAME);
121
122     if (odm_initialize() == -1) {
123         return (E_ODMINIT);
124     }
125
126     /* lock the database */
127     if (odm_lock("/etc/objrepos/config_lock",0) == -1)
128         err_exit(E_ODMLOCK);
129
130     /* open customized devices object class */
131     if ((int)(cusdev = odm_open_class(CuDv_CLASS)) == -1)
132         err_exit(E_ODMOPEN);
133
134     /* search for customized object with this logical name */
135     sprintf(sstring, "name = '%s'", lname);
136     rc = (int) odm_get_first(cusdev, sstring, &cusobj);
137     if (rc == 0) {
138         /* No CuDv object with this name */
139         err_exit(E_NOCuDv);
140     } else if (rc == -1) {
141         /* ODM failure */
142         err_exit(E_ODMGET);
143     }
144
145     /* open predefined devices object class */
146     if ((int)(predev = odm_open_class(PdDv_CLASS)) == -1)
147         err_exit(E_ODMOPEN);
148
149     /* get predefined device object for this logical name */
150     sprintf(sstring, "uniquetype = '%s'", cusobj.PdDvLn_Lvalue);
151     rc = (int)odm_get_first(predev, sstring, &preobj);
152     if (rc == 0) {
153         /* No PdDv object for this device */
154         err_exit(E_NOPdDv);
155     } else if (rc == -1) {
156         /* ODM failure */
157         err_exit(E_ODMGET);
158     }
159     /* close predefined device object class */
160     if (odm_close_class(predev) == -1)
161         err_exit(E_ODMCLOSE);
162
163     if (ipl_phase != RUNTIME_CFG)
164         setleds(preobj.led);
165
166     /*
167      * Now, if the device is already configured, we're
168      * pretty much done.
169      */
170     if (cusobj.status == AVAILABLE) {
171         /* close customized device object class */
172         if (odm_close_class(cusdev) == -1)
173                 err_exit(E_ODMCLOSE);
174         odm_terminate();
175         return(E_OK);
176     }
177     if (cusobj.status != DEFINED) {
178         vprintf("bad state: %d\n", cusobj.status);
179         err_exit(E_DEVSTATE);
180     }
181
182     /* get the device's parent object */
183     sprintf(sstring, "name = '%s'", cusobj.parent);
184     rc = (int) odm_get_first(cusdev, sstring, &parobj);
185     if (rc == 0) {
186         /* Parent device not in CuDv */
187         err_exit(E_NOCuDvPARENT);
188     } else if (rc == -1) {
189         /* ODM failure */
190         err_exit(E_ODMGET);
191     }
192
193     /* Parent MUST be available to continue */
194     if (parobj.status != AVAILABLE)
195         err_exit(E_PARENTSTATE);
196
197
198     /* make sure that no other devices are configured     */
199     /* at this location                                   */
200     sprintf(sstring, "parent = '%s' AND location='%s' AND status=%d",
201             cusobj.parent, cusobj.location, AVAILABLE);
202     rc = (int) odm_get_first(cusdev, sstring, &cusobj);
203     if (rc == -1) {
204         /* odm failure */
205         err_exit(E_ODMGET);
206     } else if (rc) {
207         /* Error: device config'd at this location */
208         err_exit(E_AVAILCONNECT);
209     }
210
211     memcpy(conns, cusobj.location, NAMESIZE);
212     vprintf("now fool with luns: location is %s\n", conns);
213     ptr = conns;
214     while (*ptr && ptr < &conns[NAMESIZE])
215         ptr++;
216     ptr--;
217     if (ptr < &conns[1]) {
218         err_exit(E_BADATTR);
219     }
220     lun = *ptr - '0';
221     vprintf("I see lun %d\n", lun);
222     if (lun < 0 || lun >= 8)
223         err_exit(E_INVCONNECT);
224     ddsinfo.lun = lun;
225     /*
226      * Generate Target
227      */
228     if (ptr[-1] == ',') {
229         *(--ptr) = 0;
230     } else {
231         *ptr = 0;
232     }
233     while (ptr > conns && *ptr != '-')
234         ptr--;
235     if (*ptr == '-')
236         ptr++;
237     ddsinfo.target = strtol(ptr, (char **) NULL, 0);
238     vprintf("I see tgt %d ptr = %d\n", ddsinfo.target, ptr - conns);
239
240     /*
241      * Generate dev_t for adapter
242      */
243     cprp = odm_open_class(CuDvDr_CLASS) ;
244     sprintf(sstring, "value3 = %s", cusobj.parent);
245     rc = (int) odm_get_obj(cprp, sstring, &dpr, TRUE);
246     if (rc == 0) {
247         err_exit(E_NOCuDvPARENT);
248     } else if (rc == -1) {
249         err_exit(E_ODMGET);
250     }
251     ddsinfo.busid = (dev_t) makedev(atoi(dpr.value1), atoi(dpr.value2));
252     vprintf("I see %d.%d for connecting adapter\n",
253         major(ddsinfo.busid), minor(ddsinfo.busid));
254
255     /*
256      * Get unit number out of logical name
257      */
258
259     ptr = lname;
260     ptr += strlen(preobj.prefix);
261     unit = atoi(ptr);
262     vprintf("I see %d as unit\n", unit);
263
264     /*
265      * Okay, now that we have the pertinent information that we'll
266      * need (adapter dev_t, device type, target, lbits, shareable,
267      * unit number), we can look into actually loading/configuring the
268      * current driver.
269      */
270     (void) sprintf(bufname, "/dev/%s", lname);
271
272     /*
273      * Get or generate major number..
274      */
275     if ((major = (long) genmajor(preobj.DvDr)) == -1) {
276         odm_terminate();
277         return (E_MAJORNO);
278     }
279     vprintf("major is %d\n", major);
280
281     /*
282      * Let's see if this is the first time through. If it's
283      * the first time through, getminor will return NULL
284      * or won't have any minors in the list.
285      */
286     mlist = getminor(major, &howmany, preobj.DvDr);
287     vprintf("getminor: %x and howmany %d for %s\n", mlist, howmany,
288                 preobj.DvDr);
289
290     domake = 1;
291     if (mlist != NULL && howmany != 0) {
292         /*
293          * We have a list of minors already.
294          * See if we already have the minor
295          * we want defined.
296          */
297         for (c = 0; c < howmany; c++) {
298             if (mlist[c] == unit) {
299                 vprintf("unit %d already has minor\n", unit);
300                 domake = 0;
301                 break;
302             }
303         }
304     }
305
306     if (domake) {
307         (void) unlink(bufname);
308         /*
309          * Now create the minor number that will match the unit number.
310          * We really don't care whether genminor succeeds, since
311          * we've alreay unlinked the device node.
312          */
313         mlist = genminor(preobj.DvDr, major, unit, 1, 1, 1);
314         if (mlist == (long *) NULL) {
315             err_exit(E_MINORNO);
316         }
317         vprintf("making %s as %d.%d with minor returned as %d\n",
318                 bufname, major, unit, *mlist);
319         if (mknod(bufname, MKNOD_MODE, makedev(major, unit))) {
320             err_exit(E_MKSPECIAL);
321         }
322     } else {
323         (void) mknod(bufname, MKNOD_MODE, makedev(major, unit));
324     }
325
326     /*
327      * Load the driver....
328      */
329     kmid = loadext(preobj.DvDr, TRUE, FALSE);
330     if (!kmid) {
331         err_exit(E_LOADEXT);
332     }
333
334     /*
335      * And configure the driver...
336      */
337     dd.kmid = kmid;
338     dd.devno = makedev(major, unit);
339     dd.cmd = CFG_INIT;
340     dd.ddsptr = (caddr_t) &ddsinfo;
341     dd.ddslen = sizeof (ddsinfo);
342
343     if (sysconfig(SYS_CFGDD, &dd, sizeof (dd)) == CONF_FAIL) {
344         int saverr = errno;
345         /*
346          * Unload driver...
347          */
348         (void) loadext(preobj.DvDr, FALSE, FALSE);
349         switch(saverr) {
350         case ENODEV:
351                 err_exit(E_WRONGDEVICE);
352                 /* NOTREACHED */
353                 break;
354         case EBUSY:
355                 err_exit(E_AVAILCONNECT);
356                 /* NOTREACHED */
357                 break;
358         case EINVAL:
359         default:
360                 err_exit(E_CFGINIT);
361                 /* NOTREACHED */
362                 break;
363         }
364     }
365
366     /* now mark the device as available */
367     cusobj.status = AVAILABLE;
368     if (odm_change_obj(CuDv_CLASS, &cusobj) == -1) {
369         /*
370          * Unconfigure driver (for this instance)...
371          */
372         dd.kmid = 0;
373         dd.ddsptr = (caddr_t) NULL;
374         dd.ddslen = (int ) 0;
375         dd.cmd = CFG_TERM;
376         (void) sysconfig(SYS_CFGDD, &dd, sizeof (dd));
377         /*
378          * Unload driver...
379          */
380         (void) loadext(preobj.DvDr, FALSE, FALSE);
381         err_exit (E_ODMUPDATE);
382     }
383
384
385     (void) odm_terminate();
386     return (E_OK);
387 }
388
389 /*
390  * Overrides for Emacs so that we follow Linus's tabbing style.
391  * Emacs will notice this stuff at the end of the file and automatically
392  * adjust the settings for this buffer only.  This must remain at the end
393  * of the file.
394  * ---------------------------------------------------------------------------
395  * Local variables:
396  * c-indent-level: 4
397  * c-brace-imaginary-offset: 0
398  * c-brace-offset: -4
399  * c-argdecl-indent: 4
400  * c-label-offset: -4
401  * c-continued-statement-offset: 4
402  * c-continued-brace-offset: 0
403  * End:
404  */