File: creatrad.cpp

package info (click to toggle)
raidutils 0.0.6-23
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 10,840 kB
  • sloc: cpp: 39,794; ansic: 22,774; sh: 8,306; makefile: 19
file content (802 lines) | stat: -rw-r--r-- 23,527 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
/* Copyright (c) 1996-2004, Adaptec Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * - Neither the name of the Adaptec Corporation nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/****************************************************************************
*
* Created:  7/20/98
*
*****************************************************************************
*
* File Name:		CreatRad.cpp
* Module:
* Contributors:		Lee Page
* Description:
* Version Control:
*
* $Revision$
* $NoKeywords: $
* $Log$
* Revision 1.1.1.1  2004-04-29 10:20:12  bap
* Imported upstream version 0.0.4. 
*
*****************************************************************************/

/*** INCLUDES ***/
#include <stdio.h>
#include "creatrad.hpp"
#include "intlist.hpp"
#include "rustring.h"
#include "rscenum.h"

extern char* EventStrings[];
/*** CONSTANTS ***/
/*** TYPES ***/
/*** STATIC DATA ***/
/*** MACROS ***/
/*** PROTOTYPES ***/
/*** FUNCTIONS ***/

Create_Raid::Create_Raid(
		SCSI_Addr_List	*addresses,
		Raid_Type		new_Raid_Type,
		uLONG			size_of_Stripe,
		uLONG			raid_Size_in_Blocks,
		bool			nobuildOption,
		bool			ignoreNonfatalErrorsOption,
		int				numDrivesPerArray,
		SCSI_Addr_List	*compsOmit
		):
		raid_Type( new_Raid_Type ),
		stripe_Size( size_of_Stripe ),
		address_List( addresses ),
		desired_Raid_Size_in_Blocks( raid_Size_in_Blocks ),
		nobuild(nobuildOption),
		ignoreNonfatalErrors(ignoreNonfatalErrorsOption),
		drivesPerArray (numDrivesPerArray),
		comps_Omit (compsOmit)
	{
	ENTER( "Create_Raid::Create_Raid(" );
	EXIT();
	}

Create_Raid::Create_Raid( const Create_Raid &new_Create_Raid ):
			raid_Type( new_Create_Raid.raid_Type ),
			stripe_Size( new_Create_Raid.stripe_Size ),
			address_List( new_Create_Raid.address_List ),
			desired_Raid_Size_in_Blocks( new_Create_Raid.desired_Raid_Size_in_Blocks ),
			nobuild(new_Create_Raid.nobuild),
			ignoreNonfatalErrors(new_Create_Raid.ignoreNonfatalErrors),
			drivesPerArray (new_Create_Raid.drivesPerArray),
			comps_Omit (new_Create_Raid.comps_Omit)
	{
	ENTER( "Create_Raid::Create_Raid( const Create_Raid &new_Create_Raid ):" );
	EXIT();
	}

Create_Raid::~Create_Raid()
	{
	ENTER( "Create_Raid::~Create_Raid()" );
	EXIT();
	}

