Home | History | Annotate | Line # | Download | only in raidframe
rf_disks.c revision 1.12
      1 /*	$NetBSD: rf_disks.c,v 1.12 1999/08/13 03:41:56 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 
     77 #include <sys/types.h>
     78 #include <sys/param.h>
     79 #include <sys/systm.h>
     80 #include <sys/proc.h>
     81 #include <sys/ioctl.h>
     82 #include <sys/fcntl.h>
     83 #include <sys/vnode.h>
     84 
     85 /* XXX these should be in a header file somewhere */
     86 int raidlookup __P((char *, struct proc * p, struct vnode **));
     87 int raidwrite_component_label(dev_t, struct vnode *, RF_ComponentLabel_t *);
     88 int raidread_component_label(dev_t, struct vnode *, RF_ComponentLabel_t *);
     89 void rf_UnconfigureVnodes( RF_Raid_t * );
     90 int rf_CheckLabels( RF_Raid_t *, RF_Config_t *);
     91 
     92 #define DPRINTF6(a,b,c,d,e,f) if (rf_diskDebug) printf(a,b,c,d,e,f)
     93 #define DPRINTF7(a,b,c,d,e,f,g) if (rf_diskDebug) printf(a,b,c,d,e,f,g)
     94 
     95 /**************************************************************************
     96  *
     97  * initialize the disks comprising the array
     98  *
     99  * We want the spare disks to have regular row,col numbers so that we can
    100  * easily substitue a spare for a failed disk.  But, the driver code assumes
    101  * throughout that the array contains numRow by numCol _non-spare_ disks, so
    102  * it's not clear how to fit in the spares.  This is an unfortunate holdover
    103  * from raidSim.  The quick and dirty fix is to make row zero bigger than the
    104  * rest, and put all the spares in it.  This probably needs to get changed
    105  * eventually.
    106  *
    107  **************************************************************************/
    108 
    109 int
    110 rf_ConfigureDisks( listp, raidPtr, cfgPtr )
    111 	RF_ShutdownList_t **listp;
    112 	RF_Raid_t *raidPtr;
    113 	RF_Config_t *cfgPtr;
    114 {
    115 	RF_RaidDisk_t **disks;
    116 	RF_SectorCount_t min_numblks = (RF_SectorCount_t) 0x7FFFFFFFFFFFLL;
    117 	RF_RowCol_t r, c;
    118 	int bs, ret;
    119 	unsigned i, count, foundone = 0, numFailuresThisRow;
    120 	int num_rows_done, num_cols_done;
    121 	int force;
    122 
    123 	num_rows_done = 0;
    124 	num_cols_done = 0;
    125 	force = cfgPtr->force;
    126 
    127 	RF_CallocAndAdd(disks, raidPtr->numRow, sizeof(RF_RaidDisk_t *),
    128 			(RF_RaidDisk_t **), raidPtr->cleanupList);
    129 	if (disks == NULL) {
    130 		ret = ENOMEM;
    131 		goto fail;
    132 	}
    133 	raidPtr->Disks = disks;
    134 
    135 	/* get space for the device-specific stuff... */
    136 	RF_CallocAndAdd(raidPtr->raid_cinfo, raidPtr->numRow,
    137 	    sizeof(struct raidcinfo *), (struct raidcinfo **),
    138 	    raidPtr->cleanupList);
    139 	if (raidPtr->raid_cinfo == NULL) {
    140 		ret = ENOMEM;
    141 		goto fail;
    142 	}
    143 	for (r = 0; r < raidPtr->numRow; r++) {
    144 		numFailuresThisRow = 0;
    145 		/* We allocate RF_MAXSPARE on the first row so that we
    146 		   have room to do hot-swapping of spares */
    147 		RF_CallocAndAdd(disks[r], raidPtr->numCol
    148 				+ ((r == 0) ? RF_MAXSPARE : 0),
    149 				sizeof(RF_RaidDisk_t), (RF_RaidDisk_t *),
    150 				raidPtr->cleanupList);
    151 		if (disks[r] == NULL) {
    152 			ret = ENOMEM;
    153 			goto fail;
    154 		}
    155 		/* get more space for device specific stuff.. */
    156 		RF_CallocAndAdd(raidPtr->raid_cinfo[r],
    157 		    raidPtr->numCol + ((r == 0) ? raidPtr->numSpare : 0),
    158 		    sizeof(struct raidcinfo), (struct raidcinfo *),
    159 		    raidPtr->cleanupList);
    160 		if (raidPtr->raid_cinfo[r] == NULL) {
    161 			ret = ENOMEM;
    162 			goto fail;
    163 		}
    164 		for (c = 0; c < raidPtr->numCol; c++) {
    165 			ret = rf_ConfigureDisk(raidPtr,
    166 					       &cfgPtr->devnames[r][c][0],
    167 					       &disks[r][c], r, c);
    168 			if (ret)
    169 				goto fail;
    170 
    171 			if (disks[r][c].status == rf_ds_optimal) {
    172 				raidread_component_label(
    173 					 raidPtr->raid_cinfo[r][c].ci_dev,
    174 					 raidPtr->raid_cinfo[r][c].ci_vp,
    175 					 &raidPtr->raid_cinfo[r][c].ci_label);
    176 			}
    177 
    178 			if (disks[r][c].status != rf_ds_optimal) {
    179 				numFailuresThisRow++;
    180 			} else {
    181 				if (disks[r][c].numBlocks < min_numblks)
    182 					min_numblks = disks[r][c].numBlocks;
    183 				DPRINTF7("Disk at row %d col %d: dev %s numBlocks %ld blockSize %d (%ld MB)\n",
    184 				    r, c, disks[r][c].devname,
    185 				    (long int) disks[r][c].numBlocks,
    186 				    disks[r][c].blockSize,
    187 				    (long int) disks[r][c].numBlocks *
    188 					 disks[r][c].blockSize / 1024 / 1024);
    189 			}
    190 			num_cols_done++;
    191 		}
    192 		/* XXX fix for n-fault tolerant */
    193 		/* XXX this should probably check to see how many failures
    194 		   we can handle for this configuration! */
    195 		if (numFailuresThisRow > 0)
    196 			raidPtr->status[r] = rf_rs_degraded;
    197 		num_rows_done++;
    198 	}
    199 
    200 	/* all disks must be the same size & have the same block size, bs must
    201 	 * be a power of 2 */
    202 	bs = 0;
    203 	for (foundone = r = 0; !foundone && r < raidPtr->numRow; r++) {
    204 		for (c = 0; !foundone && c < raidPtr->numCol; c++) {
    205 			if (disks[r][c].status == rf_ds_optimal) {
    206 				bs = disks[r][c].blockSize;
    207 				foundone = 1;
    208 			}
    209 		}
    210 	}
    211 	if (!foundone) {
    212 		RF_ERRORMSG("RAIDFRAME: Did not find any live disks in the array.\n");
    213 		ret = EINVAL;
    214 		goto fail;
    215 	}
    216 	for (count = 0, i = 1; i; i <<= 1)
    217 		if (bs & i)
    218 			count++;
    219 	if (count != 1) {
    220 		RF_ERRORMSG1("Error: block size on disks (%d) must be a power of 2\n", bs);
    221 		ret = EINVAL;
    222 		goto fail;
    223 	}
    224 
    225 	if (rf_CheckLabels( raidPtr, cfgPtr )) {
    226 		printf("raid%d: There were fatal errors\n", raidPtr->raidid);
    227 		if (force != 0) {
    228 			printf("raid%d: Fatal errors being ignored.\n",
    229 			       raidPtr->raidid);
    230 		} else {
    231 			ret = EINVAL;
    232 			goto fail;
    233 		}
    234 	}
    235 
    236 	for (r = 0; r < raidPtr->numRow; r++) {
    237 		for (c = 0; c < raidPtr->numCol; c++) {
    238 			if (disks[r][c].status == rf_ds_optimal) {
    239 				if (disks[r][c].blockSize != bs) {
    240 					RF_ERRORMSG2("Error: block size of disk at r %d c %d different from disk at r 0 c 0\n", r, c);
    241 					ret = EINVAL;
    242 					goto fail;
    243 				}
    244 				if (disks[r][c].numBlocks != min_numblks) {
    245 					RF_ERRORMSG3("WARNING: truncating disk at r %d c %d to %d blocks\n",
    246 					    r, c, (int) min_numblks);
    247 					disks[r][c].numBlocks = min_numblks;
    248 				}
    249 			}
    250 		}
    251 	}
    252 
    253 	raidPtr->sectorsPerDisk = min_numblks;
    254 	raidPtr->logBytesPerSector = ffs(bs) - 1;
    255 	raidPtr->bytesPerSector = bs;
    256 	raidPtr->sectorMask = bs - 1;
    257 	return (0);
    258 
    259 fail:
    260 
    261 	rf_UnconfigureVnodes( raidPtr );
    262 
    263 	return (ret);
    264 }
    265 
    266 
    267 /****************************************************************************
    268  * set up the data structures describing the spare disks in the array
    269  * recall from the above comment that the spare disk descriptors are stored
    270  * in row zero, which is specially expanded to hold them.
    271  ****************************************************************************/
    272 int
    273 rf_ConfigureSpareDisks( listp, raidPtr, cfgPtr )
    274 	RF_ShutdownList_t ** listp;
    275 	RF_Raid_t * raidPtr;
    276 	RF_Config_t * cfgPtr;
    277 {
    278 	int     i, ret;
    279 	unsigned int bs;
    280 	RF_RaidDisk_t *disks;
    281 	int     num_spares_done;
    282 
    283 	num_spares_done = 0;
    284 
    285 	/* The space for the spares should have already been allocated by
    286 	 * ConfigureDisks() */
    287 
    288 	disks = &raidPtr->Disks[0][raidPtr->numCol];
    289 	for (i = 0; i < raidPtr->numSpare; i++) {
    290 		ret = rf_ConfigureDisk(raidPtr, &cfgPtr->spare_names[i][0],
    291 				       &disks[i], 0, raidPtr->numCol + i);
    292 		if (ret)
    293 			goto fail;
    294 		if (disks[i].status != rf_ds_optimal) {
    295 			RF_ERRORMSG1("Warning: spare disk %s failed TUR\n",
    296 				     &cfgPtr->spare_names[i][0]);
    297 		} else {
    298 			disks[i].status = rf_ds_spare;	/* change status to
    299 							 * spare */
    300 			DPRINTF6("Spare Disk %d: dev %s numBlocks %ld blockSize %d (%ld MB)\n", i,
    301 			    disks[i].devname,
    302 			    (long int) disks[i].numBlocks, disks[i].blockSize,
    303 			    (long int) disks[i].numBlocks *
    304 				 disks[i].blockSize / 1024 / 1024);
    305 		}
    306 		num_spares_done++;
    307 	}
    308 
    309 	/* check sizes and block sizes on spare disks */
    310 	bs = 1 << raidPtr->logBytesPerSector;
    311 	for (i = 0; i < raidPtr->numSpare; i++) {
    312 		if (disks[i].blockSize != bs) {
    313 			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);
    314 			ret = EINVAL;
    315 			goto fail;
    316 		}
    317 		if (disks[i].numBlocks < raidPtr->sectorsPerDisk) {
    318 			RF_ERRORMSG3("Spare disk %s (%d blocks) is too small to serve as a spare (need %ld blocks)\n",
    319 				     disks[i].devname, disks[i].blockSize,
    320 				     (long int) raidPtr->sectorsPerDisk);
    321 			ret = EINVAL;
    322 			goto fail;
    323 		} else
    324 			if (disks[i].numBlocks > raidPtr->sectorsPerDisk) {
    325 				RF_ERRORMSG2("Warning: truncating spare disk %s to %ld blocks\n", disks[i].devname, (long int) raidPtr->sectorsPerDisk);
    326 
    327 				disks[i].numBlocks = raidPtr->sectorsPerDisk;
    328 			}
    329 	}
    330 
    331 	return (0);
    332 
    333 fail:
    334 
    335 	/* Release the hold on the main components.  We've failed to allocate
    336 	 * a spare, and since we're failing, we need to free things..
    337 
    338 	 XXX failing to allocate a spare is *not* that big of a deal...
    339 	 We *can* survive without it, if need be, esp. if we get hot
    340 	 adding working.
    341 
    342 	 If we don't fail out here, then we need a way to remove this spare...
    343 	 that should be easier to do here than if we are "live"...
    344 
    345 	 */
    346 
    347 	rf_UnconfigureVnodes( raidPtr );
    348 
    349 	return (ret);
    350 }
    351 
    352 
    353 
    354 /* configure a single disk in the array */
    355 int
    356 rf_ConfigureDisk(raidPtr, buf, diskPtr, row, col)
    357 	RF_Raid_t *raidPtr;
    358 	char   *buf;
    359 	RF_RaidDisk_t *diskPtr;
    360 	RF_RowCol_t row;
    361 	RF_RowCol_t col;
    362 {
    363 	char   *p;
    364 	int     retcode;
    365 
    366 	struct partinfo dpart;
    367 	struct vnode *vp;
    368 	struct vattr va;
    369 	struct proc *proc;
    370 	int     error;
    371 
    372 	retcode = 0;
    373 	p = rf_find_non_white(buf);
    374 	if (p[strlen(p) - 1] == '\n') {
    375 		/* strip off the newline */
    376 		p[strlen(p) - 1] = '\0';
    377 	}
    378 	(void) strcpy(diskPtr->devname, p);
    379 
    380 	proc = raidPtr->proc;	/* XXX Yes, this is not nice.. */
    381 
    382 	/* Let's start by claiming the component is fine and well... */
    383 	diskPtr->status = rf_ds_optimal;
    384 
    385 	raidPtr->raid_cinfo[row][col].ci_vp = NULL;
    386 	raidPtr->raid_cinfo[row][col].ci_dev = NULL;
    387 
    388 	error = raidlookup(diskPtr->devname, proc, &vp);
    389 	if (error) {
    390 		printf("raidlookup on device: %s failed!\n", diskPtr->devname);
    391 		if (error == ENXIO) {
    392 			/* the component isn't there... must be dead :-( */
    393 			diskPtr->status = rf_ds_failed;
    394 		} else {
    395 			return (error);
    396 		}
    397 	}
    398 	if (diskPtr->status == rf_ds_optimal) {
    399 
    400 		if ((error = VOP_GETATTR(vp, &va, proc->p_ucred, proc)) != 0) {
    401 			return (error);
    402 		}
    403 		error = VOP_IOCTL(vp, DIOCGPART, (caddr_t) & dpart,
    404 				  FREAD, proc->p_ucred, proc);
    405 		if (error) {
    406 			return (error);
    407 		}
    408 
    409 		diskPtr->blockSize = dpart.disklab->d_secsize;
    410 
    411 		diskPtr->numBlocks = dpart.part->p_size - rf_protectedSectors;
    412 
    413 		raidPtr->raid_cinfo[row][col].ci_vp = vp;
    414 		raidPtr->raid_cinfo[row][col].ci_dev = va.va_rdev;
    415 
    416 		diskPtr->dev = va.va_rdev;
    417 
    418 		/* we allow the user to specify that only a fraction of the
    419 		 * disks should be used this is just for debug:  it speeds up
    420 		 * the parity scan */
    421 		diskPtr->numBlocks = diskPtr->numBlocks *
    422 			rf_sizePercentage / 100;
    423 	}
    424 	return (0);
    425 }
    426 
    427 static void rf_print_label_status( RF_Raid_t *, int, int, char *,
    428 				  RF_ComponentLabel_t *);
    429 
    430 static void
    431 rf_print_label_status( raidPtr, row, column, dev_name, ci_label )
    432 	RF_Raid_t *raidPtr;
    433 	int row;
    434 	int column;
    435 	char *dev_name;
    436 	RF_ComponentLabel_t *ci_label;
    437 {
    438 
    439 	printf("raid%d: Component %s being configured at row: %d col: %d\n",
    440 	       raidPtr->raidid, dev_name, row, column );
    441 	printf("         Row: %d Column: %d Num Rows: %d Num Columns: %d\n",
    442 	       ci_label->row, ci_label->column,
    443 	       ci_label->num_rows, ci_label->num_columns);
    444 	printf("         Version: %d Serial Number: %d Mod Counter: %d\n",
    445 	       ci_label->version, ci_label->serial_number,
    446 	       ci_label->mod_counter);
    447 	printf("         Clean: %s Status: %d\n",
    448 	       ci_label->clean ? "Yes" : "No", ci_label->status );
    449 }
    450 
    451 static int rf_check_label_vitals( RF_Raid_t *, int, int, char *,
    452 				  RF_ComponentLabel_t *, int, int );
    453 static int rf_check_label_vitals( raidPtr, row, column, dev_name, ci_label,
    454 				  serial_number, mod_counter )
    455 	RF_Raid_t *raidPtr;
    456 	int row;
    457 	int column;
    458 	char *dev_name;
    459 	RF_ComponentLabel_t *ci_label;
    460 	int serial_number;
    461 	int mod_counter;
    462 {
    463 	int fatal_error = 0;
    464 
    465 	if (serial_number != ci_label->serial_number) {
    466 		printf("%s has a different serial number: %d %d\n",
    467 		       dev_name, serial_number, ci_label->serial_number);
    468 		fatal_error = 1;
    469 	}
    470 	if (mod_counter != ci_label->mod_counter) {
    471 		printf("%s has a different modfication count: %d %d\n",
    472 		       dev_name, mod_counter, ci_label->mod_counter);
    473 	}
    474 
    475 	if (row != ci_label->row) {
    476 		printf("Row out of alignment for: %s\n", dev_name);
    477 		fatal_error = 1;
    478 	}
    479 	if (column != ci_label->column) {
    480 		printf("Column out of alignment for: %s\n", dev_name);
    481 		fatal_error = 1;
    482 	}
    483 	if (raidPtr->numRow != ci_label->num_rows) {
    484 		printf("Number of rows do not match for: %s\n", dev_name);
    485 		fatal_error = 1;
    486 	}
    487 	if (raidPtr->numCol != ci_label->num_columns) {
    488 		printf("Number of columns do not match for: %s\n", dev_name);
    489 		fatal_error = 1;
    490 	}
    491 	if (ci_label->clean == 0) {
    492 		/* it's not clean, but that's not fatal */
    493 		printf("%s is not clean!\n", dev_name);
    494 	}
    495 	return(fatal_error);
    496 }
    497 
    498 
    499 /*
    500 
    501    rf_CheckLabels() - check all the component labels for consistency.
    502    Return an error if there is anything major amiss.
    503 
    504  */
    505 
    506 int
    507 rf_CheckLabels( raidPtr, cfgPtr )
    508 	RF_Raid_t *raidPtr;
    509 	RF_Config_t *cfgPtr;
    510 {
    511 	int r,c;
    512 	char *dev_name;
    513 	RF_ComponentLabel_t *ci_label;
    514 	int serial_number = 0;
    515 	int mod_number = 0;
    516 	int fatal_error = 0;
    517 	int mod_values[4];
    518 	int mod_count[4];
    519 	int ser_values[4];
    520 	int ser_count[4];
    521 	int num_ser;
    522 	int num_mod;
    523 	int i;
    524 	int found;
    525 	int hosed_row;
    526 	int hosed_column;
    527 	int too_fatal;
    528 	int parity_good;
    529 	int force;
    530 
    531 	hosed_row = -1;
    532 	hosed_column = -1;
    533 	too_fatal = 0;
    534 	force = cfgPtr->force;
    535 
    536 	/*
    537 	   We're going to try to be a little intelligent here.  If one
    538 	   component's label is bogus, and we can identify that it's the
    539 	   *only* one that's gone, we'll mark it as "failed" and allow
    540 	   the configuration to proceed.  This will be the *only* case
    541 	   that we'll proceed if there would be (otherwise) fatal errors.
    542 
    543 	   Basically we simply keep a count of how many components had
    544 	   what serial number.  If all but one agree, we simply mark
    545 	   the disagreeing component as being failed, and allow
    546 	   things to come up "normally".
    547 
    548 	   We do this first for serial numbers, and then for "mod_counter".
    549 
    550 	 */
    551 
    552 	num_ser = 0;
    553 	num_mod = 0;
    554 	for (r = 0; r < raidPtr->numRow && !fatal_error ; r++) {
    555 		for (c = 0; c < raidPtr->numCol; c++) {
    556 			ci_label = &raidPtr->raid_cinfo[r][c].ci_label;
    557 			found=0;
    558 			for(i=0;i<num_ser;i++) {
    559 				if (ser_values[i] == ci_label->serial_number) {
    560 					ser_count[i]++;
    561 					found=1;
    562 					break;
    563 				}
    564 			}
    565 			if (!found) {
    566 				ser_values[num_ser] = ci_label->serial_number;
    567 				ser_count[num_ser] = 1;
    568 				num_ser++;
    569 				if (num_ser>2) {
    570 					fatal_error = 1;
    571 					break;
    572 				}
    573 			}
    574 			found=0;
    575 			for(i=0;i<num_mod;i++) {
    576 				if (mod_values[i] == ci_label->mod_counter) {
    577 					mod_count[i]++;
    578 					found=1;
    579 					break;
    580 				}
    581 			}
    582 			if (!found) {
    583 			        mod_values[num_mod] = ci_label->mod_counter;
    584 				mod_count[num_mod] = 1;
    585 				num_mod++;
    586 				if (num_mod>2) {
    587 					fatal_error = 1;
    588 					break;
    589 				}
    590 			}
    591 		}
    592 	}
    593 #if DEBUG
    594 	printf("raid%d: Summary of serial numbers:\n", raidPtr->raidid);
    595 	for(i=0;i<num_ser;i++) {
    596 		printf("%d %d\n", ser_values[i], ser_count[i]);
    597 	}
    598 	printf("raid%d: Summary of mod counters:\n", raidPtr->raidid);
    599 	for(i=0;i<num_mod;i++) {
    600 		printf("%d %d\n", mod_values[i], mod_count[i]);
    601 	}
    602 #endif
    603 	serial_number = ser_values[0];
    604 	if (num_ser == 2) {
    605 		if ((ser_count[0] == 1) || (ser_count[1] == 1)) {
    606 			/* Locate the maverick component */
    607 			if (ser_count[1] > ser_count[0]) {
    608 				serial_number = ser_values[1];
    609 			}
    610 			for (r = 0; r < raidPtr->numRow; r++) {
    611 				for (c = 0; c < raidPtr->numCol; c++) {
    612 				ci_label = &raidPtr->raid_cinfo[r][c].ci_label;
    613 					if (serial_number !=
    614 					    ci_label->serial_number) {
    615 						hosed_row = r;
    616 						hosed_column = c;
    617 						break;
    618 					}
    619 				}
    620 			}
    621 			printf("Hosed component: %s\n",
    622 			       &cfgPtr->devnames[hosed_row][hosed_column][0]);
    623 			if (!force) {
    624 				/* we'll fail this component, as if there are
    625 				   other major errors, we arn't forcing things
    626 				   and we'll abort the config anyways */
    627 				raidPtr->Disks[hosed_row][hosed_column].status
    628 					= rf_ds_failed;
    629 				raidPtr->numFailures++;
    630 				raidPtr->status[hosed_row] = rf_rs_degraded;
    631 			}
    632 		} else {
    633 			too_fatal = 1;
    634 		}
    635 		if (cfgPtr->parityConfig == '0') {
    636 			/* We've identified two different serial numbers.
    637 			   RAID 0 can't cope with that, so we'll punt */
    638 			too_fatal = 1;
    639 		}
    640 
    641 	}
    642 
    643 	/* record the serial number for later.  If we bail later, setting
    644 	   this doesn't matter, otherwise we've got the best guess at the
    645 	   correct serial number */
    646 	raidPtr->serial_number = serial_number;
    647 
    648 	mod_number = mod_values[0];
    649 	if (num_mod == 2) {
    650 		if ((mod_count[0] == 1) || (mod_count[1] == 1)) {
    651 			/* Locate the maverick component */
    652 			if (mod_count[1] > mod_count[0]) {
    653 				mod_number = mod_values[1];
    654 			} else if (mod_count[1] < mod_count[0]) {
    655 				mod_number = mod_values[0];
    656 			} else {
    657 				/* counts of different modification values
    658 				   are the same.   Assume greater value is
    659 				   the correct one, all other things
    660 				   considered */
    661 				if (mod_values[0] > mod_values[1]) {
    662 					mod_number = mod_values[0];
    663 				} else {
    664 					mod_number = mod_values[1];
    665 				}
    666 
    667 			}
    668 			for (r = 0; r < raidPtr->numRow && !too_fatal ; r++) {
    669 				for (c = 0; c < raidPtr->numCol; c++) {
    670 					ci_label = &raidPtr->raid_cinfo[r][c].ci_label;
    671 					if (mod_number !=
    672 					    ci_label->mod_counter) {
    673 						if ( ( hosed_row == r ) &&
    674 						     ( hosed_column == c )) {
    675 							/* same one.  Can
    676 							   deal with it.  */
    677 						} else {
    678 							hosed_row = r;
    679 							hosed_column = c;
    680 							if (num_ser != 1) {
    681 								too_fatal = 1;
    682 								break;
    683 							}
    684 						}
    685 					}
    686 				}
    687 			}
    688 			printf("Hosed component: %s\n",
    689 			       &cfgPtr->devnames[hosed_row][hosed_column][0]);
    690 			if (!force) {
    691 				/* we'll fail this component, as if there are
    692 				   other major errors, we arn't forcing things
    693 				   and we'll abort the config anyways */
    694 				if (raidPtr->Disks[hosed_row][hosed_column].status != rf_ds_failed) {
    695 					raidPtr->Disks[hosed_row][hosed_column].status
    696 						= rf_ds_failed;
    697 					raidPtr->numFailures++;
    698 					raidPtr->status[hosed_row] = rf_rs_degraded;
    699 				}
    700 			}
    701 		} else {
    702 			too_fatal = 1;
    703 		}
    704 		if (cfgPtr->parityConfig == '0') {
    705 			/* We've identified two different mod counters.
    706 			   RAID 0 can't cope with that, so we'll punt */
    707 			too_fatal = 1;
    708 		}
    709 	}
    710 
    711 	raidPtr->mod_counter = mod_number;
    712 
    713 	if (too_fatal) {
    714 		/* we've had both a serial number mismatch, and a mod_counter
    715 		   mismatch -- and they involved two different components!!
    716 		   Bail -- make things fail so that the user must force
    717 		   the issue... */
    718 		hosed_row = -1;
    719 		hosed_column = -1;
    720 	}
    721 
    722 	if (num_ser > 2) {
    723 		printf("raid%d: Too many different serial numbers!\n",
    724 		       raidPtr->raidid);
    725 	}
    726 
    727 	if (num_mod > 2) {
    728 		printf("raid%d: Too many different mod counters!\n",
    729 		       raidPtr->raidid);
    730 	}
    731 
    732 	/* we start by assuming the parity will be good, and flee from
    733 	   that notion at the slightest sign of trouble */
    734 
    735 	parity_good = RF_RAID_CLEAN;
    736 	for (r = 0; r < raidPtr->numRow; r++) {
    737 		for (c = 0; c < raidPtr->numCol; c++) {
    738 			dev_name = &cfgPtr->devnames[r][c][0];
    739 			ci_label = &raidPtr->raid_cinfo[r][c].ci_label;
    740 
    741 			if ((r == hosed_row) && (c == hosed_column)) {
    742 				printf("raid%d: Ignoring %s\n",
    743 				       raidPtr->raidid, dev_name);
    744 			} else {
    745 				rf_print_label_status( raidPtr, r, c,
    746 						       dev_name, ci_label );
    747 				if (rf_check_label_vitals( raidPtr, r, c,
    748 							   dev_name, ci_label,
    749 							   serial_number,
    750 							   mod_number )) {
    751 					fatal_error = 1;
    752 				}
    753 				if (ci_label->clean != RF_RAID_CLEAN) {
    754 					parity_good = RF_RAID_DIRTY;
    755 				}
    756 			}
    757 		}
    758 	}
    759 	if (fatal_error) {
    760 		parity_good = RF_RAID_DIRTY;
    761 	}
    762 
    763 	/* we note the state of the parity */
    764 	raidPtr->parity_good = parity_good;
    765 
    766 	return(fatal_error);
    767 }
    768 
    769 int config_disk_queue(RF_Raid_t *, RF_DiskQueue_t *, RF_RowCol_t,
    770 		      RF_RowCol_t, RF_DiskQueueSW_t *,
    771 		      RF_SectorCount_t, dev_t, int,
    772 		      RF_ShutdownList_t **,
    773 		      RF_AllocListElem_t *);
    774 int rf_add_hot_spare(RF_Raid_t *, RF_SingleComponent_t *);
    775 int
    776 rf_add_hot_spare(raidPtr, sparePtr)
    777 	RF_Raid_t *raidPtr;
    778 	RF_SingleComponent_t *sparePtr;
    779 {
    780 	RF_RaidDisk_t *disks;
    781 	RF_DiskQueue_t *spareQueues;
    782 	int ret;
    783 	unsigned int bs;
    784 	int spare_number;
    785 
    786 	printf("Just in rf_add_hot_spare: %d\n",raidPtr->numSpare);
    787 	printf("Num col: %d\n",raidPtr->numCol);
    788 	if (raidPtr->numSpare >= RF_MAXSPARE) {
    789 		RF_ERRORMSG1("Too many spares: %d\n", raidPtr->numSpare);
    790 		return(EINVAL);
    791 	}
    792 
    793 	RF_LOCK_MUTEX(raidPtr->mutex);
    794 
    795 	/* the beginning of the spares... */
    796 	disks = &raidPtr->Disks[0][raidPtr->numCol];
    797 
    798 	spare_number = raidPtr->numSpare;
    799 
    800 	ret = rf_ConfigureDisk(raidPtr, sparePtr->component_name,
    801 			       &disks[spare_number], 0,
    802 			       raidPtr->numCol + spare_number);
    803 
    804 	if (ret)
    805 		goto fail;
    806 	if (disks[spare_number].status != rf_ds_optimal) {
    807 		RF_ERRORMSG1("Warning: spare disk %s failed TUR\n",
    808 			     sparePtr->component_name);
    809 		ret=EINVAL;
    810 		goto fail;
    811 	} else {
    812 		disks[spare_number].status = rf_ds_spare;
    813 		DPRINTF6("Spare Disk %d: dev %s numBlocks %ld blockSize %d (%ld MB)\n", spare_number,
    814 			 disks[spare_number].devname,
    815 			 (long int) disks[spare_number].numBlocks,
    816 			 disks[spare_number].blockSize,
    817 			 (long int) disks[spare_number].numBlocks *
    818 			 disks[spare_number].blockSize / 1024 / 1024);
    819 	}
    820 
    821 
    822 	/* check sizes and block sizes on the spare disk */
    823 	bs = 1 << raidPtr->logBytesPerSector;
    824 	if (disks[spare_number].blockSize != bs) {
    825 		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);
    826 		ret = EINVAL;
    827 		goto fail;
    828 	}
    829 	if (disks[spare_number].numBlocks < raidPtr->sectorsPerDisk) {
    830 		RF_ERRORMSG3("Spare disk %s (%d blocks) is too small to serve as a spare (need %ld blocks)\n",
    831 			     disks[spare_number].devname,
    832 			     disks[spare_number].blockSize,
    833 			     (long int) raidPtr->sectorsPerDisk);
    834 		ret = EINVAL;
    835 		goto fail;
    836 	} else {
    837 		if (disks[spare_number].numBlocks >
    838 		    raidPtr->sectorsPerDisk) {
    839 			RF_ERRORMSG2("Warning: truncating spare disk %s to %ld blocks\n", disks[spare_number].devname,
    840 				     (long int) raidPtr->sectorsPerDisk);
    841 
    842 			disks[spare_number].numBlocks = raidPtr->sectorsPerDisk;
    843 		}
    844 	}
    845 
    846 	spareQueues = &raidPtr->Queues[0][raidPtr->numCol];
    847 	ret = config_disk_queue( raidPtr, &spareQueues[spare_number],
    848 				 0, raidPtr->numCol + spare_number,
    849 				 raidPtr->Queues[0][0].qPtr, /* XXX */
    850 				 raidPtr->sectorsPerDisk,
    851 				 raidPtr->Disks[0][raidPtr->numCol + spare_number].dev,
    852 				 raidPtr->Queues[0][0].maxOutstanding, /* XXX */
    853 				 &raidPtr->shutdownList,
    854 				 raidPtr->cleanupList);
    855 
    856 
    857 	raidPtr->numSpare++;
    858 	RF_UNLOCK_MUTEX(raidPtr->mutex);
    859 	return (0);
    860 
    861 fail:
    862 	RF_UNLOCK_MUTEX(raidPtr->mutex);
    863 	return(ret);
    864 }
    865 
    866 int
    867 rf_remove_hot_spare(raidPtr,sparePtr)
    868 	RF_Raid_t *raidPtr;
    869 	RF_SingleComponent_t *sparePtr;
    870 {
    871 	int spare_number;
    872 
    873 
    874 	if (raidPtr->numSpare==0) {
    875 		printf("No spares to remove!\n");
    876 		return(EINVAL);
    877 	}
    878 
    879 	spare_number = sparePtr->column;
    880 
    881 	return(EINVAL); /* XXX not implemented yet */
    882 #if 0
    883 	if (spare_number < 0 || spare_number > raidPtr->numSpare) {
    884 		return(EINVAL);
    885 	}
    886 
    887 	/* verify that this spare isn't in use... */
    888 
    889 
    890 
    891 
    892 	/* it's gone.. */
    893 
    894 	raidPtr->numSpare--;
    895 
    896 	return(0);
    897 #endif
    898 }
    899 
    900 
    901