blob: 705e3e107cacff59d1055fc4af838de7b3212c49 [file] [log] [blame]
Matt Spinlerbfd10b12016-12-09 10:16:54 -06001package Inventory;
2
3use strict;
Matt Spinler39a033b2016-12-21 14:08:59 -06004use warnings;
Matt Spinlerbfd10b12016-12-09 10:16:54 -06005
Matt Spinler39a033b2016-12-21 14:08:59 -06006#Target types to always include in the inventory if present
7my %TYPES = (SYS => 1, NODE => 1, PROC => 1, BMC => 1, GPU => 1);
8
9#RU_TYPES of cards to include
10#FRU = field replaceable unit, CRU = customer replaceable unit
11my %RU_TYPES = (FRU => 1, CRU => 1);
12
Matt Spinlerfe759642016-12-21 14:13:59 -060013#Chips that are modeled as modules (card-chip together)
14my %MODULE_TYPES = (PROC => 1, GPU => 1);
15
Matt Spinler39a033b2016-12-21 14:08:59 -060016#Returns an array of hashes that represents the inventory
17#for a system. The hash elements are:
18#TARGET: The MRW target of the item
19#OBMC_NAME: The OpenBMC name for the item. This is usually
20# a simplified version of the target.
Matt Spinlerbfd10b12016-12-09 10:16:54 -060021sub getInventory
22{
23 my $targetObj = shift;
24 my @inventory;
25
Matt Spinler39a033b2016-12-21 14:08:59 -060026 if (ref($targetObj) ne "Targets") {
27 die "Invalid Targets object passed to getInventory\n";
28 }
29
30 findItems($targetObj, \@inventory);
31
Matt Spinlerfe759642016-12-21 14:13:59 -060032 pruneModuleCards($targetObj, \@inventory);
33
Matt Spinlerc119a902016-12-21 14:19:25 -060034 makeOBMCNames($targetObj, \@inventory);
35
Matt Spinlerbfd10b12016-12-09 10:16:54 -060036 return @inventory;
37}
38
Matt Spinler39a033b2016-12-21 14:08:59 -060039
40#Finds the inventory targets in the MRW.
41#It selects them if the target's type is in %TYPES
42#or the target's RU_TYPE is in %RU_TYPES.
43#This will pick up FRUs and other chips like the BMC and processor.
44sub findItems
45{
46 my ($targetObj, $inventory) = @_;
47
48 for my $target (sort keys %{$targetObj->getAllTargets()}) {
49 my $type = "";
50 my $ruType = "";
51
52 if (!$targetObj->isBadAttribute($target, "TYPE")) {
53 $type = $targetObj->getAttribute($target, "TYPE");
54 }
55
56 if (!$targetObj->isBadAttribute($target, "RU_TYPE")) {
57 $ruType = $targetObj->getAttribute($target, "RU_TYPE");
58 }
59
60 if ((exists $TYPES{$type}) || (exists $RU_TYPES{$ruType})) {
61 my %item;
62 $item{TARGET} = $target;
63 $item{OBMC_NAME} = $target; #Will fixup later
64 push @$inventory, { %item };
65 }
66 }
67}
68
69
Matt Spinlerfe759642016-12-21 14:13:59 -060070#Removes entries from the inventory for the card target of a module.
71#Needed because processors and GPUs are modeled as a package which
72#is a card-chip instance that plugs into a connector on the
73#backplane/processor card. Since we already include the chip target
74#in the inventory (that's how we can identify what it is), we don't
75#need the entry for the card target.
76#
77#For example, we'll already have .../module-0/proc-0 so we don't
78#need a separate .../module-0 entry.
79sub pruneModuleCards
80{
81 my ($targetObj, $inventory) = @_;
82 my @toRemove;
83
84 #Find the parent (a card) of items of type %type
85 for my $item (@$inventory) {
86
87 if (exists $MODULE_TYPES{$targetObj->getType($item->{TARGET})}) {
88 my $card = $targetObj->getTargetParent($item->{TARGET});
89 push @toRemove, $card;
90 }
91 }
92
93 #Remove these parent cards
94 for my $c (@toRemove) {
95 for my $i (0 .. (scalar @$inventory) - 1) {
96 if ($c eq $inventory->[$i]{TARGET}) {
97 splice(@$inventory, $i, 1);
98 last;
99 }
100 }
101 }
102}
103
Matt Spinlerc119a902016-12-21 14:19:25 -0600104
105#Makes the OpenBMC name for the targets in the inventory.
106#Removes unnecessary segments of the path name, renames
107#some segments to match standard conventions, and numbers
108#segments based on their position attribute.
109sub makeOBMCNames
110{
111 my ($targetObj, $inventory) = @_;
112
113 #Remove connector segments from the OBMC_NAME
114 removeConnectors($targetObj, $inventory);
115
Matt Spinler8fd594c2016-12-21 14:22:09 -0600116 #Don't need the card instance of a PROC/GPU module
117 removeModuleFromPath($targetObj, $inventory);
Matt Spinlerf0942d12016-12-21 14:27:57 -0600118
119 #Don't need card segments for non-FRUs
120 removeNonFRUCardSegments($targetObj, $inventory);
121}
122
123
124#Removes non-FRU cards in the middle of a hierarchy from OBMC_NAME.
125#For example, .../motherboard/fanriser-0/fan-0 ->
126# .../motherboard/fan-0 when fanriser-0 isn't a FRU.
127sub removeNonFRUCardSegments
128{
129 my ($targetObj, $inventory) = @_;
130
131 for my $item (@$inventory) {
132
133 #Split the target into segments, then start
134 #adding segments in to make new targets so we can
135 #make API calls on the segment instances.
136 my @segments = split('/', $item->{TARGET});
137 my $target = "";
138 for my $s (@segments) {
139 next if (length($s) == 0);
140
141 $target .= "/$s";
142
143 my $class = $targetObj->getAttribute($target, "CLASS");
144 next if ($class ne "CARD");
145
146 my $ruType = $targetObj->getAttribute($target, "RU_TYPE");
147
148 #If this segment is a card but not a FRU,
149 #remove it from the path.
150 if (not exists $RU_TYPES{$ruType}) {
151 my $segment = $targetObj->getInstanceName($target);
152 $item->{OBMC_NAME} =~ s/\b$segment-\d+\b\///;
153 }
154 }
155 }
Matt Spinlerc119a902016-12-21 14:19:25 -0600156}
157
158
159#Removes connectors from the OBMC_NAME element. Also
160#takes the POSITION value of the connector and adds it
161#to the card segment that plugs into the connector.
162#For example:
163# /motherboard/card-conn-5/card-0 ->
164# /motherobard/card-5
165sub removeConnectors
166{
167 my ($targetObj, $inventory) = @_;
168
169 #Find the connectors embedded in the segments
170 for my $item (@$inventory) {
171
172 #Split the target into segments, then start
173 #adding segments in to make new targets
174 my @segments = split('/', $item->{TARGET});
175 my $target = "";
176 for my $s (@segments) {
177 next if (length($s) == 0);
178
179 $target .= "/$s";
180 my $class = $targetObj->getAttribute($target, "CLASS");
181 next unless ($class eq "CONNECTOR");
182
183 my ($segment) = $target =~ /\b(\w+-\d+)$/;
184 my $pos = $targetObj->getAttribute($target, "POSITION");
185
186 #change /connector-11/card-2/ to /card-11/
187 $item->{OBMC_NAME} =~ s/\b$segment\/(\w+)-\d+/$1-$pos/;
188
189 }
190 }
191}
192
Matt Spinler8fd594c2016-12-21 14:22:09 -0600193
194#Removes the card portion of a module from OBMC_NAME.
195#For example, .../motherboard-0/module-1/proc-0 ->
196#.../motherboard-0/proc-1.
197#This needs to be revisited if multi-processor modules
198#ever come into plan.
199sub removeModuleFromPath
200{
201 my ($targetObj, $inventory) = @_;
202 my %chipNames;
203
204 #Find the names of the chips on the modules
205 for my $item (@$inventory) {
206 if (exists $MODULE_TYPES{$targetObj->getType($item->{TARGET})}) {
207 $chipNames{$targetObj->getInstanceName($item->{TARGET})} = 1;
208 }
209 }
210
211 #Now convert module-A/name-B to name-A
212 #Note that the -B isn't always present
213 for my $item (@$inventory) {
214
215 for my $name (keys %chipNames) {
216 $item->{OBMC_NAME} =~ s/\w+-(\d+)\/$name(-\d+)*/$name-$1/;
217 }
218 }
219}
220
Matt Spinlerbfd10b12016-12-09 10:16:54 -06002211;
222
223=head1 NAME
224
225Inventory
226
227=head1 DESCRIPTION
228
229Retrieves the OpenBMC inventory from the MRW.
230
231The inventory contains:
232
233=over 4
234
235=item * The system target
236
237=item * The chassis target(s) (Called a 'node' in the MRW.)
238
239=item * All targets of class CARD or CHIP that are FRUs.
240
241=item * All targets of type PROC
242
243=item * All targets of type BMC
244
245=item * All targets of type GPU
246
247=back
248
249=head2 Notes:
250
251The processor and GPU chips are usually modeled in the MRW as a
252card->chip package that would plug into a connector on the motherboard
253or other parent card. So, even if both card and chip are marked as a FRU,
254there will only be 1 entry in the inventory for both, and the MRW
255target associated with it will be for the chip and not the card.
256
257In addition, this intermediate card will be removed from the path name:
258 /system/chassis/motheboard/cpu and not
259 /system/chassis/motherboard/cpucard/cpu
260
261=head2 Inventory naming conventions
262
263The inventory names returned in the OBMC_NAME hash element will follow
264the conventions listed below. An example of an inventory name is:
265/system/chassis/motherboard/cpu5
266
267=over 4
268
269=item * If there is only 1 instance of any segment in the system, then
270 it won't have an instance number, otherwise there will be one.
271
272=item * The root of the name is '/system'.
273
274=item * After system is 'chassis', of which there can be 1 or more.
275
276=item * The name is based on the MRW card plugging order, and not what
277 the system looks like from the outside. For example, a power
278 supply that plugs into a motherboard (maybe via a non-fru riser
279 or cable, see the item below), would be:
280 /system/chassis/motherboard/psu2 and not
281 /system/chassis/psu2.
282
283=item * If a card is not a FRU so isn't in the inventory itself, then it
284 won't show up in the name of any child cards that are FRUs.
285 For example, if fan-riser isn't a FRU, it would be
286 /system/chassis/motherboard/fan3 and not
287 /system/chassis/motherboard/fan-riser/fan3.
288
289=item * The MRW models connectors between cards, but these never show up
290 in the inventory name.
291
292=item * If there is a motherboard, it is always called 'motherboard'.
293
294=item * Processors, GPUs, and BMCs are always called: 'cpu', 'gpu' and
295 'bmc' respectively.
296
297=back
298
299=head1 METHODS
300
301=over 4
302
303=item getInventory (C<TargetsObj>)
304
305Returns an array of hashes representing inventory items.
306
307The Hash contains:
308
309* TARGET: The MRW target of the item, for example:
310
311 /sys-0/node-0/motherboard-0/proc_socket-0/module-0/p9_proc_m
312
313* OBMC_NAME: The OpenBMC name of the item, for example:
314
315 /system/chassis/motherboard/cpu2
316
317=back
318
319=cut