Command::Dpt_Error Create_Raid::Create(Raid_Type raidType,
				int level,
				Int_List *componentList,
				uLONG stripeSize,
				uLONG desiredRaidSizeInBlocks,
				DPT_TAG_T *this_RAID_Tag)
{
	ENTER( "Command::Dpt_Error	Create_Raid::Create (Raid_Type raidType, int level, Int_List *componentList, uLONG stripeSize, uLONG desiredRaidSizeInBlocks, this_RAID_Tag)");
	Dpt_Error		err;
	DPT_TAG_T		this_HBAs_Tag;
	bool			hba_Index_Found;
	raidCompList_S	component;
   memset (&component, 0, sizeof(raidCompList_S));

	// verify the target hba
	this_HBAs_Tag = Get_HBA_by_Index (targetHba, &hba_Index_Found);
	if ( this_RAID_Tag != (DPT_TAG_T *) NULL)
	{
		*this_RAID_Tag = (DPT_TAG_T) NULL;
	}

	if( !hba_Index_Found )
	{
		err	= Command::Dpt_Error::DPT_CMD_ERR_CANT_FIND_HBA_INDEX;
	}

	// Verify RAID-5 is supported by the hba
	if ((!err.Is_Error()) && (raidType == RAID_TYPE_5))
	{
		err = engine->Send( MSG_GET_INFO, this_HBAs_Tag);
		dptHBAinfo_S *hba_Info = engine->hbaInfo_P;
		if (!(hba_Info->raidSupport & FLG_RAID_5))
		{
			err = Command::Dpt_Error::DPT_ERR_RAID_NOT_SUPPORTED;
		}
	}

	if (!err.Is_Error())
	{
		raidHeader_S	raid_Hdr;
      memset (&raid_Hdr, 0, sizeof(raidHeader_S));

		// set up the RAID header stuff
  		raid_Hdr.control = 0; // FLG_RCTL_ADDR;

		raid_Hdr.refNum = raidType;
		// if dual level array, don't limit the stripe size on top level
		if (level == 1) 
			stripeSize = 0;
		else if (stripeSize == 0)	// If zero, use the defaults
		{
			switch (raidType)
			{
            case RAID_TYPE_0:
               // get the default size from the hba
               err = engine->Send(MSG_RAID_GET_LIMITS, this_HBAs_Tag);
        			if (!err.Is_Error())
               {
				      dptArrayLimits_S limits;
                  engine->Extract(&limits, sizeof(dptArrayLimits_S));
      				int RAID0Stripe = limits.getR0defStripe();
				      // In case we got garbage
      				if (RAID0Stripe > 512) RAID0Stripe = 64;
                  // divide blocks in half ...
                  RAID0Stripe >>= 1;
                  // and multiply to get Ks
                  stripeSize = RAID0Stripe * 1024L;
               }
               break;
				case RAID_TYPE_1:
					// stripeSize = 128 * 1024L;
					stripeSize = 64 * 1024L;
					break;
				case RAID_TYPE_5:
               // get the default size from the hba
               err = engine->Send(MSG_RAID_GET_LIMITS, this_HBAs_Tag);
        			if (!err.Is_Error())
               {
				      dptArrayLimits_S limits;
                  engine->Extract(&limits, sizeof(dptArrayLimits_S));
                  // this gets the stripe size in BLOCKS
      				int RAID5Stripe = limits.getR5defStripe();
				      // In case we got garbage
      				if(RAID5Stripe > 512) RAID5Stripe = 64;
                  // divide blocks in half ...
                  RAID5Stripe >>= 1;
                  // and multiply to get Ks
                  stripeSize = RAID5Stripe * 1024L;
               }
					break;
				default:
					stripeSize = 64 * 1024L;
					break;
			}
		}
      if (!err.Is_Error())
      {
   		raid_Hdr.stripeSize	= stripeSize / 512L;
	   	// if this "size" is zero, it means "use the maximum".
		   raid_Hdr.size = desiredRaidSizeInBlocks;

   		// set up the component header.
	   	component.startLBA = 0;
		   component.stripeSize = stripeSize / 512L;
   		component.numStripes = 0;

	   	engine->Reset ();
		   engine->Insert (&raid_Hdr, sizeof(raidHeader_S));

   		while (componentList->num_Left())
	   	{
		   	component.tag = componentList->get_Next_Item();
			   engine->Insert (&component, sizeof(raidCompList_S));
   		}
      }
	}

	if( !err.Is_Error() )
	{
		err = engine->Send( MSG_RAID_NEW,
			(level == 0) ? this_HBAs_Tag : (DPT_TAG_T) NULL);
		if( !err.Is_Error()
		 && ((raidType == RAID_TYPE_5) || (raidType == RAID_TYPE_1))
		 && (this_RAID_Tag != (DPT_TAG_T *)NULL))
		{
			engine->Extract (this_RAID_Tag, sizeof(DPT_TAG_T));
		}
		if( !err.Is_Error() && raidType == RAID_TYPE_1 && !nobuild)
		{
			engine->Reset();
			// this is a mirrored drive.  We will default to copying from the
			// first drive to the second...
			err = engine->Send( MSG_RAID1_SET_TARGET, component.tag);
		}
	}

	EXIT();
	return( err );
}

