3 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * The contents of this file constitute Original Code as defined in and
8 * are subject to the Apple Public Source License Version 1.1 (the
9 * "License"). You may not use this file except in compliance with the
10 * License. Please obtain a copy of the License at
11 * http://www.apple.com/publicsource and read it before using this file.
13 * This Original Code and all software distributed under the License are
14 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
18 * License for the specific language governing rights and limitations
21 * @APPLE_LICENSE_HEADER_END@
24 * raid.c - Main functions for BootX.
26 * Copyright (c) 1998-2005 Apple Computer, Inc.
28 * DRI: Josh de Cesare (BootX), Soren Spies (RAID support)
33 #include <IOKit/IOKitKeys.h>
35 typedef unsigned long long UInt64
;
37 #include <IOKit/storage/RAID/AppleRAIDUserLib.h> // hooray
38 //#include "/System/Library/Frameworks/IOKit.framework/Versions/A/PrivateHeaders/storage/RAID/AppleRAIDUserLib.h"
40 /* things we could probably get from elsewhere */
41 typedef enum RAIDType
{
42 kRAIDTypeUseless
= -1,
50 /* stolen from AppleRAIDMember.h */
52 #define kAppleRAIDSignature "AppleRAIDHeader"
53 #define kAppleRAIDHeaderSize 0x1000
55 #define ARHEADER_OFFSET(s) ((UInt64)(s) / kAppleRAIDHeaderSize * kAppleRAIDHeaderSize - kAppleRAIDHeaderSize )
57 struct AppleRAIDHeaderV2
{
58 char raidSignature
[16];
64 typedef struct AppleRAIDHeaderV2 AppleRAIDHeaderV2
;
67 /* our data structure */
68 typedef struct RAIDMember
{
70 char path
[256]; // sized like gBootDevice
71 UInt64 size
; // becomes data-bearing portion once known
72 union { // switch on totMembers
73 struct RAIDMember
**members
; // dynamic array of pointers
74 // totMembers big; curMembers elements
75 CICell ih
; // after we Open() path; NULL if useless
79 // --- everything below here used for members; not leaves ---
80 UInt64 curOffset
; // absolute for Seek/RAIDRead()
81 int curMembers
; // updated as we add members and do I/O
83 // derived from the header(s - struct and plist) stored in the providers
84 char setUUID
[64]; // id used (w/seqNum) to find other members
85 RAIDType type
; // mirror, stripe, concat
86 int seqNum
; // member generation id
87 int totMembers
; // total members in set
88 UInt64 chunkSize
; // stripe width
89 UInt64 chunkCount
; // number of chunks (unused?)
90 } RAIDDevice
; // *RAIDDevicePtr;
93 #define kAppleRAIDOFPathPrefix "AppleRAID/"
95 /* -- static variables -- */
96 static int gMaxMembers
;
97 static int gTotalMembers
;
98 static struct RAIDMember
*gMembers
; // an array of structs
99 static RAIDDevicePtr gRAIDMaster
= NULL
;
101 /* -- internal helper prototypes -- */
102 static long FillInLeaf(TagPtr tagElem
, RAIDDevicePtr member
);
103 static long AssimilateMember(RAIDDevicePtr member
);
104 static RAIDDevicePtr
DetermineParent(TagPtr candidateDict
, AppleRAIDHeaderV2
*);
105 static long AdoptChild(RAIDDevicePtr parent
, RAIDDevicePtr child
, TagPtr cDict
);
106 static long isComplete(RAIDDevicePtr member
);
107 static long NextPartition(char *loaderDev
, char *memberDev
); // XX share?
108 // must call these with non-"-1" offsets
109 static long ReadMirror(RAIDDevicePtr raid
, long buf
, long nbytes
,UInt64 offset
);
110 static long ReadStripe(RAIDDevicePtr raid
, long buf
, long nbytes
,UInt64 offset
);
111 static long ReadConcat(RAIDDevicePtr raid
, long buf
, long nbytes
,UInt64 offset
);
113 /* -- accessors -- */
114 static RAIDType
GetRAIDType(TagPtr dict
);
115 static long long GetWholeNumber(TagPtr dict
, char *key
);
117 /* -- cruft XX :) -- */
118 static void problemCode(); // need to isolate crasher
120 /* -- public helpers -- */
121 int isRAIDPath(char *devSpec
)
125 rval
= (devSpec
&& !strncmp(devSpec
, kAppleRAIDOFPathPrefix
,
126 sizeof(kAppleRAIDOFPathPrefix
)-1));
130 /* only publicly a RAID device if it has members */
131 /* we could have magic in our struct to be really sure :) */
132 int isRAIDDevice(void *ih
)
138 RAIDDevicePtr p
= (RAIDDevicePtr
)ih
;
139 // is the pointer within range
140 rval
= (p
>= &gMembers
[0] && p
< &gMembers
[gTotalMembers
] && p
->curMembers
);
145 // --- open/close/read/!/seek ---
148 void RAIDClose(RAIDDevicePtr raid
)
150 int i
= raid
->totMembers
;
153 if(raid
->curMembers
) {
155 mem
= raid
->members
[i
];
158 raid
->members
[i
] = NULL
;
169 RAIDDevicePtr
RAIDOpen(char *devSpec
)
171 // steal RAID "devices"
173 char *p
= devSpec
, *endp
;
174 RAIDDevicePtr rval
= NULL
;
176 if(!devSpec
) return NULL
;
178 // walk past kAppleRAIDOFPathPrefix
179 while (*p
&& *(p
++) != '/');
181 ridx
= strtol(p
, &endp
, 10);
182 if(ridx
< gTotalMembers
)
183 rval
= &gMembers
[ridx
];
190 long RAIDSeek(RAIDDevicePtr raid
, long long position
)
193 if(position
< 0) return -1;
195 raid
->curOffset
= position
;
200 long RAIDRead(RAIDDevicePtr raid
, long buf
, long nbytes
, long long offset
)
203 static long logs
= 0;
205 // only RAIDRead() supports offset == -1 -> curOffset
207 offset
= raid
->curOffset
;
209 if(offset
> raid
->size
) {
210 printf("RAIDRead() error: offset (%x%x) > raid->size (%x%x)\n",
215 if(raid
->totMembers
) {
217 printf("RAIDRead(%x (curMembers: %d), %x, %d, %x%x)\n",
218 raid
, raid
->curMembers
, buf
, nbytes
, offset
);
220 case kRAIDTypeMirror
:
221 rval
= ReadMirror(raid
, buf
, nbytes
, offset
);
224 case kRAIDTypeStripe
:
225 rval
= ReadStripe(raid
, buf
, nbytes
, offset
);
228 case kRAIDTypeConcat
:
229 rval
= ReadConcat(raid
, buf
, nbytes
, offset
);
232 // case kRAIDTypeFive:
234 printf("unsupported RAID type id: %d\n", raid
->type
); // XX -> isComplete?
238 else { // leaf member, read from the CI; we open on demand
241 // open underlying device
242 if(!(raid
->ih
= Open(raid
->path
))) break;
244 if(Seek(raid
->ih
, offset
) < 0) break;
246 //printf("(RR): calling CI (%x from %x @ %x)\n", nbytes, raid->ih, (int)offset);
247 rval
= Read(raid
->ih
, buf
, nbytes
);
251 //if((raid->curMembers && logs < 15) || rval != nbytes)
252 //printf("RAIDRead() returning %d (vs. %d)\n", rval, nbytes);
258 // ! long WriteToRAID(RAIDDevicePtr ... )
261 // simple for now (could spare out errors, etc)
262 static long ReadMirror(RAIDDevicePtr raid
, long buf
, long nbytes
, UInt64 offset
)
266 // find a working member
267 while(ridx
< raid
->totMembers
) {
268 if(raid
->members
[ridx
])
274 if(ridx
== raid
->totMembers
)
277 return RAIDRead(raid
->members
[ridx
], buf
, nbytes
, offset
);
280 static long ReadStripe(RAIDDevicePtr raid
, long buf
, long nbytes
, UInt64 offset
)
282 UInt64 chunkSize
= raid
->chunkSize
;
283 int nMems
= raid
->totMembers
;
284 UInt64 subChunkStart
= offset
% chunkSize
; // where in the final chunk?
286 UInt64 chunkIdx
= offset
/ chunkSize
; // which chunk of all of them?
287 int midx
= chunkIdx
% nMems
; // on which member?
288 UInt64 mChunk
= chunkIdx
/ nMems
; // which chunk in the member?
289 UInt64 mChunkOffset
= mChunk
* chunkSize
; // which offset in the member?
291 long thisTime
, totalRead
= 0;
292 long bytesRead
, bytesLeft
= nbytes
;
296 if(subChunkStart
+ nbytes
> chunkSize
)
297 thisTime
= chunkSize
- subChunkStart
;
299 thisTime
= nbytes
; // nbytes is within the chunk
301 // tempting to do a partial read here ...
303 while(bytesLeft
/* ALT: bufp < buf + nbytes */) {
304 bytesRead
= RAIDRead(raid
->members
[midx
], bufp
, thisTime
, mChunkOffset
+subChunkStart
);
305 if(bytesRead
== -1) goto fail
;
306 totalRead
+= bytesRead
; // record what we read
307 bytesLeft
-= bytesRead
;
308 if(bytesRead
!= thisTime
) break; // detect partial read and return
310 // set up for next read
312 // effect "chunkIdx++" by walking across the members
313 midx
++; // next member
314 if(midx
% nMems
== 0) { // did we wrap?
315 midx
= 0; // back to 0th member
316 mChunkOffset
+= chunkSize
; // next chunk ("mChunk++")
319 // adjust other parameters
320 bufp
+= bytesRead
; // bytesRead == thisTime
321 if(bytesLeft
> chunkSize
) // are we in the last chunk yet?
322 thisTime
= chunkSize
;
324 thisTime
= bytesLeft
;
325 subChunkStart
= 0; // reset after first read (& beyond :P)
335 // XX okay to compare UInt64 values to -1?
336 static long ReadConcat(RAIDDevicePtr raid
, long buf
, long nbytes
, UInt64 offset
)
338 //static UInt64 predoffset = -1;
340 UInt64 nextStart
= 0, curStart
= 0;
341 long totalRead
= 0, bytesRead
;
343 // assume curMembers!=0 since RAIDRead() should be our only caller
344 for(midx
= 0; midx
< raid
->curMembers
; midx
++) {
345 nextStart
= curStart
+ raid
->members
[midx
]->size
;
347 // are we in range yet?
348 if(offset
< nextStart
) {
350 UInt64 curOffset
= offset
- curStart
;
352 // make sure we aren't reading out too far
353 if(offset
+ nbytes
< nextStart
)
356 thisTime
= nextStart
- offset
; // distance to the end
358 bytesRead
= RAIDRead(raid
->members
[midx
],buf
,thisTime
,curOffset
);
359 if(bytesRead
== -1) goto fail
;
360 totalRead
+= bytesRead
; // record what was read
361 if(bytesRead
!= thisTime
) break; // detect partial read and return
363 // XX need to lay out a volume to test crossing boundary in one read
364 if(thisTime
!= nbytes
) {
365 printf("ReadConcat crossing a boundary in a single read\n");
369 continue; // take another spin around the loop
371 break; // exit from the enclosing loop
373 curStart
= nextStart
;
379 printf("ReadConcat: %d for %x%x (ended %x%x..%x%x)\n",
380 totalRead
, offset
, curStart
, nextStart
);
386 // --- seek out RAID members and build sets ---
389 How we find and build RAID sets (not our first stab :):
391 1) initialize with the OF paths in Boot.plist (Tiger)
393 *) there is no else until we find a way to divine partition sizes
395 while(unread potential members)
396 3) read new members and populate structs
397 4) assimilate them ("resistance is futile!")
398 * DetermineParent() looks through existing sets and creates on demand
399 * give the child to the parent for adoption
400 * if the parent becomes complete, proactively probe it as a member
403 // process gBootDict looking for path/size pairs where we can sniff for RAID
404 // allocate gMembers (3x the number of members)
405 // make some stub members pointing to these paths
406 long LookForRAID(TagPtr bootDict
)
412 // count and allocate gMembers array
413 // assume no Apple_RAID could contribute > 2 members
414 if(bootDict
->type
== kTagTypeArray
)
415 for(partSpec
= bootDict
->tag
; partSpec
; partSpec
= partSpec
->tagNext
)
416 gMaxMembers
+= 3; // XX [re]think degraded mirrors trying to stack
420 gMembers
= AllocateBootXMemory(gMaxMembers
*sizeof(RAIDDevice
));
422 bzero(gMembers
, gMaxMembers
*sizeof(RAIDDevice
));
424 // walk list of potential members, skipping on error
425 // FillInLeaf() on each
426 // AssimilateMember() on each
427 if(bootDict
->type
== kTagTypeArray
) {
428 char masterMemberPath
[256];
430 if(NextPartition(gBootDevice
, masterMemberPath
)) break;
432 for(partSpec
= bootDict
->tag
; partSpec
; partSpec
= partSpec
->tagNext
) {
433 RAIDDevicePtr newLeaf
= &gMembers
[gTotalMembers
++]; // burn entries
434 if(FillInLeaf(partSpec
, newLeaf
)) continue;
436 // is this the master (from whose Apple_Boot we loaded)?
437 // if either device doesn't exist (e.g. if both FindDevice calls
438 // returned NULL), we'd fail later.
439 if(FindDevice(newLeaf
->path
) == FindDevice(masterMemberPath
)) {
440 printf("raid: found member affiliated with our boot device\n");
441 gRAIDMaster
= newLeaf
;
444 // assertion: leaves are always complete
445 printf("raid: assimilating leaf %x\n", newLeaf
);
446 if(AssimilateMember(newLeaf
)) continue;
450 // even degraded mirror (one member) is in an array
451 else if(bootDict
->type
== kTagTypeDict
) {
452 if(FillInLeaf(bootDict
, &gMembers
[0])) break;
453 if(AssimilateMember(&gMembers
[0])) break;
454 gRAIDMaster
= &gMembers
[1];
459 printf("LookForRAID() made %d happy structs ", nsuccesses
);
460 printf("which resulted in %d total objects\n", gTotalMembers
);
462 if(isComplete(gRAIDMaster
)) {
463 int masteridx
= gRAIDMaster
- gMembers
;
464 sprintf(gBootDevice
, "%s%d:0,\\\\tbxi",kAppleRAIDOFPathPrefix
,masteridx
);
465 printf("raid: set gBootDevice to %s\n", gBootDevice
);
468 printf("raid: boot-device didn't lead to a RAID device\n");
470 printf("raid: master RAID device %x missing members (has %d of %d)\n",
471 gRAIDMaster
, gRAIDMaster
->curMembers
, gRAIDMaster
->totMembers
);
481 // FillInLeaf() fills in a member's struct so the partition can later be probed
482 // (just need the path and size)
483 static long FillInLeaf(TagPtr partSpec
, RAIDDevicePtr newMember
)
491 prop
= GetProperty(partSpec
, kIOBootDevicePathKey
);
492 if(!prop
|| prop
->type
!= kTagTypeString
) break;
493 path
= prop
->string
+ sizeof(kIODeviceTreePlane
); // +1(':') -1('\0')
494 if((size
= GetWholeNumber(partSpec
, kIOBootDeviceSizeKey
)) < 0) break;
496 //printf("got path and size (%x%x)\n", size);
498 // and copy in the values
499 if(!strcpy(newMember
->path
, path
)) break;
500 newMember
->size
= size
;
502 // gMembers got the big bzero() so all else is fine
510 // need to extract logical bits so we can find a parent
511 static long AssimilateMember(RAIDDevicePtr candidate
)
513 TagPtr candDict
= NULL
;
514 void *bufp
= (char*)kLoadAddr
;
515 AppleRAIDHeaderV2
*cHeader
= (AppleRAIDHeaderV2
*)bufp
;
516 RAIDDevicePtr parent
= NULL
;
520 // suck headers from candidate
521 if(RAIDRead(candidate
, (long)bufp
, kAppleRAIDHeaderSize
,
522 ARHEADER_OFFSET(candidate
->size
)) != kAppleRAIDHeaderSize
) break;
523 printf("raid: checking for magic: %s\n", bufp
); // should point to magic
525 // validate the magic
526 if(strcmp(kAppleRAIDSignature
, bufp
)) {
527 printf("RAID magic not found in member %x\n", candidate
);
530 //printf("raid set UUID: %s\n", cHeader->raidUUID);
531 //printf("memberUUID: %s\n", cHeader->memberUUID);
533 // batten down the size to hide the header
534 printf("raid: member size (%x%x) -> data size (%x%x)\n",candidate
->size
,
536 candidate
->size
= cHeader
->size
; // -msoft-flaot required!
538 // and skip to and parse the embedded plist (to get the type, etc)
539 bufp
+= sizeof(AppleRAIDHeaderV2
);
540 //printf("bufp: %s\n", bufp);
541 if((ParseXML(bufp
, &candDict
) < 0) || !candDict
) break;
542 //printf("parsed RAID member dict (%x):\n", candDict);
543 //DumpTag(candDict, 0);
546 // DetermineParent will create a parent if it didn't already exist
547 if(!(parent
= DetermineParent(candDict
, cHeader
))) break;
548 printf("raid: %x being given to %x for adoption\n", candidate
, parent
);
549 if(AdoptChild(parent
, candidate
, candDict
)) break;
551 printf("raid: checking if set is ready to be probed...\n");
552 if(isComplete(parent
))
553 (void)AssimilateMember(parent
); // we might be done ...
561 static long AdoptChild(RAIDDevicePtr parent
, RAIDDevicePtr child
, TagPtr cDict
)
563 int candIdx
, childSeq
;
567 if((childSeq
= GetWholeNumber(cDict
, kAppleRAIDSequenceNumberKey
)) < 0)
570 // check for "one"ness early (the child might be otherwise unwanted)
571 if(child
== gRAIDMaster
) {
572 printf("raid: SUCCESSION %x was master; now to parent %x\n", child
, parent
);
573 gRAIDMaster
= parent
;
576 // do per-type actions (e.g. adjust size, cast out degraded mirrors, etc)
577 switch(parent
->type
) {
578 case kRAIDTypeMirror
:
579 // only want the most up to date n-way twins (n=1..k)
580 if(childSeq
< parent
->seqNum
) {
581 printf("child seq # (%d) < parent's (%d) skip\n",childSeq
,parent
->seqNum
);
584 if(childSeq
> parent
->seqNum
) {
586 // more recent; take the new seqNum and cast out old members
587 printf("child seq (%d) > parent's (%d) update\n",childSeq
,parent
->seqNum
);
588 parent
->seqNum
= childSeq
;
589 for(midx
= 0; midx
< parent
->totMembers
; midx
++)
590 parent
->members
[midx
] = NULL
;
591 parent
->curMembers
= 0;
593 parent
->size
= child
->size
;
597 case kRAIDTypeStripe
:
598 printf("st parent->size(%x%x) += child->size(%x%x)\n",parent
->size
,child
->size
);
599 parent
->size
+= child
->size
;
600 /* could validate that sizes/#totMembers match */
604 // yes, concat and stripe are the same for now
605 case kRAIDTypeConcat
:
606 parent
->size
+= child
->size
;
610 case kRAIDTypeUseless
: return -1; // yuck
613 // get the index of this member in the set
614 if((candIdx
= GetWholeNumber(cDict
, kAppleRAIDMemberIndexKey
)) == -1) break;
616 // just in case we find the same member twice?
617 // invariant: curMembers == PopCount(members)
618 if(!parent
->members
[candIdx
])
619 parent
->curMembers
++;
621 printf("raid: members[%d] non-NULL: %x\n", candIdx
, parent
->members
[candIdx
]);
623 printf("raid: assigning %x to parent->members[%d]\n", child
, candIdx
);
624 parent
->members
[candIdx
] = child
;
632 // aka "MakeNewParent()" if parent doesn't exist
633 static RAIDDevicePtr
DetermineParent(TagPtr cDict
, AppleRAIDHeaderV2
*cHeader
)
636 RAIDDevicePtr rval
= NULL
;
637 int seqNum
= GetWholeNumber(cDict
, kAppleRAIDSequenceNumberKey
);
638 int candIdx
= GetWholeNumber(cDict
, kAppleRAIDMemberIndexKey
);
640 if(seqNum
== -1 || candIdx
== -1) return rval
;
642 // search all non-leaf parents for a potential match
643 for(ridx
= 0; ridx
< gTotalMembers
; ridx
++) {
644 RAIDDevicePtr potential
= &gMembers
[ridx
];
645 if(!potential
->totMembers
) continue; // not interested in children
646 if(potential
->totMembers
<= candIdx
) continue; // no slot for child
647 if(potential
->type
!= kRAIDTypeMirror
) // mirrors will consider any child
648 if(potential
->seqNum
!= seqNum
) continue; // wrong generation
650 // XX could check for UUID in members-UUID array
652 // if the IDs match, hooray
653 if(!strcmp(cHeader
->raidUUID
, potential
->setUUID
)) {
654 printf("raid: matched a child to a parent in %s\n", cHeader
->raidUUID
);
661 // If we didn't find a parent, make one
662 if(ridx
== gTotalMembers
)
663 // get values, minimally validate, and populate new parent
665 RAIDDevicePtr parent
= &gMembers
[gTotalMembers
++];
669 UInt64 chunkSize
= 0;
670 UInt64 chunkCount
= 0;
672 printf("raid: making new parent %x\n", parent
);
673 // count up totMembers
674 prop
= GetProperty(cDict
, kAppleRAIDMembersKey
);
675 if(!prop
|| prop
->type
!= kTagTypeArray
) break;
676 //printf("cDict->raidMembers:\n");
680 // count elements of the array
684 prop
= prop
->tagNext
;
686 printf("raid: parent->totMembers: %d\n", totMembers
);
687 if(totMembers
<= candIdx
) {
688 printf("raid: candidate claims index %d in a %d-member set; ignoring\n",
689 candIdx
, totMembers
);
693 // grab type, chunk info from child dict (sequence # above)
694 type
= GetRAIDType(cDict
);
695 if(type
== kRAIDTypeUseless
) break;
696 if(type
== kRAIDTypeStripe
) {
697 chunkSize
= GetWholeNumber(cDict
, kAppleRAIDChunkSizeKey
);
698 if(chunkSize
== -1) break;
699 chunkCount
= GetWholeNumber(cDict
, kAppleRAIDChunkCountKey
);
700 if(chunkCount
== -1) break;
703 // and set up the parent structure's values
704 parent
->size
= 0; // let AssimilateMember increment the size
706 parent
->members
= AllocateBootXMemory(totMembers
*sizeof(RAIDDevicePtr
));
707 if(!parent
->members
) break;
708 bzero(parent
->members
, totMembers
*sizeof(RAIDDevicePtr
));
710 // curMembers, curOffset == 0 from initial bzero()
712 if(!strcpy(parent
->setUUID
, cHeader
->raidUUID
)) break;
714 parent
->seqNum
= seqNum
;
715 parent
->totMembers
= totMembers
;
716 if(type
== kRAIDTypeStripe
) {
717 parent
->chunkSize
= chunkSize
;
718 parent
->chunkCount
= chunkCount
;
719 //printf("stripe: size * count %x%x vs. size %x%x\n", chunkSize * chunkCount, cHeader->size);
728 static long NextPartition(char *loaderDev
, char *memberDev
)
730 int cnt
, cnt2
, partNum
;
731 // stolen from main.c
733 // Find the first ':'.
735 while ((loaderDev
[cnt
] != '\0') && (loaderDev
[cnt
] != ':')) cnt
++;
736 if (loaderDev
[cnt
] == '\0') return -1;
738 // Find the comma after the ':'.
740 while ((loaderDev
[cnt2
] != '\0') && (loaderDev
[cnt
] != ',')) cnt2
++;
742 // Get just the partition number
743 strncpy(memberDev
, loaderDev
+ cnt
+ 1, cnt2
- cnt
- 1);
744 partNum
= strtol(memberDev
, 0, 10);
745 if (partNum
== 0) partNum
= strtol(gBootFile
, 0, 16);
747 // looking for the Apple_RAID following the Apple_Boot
750 // Construct the boot-file
751 strncpy(memberDev
, loaderDev
, cnt
+ 1);
752 sprintf(memberDev
+ cnt
+ 1, "%d", partNum
);
757 static long isComplete(RAIDDevicePtr member
)
762 if(!member
|| !member
->curMembers
) break;
764 switch(member
->type
) {
765 case kRAIDTypeMirror
:
766 rval
= (member
->curMembers
> 0);
769 case kRAIDTypeStripe
:
770 case kRAIDTypeConcat
:
771 rval
= (member
->curMembers
== member
->totMembers
);
778 printf("raid: isComplete on %x (type %d, #mems %d): %d\n",
779 member
, member
->type
, member
->curMembers
, rval
);
784 // --- dictionary accessors ---
785 static RAIDType
GetRAIDType(TagPtr dict
)
787 RAIDType type
= kRAIDTypeUseless
;
792 prop
= GetProperty(dict
, kAppleRAIDLevelNameKey
);
793 if(!prop
|| prop
->type
!= kTagTypeString
) break;
794 typeString
= prop
->string
;
795 switch(typeString
[0]) {
796 case 'M': type
= kRAIDTypeMirror
; break;
797 case 'S': type
= kRAIDTypeStripe
; break;
798 case 'C': type
= kRAIDTypeConcat
; break;
800 printf("raid: didn't like level: %s\n", typeString
);
801 type
= kRAIDTypeUseless
;
808 // "whole numbers are the counting numbers plus zero" - math team coach
809 // -1 indicates an error
810 static long long GetWholeNumber(TagPtr dict
, char *key
)
817 prop
= GetProperty(dict
, key
);
818 if(!prop
|| prop
->type
!= kTagTypeInteger
) break;
819 num
= strtouq(prop
->string
, &endp
, 0); // as long as not > #mems :)
830 static void problemCode()
832 RAIDDevice rmem
, *tmem
= &rmem
;
833 AppleRAIDHeaderV2 rheader
, *theader
= &rheader
;
834 void *fp
= &problemCode
;
836 printf("\n ... calling probleCode() ...\n");
838 printf("populating a size member\n");
839 theader
->size
= 123456789;
840 //printf("trying to copy tmem->size = theader->size");
841 tmem
->size
= theader
->size
;
842 printf("dumping size: %x,%x\n", (int)(tmem
->size
>>32), (int)tmem
);