|
|
1.1 root 1: #define _DDI_DKI 1
2: #define _SYSV4 1
3:
4: /*
5: * This file assigns device major and minor numbers based on configuration
6: * data read in by "devadm.c".
7: */
8: /*
9: *-IMPORTS:
10: * <sys/compat.h>
11: * CONST
12: * PROTO
13: * ARGS ()
14: * LOCAL
15: * <kernel/v_types.h>
16: * NODEV
17: * major_t
18: * minor_t
19: * <stddef.h>
20: * size_t
21: * offsetof ()
22: * <stdlib.h>
23: * NULL
24: * free ()
25: * malloc ()
26: * "ehand.h"
27: * throw_error ()
28: * "mdev.h"
29: * mdev_t
30: * mdev_sort ()
31: */
32:
33: #include <sys/compat.h>
34: #include <kernel/v_types.h>
35: #include <stddef.h>
36: #include <stdlib.h>
37:
38: #include "ehand.h"
39: #include "mdev.h"
40:
41: #include "assign.h"
42:
43: /*
44: * Selection predicate for choosing enabled character devices.
45: */
46:
47: #if USE_PROTO
48: LOCAL int chr_sel (mdev_t * mdevp)
49: #else
50: LOCAL int
51: chr_sel (mdevp)
52: mdev_t * mdevp;
53: #endif
54: {
55: return mdevp->md_configure == MD_ENABLED &&
56: mdev_flag (mdevp, MDEV_CHAR);
57: }
58:
59:
60: /*
61: * Predicate for comparing two mdevice entries on the basis of minimum
62: * external character-device number.
63: */
64:
65: #if USE_PROTO
66: LOCAL int chr_pred (mdev_t * left, mdev_t * right)
67: #else
68: LOCAL int
69: chr_pred (left, right)
70: mdev_t * left;
71: mdev_t * right;
72: #endif
73: {
74: return left->md_chr_maj [0] < right->md_chr_maj [0];
75: }
76:
77:
78: /*
79: * Selection predicate for choosing enabled block devices.
80: */
81:
82: #if USE_PROTO
83: LOCAL int blk_sel (mdev_t * mdevp)
84: #else
85: LOCAL int
86: blk_sel (mdevp)
87: mdev_t * mdevp;
88: #endif
89: {
90: return mdevp->md_configure == MD_ENABLED &&
91: mdev_flag (mdevp, MDEV_BLOCK);
92: }
93:
94:
95: /*
96: * Predicate for comparing two mdevice entries on the basis of minimum
97: * external block-device number.
98: */
99:
100: #if USE_PROTO
101: LOCAL int blk_pred (mdev_t * left, mdev_t * right)
102: #else
103: LOCAL int
104: blk_pred (left, right)
105: mdev_t * left;
106: mdev_t * right;
107: #endif
108: {
109: return left->md_blk_maj [0] < right->md_blk_maj [0];
110: }
111:
112:
113: /*
114: * Predicate for selecting modules (streams drivers that are not devices).
115: */
116:
117: #if USE_PROTO
118: LOCAL int mod_sel (mdev_t * mdevp)
119: #else
120: LOCAL int
121: mod_sel (mdevp)
122: mdev_t * mdevp;
123: #endif
124: {
125: return mdevp->md_configure == MD_ENABLED &&
126: mdev_flag (mdevp, MDEV_STREAM) &&
127: ! mdev_flag (mdevp, MDEV_CHAR);
128: }
129:
130:
131: /*
132: * Predicate for selecting Coherent drivers.
133: */
134:
135: #if USE_PROTO
136: LOCAL int coh_sel (mdev_t * mdevp)
137: #else
138: LOCAL int
139: coh_sel (mdevp)
140: mdev_t * mdevp;
141: #endif
142: {
143: return mdevp->md_configure == MD_ENABLED &&
144: mdev_flag (mdevp, MDEV_COHERENT);
145: }
146:
147:
148: /*
149: * Predicate for comparing two Coherent devices on the basis of major number.
150: */
151:
152: #if USE_PROTO
153: LOCAL int coh_pred (mdev_t * left, mdev_t * right)
154: #else
155: LOCAL int
156: coh_pred (left, right)
157: mdev_t * left;
158: mdev_t * right;
159: #endif
160: {
161: return left->md_blk_maj [0] < right->md_blk_maj [0];
162: }
163:
164:
165: /*
166: * This is where we build the external->internal major number mapping table.
167: *
168: * The external->internal device number system becomes immediately useful
169: * under STREAMS, where a) STREAMS cannot use device major numbers lower than
170: * MAJOR_RESERVED under Coherent, and b) Coherent uses old-style 16-bit
171: * dev_t's, so that the ability to transform a range of external majors into
172: * a contiguous sequence of internal minor numbers will be of immediate value
173: * in supporting connection-oriented services (although this is also pending
174: * on the addition of support for cloning to the kernel).
175: *
176: * Mapping between internal and external numbers is not simple; what makes it
177: * worse is that because there is a single mapping that has to be the same
178: * for both block and character tables, the construction of the bdevsw [] and
179: * cdevsw [] internal tables is constrained. This is only a problem if
180: * multiple external major numbers are allowed, and each device is only
181: * permitted to have a single internal major number. The interpretation of the
182: * 'M' flag in this circumstance is unclear.
183: *
184: * The assign_imajors () code should be able to deal with the most complex
185: * case, which is where multiple external majors may actually be mapped to
186: * multiple internal numbers, thus
187: *
188: * Block external : |-----scsi-------|
189: * Character external: |--tcp--| |-udp-| |ttys|
190: *
191: * Might map 'tcp' to internal 0, 'udp' to internal 1, 'ttys' to internal 2,
192: * while 'scsi' would have 0, 1, and 2 as internal major numbers.
193: *
194: * This is all hypothetical at the moment, since multiple majors are new to
195: * Coherent anyway. For simplicity, we may constrain the above to be an error
196: * by requiring unique internal number for each device. However, the machinery
197: * in assign_imajors () will have to be flexible enough to deal with the
198: * above.
199: *
200: * NOTE: The complex model is only applicable if a device does not care what
201: * minor numbers are given to it, since there is a single shared table used
202: * to map a range of external major numbers into a range of internal minor
203: * numbers. Since this table is shared, it constrains even more heavily the
204: * circumstances in which numbers can overlap. Without a flag to detect when
205: * a driver doesn't care about minor numbers, we simply forget about the
206: * complex model.
207: */
208:
209: /*
210: * Definitions used to control parts of the way assign_imajors () deals with
211: * the external->internal mapping (as discussed above). The main things we
212: * isolate here are the calculations of the upper bounds for table allocations
213: * since the constraint of a common mapping means that the cdevsw [] and
214: * bdevsw [] tables may be larger than a separate mapping would permit.
215: *
216: * In particular, if ncdevs is the number of character devices and nbdevs is
217: * the number of block devices, the upper bound on table size is:
218: * Simple model: block = char = max (ncdevs, nbdevs)
219: * Complex model: char = ncdevs + max (nbdevs - 1, 0)
220: * block = nbdevs + max (ncdevs - 1, 0)
221: */
222:
223: #define MAX(a,b) ((a) > (b) ? (a) : (b))
224: #define MIN(a,b) ((a) < (b) ? (a) : (b))
225:
226: #define MAX_CHR_IMAJORS(c,b) MAX (c, b)
227: #define MAX_BLK_IMAJORS(c,b) MAX (c, b)
228:
229:
230: /*
231: * Assign internal major numbers to devices. For now, this function does not
232: * attempt to deal with assigning major number ranges.
233: */
234:
235: #if USE_PROTO
236: extinfo_t * (assign_imajors) (void)
237: #else
238: extinfo_t *
239: assign_imajors ARGS (())
240: #endif
241: {
242: extinfo_t * extinfop;
243: mdev_t * blk_list;
244: mdev_t * blk_end;
245: mdev_t * chr_list;
246: mdev_t * chr_end;
247: mdev_t * mod_list;
248: mdev_t * coh_list;
249: int n_blk_list;
250: int n_chr_list;
251: int n_mod_list;
252: int n_coh_list;
253:
254: int nemajors;
255: int i;
256:
257:
258: /*
259: * The algorithm for assigning internal numbers for the block and
260: * character-device tables will be able to run in a single pass if we
261: * are able to provide lists of character and block devices sorted by
262: * beginning external major number. This sort process also provides us
263: * a variety of other useful information directly, such as the maximum
264: * external number used.
265: */
266:
267: n_chr_list = mdev_sort (& chr_list, & chr_end, chr_sel, chr_pred,
268: offsetof (mdev_t, md_chrlink));
269: n_blk_list = mdev_sort (& blk_list, & blk_end, blk_sel, blk_pred,
270: offsetof (mdev_t, md_blklink));
271: n_mod_list = mdev_sort (& mod_list, NULL, mod_sel, NULL,
272: offsetof (mdev_t, md_modlink));
273: n_coh_list = mdev_sort (& coh_list, NULL, coh_sel, coh_pred,
274: offsetof (mdev_t, md_cohlink));
275:
276: nemajors = 0;
277:
278: if (chr_end != NULL)
279: nemajors = MAX (nemajors, chr_end->md_chr_maj [1]);
280:
281: if (blk_end != NULL)
282: nemajors = MAX (nemajors, blk_end->md_blk_maj [1]);
283:
284: nemajors ++;
285:
286:
287: /*
288: * Now we know how many of everything there is, allocate space for
289: * tables.
290: */
291:
292: i = sizeof (* extinfop) +
293: sizeof (mdev_t *) * (MAX_CHR_IMAJORS (n_chr_list, n_blk_list) +
294: MAX_BLK_IMAJORS (n_chr_list, n_blk_list) +
295: n_mod_list + n_coh_list) +
296: 2 * sizeof (minor_t) * nemajors;
297:
298: if ((extinfop = (extinfo_t *) malloc (i)) == NULL)
299: throw_error ("insufficient memory in assign_imajors ()");
300:
301: extinfop->ei_etoimajor = (minor_t *) (extinfop + 1);
302: extinfop->ei_minoroffset = extinfop->ei_etoimajor + nemajors;
303: extinfop->ei_modules = (mdev_t **) (extinfop->ei_minoroffset +
304: nemajors);
305: extinfop->ei_cohdrivers = extinfop->ei_modules + n_mod_list;
306: extinfop->ei_cdevsw = extinfop->ei_cohdrivers + n_coh_list;
307: extinfop->ei_bdevsw = extinfop->ei_cdevsw +
308: MAX_CHR_IMAJORS (n_chr_list, n_blk_list);
309:
310: /*
311: * Since we allocate space for the maximum number of table entries,
312: * the loops below assign internal numbers which may not be
313: * contiguous, or may be below the upper limit allocated.
314: */
315:
316: extinfop->ei_nemajors = nemajors;
317: extinfop->ei_ncdevs = 0;
318: extinfop->ei_nbdevs = 0;
319: extinfop->ei_nmodules = n_mod_list;
320: extinfop->ei_ncohdrivers = n_coh_list;
321:
322: for (i = 0 ; i < nemajors ; i ++) {
323:
324: extinfop->ei_etoimajor [i] = NODEV;
325: extinfop->ei_minoroffset [i] = 0;
326: }
327:
328:
329: for (i = 0 ; i < MAX_CHR_IMAJORS (n_chr_list, n_blk_list) ; i ++)
330: extinfop->ei_cdevsw [i] = NULL;
331:
332: for (i = 0 ; i < MAX_BLK_IMAJORS (n_chr_list, n_blk_list) ; i ++)
333: extinfop->ei_bdevsw [i] = NULL;
334:
335:
336: while (chr_list != NULL || blk_list != NULL) {
337: mdev_t * chrp;
338: mdev_t * blkp;
339: int extlo;
340: int exthi;
341: int internal;
342: int minorinc;
343: int minorofs;
344:
345: /*
346: * Choose a range of external numbers that we are going to
347: * assign to a single internal number. If our choice is not
348: * constrained by an overlap between character and block
349: * external numbers, then we deal with that.
350: */
351:
352: blkp = blk_list;
353:
354: if ((chrp = chr_list) != NULL) {
355:
356: extlo = chrp->md_chr_maj [0];
357: exthi = chrp->md_chr_maj [1];
358: minorinc = chrp->md_minor_max;
359:
360: if (blkp != NULL) {
361:
362: if (blkp->md_blk_maj [1] < extlo) {
363:
364: chrp = NULL;
365: goto doblock;
366: }
367:
368: if (blkp->md_blk_maj [0] > exthi) {
369: blkp = NULL;
370: goto dochar;
371: }
372:
373: /*
374: * Because of minor-number mapping, overlap is
375: * only valid in special circumstances.
376: */
377:
378: if (blkp->md_blk_maj [0] != extlo ||
379: (blkp->md_minor_max != minorinc &&
380: blkp->md_blk_maj [1] >
381: blkp->md_blk_maj [0] &&
382: exthi > extlo)) {
383:
384: free (extinfop);
385: throw_error ("minor number mapping conflict");
386: }
387:
388:
389: /*
390: * Choose a suitable internal major number.
391: */
392:
393: if (exthi < blkp->md_blk_maj [1]) {
394:
395: exthi = blkp->md_blk_maj [1];
396: minorinc = blkp->md_minor_max;
397: }
398:
399: internal = MAX (extinfop->ei_ncdevs,
400: extinfop->ei_nbdevs);
401:
402: goto done;
403: }
404: dochar:
405: /*
406: * Simple case, select an internal number.
407: */
408:
409: for (internal = 0 ;
410: extinfop->ei_cdevsw [internal] != NULL ;
411: internal ++)
412: ;
413:
414: if (internal > extinfop->ei_ncdevs) {
415:
416: free (extinfop);
417: throw_error ("internal check failed, assign_imajors ()");
418: }
419: } else {
420: /*
421: * Simple case for block device, select an internal
422: * number.
423: */
424:
425: doblock:
426: extlo = blkp->md_blk_maj [0];
427: exthi = blkp->md_blk_maj [1];
428: minorinc = blkp->md_minor_max;
429:
430: for (internal = 0 ;
431: extinfop->ei_bdevsw [internal] != NULL ;
432: internal ++)
433: ;
434:
435: if (internal > extinfop->ei_nbdevs) {
436:
437: free (extinfop);
438: throw_error ("internal check failed, assign_imajors ()");
439: }
440: }
441: done:
442: /*
443: * Now we have decided when, where, and how much, fill in the
444: * table.
445: */
446:
447: minorofs = 0;
448:
449: while (extlo <= exthi) {
450:
451: if (extinfop->ei_etoimajor [extlo] != NODEV) {
452:
453: free (extinfop);
454: throw_error ("major-number mapping conflict");
455: }
456:
457: extinfop->ei_etoimajor [extlo] = internal;
458: extinfop->ei_minoroffset [extlo] = minorofs;
459:
460: minorofs += minorinc;
461: extlo ++;
462: }
463:
464: if ((extinfop->ei_cdevsw [internal] = chrp) != NULL) {
465:
466: if (internal >= extinfop->ei_ncdevs)
467: extinfop->ei_ncdevs = internal + 1;
468:
469: chr_list = chrp->md_chrlink;
470: }
471:
472:
473: if ((extinfop->ei_bdevsw [internal] = blkp) != NULL) {
474:
475: if (internal >= extinfop->ei_nbdevs)
476: extinfop->ei_nbdevs = internal + 1;
477:
478: blk_list = blkp->md_blklink;
479: }
480: }
481:
482:
483: /*
484: * Now we can build a table of all the STREAMS modules.
485: */
486:
487: i = 0;
488:
489: while (mod_list != NULL) {
490:
491: extinfop->ei_modules [i ++] = mod_list;
492: mod_list = mod_list->md_modlink;
493: }
494:
495:
496: /*
497: * Now we can build a table of all the Coherent drivers.
498: */
499:
500: i = 0;
501:
502: while (coh_list != NULL) {
503:
504: extinfop->ei_cohdrivers [i ++] = coh_list;
505: coh_list = coh_list->md_cohlink;
506: }
507:
508: return extinfop;
509: }
510:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.