Command::Dpt_Error Create_Raid::execute (String_List **output)
{
	ENTER ("Command::Dpt_Error	Create_Raid::execute (String_List **output)");
	Dpt_Error err, busy_err;
	String_List	*out;
	get_Devs_Type devType;
	DPT_TAG_T tempTag;
	SCSI_Address dummyAddr;

	*output = out = new String_List();

	Init_Engine();
	engine->Reset();

	bool component_Found = true;
	bool tagValid = true;

	// if hba or hba/bus specified (all), make new address list
	if ((address_List->get_Num_Items() == 1) &&
			(raid_Type != RAID_TYPE_HOT_SPARE))
	{
		// Fix / verify drivesPerArray according to raid
		if (raid_Type == RAID_TYPE_1)
			drivesPerArray = 2;
		else if (((raid_Type == RAID_TYPE_0) &&
				  (drivesPerArray < 1)) ||
				 ((raid_Type == RAID_TYPE_5) &&
				  (drivesPerArray < 3)))
		{
			err = Dpt_Error::DPT_ERR_RAID_TOO_FEW;
			out->add_Item ((char *) err);
			return (err);
		}

		// get this hba or hba/bus OUT OF THERE!!!
		SCSI_Address tempAddr = address_List->shift_Item();

		for (int devIndex = 0; component_Found; devIndex++)
		{
			tempTag = Get_Address_by_Index(tempAddr, devIndex,
												&component_Found, &devType);
			if ((component_Found) && (devType == GET_SCSI_DASD))
			{
				if (!comps_Omit->In_List (DPT_Tag_to_Address (tempTag, &tagValid)))
					address_List->add_Item(DPT_Tag_to_Address (tempTag, &tagValid));
				// if found the wanted # of drives, go ahead and make the raid
				if (address_List->get_Num_Items() == drivesPerArray)
				{
					MakeGroupLists (output);
					// take items out of list
					for (int i = 0; i < drivesPerArray; i++)
						dummyAddr = address_List->shift_Item();
				}
			}
   		else if (!component_Found && (devIndex == 0))
	   	{
		   	err = Dpt_Error::DPT_CMD_ERR_CANT_FIND_COMPONENT;
   			out->add_Item ((char *) err);
	   		return (err);
		   }
		}
	}
   if ((drivesPerArray == 0) && (address_List->get_Num_Items()))
   {  
  		// do this just for some protection in case user doesn't
   	// really know what HE is doing
	   drivesPerArray = 0;
  		MakeGroupLists (output);
   }

	EXIT();
	return( err );
}

