1 /* @(#)maptodisk.c	1.33 21/07/22 Copyright 1991-2021 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)maptodisk.c	1.33 21/07/22 Copyright 1991-2021 J. Schilling";
6 #endif
7 /*
8  *	Routines to map SCSI targets to logical disk names
9  *
10  *	Copyright (c) 1991-2021 J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 /*
27  *	Wenn unterschiedliche SCSI Kontroller zugelassen werden sollen,
28  *	dann mu� im scg Treiber der DKIOGCONF ioctl eingebaut sein.
29  *
30  *	XXX #ifdef HAVE_DKIO ist vorerst nur ein Hack
31  *
32  */
33 #include <schily/stdio.h>
34 #include <schily/unistd.h>
35 #include <schily/standard.h>
36 #include <schily/string.h>
37 #include <schily/fcntl.h>
38 #include <schily/errno.h>
39 #include <schily/stat.h>
40 #include <schily/ioctl.h>
41 #include "dsklabel.h"
42 #include <schily/dirent.h>
43 #include <schily/utypes.h>
44 #include <schily/schily.h>
45 #include <schily/libport.h>
46 #include <schily/ctype.h>
47 #ifndef	SVR4
48 #ifdef	sun
49 #include <sun3/cpu.h>	/* Tempor�r f�r alte Maschinen */
50 #endif
51 #endif
52 #include "fmt.h"
53 #include "map.h"
54 
55 #define	TARGET(slave)	((slave >> 3) & 07)
56 #define	LUN(slave)	(slave & 07)
57 
58 #define	MAX_SCG	8
59 
60 typedef struct scsi_devices {
61 	char	lun[8];
62 }scdev;
63 
64 #define	NDISKNAMES	64
65 
66 LOCAL	scdev	diskmap[8][8];
67 LOCAL	char	*disknames[NDISKNAMES];
68 LOCAL	char	*diskdevnames[NDISKNAMES];
69 LOCAL	scgdrv	scgmap[MAX_SCG];
70 #ifdef	HAVE_DKIO
71 LOCAL	int	scgmap_known = FALSE;
72 #endif
73 LOCAL	BOOL	diskmap_init = FALSE;
74 LOCAL	BOOL	scgmap_init = FALSE;
75 
76 LOCAL	void	init_diskmap	__PR((void));
77 LOCAL	void	diskmap_null	__PR((void));
78 LOCAL	void	scgmap_null	__PR((void));
79 #ifdef	HAVE_DKIO
80 LOCAL	BOOL	have_diskname	__PR((char *));
81 #endif
82 #ifdef	HAVE_DKIO
83 #ifdef	SVR4
84 LOCAL	BOOL	is_svr4_disk	__PR((char *));
85 #else
86 LOCAL	BOOL	is_4x_disk	__PR((char *));
87 #endif
88 #endif
89 #ifdef	HAVE_DKIO
90 #ifdef	SVR4
91 LOCAL	void	make_svr4_dname	__PR((char *, char *));
92 #else
93 LOCAL	void	make_dname	__PR((char *, char *));
94 #endif
95 #endif
96 #ifdef	HAVE_DKIO
97 LOCAL	BOOL	make_disknames	__PR((char *, char *, char *));
98 LOCAL	int	opendisk	__PR((char *));
99 #endif
100 LOCAL	void	map_alldisks	__PR((void));
101 #ifdef	HAVE_DKIO
102 LOCAL	BOOL	map_disk	__PR((int, int, char *, char *));
103 LOCAL	int	scg_mapbus	__PR((struct dk_conf *));
104 #endif	/* HAVE_DKIO */
105 LOCAL	void	map_scg		__PR((void));
106 
107 extern	int	nomap;
108 extern	int	debug;
109 
110 EXPORT int
maptodisk(scsibus,target,lun)111 maptodisk(scsibus, target, lun)
112 	int	scsibus;
113 	int	target;
114 	int	lun;
115 {
116 	if (nomap)
117 		return (-1);
118 
119 	if (!diskmap_init)
120 		init_diskmap();
121 
122 	if (scsibus < 0 || target < 0 || lun < 0 ||
123 				scsibus >= MAX_SCG || target >= 8 || lun >= 8)
124 		return (-1);
125 
126 	if (debug)
127 		printf("maptodisk(%d, %d, %d) = %d\n",
128 					scsibus, target, lun,
129 					diskmap[scsibus][target].lun[lun]);
130 	return (diskmap[scsibus][target].lun[lun]);
131 }
132 
133 EXPORT scgdrv	*
scg_getdrv(scsibus)134 scg_getdrv(scsibus)
135 	int	scsibus;
136 {
137 	return (&scgmap[scsibus]);
138 }
139 
140 EXPORT char *
diskname(diskno)141 diskname(diskno)
142 	int	diskno;
143 {
144 	return (disknames[diskno]);
145 }
146 
147 EXPORT char *
diskdevname(diskno)148 diskdevname(diskno)
149 	int	diskno;
150 {
151 	return (diskdevnames[diskno]);
152 }
153 
154 EXPORT int
print_disknames(scsibus,target,lun)155 print_disknames(scsibus, target, lun)
156 	int	scsibus;
157 	int	target;
158 	int	lun;
159 {
160 	int	printed = 0;
161 	int	dnum;
162 	int	i;
163 	int	ccnt	= 0;
164 
165 	if (nomap)
166 		return (0);
167 
168 	if (lun >= 0) {
169 		dnum = maptodisk(scsibus, target, lun);
170 		if (dnum >= 0)
171 			ccnt += printf("%s", disknames[dnum]);
172 		return (ccnt);
173 	}
174 	for (i = 0; i < 8; i++) {
175 		dnum = maptodisk(scsibus, target, i);
176 		if (dnum >= 0) {
177 			ccnt += printf("%s%s", printed?",":"", disknames[dnum]);
178 			printed++;
179 		}
180 	}
181 	return (ccnt);
182 }
183 
184 #ifdef	needed
185 /*
186  * No more needed. Now part of libscg.
187  */
188 EXPORT int
scg_initiator_id(scsibus)189 scg_initiator_id(scsibus)
190 	int	scsibus;
191 {
192 	short	id;
193 
194 	if (!scgmap_init)
195 		map_scg();
196 	if ((id = scgmap[scsibus].scg_slave) != -1)
197 		id = TARGET(id);
198 	return (id);
199 }
200 #endif
201 
202 LOCAL void
init_diskmap()203 init_diskmap()
204 {
205 	if (!scgmap_init)
206 		map_scg();
207 	map_alldisks();
208 }
209 
210 LOCAL void
diskmap_null()211 diskmap_null()
212 {
213 	register int	i;
214 	register int	j;
215 	register int	k;
216 	register scdev	*sp;
217 
218 	for (i = 8; --i >= 0; ) {
219 		for (j = 8; --j >= 0; ) {
220 			sp = &diskmap[i][j];
221 			for (k = 8; --k >= 0; ) {
222 				sp->lun[k] = -1;
223 			}
224 		}
225 	}
226 }
227 
228 LOCAL void
scgmap_null()229 scgmap_null()
230 {
231 	register int	i;
232 
233 	for (i = MAX_SCG; --i >= 0; ) {
234 		scgmap[i].scg_cname[0] = 0;
235 		scgmap[i].scg_caddr = 0;
236 		scgmap[i].scg_cunit = -1;
237 		scgmap[i].scg_slave = -1;
238 	}
239 }
240 
241 #ifdef	HAVE_DKIO
242 LOCAL BOOL
have_diskname(name)243 have_diskname(name)
244 	char	*name;
245 {
246 	int	i;
247 
248 	for (i = 0; i < NDISKNAMES; i++) {
249 		if (disknames[i] && streql(disknames[i], name))
250 			return (TRUE);
251 	}
252 	return (FALSE);
253 }
254 #endif
255 
256 #define	check_if(s, c)	if (*s++ != c) return (FALSE);
257 #define	skip_digits(s)	while (isdigit(*s)) s++;
258 
259 #ifdef	SVR4
260 
261 #ifdef	HAVE_DKIO
262 LOCAL BOOL
is_svr4_disk(s)263 is_svr4_disk(s)
264 	char	*s;
265 {
266 	Uchar	*s1 = (Uchar *)s;
267 	char	*s2;
268 
269 	if ((s2 = strrchr((char *)s1, '/')) != NULL)
270 		s1 = (Uchar *)++s2;
271 	check_if(s1, 'c');
272 	skip_digits(s1);
273 	if (*s1 == 't') {
274 		s1++;
275 		skip_digits(s1);
276 	}
277 	check_if(s1, 'd');
278 	skip_digits(s1);
279 	check_if(s1, 's');
280 	skip_digits(s1);
281 	return (*s1 == '\0');
282 }
283 
284 LOCAL void
make_svr4_dname(to,from)285 make_svr4_dname(to, from)
286 	char	*to;
287 	char	*from;
288 {
289 	char	*p;
290 
291 	if ((p = strchr(from, 'c')) != NULL) {
292 		strcpy(to, p);
293 		if ((p = strrchr(to, 's')) != NULL)
294 			*p = '\0';
295 	} else {
296 		*to = '\0';
297 	}
298 }
299 
300 LOCAL BOOL
make_disknames(name,dname,cdname)301 make_disknames(name, dname, cdname)
302 	char	*name;
303 	char	*dname;
304 	char	*cdname;
305 {
306 	if (is_svr4_disk(name)) {
307 		make_svr4_dname(cdname, name);
308 		if (have_diskname(cdname)) {
309 			return (FALSE);
310 		}
311 		sprintf(dname, "/dev/rdsk/%s", name);
312 	} else {
313 		sprintf(dname, "/dev/rdsk/%s", name);
314 		strcpy(cdname, name);
315 	}
316 	return (TRUE);
317 }
318 #endif
319 
320 #else	/* !SVR4 */
321 
322 #ifdef	HAVE_DKIO
323 LOCAL BOOL
is_4x_disk(s)324 is_4x_disk(s)
325 	char	*s;
326 {
327 	Uchar	*s1 = (Uchar *)s;
328 	char	*s2;
329 
330 	if ((s2 = strrchr((char *)s1, '/')) != NULL)
331 		s1 = (Uchar *)++s2;
332 	if (!strstr((char *)s1, "rsd"))
333 		return (FALSE);
334 	s1 += 3;
335 	skip_digits(s1);
336 	if (!strchr("abcdefgh", *s1))
337 		return (FALSE);
338 	return (*++s1 == '\0');
339 }
340 
341 LOCAL void
make_dname(to,from)342 make_dname(to, from)
343 	char	*to;
344 	char	*from;
345 {
346 	char	*p;
347 
348 	if ((p = strchr(from, 'r')) != NULL) {
349 		p++;
350 		strcpy(to, p);
351 		to[strlen(to)-1] = '\0';
352 	} else {
353 		*to = '\0';
354 	}
355 }
356 #endif
357 
358 #ifdef	HAVE_DKIO
359 LOCAL BOOL
make_disknames(name,dname,cdname)360 make_disknames(name, dname, cdname)
361 	char	*name;
362 	char	*dname;
363 	char	*cdname;
364 {
365 	if (!is_4x_disk(name))
366 		return (FALSE);
367 
368 	make_dname(cdname, name);
369 	if (have_diskname(cdname)) {
370 		return (FALSE);
371 	}
372 	sprintf(dname, "/dev/%s", name);
373 	return (TRUE);
374 }
375 #endif
376 #endif
377 
378 #ifdef	SVR4
379 #define	is_disk(n)	is_svr4_disk(n)
380 #else
381 #define	is_disk(n)	is_4x_disk(n)
382 #endif
383 
384 #ifdef	HAVE_DKIO
385 LOCAL int
opendisk(dname)386 opendisk(dname)
387 	char	*dname;
388 {
389 	struct stat	sb;
390 	register int	c = -1;
391 	register int	nlen = 0;
392 	int		f;
393 
394 	f = -1;
395 	/*
396 	 * we always try to open 'c' partition (slice 2) first
397 	 * XXX This only works on sun's with NDKMAP <= 10 and
398 	 * XXX slice 2 beeing the whole disk!
399 	 */
400 	if (is_disk(dname)) {
401 		nlen = strlen(dname);
402 		c = dname[nlen-1];
403 		dname[nlen-1] = PARTOFF+2;
404 	}
405 	if (stat(dname, &sb) < 0 ||
406 				((f = open(dname, O_RDONLY|O_NDELAY)) < 0 &&
407 							geterrno() == ENOENT)) {
408 		/*
409 		 * It did'nt work try to open the original dname
410 		 */
411 		if (c >= 0) {
412 			dname[nlen-1] = c;
413 			if (stat(dname, &sb) < 0)
414 				return (f);
415 			f = open(dname, O_RDONLY|O_NDELAY);
416 		}
417 	}
418 	return (f);
419 }
420 #endif
421 
422 LOCAL void
map_alldisks()423 map_alldisks()
424 {
425 #ifdef	HAVE_DKIO
426 	char		dname[64];
427 	char		cdname[64];
428 	register int	i;
429 	int		f;
430 	DIR		*d;
431 	struct dirent	*dp;
432 #endif	/* HAVE_DKIO */
433 
434 	diskmap_null();
435 	diskmap_init = TRUE;
436 
437 #ifdef	HAVE_DKIO
438 #ifdef	SVR4
439 	d = opendir("/dev/rdsk/");
440 	if (d == 0) {
441 		errmsg("Cannot open '/dev/rdsk'\n");
442 		return;
443 	}
444 #else
445 	d = opendir("/dev/");
446 	if (d == 0) {
447 		errmsg("Cannot open '/dev'\n");
448 		return;
449 	}
450 #endif
451 
452 	i = -1;
453 	while ((dp = readdir(d)) != 0) {
454 		if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
455 			(dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
456 			continue;
457 
458 		if (!make_disknames(dp->d_name, dname, cdname))
459 			continue;
460 
461 		if (++i >= NDISKNAMES) {
462 			errmsgno(EX_BAD,
463 				"WARNING: Too many disks. Cannot map %s\n",
464 				cdname);
465 			break;
466 		}
467 		f = opendisk(dname);
468 		if (f < 0) {
469 			if (geterrno() == ENXIO) {
470 				/*
471 				 * The device node exists!
472 				 * Store the name to avoid looking up all other
473 				 * partitions.
474 				 */
475 				disknames[i] = permstring(cdname);
476 				diskdevnames[i] = permstring(dname);
477 			} else {
478 				--i;
479 			}
480 			continue;
481 		}
482 		if (!map_disk(f, i, dname, cdname))
483 			--i;
484 		close(f);
485 	}
486 	closedir(d);
487 #endif	/* HAVE_DKIO */
488 }
489 
490 #ifdef	HAVE_DKIO
491 LOCAL BOOL
map_disk(f,dnum,dname,cdname)492 map_disk(f, dnum, dname, cdname)
493 	int	f;
494 	int	dnum;
495 	char	*dname;
496 	char	*cdname;
497 {
498 	struct dk_conf  conf;
499 	int		scg_bus;
500 
501 	if (ioctl(f, DKIOCGCONF, &conf) < 0) {
502 		errmsg("DKIOGCONF on disk '%s'\n", dname);
503 		return (FALSE);
504 	}
505 	scg_bus = scg_mapbus(&conf);
506 	if (scg_bus == -1) {
507 		errmsgno(-1, "No scg driver for disk '%s' on %s%d\n",
508 				dname, conf.dkc_cname, conf.dkc_cnum);
509 		return (FALSE);
510 	}
511 	if (diskmap[scg_bus][TARGET(conf.dkc_slave)].
512 					lun[LUN(conf.dkc_slave)] != -1)
513 		errmsgno(EX_BAD, "Double diskmap entry: '%s'\n", dname);
514 
515 	diskmap[scg_bus][TARGET(conf.dkc_slave)].
516 					lun[LUN(conf.dkc_slave)] = dnum;
517 	if (disknames[dnum]) {
518 		errmsgno(EX_BAD, "Double diskname entry: '%s'\n", cdname);
519 	} else {
520 		disknames[dnum] = permstring(cdname);
521 		diskdevnames[dnum] = permstring(dname);
522 	}
523 	return (TRUE);
524 }
525 
526 LOCAL int
scg_mapbus(conf)527 scg_mapbus(conf)
528 	struct dk_conf  *conf;
529 {
530 	register int	i;
531 
532 	/*
533 	 * Stimmt dann, wenn nur ein Typ SCSI Kontroller vorhanden ist.
534 	 */
535 	if (!scgmap_known)
536 		return (conf->dkc_cnum);
537 
538 	for (i = 0; i < MAX_SCG; i++) {
539 		if (conf->dkc_cnum == scgmap[i].scg_cunit &&
540 			conf->dkc_addr == scgmap[i].scg_caddr &&
541 				streql(conf->dkc_cname, scgmap[i].scg_cname))
542 			return (i);
543 	}
544 	return (-1);
545 }
546 #endif	/* HAVE_DKIO */
547 
548 LOCAL void
map_scg()549 map_scg()
550 {
551 #ifdef	HAVE_DKIO
552 	struct dk_conf  conf;
553 	char		dname[64];
554 	register int	i;
555 	int		f;
556 #ifndef	SVR4
557 	int		cpu_type = gethostid() >> 24;
558 #endif
559 #endif	/* HAVE_DKIO */
560 
561 
562 	scgmap_null();
563 	scgmap_init = TRUE;
564 #ifdef	HAVE_DKIO
565 	for (i = 0; i < MAX_SCG; i++) {
566 		sprintf(dname, "/dev/scg%d", i);
567 		if ((f = open(dname, O_RDONLY)) < 0)
568 			continue;
569 
570 		if (ioctl(f, DKIOCGCONF, &conf) < 0) {
571 #ifndef	SVR4
572 #ifdef	sun
573 			if (cpu_type != CPU_SUN3_50 &&
574 				cpu_type != CPU_SUN3_60)
575 #endif
576 #endif
577 				errmsg("DKIOGCONF not supported by '%s'.\n\
578 \nUpgrade Kernel for proper logical disk mapping.\n\n", dname);
579 			return;
580 		}
581 		scgmap_known = TRUE;
582 		strcpy(scgmap[i].scg_cname, conf.dkc_cname);
583 		scgmap[i].scg_caddr =  conf.dkc_addr;
584 		scgmap[i].scg_cunit =  conf.dkc_cnum;
585 		scgmap[i].scg_slave =  conf.dkc_slave;
586 		close(f);
587 
588 		printf("scg%d at %s%d initiator id %d\n",
589 			i,
590 			conf.dkc_cname, conf.dkc_cnum,
591 			conf.dkc_slave == -1 ? -1 : conf.dkc_slave/8);
592 	}
593 #endif	/* HAVE_DKIO */
594 }
595