Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * get dev_t list
     29  */
     30 
     31 #include <meta.h>
     32 
     33 #include <sys/mhd.h>
     34 #include <strings.h>
     35 
     36 /*
     37  * private version of minor(), able to handle 64 bit and 32 bit devices.
     38  * print a warning out in case a 32 bit dev is specified.
     39  */
     40 minor_t
     41 meta_getminor(md_dev64_t dev64)
     42 {
     43 	/* check if it's a real 64 bit dev */
     44 	if ((dev64 >> NBITSMAJOR64) > 0) {
     45 		return ((minor_t)(dev64 & MAXMIN64));
     46 	} else {
     47 		if (getenv("META_DEBUG"))
     48 			(void) printf(
     49 			    "meta_getminor called with 32 bit dev: 0x%llx\n",
     50 			    dev64);
     51 		return ((minor_t)(dev64 & MAXMIN32));
     52 	}
     53 }
     54 
     55 /*
     56  * private version of major(), able to handle 64 bit and 32 bit devices.
     57  * print a warning out in case a 32 bit dev is specified.
     58  */
     59 major_t
     60 meta_getmajor(md_dev64_t dev64)
     61 {
     62 	/* check if it's a real 64 bit dev */
     63 	if ((dev64 >> NBITSMAJOR64) > 0) {
     64 		return ((major_t)((dev64 >> NBITSMINOR64) & MAXMAJ64));
     65 	} else {
     66 		if (getenv("META_DEBUG"))
     67 			(void) printf(
     68 			    "meta_getmajor called with 32 bit dev: 0x%llx\n",
     69 			    dev64);
     70 		return ((major_t)((dev64 >> NBITSMINOR32) & MAXMAJ32));
     71 	}
     72 }
     73 
     74 /*
     75  * private version of cmpldev(), able to handle 64 bit and 32 bit devices.
     76  */
     77 dev32_t
     78 meta_cmpldev(md_dev64_t dev64)
     79 {
     80 	minor_t minor;
     81 	major_t major;
     82 
     83 	major = (major_t)(dev64 >> NBITSMAJOR64);
     84 	if (major == 0) {
     85 		return ((dev32_t)dev64);
     86 	}
     87 	minor = (dev32_t)dev64 & MAXMIN32;
     88 	return ((major << NBITSMINOR32) | minor);
     89 }
     90 
     91 /*
     92  * private version of expldev(), able to handle 64 bit and 32 bit devices.
     93  */
     94 md_dev64_t
     95 meta_expldev(md_dev64_t dev64)
     96 {
     97 	minor_t minor;
     98 	major_t major;
     99 
    100 	major = (major_t)(dev64 >> NBITSMAJOR64);
    101 	if (major > 0) { /* a 64 bit device was given, return unchanged */
    102 		return (dev64);
    103 	}
    104 	minor = (minor_t)(dev64) & MAXMIN32;
    105 	major = ((major_t)dev64 >> NBITSMINOR32) & MAXMAJ32;
    106 	return (((md_dev64_t)major << NBITSMINOR64) | minor);
    107 }
    108 
    109 /*
    110  * get underlying devices (recursively)
    111  */
    112 int
    113 meta_getdevs(
    114 	mdsetname_t		*sp,
    115 	mdname_t		*namep,
    116 	mdnamelist_t		**nlpp,
    117 	md_error_t		*ep
    118 )
    119 {
    120 	char			*miscname;
    121 	md_dev64_t		*mydevs = NULL;
    122 	md_getdevs_params_t	mgd;
    123 	size_t			i;
    124 	int			rval = -1;
    125 	md_sys_error_t		*ip;
    126 
    127 	/* must have local set */
    128 	assert(sp != NULL);
    129 
    130 	/* if no valid name then return an error */
    131 	if (namep == NULL)
    132 		return (-1);
    133 
    134 	/* just add regular devices */
    135 	if (! metaismeta(namep)) {
    136 		mdnamelist_t	*p;
    137 
    138 		/*
    139 		 * If the dev_t is in the array already
    140 		 * then let's continue.
    141 		 */
    142 		for (p = *nlpp; (p != NULL); p = p->next) {
    143 			if (strcmp(namep->bname, p->namep->bname) == 0) {
    144 				rval = 0;
    145 				goto out;
    146 			}
    147 		}
    148 
    149 		/* add to list */
    150 		(void) metanamelist_append(nlpp, namep);
    151 		rval = 0;
    152 		goto out;
    153 	}
    154 
    155 	/* get MD misc module */
    156 	if ((miscname = metagetmiscname(namep, ep)) == NULL)
    157 		goto out;
    158 
    159 	/* get count of underlying devices */
    160 	(void) memset(&mgd, '\0', sizeof (mgd));
    161 	MD_SETDRIVERNAME(&mgd, miscname, sp->setno);
    162 	mgd.mnum = meta_getminor(namep->dev);
    163 	mgd.cnt = 0;
    164 	mgd.devs = NULL;
    165 	if (metaioctl(MD_IOCGET_DEVS, &mgd, &mgd.mde, namep->cname) != 0) {
    166 		if (mgd.mde.info.errclass == MDEC_SYS) {
    167 			ip = &mgd.mde.info.md_error_info_t_u.sys_error;
    168 			if (ip->errnum == ENODEV) {
    169 				rval = 0;
    170 				goto out;
    171 			}
    172 		}
    173 		(void) mdstealerror(ep, &mgd.mde);
    174 		goto out;
    175 	} else if (mgd.cnt <= 0) {
    176 		assert(mgd.cnt >= 0);
    177 		rval = 0;
    178 		goto out;
    179 	}
    180 
    181 	/* get underlying devices */
    182 	mydevs = Zalloc(sizeof (*mydevs) * mgd.cnt);
    183 	mgd.devs = (uintptr_t)mydevs;
    184 	if (metaioctl(MD_IOCGET_DEVS, &mgd, &mgd.mde, namep->cname) != 0) {
    185 		if (mgd.mde.info.errclass == MDEC_SYS) {
    186 			ip = &mgd.mde.info.md_error_info_t_u.sys_error;
    187 			if (ip->errnum == ENODEV) {
    188 				rval = 0;
    189 				goto out;
    190 			}
    191 		}
    192 		(void) mdstealerror(ep, &mgd.mde);
    193 		goto out;
    194 	} else if (mgd.cnt <= 0) {
    195 		assert(mgd.cnt >= 0);
    196 		rval = 0;
    197 		goto out;
    198 	}
    199 	/* recurse */
    200 	for (i = 0; (i < mgd.cnt); ++i) {
    201 		mdname_t	*devnp;
    202 
    203 		if (mydevs[i] == NODEV64) {
    204 			continue;
    205 		}
    206 		if ((devnp = metadevname(&sp, mydevs[i], ep)) == NULL) {
    207 			if (mdissyserror(ep, ENOENT)) {
    208 				mdclrerror(ep);
    209 				/*
    210 				 * If the device doesn't exist, it could be
    211 				 * that we have a wrong dev_t/name
    212 				 * combination in the namespace, so
    213 				 * meta_fix_compnames try to check this
    214 				 * with the unit structure and fix this.
    215 				 */
    216 				if (meta_fix_compnames(sp, namep,
    217 				    mydevs[i], ep) == 0)
    218 					continue;
    219 			}
    220 			goto out;
    221 		}
    222 		if (meta_getdevs(sp, devnp, nlpp, ep) != 0)
    223 			goto out;
    224 	}
    225 
    226 	/* success */
    227 	rval = 0;
    228 
    229 	/* cleanup, return error */
    230 out:
    231 	if (mydevs != NULL)
    232 		Free(mydevs);
    233 	return (rval);
    234 }
    235 
    236 /*
    237  * get all dev_t for a set
    238  */
    239 int
    240 meta_getalldevs(
    241 	mdsetname_t		*sp,		/* set to look in */
    242 	mdnamelist_t		**nlpp,		/* returned devices */
    243 	int			check_db,
    244 	md_error_t		*ep
    245 )
    246 {
    247 	md_replicalist_t	*rlp, *rp;
    248 	mdnamelist_t		*nlp, *np;
    249 	mdhspnamelist_t		*hspnlp, *hspp;
    250 	int			rval = 0;
    251 
    252 	assert(sp != NULL);
    253 
    254 	/*
    255 	 * Get a replica namelist,
    256 	 * and then get all the devs within the replicas.
    257 	 */
    258 	if (check_db == TRUE) {
    259 		rlp = NULL;
    260 		if (metareplicalist(sp, MD_BASICNAME_OK, &rlp, ep) < 0)
    261 			rval = -1;
    262 		for (rp = rlp; (rp != NULL); rp = rp->rl_next) {
    263 			if (meta_getdevs(sp, rp->rl_repp->r_namep,
    264 			    nlpp, ep) != 0)
    265 				rval = -1;
    266 		}
    267 		metafreereplicalist(rlp);
    268 	}
    269 
    270 	/*
    271 	 * Get a stripe namelist,
    272 	 * and then get all the devs within the stripes.
    273 	 */
    274 	nlp = NULL;
    275 	if (meta_get_stripe_names(sp, &nlp, 0, ep) < 0)
    276 		rval = -1;
    277 	for (np = nlp; (np != NULL); np = np->next) {
    278 		if (meta_getdevs(sp, np->namep, nlpp, ep) != 0)
    279 			rval = -1;
    280 	}
    281 	metafreenamelist(nlp);
    282 
    283 	/*
    284 	 * Get a mirror namelist,
    285 	 * and then get all the devs within the mirrors.
    286 	 */
    287 	nlp = NULL;
    288 	if (meta_get_mirror_names(sp, &nlp, 0, ep) < 0)
    289 		rval = -1;
    290 	for (np = nlp; (np != NULL); np = np->next) {
    291 		if (meta_getdevs(sp, np->namep, nlpp, ep) != 0)
    292 			rval = -1;
    293 	}
    294 	metafreenamelist(nlp);
    295 
    296 	/*
    297 	 * Get a trans namelist,
    298 	 * and then get all the devs within the trans.
    299 	 */
    300 	nlp = NULL;
    301 
    302 	if (meta_get_trans_names(sp, &nlp, 0, ep) < 0)
    303 		rval = -1;
    304 	for (np = nlp; (np != NULL); np = np->next) {
    305 		if (meta_getdevs(sp, np->namep, nlpp, ep) != 0)
    306 			rval = -1;
    307 	}
    308 	metafreenamelist(nlp);
    309 
    310 	/*
    311 	 * Get a hot spare pool namelist,
    312 	 * and then get all the devs within the hot spare pools.
    313 	 */
    314 	hspnlp = NULL;
    315 	if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
    316 		rval = -1;
    317 	for (hspp = hspnlp; (hspp != NULL); hspp = hspp->next) {
    318 		md_hsp_t	*hsp;
    319 		uint_t		i;
    320 
    321 		if ((hsp = meta_get_hsp(sp, hspp->hspnamep, ep)) == NULL)
    322 			rval = -1;
    323 		else for (i = 0; (i < hsp->hotspares.hotspares_len); ++i) {
    324 			md_hs_t	*hs = &hsp->hotspares.hotspares_val[i];
    325 
    326 			if (meta_getdevs(sp, hs->hsnamep, nlpp, ep) != 0)
    327 				rval = -1;
    328 		}
    329 	}
    330 	metafreehspnamelist(hspnlp);
    331 
    332 	/*
    333 	 * Get a raid namelist,
    334 	 * and then get all the devs within the raids.
    335 	 */
    336 	nlp = NULL;
    337 	if (meta_get_raid_names(sp, &nlp, 0, ep) < 0)
    338 		rval = -1;
    339 	for (np = nlp; (np != NULL); np = np->next) {
    340 		if (meta_getdevs(sp, np->namep, nlpp, ep) != 0)
    341 			rval = -1;
    342 	}
    343 	metafreenamelist(nlp);
    344 
    345 	/*
    346 	 * Get a soft partition namelist,
    347 	 * and then get all the devs within the softpartitions
    348 	 */
    349 	nlp = NULL;
    350 	if (meta_get_sp_names(sp, &nlp, 0, ep) < 0)
    351 		rval = -1;
    352 	for (np = nlp; (np != NULL); np = np->next) {
    353 		if (meta_getdevs(sp, np->namep, nlpp, ep) != 0)
    354 			rval = -1;
    355 	}
    356 	metafreenamelist(nlp);
    357 
    358 	return (rval);
    359 }
    360 
    361 /*
    362  * get vtoc from a device already opened.
    363  * returns
    364  *	0 on success,
    365  *	-1 on error. If the error was  ENOTSUP, partno will be set to
    366  *		VT_ENOTSUP if possible.
    367  */
    368 int
    369 meta_getvtoc(
    370 	int		fd,		/* fd for named device */
    371 	char		*devname,	/* name of device */
    372 	struct extvtoc	*vtocbufp,	/* vtoc buffer to fill */
    373 	int		*partno,	/* return partno here */
    374 	md_error_t	*ep
    375 )
    376 {
    377 	int		part;
    378 
    379 	(void) memset(vtocbufp, 0, sizeof (*vtocbufp));
    380 	if ((part = read_extvtoc(fd, vtocbufp)) < 0) {
    381 		int	err = errno;
    382 
    383 		if (ioctl(fd, MHIOCSTATUS, NULL) == 1)
    384 			err = EACCES;
    385 		else if (part == VT_EINVAL)
    386 			err = EINVAL;
    387 		else if (part == VT_EIO)
    388 			err = EIO;
    389 		else if (part == VT_ENOTSUP) {
    390 			if (partno) {
    391 				*partno = VT_ENOTSUP;
    392 				return (-1);
    393 			}
    394 		}
    395 		return (mdsyserror(ep, err, devname));
    396 	}
    397 
    398 	/* Slice number for *p0 partition (whole disk on x86) is 16 */
    399 	if (part >= V_NUMPAR)
    400 		return (mdsyserror(ep, EINVAL, devname));
    401 
    402 	/* Slice number for *p0 partition (whole disk on x86) is 16 */
    403 	if (part >= V_NUMPAR)
    404 		return (mdsyserror(ep, EINVAL, devname));
    405 
    406 	if (partno)
    407 		*partno = part;
    408 	return (0);
    409 }
    410 /*
    411  * set mdvtoc for a meta devices
    412  */
    413 int
    414 meta_setmdvtoc(
    415 	int		fd,		/* fd for named device */
    416 	char		*devname,	/* name of device */
    417 	mdvtoc_t	*mdvtocp,	/* mdvtoc buffer to fill */
    418 	md_error_t	*ep
    419 )
    420 {
    421 	uint_t i;
    422 
    423 	/*
    424 	 * Sanity-check the mdvtoc
    425 	 */
    426 
    427 	if (mdvtocp->nparts > V_NUMPAR) {
    428 		return (-1);
    429 	}
    430 
    431 	/*
    432 	 * since many drivers won't allow opening a device make sure
    433 	 * all partitions aren't being set to zero. If all are zero then
    434 	 * we have no way to set them to something else
    435 	 */
    436 
    437 	for (i = 0; i < mdvtocp->nparts; i++)
    438 		if (mdvtocp->parts[i].size > 0)
    439 			break;
    440 	if (i == mdvtocp->nparts)
    441 		return (-1);
    442 
    443 	/*
    444 	 * Write the mdvtoc
    445 	 */
    446 	if (ioctl(fd, DKIOCSVTOC, (caddr_t)mdvtocp) == -1) {
    447 		return (mdsyserror(ep, errno, devname));
    448 	}
    449 
    450 	return (0);
    451 }
    452 
    453 /*
    454  * set vtoc
    455  */
    456 int
    457 meta_setvtoc(
    458 	int		fd,		/* fd for named device */
    459 	char		*devname,	/* name of device */
    460 	struct extvtoc	*vtocbufp,	/* vtoc buffer to fill */
    461 	md_error_t	*ep
    462 )
    463 {
    464 	int		part;
    465 	int		err;
    466 
    467 	if ((part = write_extvtoc(fd, vtocbufp)) < 0) {
    468 		if (part == VT_EINVAL)
    469 			err = EINVAL;
    470 		else if (part == VT_EIO)
    471 			err = EIO;
    472 		else
    473 			err = errno;
    474 		return (mdsyserror(ep, err, devname));
    475 	}
    476 
    477 	return (0);
    478 }
    479 
    480 /*
    481  * FUNCTION:	meta_get_names()
    482  * INPUT:	drivername - char string containing the driver name
    483  *		sp	- the set name to get soft partitions from
    484  *		options	- options from the command line
    485  * OUTPUT:	nlpp	- list of all soft partition names
    486  *		ep	- return error pointer
    487  * RETURNS:	int	- -1 if error, 0 success
    488  * PURPOSE:	returns a list of all specified devices in the metadb
    489  *		for all devices in the specified set
    490  */
    491 int
    492 meta_get_names(
    493 	char		*drivername,
    494 	mdsetname_t	*sp,
    495 	mdnamelist_t	**nlpp,
    496 	mdprtopts_t	options,
    497 	md_error_t	*ep
    498 )
    499 {
    500 	md_i_getnum_t	gn;		/* MD_IOCGET_NUM params */
    501 	mdnamelist_t	**tailpp = nlpp;
    502 	minor_t		*minors = NULL;
    503 	minor_t		*m_ptr;
    504 	int		i;
    505 
    506 	(void) memset(&gn, '\0', sizeof (gn));
    507 	MD_SETDRIVERNAME(&gn, drivername, sp->setno);
    508 
    509 	/* get number of devices */
    510 	if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
    511 		if (mdiserror(&gn.mde, MDE_UNIT_NOT_FOUND)) {
    512 			mdclrerror(&gn.mde);
    513 		} else {
    514 			(void) mdstealerror(ep, &gn.mde);
    515 			return (-1);
    516 		}
    517 	}
    518 
    519 	if (gn.size > 0) {
    520 		/* malloc minor number buffer to be filled by ioctl */
    521 		if ((minors = (minor_t *)malloc(
    522 		    gn.size * sizeof (minor_t))) == 0) {
    523 			return (ENOMEM);
    524 		}
    525 		gn.minors = (uintptr_t)minors;
    526 		if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
    527 			(void) mdstealerror(ep, &gn.mde);
    528 			free(minors);
    529 			return (-1);
    530 		}
    531 		m_ptr = minors;
    532 		for (i = 0; i < gn.size; i++) {
    533 			mdname_t	*np;
    534 
    535 			/* get name */
    536 			np = metamnumname(&sp, *m_ptr,
    537 			    ((options & PRINT_FAST) ? 1 : 0), ep);
    538 
    539 			/*
    540 			 * np can be NULL if the /dev/md namespace entries
    541 			 * do not exist. This could have happened due to
    542 			 * devfsadmd not having created them.
    543 			 * Therefore assume devfsadmd has not run and tell
    544 			 * it to run for the specific device that is missing.
    545 			 * Ignore any error return from meta_update_devtree
    546 			 * as a failure to create the device nodes will be
    547 			 * picked up in the metamnumname() call. Note that
    548 			 * the call to meta_update_devtree should not return
    549 			 * until the /dev/md links have been created or if
    550 			 * there has been a failure of some sort.
    551 			 */
    552 			if (np == NULL) {
    553 				(void) meta_update_devtree(*m_ptr);
    554 				np = metamnumname(&sp, *m_ptr,
    555 				    ((options & PRINT_FAST) ? 1 : 0), ep);
    556 			}
    557 
    558 			if (np == NULL)
    559 				goto out;
    560 
    561 			tailpp = meta_namelist_append_wrapper(tailpp, np);
    562 
    563 			/* next device */
    564 			m_ptr++;
    565 		}
    566 		free(minors);
    567 	}
    568 	return (gn.size);
    569 
    570 out:
    571 	if (minors != NULL)
    572 		free(minors);
    573 	metafreenamelist(*nlpp);
    574 	*nlpp = NULL;
    575 	return (-1);
    576 }
    577 
    578 /*
    579  * Wrap lib/libdevid/devid_deviceid_to_nmlist.  We want to take the
    580  * results from that function and filter out the c[t]dp style names that
    581  * we typically see on x86 so that we never see them.
    582  */
    583 int
    584 meta_deviceid_to_nmlist(char *search_path, ddi_devid_t devid, char *minor_name,
    585 	devid_nmlist_t	**retlist)
    586 {
    587 	int		res;
    588 	devid_nmlist_t	*dp;
    589 	devid_nmlist_t	*tmp_retlist;
    590 	int		i = 1;
    591 	devid_nmlist_t	*rp;
    592 
    593 	res = devid_deviceid_to_nmlist(search_path, devid, minor_name, retlist);
    594 	if (res != 0) {
    595 		return (res);
    596 	}
    597 
    598 
    599 	/* first count the number of non c[t]dp items in retlist */
    600 	for (dp = *retlist; dp->dev != NODEV; dp++) {
    601 		uint_t		s;
    602 
    603 		/* Check if this is a c[t]dp style name.  */
    604 		if (parse_ctd(basename(dp->devname), &s) != 1) {
    605 			i++;
    606 		}
    607 	}
    608 
    609 	/* create an array to hold the non c[t]dp items */
    610 	tmp_retlist = Malloc(sizeof (devid_nmlist_t) * i);
    611 	/* copy the non c[t]dp items to the array */
    612 	for (dp = *retlist, rp = tmp_retlist; dp->dev != NODEV; dp++) {
    613 		uint_t		s;
    614 
    615 		/* Check if this is a c[t]dp style name.  */
    616 		if (parse_ctd(basename(dp->devname), &s) != 1) {
    617 			/* nope, so copy and go to the next */
    618 			rp->dev = dp->dev;
    619 			rp->devname = Strdup(dp->devname);
    620 			rp++;
    621 		}
    622 		/* if it is c[t]dp, just skip the element */
    623 	}
    624 	/* copy the list terminator */
    625 	rp->dev = NODEV;
    626 	rp->devname = NULL;
    627 	devid_free_nmlist (*retlist);
    628 	*retlist = tmp_retlist;
    629 	return (res);
    630 }
    631 
    632 /*
    633  * Check each real device that makes up a metadevice so that
    634  * un_dev entries can be matched against the entries in the
    635  * namespace.
    636  *
    637  * RETURN:
    638  *      -1      error
    639  *       0      success
    640  */
    641 int
    642 meta_fix_compnames(
    643 	mdsetname_t	*sp,
    644 	mdname_t	*namep,
    645 	md_dev64_t	dev,
    646 	md_error_t	*ep
    647 )
    648 {
    649 	int	ret = 0;
    650 	char	*miscname;
    651 
    652 	/* get miscname and unit */
    653 	if ((miscname = metagetmiscname(namep, ep)) == NULL)
    654 		return (-1);
    655 	if (strcmp(miscname, MD_STRIPE) == 0) {
    656 		if (meta_stripe_check_component(sp, namep, dev, ep) < 0) {
    657 			ret = -1;
    658 		}
    659 	} else if (strcmp(miscname, MD_SP) == 0) {
    660 		if (meta_sp_check_component(sp, namep, ep) < 0) {
    661 			ret = -1;
    662 		}
    663 	} else if (strcmp(miscname, MD_RAID) == 0) {
    664 		if (meta_raid_check_component(sp, namep, dev, ep) < 0) {
    665 			ret = -1;
    666 		}
    667 	} else {
    668 		(void) mdmderror(ep, MDE_INVAL_UNIT, 0, namep->cname);
    669 		return (-1);
    670 	}
    671 	return (ret);
    672 }
    673