Command::Dpt_Error Create_Raid::MakeGroupLists (String_List **output)
{
	int this_RAID_Type;
	bool component_Found = true;
	int group = -2;
	Dpt_Error err, busy_err;
	Int_List	component_List;
	Int_List	group_List;
	int is_Group_List_Valid = 0;
	DPT_TAG_T this_RAID_Tag = (DPT_TAG_T) NULL;
	String_List	*out;
   bool fromRedirect = false;

	out = *output;

	// The old DriveBusy class, leaving for a bit for
	// logic verification from Mark Salyzyn.
	//DPTDriveBusy * busy = new DPTDriveBusy();
	component_Found = true;
	while (component_Found && address_List->num_Left())
	{
		DPT_TAG_T		component_Tag;
		SCSI_Address	component;

		component_Tag = Get_Dev_by_Address_and_Type(GET_SCSI_DASD,
			component = address_List->get_Next_Item(), &component_Found );
		if ( group == -2 )
		{
			group = component.level;
		}

		if ( group != component.level )
		{
			group = -3;
		}

		if( component_Found )
		{
#if !defined _DPT_LINUX
			// Determine if the component is busy.
			// This replaces the old DriveBusy class.
			uLONG devStatus;
			busy_err |= engine->Send( MSG_CHECK_BUSY, component_Tag );	

			// If busy_err = MSG_RTN_IGNORED, then the engine does not
			// support this command.  Simply treat as not busy.
			if ((busy_err.Is_Error()) && 
				(busy_err != Dpt_Error::DPT_MSG_RTN_IGNORED))
				err |= busy_err;
			if( !err.Is_Error() )
			{
				engine->Extract( &devStatus, sizeof(uLONG) );	
		
				// If 1, then this device is busy, otherwise
				// the device is considered NOT busy.
				if ( devStatus == 1 )
				{
					err = Dpt_Error::DPT_CMD_ERR_COMPONENT_BUSY;
				}
			}
/*
				// OLD DriveBusy stuff.. Leaving here for logic verification.
				if( busy->drvBusy( component.hba, component.bus,
				  component.id, component.lun ))
					{
					err = Dpt_Error::DPT_CMD_ERR_COMPONENT_BUSY;
					}
*/
#endif
			component_List.add_Item( component_Tag );
			group_List.add_Item( component.level );
			targetHba = component.hba;
		}
		else
		{
			err	= Dpt_Error::DPT_CMD_ERR_CANT_FIND_COMPONENT;
		}
	}
	is_Group_List_Valid = ( group == -3 );
	int level = 0;
	uLONG calcRaidSize = 0; 

	// Determine if it is necessary to construct multiple level arrays
	if( !err.Is_Error() ) 
	{
		DPT_TAG_T component;
        SCSI_Address saddr;
        // If drive is NOT a redirect,
        // leave the original list as it is.  
        // If drive IS a redirect, delete the redirect,
        // get the new tag and put back in the original list.
        address_List->reset_Next_Index();
		component_List.reset_Next_Index();
		component_Found = true;
		while (component_Found && address_List->num_Left())
		{
			// variable created to keep track of component_List position
			int next_Item_In_Component_List = 0;

			saddr = address_List->get_Next_Item();
			component = component_List.get_Next_Item();
			next_Item_In_Component_List++;
			
			err = engine->Send(MSG_GET_INFO, component);
			if (engine->devInfo_P->raidType == RAID_TYPE_REDIRECT)
			{
				DPT_TAG_T newComponent, hbaTag;
				//fromRedirect = true;
				raidHeader_S hdr;
				raidCompList_S cList;
				memset (&hdr, 0, sizeof(raidHeader_S));
				memset (&cList, 0, sizeof(raidCompList_S));
				hdr.control = FLG_RCTL_ADDR;
				// get the tag for the matching
				// physical device and put in the list
				bool compFound = true;
				get_Devs_Type comp_Type;
				for (int cmpIdx = 0; compFound; ++cmpIdx)
				{
					newComponent = Get_Component(component, cmpIdx, &compFound, &comp_Type);
					err = engine->Send(MSG_GET_INFO, newComponent);
					if (compFound && (comp_Type == GET_SCSI_DASD))
					{
						hbaTag = engine->devInfo_P->hbaTag;
                        hdr.refNum = raid_Type;
                        hdr.addr.hba = saddr.hba;
                        hdr.addr.chan = saddr.bus;
                        hdr.addr.id = saddr.id;
                        hdr.addr.lun = saddr.lun;
                        cList.tag = newComponent;
                        break;
                     }
                     else
						err = Dpt_Error::DPT_CMD_ERR_CANT_FIND_COMPONENT;
				}
				// delete the redirect
				engine->Reset();
				err = engine->Send(MSG_DELETE, component);
				// put the new tag in the list
				component_List.set_Item((next_Item_In_Component_List - 1), newComponent);
				// now send header and list and make the raid
				engine->Insert (&hdr, sizeof(raidHeader_S));
				engine->Insert (&cList, sizeof(raidCompList_S));
				err = engine->Send (MSG_RAID_NEW, hbaTag);
			}
			// not a redirected drive
			// leave entry alone
		}
		component_List.reset_Next_Index();
	}

	//Check all components for reserve conflict before attempting to create.

	bool reserve_Conflict = false;
	while (component_List.num_Left()){
	
		DPT_TAG_T temp_comp_Tag = component_List.get_Next_Item();
		engine->Reset();
		err = engine->Send(MSG_GET_INFO, temp_comp_Tag);
		
		if (engine->devInfo_P->flags3 & FLG_DEV_RES_CONFLICT)
			reserve_Conflict = true;
		
	}
	component_List.reset_Next_Index();

	

	int numDrvs = component_List.get_Num_Items();
	//drives not counted in size calculation
	int groupNum = 0;
	// Check to see if TOTAL raid size exceeds 2TB limit, if it does, create fails
	if (raid_Type == RAID_TYPE_1)
		groupNum = numDrvs/2;
	else if (raid_Type == RAID_TYPE_5){
		if (is_Group_List_Valid) // RAID-50, one drive per RAID-5 group is not counted in size calculation
			groupNum = group_List.get_Num_Uniques();
		else //regular RAID-5 only one parity drive is not counted in the size calculation
			groupNum = 1;
	}
	uLONG totalRaidSize = CalculateRaidSize(&component_List, groupNum);

	const uLONG NUM_MB_IN_TWO_TB = 2097152;  
	if (totalRaidSize > NUM_MB_IN_TWO_TB)
		err = Dpt_Error::DPT_ERR_TWO_TB_RAID;

	component_List.reset_Next_Index();

	if (!reserve_Conflict && !err.Is_Error()){
		switch( this_RAID_Type = raid_Type )
		{
			case RAID_TYPE_1:
			{
				//
				// Check for copying from a larger drive to a smaller drive.
				// CR2789
				//
				component_List.reset_Next_Index();
				while ( component_List.num_Left() >= 2 )
				{
					//
					// Get the size of the source drive.
					//
					const DPT_TAG_T srcDriveTag = component_List.get_Next_Item();
					engine->Reset();
					err = engine->Send(MSG_GET_INFO, srcDriveTag);
					const uLONG srcDriveSize = engine->devInfo_P->capacity.maxLBA;



					//
					// Get the size of the destination drive.
					//
					const DPT_TAG_T dstDriveTag = component_List.get_Next_Item();
					engine->Reset();
					err |= engine->Send(MSG_GET_INFO, dstDriveTag);
					const uLONG dstDriveSize = engine->devInfo_P->capacity.maxLBA;

										//
					// Check if the source drive is larger than the destination drive.
					//
					if ( err.Success() )
					{
						if (( srcDriveSize > dstDriveSize ) && ( !ignoreNonfatalErrors ))
						{
							err = Dpt_Error::DPT_ERR_RAID_DIFF_CAPACITY;
							break;
						}
					}
				}

				//
				// If an error has occurred then don't proceed with creating the array.
				//
				if ( err.Failure() )
				{
					break;
				}

				component_List.reset_Next_Index();
				int numComps = component_List.get_Num_Items();
				if ((numComps > 2) && ((numComps & 1) == 0 ))
				{
					Int_List components;
				
				// figure out the size of underlying arrays if limited size
				if (desired_Raid_Size_in_Blocks)
				{
					int numGroups = numComps / 2;
					calcRaidSize = desired_Raid_Size_in_Blocks / numGroups;
					desired_Raid_Size_in_Blocks = 0;
				}

				while (component_List.num_Left())
				{
					Int_List	pair;
					DPT_TAG_T component;

					component = component_List.get_Next_Item();
					pair.add_Item (component);
					component = component_List.get_Next_Item();
					pair.add_Item (component);

					err = Create (raid_Type, level, & pair, 
					stripe_Size, calcRaidSize, &this_RAID_Tag);
					if( err.Is_Error())
					{
						break;
					}
					components.add_Item (this_RAID_Tag);
				}
				raid_Type = RAID_TYPE_0;
				this_RAID_Type = 10;
				component_List = components;
				level = 1;
				}
			}
			break;
		case RAID_TYPE_5:
			if (is_Group_List_Valid)
			{
				Int_List components;
				int blksPerComp;
				int numComps = component_List.get_Num_Items();
				int numGroups = group_List.get_Num_Uniques();
				int group = group_List.get_Next_Item();
				numComps -= numGroups;
				if (desired_Raid_Size_in_Blocks)
					blksPerComp = desired_Raid_Size_in_Blocks / numComps;

				component_List.reset_Next_Index();
				DPT_TAG_T component = component_List.get_Next_Item();
				while (component_List.num_Left())
				{
					Int_List	groups;
					int last_group = group;
					while (group == last_group)
					{
						groups.add_Item (component);
						if (component_List.num_Left () == 0)
						{
							break;
						}
						component = component_List.get_Next_Item();
						group = group_List.get_Next_Item();
					}
					// get # components in this group -1 (for parity drive)
					int numInThisGroup = groups.get_Num_Items() - 1;
					// figure out the size of underlying arrays if limited size
					if (desired_Raid_Size_in_Blocks)
						calcRaidSize = blksPerComp * numInThisGroup;

					err = Create (raid_Type, level, &groups, stripe_Size, calcRaidSize, &this_RAID_Tag);
					if (err.Is_Error ())
					{
						break;
					}
					components.add_Item (this_RAID_Tag);
				}

				if (desired_Raid_Size_in_Blocks)
					desired_Raid_Size_in_Blocks = 0;
				raid_Type = RAID_TYPE_0;
				this_RAID_Type = 50;
				component_List = components;
				level = 1;
			}
			break;
		}
	}
		
	if (!err.Is_Error() && !fromRedirect && !reserve_Conflict)
	{
		err = Create(raid_Type, level, &component_List, stripe_Size, desired_Raid_Size_in_Blocks, & this_RAID_Tag);
	}

	// If there was a reserve conflict detected, create fails and user is informed of failure.
	if (reserve_Conflict)
	{
		out->add_Item( EventStrings[STR_RESCONFLICT] );
	}

	if( err.Is_Error() )
	{
		out->add_Item ((char *) err);


		//
		// If the error relates to different capacities and this is RAID 1 then print
		// an additional message explaining to the user how to get around the problem.
		// CR2789
		//
		if (( err == Dpt_Error::DPT_ERR_RAID_DIFF_CAPACITY ) && ( raid_Type == 1 ))
		{
         out->add_Item(EventStrings[STR_MIRROR_MSG1]);
         out->add_Item(EventStrings[STR_MIRROR_MSG2]);
         out->add_Item(EventStrings[STR_MIRROR_MSG3]);
         out->add_Item(EventStrings[STR_MIRROR_MSG4]);
         out->add_Item(EventStrings[STR_MIRROR_MSG5]);
		}
	}
	else
	{
		char	address_Buf[ 80 ];

		switch( raid_Type )
			{
			case RAID_TYPE_0:
			case RAID_TYPE_1:
			case RAID_TYPE_3:
			case RAID_TYPE_5:
				sprintf( address_Buf, "%s:  %s %d",
							EventStrings[STR_CREATED], 
                     EventStrings[STR_RAID],  this_RAID_Type );
				break;

			case RAID_TYPE_HOT_SPARE:
				sprintf( address_Buf, "%s:  %s",
							EventStrings[STR_CREATED], 
                     EventStrings[STR_RAID_HOT_SPARE]);
				break;

			case RAID_TYPE_REDIRECT:
				sprintf( address_Buf, "%s:  %s",
							EventStrings[STR_CREATED], 
                     EventStrings[STR_RAID_REDIRECT]);
				break;
			}

		// out->add_Item( STR_SUCCESS );
		out->add_Item( address_Buf );
		out->add_Item( "\n" );

		if ( this_RAID_Type >= 10 )
		{
			this_RAID_Tag = component_List.get_Item( 0 );
		}

		Commit (this_RAID_Tag, nobuild);
//		out->add_Item( STR_REBOOT );
	}

	return( err );
}



