Home | History | Annotate | Line # | Download | only in raidframe
rf_disks.c revision 1.28
      1 /*	$NetBSD: rf_disks.c,v 1.28 2000/05/28 05:23:42 oster Exp $	*/
      2 /*-
      3  * Copyright (c) 1999 The NetBSD Foundation, Inc.
      4  * All rights reserved.
      5  *
      6  * This code is derived from software contributed to The NetBSD Foundation
      7  * by Greg Oster
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. All advertising materials mentioning features or use of this software
     18  *    must display the following acknowledgement:
     19  *        This product includes software developed by the NetBSD
     20  *        Foundation, Inc. and its contributors.
     21  * 4. Neither the name of The NetBSD Foundation nor the names of its
     22  *    contributors may be used to endorse or promote products derived
     23  *    from this software without specific prior written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     26  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     35  * POSSIBILITY OF SUCH DAMAGE.
     36  */
     37 
     38 /*
     39  * Copyright (c) 1995 Carnegie-Mellon University.
     40  * All rights reserved.
     41  *
     42  * Author: Mark Holland
     43  *
     44  * Permission to use, copy, modify and distribute this software and
     45  * its documentation is hereby granted, provided that both the copyright
     46  * notice and this permission notice appear in all copies of the
     47  * software, derivative works or modified versions, and any portions
     48  * thereof, and that both notices appear in supporting documentation.
     49  *
     50  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     51  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
     52  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     53  *
     54  * Carnegie Mellon requests users of this software to return to
     55  *
     56  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     57  *  School of Computer Science
     58  *  Carnegie Mellon University
     59  *  Pittsburgh PA 15213-3890
     60  *
     61  * any improvements or extensions that they make and grant Carnegie the
     62  * rights to redistribute these changes.
     63  */
     64 
     65 /***************************************************************
     66  * rf_disks.c -- code to perform operations on the actual disks
     67  ***************************************************************/
     68 
     69 #include "rf_types.h"
     70 #include "rf_raid.h"
     71 #include "rf_alloclist.h"
     72 #include "rf_utils.h"
     73 #include "rf_configure.h"
     74 #include "rf_general.h"
     75 #include "rf_options.h"
     76 #include "rf_kintf.h"
     77 #include "rf_netbsd.h"
     78 
     79 #include <sys/types.h>
     80 #include <sys/param.h>
     81 #include <sys/systm.h>
     82 #include <sys/proc.h>
     83 #include <sys/ioctl.h>
     84 #include <sys/fcntl.h>
     85 #include <sys/vnode.h>
     86 
     87 static int rf_AllocDiskStructures(RF_Raid_t *, RF_Config_t *);
     88 static void rf_print_label_status( RF_Raid_t *, int, int, char *,
     89 				  RF_ComponentLabel_t *);
     90 static int rf_check_label_vitals( RF_Raid_t *, int, int, char *,
     91 				  RF_ComponentLabel_t *, int, int );
     92 
     93 #define DPRINTF6(a,b,c,d,e,f) if (rf_diskDebug) printf(a,b,c,d,e,f)
     94 #define DPRINTF7(a,b,c,d,e,f,g) if (rf_diskDebug) printf(a,b,c,d,e,f,g)
     95 
     96 /**************************************************************************
     97  *
     98  * initialize the disks comprising the array
     99  *
    100  * We want the spare disks to have regular row,col numbers so that we can
    101  * easily substitue a spare for a failed disk.  But, the driver code assumes
    102  * throughout that the array contains numRow by numCol _non-spare_ disks, so
    103  * it's not clear how to fit in the spares.  This is an unfortunate holdover
    104  * from raidSim.  The quick and dirty fix is to make row zero bigger than the
    105  * rest, and put all the spares in it.  This probably needs to get changed
    106  * eventually.
    107  *
    108  **************************************************************************/
    109 
    110 int
    111 rf_ConfigureDisks( listp, raidPtr, cfgPtr )
    112 	RF_ShutdownList_t **listp;
    113 	RF_Raid_t *raidPtr;
    114 	RF_Config_t *cfgPtr;
    115 {
    116 	RF_RaidDisk_t **disks;
    117 	RF_SectorCount_t min_numblks = (RF_SectorCount_t) 0x7FFFFFFFFFFFLL;
    118 	RF_RowCol_t r, c;
    119 	int bs, ret;
    120 	unsigned i, count, foundone = 0, numFailuresThisRow;
    121 	int force;
    122 
    123 	force = cfgPtr->force;
    124 
    125 	ret = rf_AllocDiskStructures(raidPtr, cfgPtr);
    126 	if (ret)
    127 		goto fail;
    128 
    129 	disks = raidPtr->Disks;
    130 
    131 	for (r = 0; r < raidPtr->numRow; r++) {
    132 		numFailuresThisRow = 0;
    133 		for (c = 0; c < raidPtr->numCol; c++) {
    134 			ret = rf_ConfigureDisk(raidPtr,
    135 					       &cfgPtr->devnames[r][c][0],
    136 					       &disks[r][c], r, c);
    137 
    138 			if (ret)
    139 				goto fail;
    140 
    141 			if (disks[r][c].status == rf_ds_optimal) {
    142 				raidread_component_label(
    143 					 raidPtr->raid_cinfo[r][c].ci_dev,
    144 					 raidPtr->raid_cinfo[r][c].ci_vp,
    145 					 &raidPtr->raid_cinfo[r][c].ci_label);
    146 			}
    147 
    148 			if (disks[r][c].status != rf_ds_optimal) {
    149 				numFailuresThisRow++;
    150 			} else {
    151 				if (disks[r][c].numBlocks < min_numblks)
    152 					min_numblks = disks[r][c].numBlocks;
    153 				DPRINTF7("Disk at row %d col %d: dev %s numBlocks %ld blockSize %d (%ld MB)\n",
    154 				    r, c, disks[r][c].devname,
    155 				    (long int) disks[r][c].numBlocks,
    156 				    disks[r][c].blockSize,
    157 				    (long int) disks[r][c].numBlocks *
    158 					 disks[r][c].blockSize / 1024 / 1024);
    159 			}
    160 		}
    161 		/* XXX fix for n-fault tolerant */
    162 		/* XXX this should probably check to see how many failures
    163 		   we can handle for this configuration! */
    164 		if (numFailuresThisRow > 0)
    165 			raidPtr->status[r] = rf_rs_degraded;
    166 	}
    167 
    168 	/* all disks must be the same size & have the same block size, bs must
    169 	 * be a power of 2 */
    170 	bs = 0;
    171 	for (foundone = r = 0; !foundone && r < raidPtr->numRow; r++) {
    172 		for (c = 0; !foundone && c < raidPtr->numCol; c++) {
    173 			if (disks[r][c].status == rf_ds_optimal) {
    174 				bs = disks[r][c].blockSize;
    175 				foundone = 1;
    176 			}
    177 		}
    178 	}
    179 	if (!foundone) {
    180 		RF_ERRORMSG("RAIDFRAME: Did not find any live disks in the array.\n");
    181 		ret = EINVAL;
    182 		goto fail;
    183 	}
    184 	for (count = 0, i = 1; i; i <<= 1)
    185 		if (bs & i)
    186 			count++;
    187 	if (count != 1) {
    188 		RF_ERRORMSG1("Error: block size on disks (%d) must be a power of 2\n", bs);
    189 		ret = EINVAL;
    190 		goto fail;
    191 	}
    192 
    193 	if (rf_CheckLabels( raidPtr, cfgPtr )) {
    194 		printf("raid%d: There were fatal errors\n", raidPtr->raidid);
    195 		if (force != 0) {
    196 			printf("raid%d: Fatal errors being ignored.\n",
    197 			       raidPtr->raidid);
    198 		} else {
    199 			ret = EINVAL;
    200 			goto fail;
    201 		}
    202 	}
    203 
    204 	for (r = 0; r < raidPtr->numRow; r++) {
    205 		for (c = 0; c < raidPtr->numCol; c++) {
    206 			if (disks[r][c].status == rf_ds_optimal) {
    207 				if (disks[r][c].blockSize != bs) {
    208 					RF_ERRORMSG2("Error: block size of disk at r %d c %d different from disk at r 0 c 0\n", r, c);
    209 					ret = EINVAL;
    210 					goto fail;
    211 				}
    212 				if (disks[r][c].numBlocks != min_numblks) {
    213 					RF_ERRORMSG3("WARNING: truncating disk at r %d c %d to %d blocks\n",
    214 					    r, c, (int) min_numblks);
    215 					disks[r][c].numBlocks = min_numblks;
    216 				}
    217 			}
    218 		}
    219 	}
    220 
    221 	raidPtr->sectorsPerDisk = min_numblks;
    222 	raidPtr->logBytesPerSector = ffs(bs) - 1;
    223 	raidPtr->bytesPerSector = bs;
    224 	raidPtr->sectorMask = bs - 1;
    225 	return (0);
    226 
    227 fail:
    228 
    229 	rf_UnconfigureVnodes( raidPtr );
    230 
    231 	return (ret);
    232 }
    233 
    234 
    235 /****************************************************************************
    236  * set up the data structures describing the spare disks in the array
    237  * recall from the above comment that the spare disk descriptors are stored
    238  * in row zero, which is specially expanded to hold them.
    239  ****************************************************************************/
    240 int
    241 rf_ConfigureSpareDisks( listp, raidPtr, cfgPtr )
    242 	RF_ShutdownList_t ** listp;
    243 	RF_Raid_t * raidPtr;
    244 	RF_Config_t * cfgPtr;
    245 {
    246 	int     i, ret;
    247 	unsigned int bs;
    248 	RF_RaidDisk_t *disks;
    249 	int     num_spares_done;
    250 
    251 	num_spares_done = 0;
    252 
    253 	/* The space for the spares should have already been allocated by
    254 	 * ConfigureDisks() */
    255 
    256 	disks = &raidPtr->Disks[0][raidPtr->numCol];
    257 	for (i = 0; i < raidPtr->numSpare; i++) {
    258 		ret = rf_ConfigureDisk(raidPtr, &cfgPtr->spare_names[i][0],
    259 				       &disks[i], 0, raidPtr->numCol + i);
    260 		if (ret)
    261 			goto fail;
    262 		if (disks[i].status != rf_ds_optimal) {
    263 			RF_ERRORMSG1("Warning: spare disk %s failed TUR\n",
    264 				     &cfgPtr->spare_names[i][0]);
    265 		} else {
    266 			disks[i].status = rf_ds_spare;	/* change status to
    267 							 * spare */
    268 			DPRINTF6("Spare Disk %d: dev %s numBlocks %ld blockSize %d (%ld MB)\n", i,
    269 			    disks[i].devname,
    270 			    (long int) disks[i].numBlocks, disks[i].blockSize,
    271 			    (long int) disks[i].numBlocks *
    272 				 disks[i].blockSize / 1024 / 1024);
    273 		}
    274 		num_spares_done++;
    275 	}
    276 
    277 	/* check sizes and block sizes on spare disks */
    278 	bs = 1 << raidPtr->logBytesPerSector;
    279 	for (i = 0; i < raidPtr->numSpare; i++) {
    280 		if (disks[i].blockSize != bs) {
    281 			RF_ERRORMSG3("Block size of %d on spare disk %s is not the same as on other disks (%d)\n", disks[i].blockSize, disks[i].devname, bs);
    282 			ret = EINVAL;
    283 			goto fail;
    284 		}
    285 		if (disks[i].numBlocks < raidPtr->sectorsPerDisk) {
    286 			RF_ERRORMSG3("Spare disk %s (%d blocks) is too small to serve as a spare (need %ld blocks)\n",
    287 				     disks[i].devname, disks[i].blockSize,
    288 				     (long int) raidPtr->sectorsPerDisk);
    289 			ret = EINVAL;
    290 			goto fail;
    291 		} else
    292 			if (disks[i].numBlocks > raidPtr->sectorsPerDisk) {
    293 				RF_ERRORMSG2("Warning: truncating spare disk %s to %ld blocks\n", disks[i].devname, (long int) raidPtr->sectorsPerDisk);
    294 
    295 				disks[i].numBlocks = raidPtr->sectorsPerDisk;
    296 			}
    297 	}
    298 
    299 	return (0);
    300 
    301 fail:
    302 
    303 	/* Release the hold on the main components.  We've failed to allocate
    304 	 * a spare, and since we're failing, we need to free things..
    305 
    306 	 XXX failing to allocate a spare is *not* that big of a deal...
    307 	 We *can* survive without it, if need be, esp. if we get hot
    308 	 adding working.
    309 
    310 	 If we don't fail out here, then we need a way to remove this spare...
    311 	 that should be easier to do here than if we are "live"...
    312 
    313 	 */
    314 
    315 	rf_UnconfigureVnodes( raidPtr );
    316 
    317 	return (ret);
    318 }
    319 
    320 static int
    321 rf_AllocDiskStructures(raidPtr, cfgPtr)
    322 	RF_Raid_t *raidPtr;
    323  	RF_Config_t *cfgPtr;
    324 {
    325 	RF_RaidDisk_t **disks;
    326 	int ret;
    327 	int r;
    328 
    329 	RF_CallocAndAdd(disks, raidPtr->numRow, sizeof(RF_RaidDisk_t *),
    330 			(RF_RaidDisk_t **), raidPtr->cleanupList);
    331 	if (disks == NULL) {
    332 		ret = ENOMEM;
    333 		goto fail;
    334 	}
    335 	raidPtr->Disks = disks;
    336 	/* get space for the device-specific stuff... */
    337 	RF_CallocAndAdd(raidPtr->raid_cinfo, raidPtr->numRow,
    338 	    sizeof(struct raidcinfo *), (struct raidcinfo **),
    339 	    raidPtr->cleanupList);
    340 	if (raidPtr->raid_cinfo == NULL) {
    341 		ret = ENOMEM;
    342 		goto fail;
    343 	}
    344 
    345 	for (r = 0; r < raidPtr->numRow; r++) {
    346 		/* We allocate RF_MAXSPARE on the first row so that we
    347 		   have room to do hot-swapping of spares */
    348 		RF_CallocAndAdd(disks[r], raidPtr->numCol
    349 				+ ((r == 0) ? RF_MAXSPARE : 0),
    350 				sizeof(RF_RaidDisk_t), (RF_RaidDisk_t *),
    351 				raidPtr->cleanupList);
    352 		if (disks[r] == NULL) {
    353 			ret = ENOMEM;
    354 			goto fail;
    355 		}
    356 		/* get more space for device specific stuff.. */
    357 		RF_CallocAndAdd(raidPtr->raid_cinfo[r],
    358 		    raidPtr->numCol + ((r == 0) ? raidPtr->numSpare : 0),
    359 		    sizeof(struct raidcinfo), (struct raidcinfo *),
    360 		    raidPtr->cleanupList);
    361 		if (raidPtr->raid_cinfo[r] == NULL) {
    362 			ret = ENOMEM;
    363 			goto fail;
    364 		}
    365 	}
    366 	return(0);
    367 fail:
    368 	rf_UnconfigureVnodes( raidPtr );
    369 
    370 	return(ret);
    371 }
    372 
    373 
    374 /* configure a single disk during auto-configuration at boot */
    375 int
    376 rf_AutoConfigureDisks(raidPtr, cfgPtr, auto_config)
    377 	RF_Raid_t *raidPtr;
    378 	RF_Config_t *cfgPtr;
    379 	RF_AutoConfig_t *auto_config;
    380 {
    381 	RF_RaidDisk_t **disks;
    382 	RF_RaidDisk_t *diskPtr;
    383 	RF_RowCol_t r, c;
    384 	RF_SectorCount_t min_numblks = (RF_SectorCount_t) 0x7FFFFFFFFFFFLL;
    385 	int bs, ret;
    386 	int numFailuresThisRow;
    387 	int force;
    388 	RF_AutoConfig_t *ac;
    389 	int parity_good;
    390 	int mod_counter;
    391 
    392 #if DEBUG
    393 	printf("Starting autoconfiguration of RAID set...\n");
    394 #endif
    395 	force = cfgPtr->force;
    396 
    397 	ret = rf_AllocDiskStructures(raidPtr, cfgPtr);
    398 	if (ret)
    399 		goto fail;
    400 
    401 	disks = raidPtr->Disks;
    402 
    403 	/* assume the parity will be fine.. */
    404 	parity_good = RF_RAID_CLEAN;
    405 
    406 	/* Check for mod_counters that are too low */
    407 	mod_counter = -1;
    408 	ac = auto_config;
    409 	while(ac!=NULL) {
    410 		if (ac->clabel->mod_counter > mod_counter) {
    411 			mod_counter = ac->clabel->mod_counter;
    412 		}
    413 		ac = ac->next;
    414 	}
    415 	if (mod_counter == -1) {
    416 		/* mod_counters were all negative!?!?!?
    417 		   Ok, we can deal with that. */
    418 #if 0
    419 		ac = auto_config;
    420 		while(ac!=NULL) {
    421 			if (ac->clabel->mod_counter > mod_counter) {
    422 				mod_counter = ac->clabel->mod_counter;
    423 			}
    424 			ac = ac->next;
    425 		}
    426 #endif
    427 	}
    428 	/* close the device for the ones that don't match */
    429 
    430 	ac = auto_config;
    431 	while(ac!=NULL) {
    432 		if (ac->clabel->mod_counter != mod_counter) {
    433 			VOP_CLOSE(ac->vp, FREAD, NOCRED, 0);
    434 			vput(ac->vp);
    435 			ac->vp = NULL;
    436 #if DEBUG
    437 			printf("Ignoring %s due to low mod_counter.\n",
    438 			       ac->devname);
    439 #endif
    440 		}
    441 		ac = ac->next;
    442 	}
    443 
    444 	for (r = 0; r < raidPtr->numRow; r++) {
    445 		numFailuresThisRow = 0;
    446 		for (c = 0; c < raidPtr->numCol; c++) {
    447 			diskPtr = &disks[r][c];
    448 
    449 			/* find this row/col in the autoconfig */
    450 #if DEBUG
    451 			printf("Looking for %d,%d in autoconfig\n",r,c);
    452 #endif
    453 			ac = auto_config;
    454 			while(ac!=NULL) {
    455 				if (ac->clabel==NULL) {
    456 					/* big-time bad news. */
    457 					goto fail;
    458 				}
    459 				if ((ac->clabel->row == r) &&
    460 				    (ac->clabel->column == c) &&
    461 				    (ac->clabel->mod_counter == mod_counter)) {
    462 					/* it's this one... */
    463 #if DEBUG
    464 					printf("Found: %s at %d,%d\n",
    465 					       ac->devname,r,c);
    466 #endif
    467 
    468 					break;
    469 				}
    470 				ac=ac->next;
    471 			}
    472 
    473 			if (ac!=NULL) {
    474 				/* Found it.  Configure it.. */
    475 				diskPtr->blockSize = ac->clabel->blockSize;
    476 				diskPtr->numBlocks = ac->clabel->numBlocks;
    477 				/* Note: rf_protectedSectors is already
    478 				   factored into numBlocks here */
    479 				raidPtr->raid_cinfo[r][c].ci_vp = ac->vp;
    480 				raidPtr->raid_cinfo[r][c].ci_dev = ac->dev;
    481 
    482 				memcpy(&raidPtr->raid_cinfo[r][c].ci_label,
    483 				       ac->clabel, sizeof(*ac->clabel));
    484 				sprintf(diskPtr->devname, "/dev/%s",
    485 					ac->devname);
    486 
    487 				/* note the fact that this component was
    488 				   autoconfigured.  You'll need this info
    489 				   later.  Trust me :) */
    490 				diskPtr->auto_configured = 1;
    491 				diskPtr->dev = ac->dev;
    492 
    493 				/*
    494 				 * we allow the user to specify that
    495 				 * only a fraction of the disks should
    496 				 * be used this is just for debug: it
    497 				 * speeds up the parity scan
    498 				 */
    499 
    500 				diskPtr->numBlocks = diskPtr->numBlocks *
    501 					rf_sizePercentage / 100;
    502 
    503 				/* XXX these will get set multiple times,
    504 				   but since we're autoconfiguring, they'd
    505 				   better be always the same each time!
    506 				   If not, this is the least of your worries */
    507 
    508 				bs = diskPtr->blockSize;
    509 				min_numblks = diskPtr->numBlocks;
    510 
    511 				/* this gets done multiple times, but that's
    512 				   fine -- the serial number will be the same
    513 				   for all components, guaranteed */
    514 				raidPtr->serial_number =
    515 					ac->clabel->serial_number;
    516 				/* check the last time the label
    517 				   was modified */
    518 				if (ac->clabel->mod_counter !=
    519 				    mod_counter) {
    520 					/* Even though we've filled in all
    521 					   of the above, we don't trust
    522 					   this component since it's
    523 					   modification counter is not
    524 					   in sync with the rest, and we really
    525 					   consider it to be failed.  */
    526 					disks[r][c].status = rf_ds_failed;
    527 					numFailuresThisRow++;
    528 				} else {
    529 					if (ac->clabel->clean !=
    530 					    RF_RAID_CLEAN) {
    531 						parity_good = RF_RAID_DIRTY;
    532 					}
    533 				}
    534 			} else {
    535 				/* Didn't find it at all!!
    536 				   Component must really be dead */
    537 				disks[r][c].status = rf_ds_failed;
    538 				numFailuresThisRow++;
    539 			}
    540 		}
    541 		/* XXX fix for n-fault tolerant */
    542 		/* XXX this should probably check to see how many failures
    543 		   we can handle for this configuration! */
    544 		if (numFailuresThisRow > 0)
    545 			raidPtr->status[r] = rf_rs_degraded;
    546 	}
    547 
    548 	raidPtr->mod_counter = mod_counter;
    549 
    550 	/* note the state of the parity, if any */
    551 	raidPtr->parity_good = parity_good;
    552 	raidPtr->sectorsPerDisk = min_numblks;
    553 	raidPtr->logBytesPerSector = ffs(bs) - 1;
    554 	raidPtr->bytesPerSector = bs;
    555 	raidPtr->sectorMask = bs - 1;
    556 	return (0);
    557 
    558 fail:
    559 
    560 	rf_UnconfigureVnodes( raidPtr );
    561 
    562 	return (ret);
    563 
    564 }
    565 
    566 /* configure a single disk in the array */
    567 int
    568 rf_ConfigureDisk(raidPtr, buf, diskPtr, row, col)
    569 	RF_Raid_t *raidPtr;
    570 	char   *buf;
    571 	RF_RaidDisk_t *diskPtr;
    572 	RF_RowCol_t row;
    573 	RF_RowCol_t col;
    574 {
    575 	char   *p;
    576 	int     retcode;
    577 
    578 	struct partinfo dpart;
    579 	struct vnode *vp;
    580 	struct vattr va;
    581 	struct proc *proc;
    582 	int     error;
    583 
    584 	retcode = 0;
    585 	p = rf_find_non_white(buf);
    586 	if (p[strlen(p) - 1] == '\n') {
    587 		/* strip off the newline */
    588 		p[strlen(p) - 1] = '\0';
    589 	}
    590 	(void) strcpy(diskPtr->devname, p);
    591 
    592 	proc = raidPtr->engine_thread;
    593 
    594 	/* Let's start by claiming the component is fine and well... */
    595 	diskPtr->status = rf_ds_optimal;
    596 
    597 	raidPtr->raid_cinfo[row][col].ci_vp = NULL;
    598 	raidPtr->raid_cinfo[row][col].ci_dev = NULL;
    599 
    600 	error = raidlookup(diskPtr->devname, proc, &vp);
    601 	if (error) {
    602 		printf("raidlookup on device: %s failed!\n", diskPtr->devname);
    603 		if (error == ENXIO) {
    604 			/* the component isn't there... must be dead :-( */
    605 			diskPtr->status = rf_ds_failed;
    606 		} else {
    607 			return (error);
    608 		}
    609 	}
    610 	if (diskPtr->status == rf_ds_optimal) {
    611 
    612 		if ((error = VOP_GETATTR(vp, &va, proc->p_ucred, proc)) != 0) {
    613 			return (error);
    614 		}
    615 		error = VOP_IOCTL(vp, DIOCGPART, (caddr_t) & dpart,
    616 				  FREAD, proc->p_ucred, proc);
    617 		if (error) {
    618 			return (error);
    619 		}
    620 
    621 		diskPtr->blockSize = dpart.disklab->d_secsize;
    622 
    623 		diskPtr->numBlocks = dpart.part->p_size - rf_protectedSectors;
    624 		diskPtr->partitionSize = dpart.part->p_size;
    625 
    626 		raidPtr->raid_cinfo[row][col].ci_vp = vp;
    627 		raidPtr->raid_cinfo[row][col].ci_dev = va.va_rdev;
    628 
    629 		/* This component was not automatically configured */
    630 		diskPtr->auto_configured = 0;
    631 		diskPtr->dev = va.va_rdev;
    632 
    633 		/* we allow the user to specify that only a fraction of the
    634 		 * disks should be used this is just for debug:  it speeds up
    635 		 * the parity scan */
    636 		diskPtr->numBlocks = diskPtr->numBlocks *
    637 			rf_sizePercentage / 100;
    638 	}
    639 	return (0);
    640 }
    641 
    642 static void
    643 rf_print_label_status( raidPtr, row, column, dev_name, ci_label )
    644 	RF_Raid_t *raidPtr;
    645 	int row;
    646 	int column;
    647 	char *dev_name;
    648 	RF_ComponentLabel_t *ci_label;
    649 {
    650 
    651 	printf("raid%d: Component %s being configured at row: %d col: %d\n",
    652 	       raidPtr->raidid, dev_name, row, column );
    653 	printf("         Row: %d Column: %d Num Rows: %d Num Columns: %d\n",
    654 	       ci_label->row, ci_label->column,
    655 	       ci_label->num_rows, ci_label->num_columns);
    656 	printf("         Version: %d Serial Number: %d Mod Counter: %d\n",
    657 	       ci_label->version, ci_label->serial_number,
    658 	       ci_label->mod_counter);
    659 	printf("         Clean: %s Status: %d\n",
    660 	       ci_label->clean ? "Yes" : "No", ci_label->status );
    661 }
    662 
    663 static int rf_check_label_vitals( raidPtr, row, column, dev_name, ci_label,
    664 				  serial_number, mod_counter )
    665 	RF_Raid_t *raidPtr;
    666 	int row;
    667 	int column;
    668 	char *dev_name;
    669 	RF_ComponentLabel_t *ci_label;
    670 	int serial_number;
    671 	int mod_counter;
    672 {
    673 	int fatal_error = 0;
    674 
    675 	if (serial_number != ci_label->serial_number) {
    676 		printf("%s has a different serial number: %d %d\n",
    677 		       dev_name, serial_number, ci_label->serial_number);
    678 		fatal_error = 1;
    679 	}
    680 	if (mod_counter != ci_label->mod_counter) {
    681 		printf("%s has a different modfication count: %d %d\n",
    682 		       dev_name, mod_counter, ci_label->mod_counter);
    683 	}
    684 
    685 	if (row != ci_label->row) {
    686 		printf("Row out of alignment for: %s\n", dev_name);
    687 		fatal_error = 1;
    688 	}
    689 	if (column != ci_label->column) {
    690 		printf("Column out of alignment for: %s\n", dev_name);
    691 		fatal_error = 1;
    692 	}
    693 	if (raidPtr->numRow != ci_label->num_rows) {
    694 		printf("Number of rows do not match for: %s\n", dev_name);
    695 		fatal_error = 1;
    696 	}
    697 	if (raidPtr->numCol != ci_label->num_columns) {
    698 		printf("Number of columns do not match for: %s\n", dev_name);
    699 		fatal_error = 1;
    700 	}
    701 	if (ci_label->clean == 0) {
    702 		/* it's not clean, but that's not fatal */
    703 		printf("%s is not clean!\n", dev_name);
    704 	}
    705 	return(fatal_error);
    706 }
    707 
    708 
    709 /*
    710 
    711    rf_CheckLabels() - check all the component labels for consistency.
    712    Return an error if there is anything major amiss.
    713 
    714  */
    715 
    716 int
    717 rf_CheckLabels( raidPtr, cfgPtr )
    718 	RF_Raid_t *raidPtr;
    719 	RF_Config_t *cfgPtr;
    720 {
    721 	int r,c;
    722 	char *dev_name;
    723 	RF_ComponentLabel_t *ci_label;
    724 	int serial_number = 0;
    725 	int mod_number = 0;
    726 	int fatal_error = 0;
    727 	int mod_values[4];
    728 	int mod_count[4];
    729 	int ser_values[4];
    730 	int ser_count[4];
    731 	int num_ser;
    732 	int num_mod;
    733 	int i;
    734 	int found;
    735 	int hosed_row;
    736 	int hosed_column;
    737 	int too_fatal;
    738 	int parity_good;
    739 	int force;
    740 
    741 	hosed_row = -1;
    742 	hosed_column = -1;
    743 	too_fatal = 0;
    744 	force = cfgPtr->force;
    745 
    746 	/*
    747 	   We're going to try to be a little intelligent here.  If one
    748 	   component's label is bogus, and we can identify that it's the
    749 	   *only* one that's gone, we'll mark it as "failed" and allow
    750 	   the configuration to proceed.  This will be the *only* case
    751 	   that we'll proceed if there would be (otherwise) fatal errors.
    752 
    753 	   Basically we simply keep a count of how many components had
    754 	   what serial number.  If all but one agree, we simply mark
    755 	   the disagreeing component as being failed, and allow
    756 	   things to come up "normally".
    757 
    758 	   We do this first for serial numbers, and then for "mod_counter".
    759 
    760 	 */
    761 
    762 	num_ser = 0;
    763 	num_mod = 0;
    764 	for (r = 0; r < raidPtr->numRow && !fatal_error ; r++) {
    765 		for (c = 0; c < raidPtr->numCol; c++) {
    766 			ci_label = &raidPtr->raid_cinfo[r][c].ci_label;
    767 			found=0;
    768 			for(i=0;i<num_ser;i++) {
    769 				if (ser_values[i] == ci_label->serial_number) {
    770 					ser_count[i]++;
    771 					found=1;
    772 					break;
    773 				}
    774 			}
    775 			if (!found) {
    776 				ser_values[num_ser] = ci_label->serial_number;
    777 				ser_count[num_ser] = 1;
    778 				num_ser++;
    779 				if (num_ser>2) {
    780 					fatal_error = 1;
    781 					break;
    782 				}
    783 			}
    784 			found=0;
    785 			for(i=0;i<num_mod;i++) {
    786 				if (mod_values[i] == ci_label->mod_counter) {
    787 					mod_count[i]++;
    788 					found=1;
    789 					break;
    790 				}
    791 			}
    792 			if (!found) {
    793 			        mod_values[num_mod] = ci_label->mod_counter;
    794 				mod_count[num_mod] = 1;
    795 				num_mod++;
    796 				if (num_mod>2) {
    797 					fatal_error = 1;
    798 					break;
    799 				}
    800 			}
    801 		}
    802 	}
    803 #if DEBUG
    804 	printf("raid%d: Summary of serial numbers:\n", raidPtr->raidid);
    805 	for(i=0;i<num_ser;i++) {
    806 		printf("%d %d\n", ser_values[i], ser_count[i]);
    807 	}
    808 	printf("raid%d: Summary of mod counters:\n", raidPtr->raidid);
    809 	for(i=0;i<num_mod;i++) {
    810 		printf("%d %d\n", mod_values[i], mod_count[i]);
    811 	}
    812 #endif
    813 	serial_number = ser_values[0];
    814 	if (num_ser == 2) {
    815 		if ((ser_count[0] == 1) || (ser_count[1] == 1)) {
    816 			/* Locate the maverick component */
    817 			if (ser_count[1] > ser_count[0]) {
    818 				serial_number = ser_values[1];
    819 			}
    820 			for (r = 0; r < raidPtr->numRow; r++) {
    821 				for (c = 0; c < raidPtr->numCol; c++) {
    822 				ci_label = &raidPtr->raid_cinfo[r][c].ci_label;
    823 					if (serial_number !=
    824 					    ci_label->serial_number) {
    825 						hosed_row = r;
    826 						hosed_column = c;
    827 						break;
    828 					}
    829 				}
    830 			}
    831 			printf("Hosed component: %s\n",
    832 			       &cfgPtr->devnames[hosed_row][hosed_column][0]);
    833 			if (!force) {
    834 				/* we'll fail this component, as if there are
    835 				   other major errors, we arn't forcing things
    836 				   and we'll abort the config anyways */
    837 				raidPtr->Disks[hosed_row][hosed_column].status
    838 					= rf_ds_failed;
    839 				raidPtr->numFailures++;
    840 				raidPtr->status[hosed_row] = rf_rs_degraded;
    841 			}
    842 		} else {
    843 			too_fatal = 1;
    844 		}
    845 		if (cfgPtr->parityConfig == '0') {
    846 			/* We've identified two different serial numbers.
    847 			   RAID 0 can't cope with that, so we'll punt */
    848 			too_fatal = 1;
    849 		}
    850 
    851 	}
    852 
    853 	/* record the serial number for later.  If we bail later, setting
    854 	   this doesn't matter, otherwise we've got the best guess at the
    855 	   correct serial number */
    856 	raidPtr->serial_number = serial_number;
    857 
    858 	mod_number = mod_values[0];
    859 	if (num_mod == 2) {
    860 		if ((mod_count[0] == 1) || (mod_count[1] == 1)) {
    861 			/* Locate the maverick component */
    862 			if (mod_count[1] > mod_count[0]) {
    863 				mod_number = mod_values[1];
    864 			} else if (mod_count[1] < mod_count[0]) {
    865 				mod_number = mod_values[0];
    866 			} else {
    867 				/* counts of different modification values
    868 				   are the same.   Assume greater value is
    869 				   the correct one, all other things
    870 				   considered */
    871 				if (mod_values[0] > mod_values[1]) {
    872 					mod_number = mod_values[0];
    873 				} else {
    874 					mod_number = mod_values[1];
    875 				}
    876 
    877 			}
    878 			for (r = 0; r < raidPtr->numRow && !too_fatal ; r++) {
    879 				for (c = 0; c < raidPtr->numCol; c++) {
    880 					ci_label = &raidPtr->raid_cinfo[r][c].ci_label;
    881 					if (mod_number !=
    882 					    ci_label->mod_counter) {
    883 						if ( ( hosed_row == r ) &&
    884 						     ( hosed_column == c )) {
    885 							/* same one.  Can
    886 							   deal with it.  */
    887 						} else {
    888 							hosed_row = r;
    889 							hosed_column = c;
    890 							if (num_ser != 1) {
    891 								too_fatal = 1;
    892 								break;
    893 							}
    894 						}
    895 					}
    896 				}
    897 			}
    898 			printf("Hosed component: %s\n",
    899 			       &cfgPtr->devnames[hosed_row][hosed_column][0]);
    900 			if (!force) {
    901 				/* we'll fail this component, as if there are
    902 				   other major errors, we arn't forcing things
    903 				   and we'll abort the config anyways */
    904 				if (raidPtr->Disks[hosed_row][hosed_column].status != rf_ds_failed) {
    905 					raidPtr->Disks[hosed_row][hosed_column].status
    906 						= rf_ds_failed;
    907 					raidPtr->numFailures++;
    908 					raidPtr->status[hosed_row] = rf_rs_degraded;
    909 				}
    910 			}
    911 		} else {
    912 			too_fatal = 1;
    913 		}
    914 		if (cfgPtr->parityConfig == '0') {
    915 			/* We've identified two different mod counters.
    916 			   RAID 0 can't cope with that, so we'll punt */
    917 			too_fatal = 1;
    918 		}
    919 	}
    920 
    921 	raidPtr->mod_counter = mod_number;
    922 
    923 	if (too_fatal) {
    924 		/* we've had both a serial number mismatch, and a mod_counter
    925 		   mismatch -- and they involved two different components!!
    926 		   Bail -- make things fail so that the user must force
    927 		   the issue... */
    928 		hosed_row = -1;
    929 		hosed_column = -1;
    930 	}
    931 
    932 	if (num_ser > 2) {
    933 		printf("raid%d: Too many different serial numbers!\n",
    934 		       raidPtr->raidid);
    935 	}
    936 
    937 	if (num_mod > 2) {
    938 		printf("raid%d: Too many different mod counters!\n",
    939 		       raidPtr->raidid);
    940 	}
    941 
    942 	/* we start by assuming the parity will be good, and flee from
    943 	   that notion at the slightest sign of trouble */
    944 
    945 	parity_good = RF_RAID_CLEAN;
    946 	for (r = 0; r < raidPtr->numRow; r++) {
    947 		for (c = 0; c < raidPtr->numCol; c++) {
    948 			dev_name = &cfgPtr->devnames[r][c][0];
    949 			ci_label = &raidPtr->raid_cinfo[r][c].ci_label;
    950 
    951 			if ((r == hosed_row) && (c == hosed_column)) {
    952 				printf("raid%d: Ignoring %s\n",
    953 				       raidPtr->raidid, dev_name);
    954 			} else {
    955 				rf_print_label_status( raidPtr, r, c,
    956 						       dev_name, ci_label );
    957 				if (rf_check_label_vitals( raidPtr, r, c,
    958 							   dev_name, ci_label,
    959 							   serial_number,
    960 							   mod_number )) {
    961 					fatal_error = 1;
    962 				}
    963 				if (ci_label->clean != RF_RAID_CLEAN) {
    964 					parity_good = RF_RAID_DIRTY;
    965 				}
    966 			}
    967 		}
    968 	}
    969 	if (fatal_error) {
    970 		parity_good = RF_RAID_DIRTY;
    971 	}
    972 
    973 	/* we note the state of the parity */
    974 	raidPtr->parity_good = parity_good;
    975 
    976 	return(fatal_error);
    977 }
    978 
    979 int
    980 rf_add_hot_spare(raidPtr, sparePtr)
    981 	RF_Raid_t *raidPtr;
    982 	RF_SingleComponent_t *sparePtr;
    983 {
    984 	RF_RaidDisk_t *disks;
    985 	RF_DiskQueue_t *spareQueues;
    986 	int ret;
    987 	unsigned int bs;
    988 	int spare_number;
    989 
    990 #if 0
    991 	printf("Just in rf_add_hot_spare: %d\n",raidPtr->numSpare);
    992 	printf("Num col: %d\n",raidPtr->numCol);
    993 #endif
    994 	if (raidPtr->numSpare >= RF_MAXSPARE) {
    995 		RF_ERRORMSG1("Too many spares: %d\n", raidPtr->numSpare);
    996 		return(EINVAL);
    997 	}
    998 
    999 	RF_LOCK_MUTEX(raidPtr->mutex);
   1000 
   1001 	/* the beginning of the spares... */
   1002 	disks = &raidPtr->Disks[0][raidPtr->numCol];
   1003 
   1004 	spare_number = raidPtr->numSpare;
   1005 
   1006 	ret = rf_ConfigureDisk(raidPtr, sparePtr->component_name,
   1007 			       &disks[spare_number], 0,
   1008 			       raidPtr->numCol + spare_number);
   1009 
   1010 	if (ret)
   1011 		goto fail;
   1012 	if (disks[spare_number].status != rf_ds_optimal) {
   1013 		RF_ERRORMSG1("Warning: spare disk %s failed TUR\n",
   1014 			     sparePtr->component_name);
   1015 		ret=EINVAL;
   1016 		goto fail;
   1017 	} else {
   1018 		disks[spare_number].status = rf_ds_spare;
   1019 		DPRINTF6("Spare Disk %d: dev %s numBlocks %ld blockSize %d (%ld MB)\n", spare_number,
   1020 			 disks[spare_number].devname,
   1021 			 (long int) disks[spare_number].numBlocks,
   1022 			 disks[spare_number].blockSize,
   1023 			 (long int) disks[spare_number].numBlocks *
   1024 			 disks[spare_number].blockSize / 1024 / 1024);
   1025 	}
   1026 
   1027 
   1028 	/* check sizes and block sizes on the spare disk */
   1029 	bs = 1 << raidPtr->logBytesPerSector;
   1030 	if (disks[spare_number].blockSize != bs) {
   1031 		RF_ERRORMSG3("Block size of %d on spare disk %s is not the same as on other disks (%d)\n", disks[spare_number].blockSize, disks[spare_number].devname, bs);
   1032 		ret = EINVAL;
   1033 		goto fail;
   1034 	}
   1035 	if (disks[spare_number].numBlocks < raidPtr->sectorsPerDisk) {
   1036 		RF_ERRORMSG3("Spare disk %s (%d blocks) is too small to serve as a spare (need %ld blocks)\n",
   1037 			     disks[spare_number].devname,
   1038 			     disks[spare_number].blockSize,
   1039 			     (long int) raidPtr->sectorsPerDisk);
   1040 		ret = EINVAL;
   1041 		goto fail;
   1042 	} else {
   1043 		if (disks[spare_number].numBlocks >
   1044 		    raidPtr->sectorsPerDisk) {
   1045 			RF_ERRORMSG2("Warning: truncating spare disk %s to %ld blocks\n", disks[spare_number].devname,
   1046 				     (long int) raidPtr->sectorsPerDisk);
   1047 
   1048 			disks[spare_number].numBlocks = raidPtr->sectorsPerDisk;
   1049 		}
   1050 	}
   1051 
   1052 	spareQueues = &raidPtr->Queues[0][raidPtr->numCol];
   1053 	ret = rf_ConfigureDiskQueue( raidPtr, &spareQueues[spare_number],
   1054 				 0, raidPtr->numCol + spare_number,
   1055 				 raidPtr->qType,
   1056 				 raidPtr->sectorsPerDisk,
   1057 				 raidPtr->Disks[0][raidPtr->numCol +
   1058 						  spare_number].dev,
   1059 				 raidPtr->maxOutstanding,
   1060 				 &raidPtr->shutdownList,
   1061 				 raidPtr->cleanupList);
   1062 
   1063 
   1064 	raidPtr->numSpare++;
   1065 	RF_UNLOCK_MUTEX(raidPtr->mutex);
   1066 	return (0);
   1067 
   1068 fail:
   1069 	RF_UNLOCK_MUTEX(raidPtr->mutex);
   1070 	return(ret);
   1071 }
   1072 
   1073 int
   1074 rf_remove_hot_spare(raidPtr,sparePtr)
   1075 	RF_Raid_t *raidPtr;
   1076 	RF_SingleComponent_t *sparePtr;
   1077 {
   1078 	int spare_number;
   1079 
   1080 
   1081 	if (raidPtr->numSpare==0) {
   1082 		printf("No spares to remove!\n");
   1083 		return(EINVAL);
   1084 	}
   1085 
   1086 	spare_number = sparePtr->column;
   1087 
   1088 	return(EINVAL); /* XXX not implemented yet */
   1089 #if 0
   1090 	if (spare_number < 0 || spare_number > raidPtr->numSpare) {
   1091 		return(EINVAL);
   1092 	}
   1093 
   1094 	/* verify that this spare isn't in use... */
   1095 
   1096 
   1097 
   1098 
   1099 	/* it's gone.. */
   1100 
   1101 	raidPtr->numSpare--;
   1102 
   1103 	return(0);
   1104 #endif
   1105 }
   1106 
   1107 
   1108 int
   1109 rf_delete_component(raidPtr,component)
   1110 	RF_Raid_t *raidPtr;
   1111 	RF_SingleComponent_t *component;
   1112 {
   1113 	RF_RaidDisk_t *disks;
   1114 
   1115 	if ((component->row < 0) ||
   1116 	    (component->row >= raidPtr->numRow) ||
   1117 	    (component->column < 0) ||
   1118 	    (component->column >= raidPtr->numCol)) {
   1119 		return(EINVAL);
   1120 	}
   1121 
   1122 	disks = &raidPtr->Disks[component->row][component->column];
   1123 
   1124 	/* 1. This component must be marked as 'failed' */
   1125 
   1126 	return(EINVAL); /* Not implemented yet. */
   1127 }
   1128 
   1129 int
   1130 rf_incorporate_hot_spare(raidPtr,component)
   1131 	RF_Raid_t *raidPtr;
   1132 	RF_SingleComponent_t *component;
   1133 {
   1134 
   1135 	/* Issues here include how to 'move' this in if there is IO
   1136 	   taking place (e.g. component queues and such) */
   1137 
   1138 	return(EINVAL); /* Not implemented yet. */
   1139 }
   1140