//Function - 
//Command::Dpt_Error Create_Raid::CalculateRaidSize (Int_List Comp_List, int groupNum) - start
//===========================================================================
//
//Description:
//
// This method takes in a component list of the drives to be used in creation, and 
// the number of groups the drives are separated into to calculate total raid size before creation.
// If the raid is <2TB then the raid creation fails.
//
//---------------------------------------------------------------------------
uLONG Create_Raid::CalculateRaidSize (Int_List* drive_List, int groupNum)
{
	drive_List->reset_Next_Index();
	DPT_TAG_T smallestDriveTag = 0;
	uLONG smallestDriveSize = 0;
	uLONG currDriveSize = 0;

	//parse through component list to calculate 
	while (drive_List->num_Left()){

		//get drive tag for get info call
		const DPT_TAG_T driveTag = drive_List->get_Next_Item();
		
		engine->Reset();
		engine->Send(MSG_GET_INFO, driveTag);
		
		//get size of current drive
		currDriveSize = engine->devInfo_P->capacity.maxLBA;

		//if first time through, the smallest drive is set to the first drive found
		if (smallestDriveTag == 0)
			 smallestDriveTag = driveTag;
		else{

			engine->Reset();
			engine->Send(MSG_GET_INFO, smallestDriveTag);

			smallestDriveSize = engine->devInfo_P->capacity.maxLBA;

			// If a smaller drive is found, update smallestDriveTag
			if (currDriveSize < smallestDriveSize)
				smallestDriveTag = driveTag;
		}
	}

	//get smallest drive size
	engine->Reset();
	engine->Send(MSG_GET_INFO, smallestDriveTag);
	smallestDriveSize = engine->devInfo_P->capacity.maxLBA;

	// convert from blocks to MB
	uLONG drvSzInMB = smallestDriveSize/2048;

	// drive_List.num_Items - groupNum refers to the drives not counted when calculating raid size
	// for RAID-0 ALL drives are counted (groupNum == 0)
	// for RAID-1 only half of the components count for size
	// for RAID-5 one drive per group is not counted (parity drives)
	uLONG raidSize = drvSzInMB * (drive_List->get_Num_Items() - groupNum);
			

	return raidSize;

}

//Command::Dpt_Error Create_Raid::CalculateRaidSize (Int_List Comp_List, int groupNum) - end

Command	&Create_Raid::Clone() const
	{
	ENTER( "Command	&Create_Raid::Clone() const" );
	EXIT();
	return( *new Create_Raid( *this ) );
	}

/*** END OF FILE ***/