1#!/usr/bin/perl 2 3# test_fru 4# 5# Test of the FRU code. 6# 7# Author: MontaVista Software, Inc. 8# Corey Minyard <minyard@mvista.com> 9# source@mvista.com 10# 11# Copyright 2004 MontaVista Software Inc. 12# 13# This program is free software; you can redistribute it and/or 14# modify it under the terms of the GNU Lesser General Public License 15# as published by the Free Software Foundation; either version 2 of 16# the License, or (at your option) any later version. 17# 18# 19# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 20# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 25# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 27# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 28# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29# 30# You should have received a copy of the GNU Lesser General Public 31# License along with this program; if not, write to the Free 32# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 33# 34 35use Lanserv; 36use OpenIPMI; 37 38my $errcountholder : shared = 0; 39$errcount = \$errcountholder; 40 41my $fru_field_table = {}; 42 43sub reg_err { 44 my $str = shift; 45 46 $$errcount++; 47 print STDERR "***", $str, "\n"; 48} 49 50sub get_errcount { 51 return $$errcount; 52} 53 54# Check a data field from the fru. Parameters are: 55# fru - where to get the data from 56# name - The name of the field to check 57# num - The number of the field to check, ignored if the field doesn't 58# support numbers. 59# exp_type - The expected type (integer, time, ascii, binary, unicode). 60# exp_val - The expected value. For integers and ASCII strings, this 61# is the value. For binary and unicode, this is a string with the 62# values listed out. If the value is expected to not be there, this 63# should be undefined. 64sub check_fru_data { 65 my $fru = shift; 66 my $name = shift; 67 my $num = shift; 68 my $exp_type = shift; 69 my $exp_val = shift; 70 my $idx = $fru_field_table->{$name}; 71 my ($tname, $type, $val); 72 my $tnum = $num; 73 74 if (!defined $idx) { 75 main::reg_err("Invalid name in check_fru_data: $name"); 76 return; 77 } 78 79 ($tname, $type, $val) = split /\s+/, $fru->get($idx, \$tnum), 3; 80 81 if (!defined $tname) { 82 main::reg_err("Internal error on: $name [$num]"); 83 return; 84 } 85 86 if (!defined $type) { 87 if (defined $exp_val) { 88 main::reg_err("value for $name [$num] was undefined, expected $exp_val"); 89 } 90 return; 91 } 92 93 if ($name ne $tname) { 94 main::reg_err("Internal error on: $name [$num], $tname"); 95 return; 96 } 97 98 if ($exp_type ne $type) { 99 main::reg_err("Type mismatch on $name [$num], expected $exp_type, got $type"); 100 return; 101 } 102 103 # If the length of the thing is zero, there won't be anything in the string. That's ok, 104 # but make the comparisons work. 105 if (!defined $val) { 106 $val = ""; 107 } 108 109 if (($exp_type eq "integer") || ($exp_type eq "time")) { 110 if ($exp_val != $val) { 111 main::reg_err("Value mismatch on $name [$num], expected $exp_val, got $val"); 112 return; 113 } 114 } elsif ($exp_type eq "ascii") { 115 if ($exp_val ne $val) { 116 main::reg_err("Value mismatch on $name [$num], expected '$exp_val', got '$val'"); 117 return; 118 } 119 } elsif (($exp_type ne "binary") || ($exp_type ne "unicode")) { 120 my @vals = split /\s+/, $val; 121 my @exp_vals = split /\s+/, $exp_val; 122 my $i; 123 if ($#vals != $#exp_vals) { 124 main::reg_err("Value mismatch on $name [$num], expected $#exp_vals values, got $#vals"); 125 return; 126 } 127 $i = 1; 128 $val = shift(@vals); 129 $exp_val = shift(@exp_vals); 130 while (defined $val) { 131 if (hex($val) != hex($exp_val)) { 132 main::reg_err("Value mismatch on $name [$num] item $i, expected $exp_val, got $val"); 133 return; 134 } 135 $val = shift(@vals); 136 $exp_val = shift(@exp_vals); 137 $i++; 138 } 139 } else { 140 main::reg_err("Invalid type on $name [$num]: $exp_type"); 141 return; 142 } 143} 144 145sub check_fru_mr_data { 146 my $fru = shift; 147 my $num = shift; 148 my $exp_type = shift; 149 my $exp_version = shift; 150 my $exp_val = shift; 151 my ($type, $version, $val); 152 my $readval = $fru->get_multirecord($num); 153 154 if (!defined $readval) { 155 if (defined $exp_type) { 156 main::reg_err("value for multirecord [$num] was undefined, expected value"); 157 } 158 return; 159 } 160 161 ($type, $version, $val) = split /\s+/, $readval, 3; 162 163 if ($type ne $exp_type) { 164 main::reg_err("Value mismatch on multirecord [$num] type, expected $exp_type, got $type"); 165 return; 166 } 167 168 if ($version ne $exp_version) { 169 main::reg_err("Value mismatch on multirecord [$num] version, expected $exp_version, got $version"); 170 return; 171 } 172 173 # If the length of the thing is zero, there won't be anything in the string. That's ok, 174 # but make the comparisons work. 175 if (!defined $val) { 176 $val = ""; 177 } 178 179 my @vals = split /\s+/, $val; 180 my @exp_vals = split /\s+/, $exp_val; 181 my $i; 182 if ($#vals != $#exp_vals) { 183 main::reg_err("Value mismatch on multirecord [$num], expected $#exp_vals values, got $#vals"); 184 return; 185 } 186 $i = 1; 187 $val = shift(@vals); 188 $exp_val = shift(@exp_vals); 189 while (defined $val) { 190 if (hex($val) != hex($exp_val)) { 191 main::reg_err("Value mismatch on multirecord [$num], expected $exp_val, got $val"); 192 return; 193 } 194 $val = shift(@vals); 195 $exp_val = shift(@exp_vals); 196 $i++; 197 } 198} 199 200sub fru_1_data_check { 201 my $fru = shift; 202 my $version = shift; 203 204 main::check_fru_data($fru, "internal_use_version", -1, "integer", "1"); 205 if ($version == 0) { 206 main::check_fru_data($fru, "internal_use", -1, "binary", 207 "0x02 0x03 0x04 0x05 0x06 0x07 0x08"); 208 } else { 209 main::check_fru_data($fru, "internal_use", -1, "binary", 210 "0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10"); 211 } 212 213 main::check_fru_data($fru, "chassis_info_version", -1, "integer", "1"); 214 main::check_fru_data($fru, "chassis_info_type", -1, "integer", "1"); 215 if ($version == 0) { 216 main::check_fru_data($fru, "chassis_info_part_number", -1, "ascii", 217 "ATCA"); 218 main::check_fru_data($fru, "chassis_info_serial_number", -1, "ascii", 219 "Tes0"); 220 main::check_fru_data($fru, "chassis_info_custom", 0, "ascii", ""); 221 main::check_fru_data($fru, "chassis_info_custom", 1, "ascii", "xyz"); 222 main::check_fru_data($fru, "chassis_info_custom", 2, "ascii", undef); 223 } else { 224 main::check_fru_data($fru, "chassis_info_part_number", -1, "binary", 225 "0x40"); 226 main::check_fru_data($fru, "chassis_info_serial_number", -1, "binary", 227 "0x99 0x88 0x77"); 228 main::check_fru_data($fru, "chassis_info_custom", 0, "ascii", undef); 229 } 230 231 main::check_fru_data($fru, "board_info_version", -1, "integer", "1"); 232 # OpenIPMI converts 0 to 25 (english) 233 main::check_fru_data($fru, "board_info_lang_code", -1, "integer", "25"); 234 main::check_fru_data($fru, "board_info_mfg_time", -1, "time", "820476000"); 235 main::check_fru_data($fru, "board_info_board_manufacturer", -1, "ascii", "Tes1"); 236 if ($version == 0) { 237 main::check_fru_data($fru, "board_info_board_product_name", -1, "ascii", "am4001"); 238 } else { 239 main::check_fru_data($fru, "board_info_board_product_name", -1, "ascii", "AM4001"); 240 } 241 main::check_fru_data($fru, "board_info_board_serial_number", -1, "ascii", "Tes3"); 242 main::check_fru_data($fru, "board_info_board_part_number", -1, "ascii", "Tes4"); 243 main::check_fru_data($fru, "board_info_fru_file_id", -1, "ascii", "Tes5"); 244 main::check_fru_data($fru, "board_info_custom", 0, "ascii", undef); 245 246 main::check_fru_data($fru, "product_info_version", -1, "integer", "1"); 247 # OpenIPMI converts 0 to 25 (english) 248 main::check_fru_data($fru, "product_info_lang_code", -1, "integer", "25"); 249 main::check_fru_data($fru, "product_info_manufacturer_name", -1, "ascii", ""); 250 if ($version == 0) { 251 main::check_fru_data($fru, "product_info_product_name", -1, "ascii", "Te6"); 252 } else { 253 main::check_fru_data($fru, "product_info_product_name", -1, "ascii", "TE"); 254 } 255 main::check_fru_data($fru, "product_info_product_part_model_number", -1, "ascii", 256 "abcdefghijklmnopqrstuvwxyz012345abcdefghijklmnopqrstuvwxyz01234"); 257 main::check_fru_data($fru, "product_info_product_version", -1, "binary", 258 "0x01 0x02 0x03 0x04 0x05 0x06 0x07"); 259 main::check_fru_data($fru, "product_info_product_serial_number", -1, "ascii", ""); 260 main::check_fru_data($fru, "product_info_asset_tag", -1, "ascii", "12345678"); 261 main::check_fru_data($fru, "product_info_fru_file_id", -1, "ascii", '3=8FH$ B'); 262 main::check_fru_data($fru, "product_info_custom", 0, "ascii", 'abcd'); 263 if ($version == 0) { 264 main::check_fru_data($fru, "product_info_custom", 1, "ascii", undef); 265 } else { 266 main::check_fru_data($fru, "product_info_custom", 1, "ascii", 267 "abcdefghijklmnopqrstuvwxyz012345abcdefghijklmnopqrstuvwxyz01234"); 268 main::check_fru_data($fru, "product_info_custom", 2, "ascii", 269 "ASDF1234*()"); 270 main::check_fru_data($fru, "product_info_custom", 3, "ascii", 271 "1234567890--."); 272 } 273 274 275 if ($version == 0) { 276 main::check_fru_mr_data($fru, 0, 0xc0, 2, "0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10"); 277 main::check_fru_mr_data($fru, 1, 0xc1, 2, ""); 278 main::check_fru_mr_data($fru, 2, undef, undef, undef); 279 } else { 280 main::check_fru_mr_data($fru, 0, 0xc1, 2, ""); 281 main::check_fru_mr_data($fru, 1, 0xc2, 2, "0x87 0x55 0x23 0x32 0x99"); 282 main::check_fru_mr_data($fru, 2, 0xc3, 2, "0x87 0xfe 0x99"); 283 main::check_fru_mr_data($fru, 3, 0xc4, 2, ""); 284 main::check_fru_mr_data($fru, 4, undef, undef, undef); 285 } 286} 287 288sub check_area_offset { 289 my $fru = shift; 290 my $area = shift; 291 my $exp_size = shift; 292 my $size; 293 my $rv; 294 295 $rv = $fru->area_get_offset($area, \$size); 296 if ($rv) { 297 if (!defined $exp_size) { 298 # expected 299 return; 300 } 301 302 main::reg_err("or getting area offset for area $area: $rv"); 303 return; 304 } 305 306 if ($size != $exp_size) { 307 main::reg_err(" offset for area $area was $size, expected $exp_size"); 308 } 309} 310 311sub check_area_length { 312 my $fru = shift; 313 my $area = shift; 314 my $exp_length = shift; 315 my $length; 316 my $rv; 317 318 $rv = $fru->area_get_length($area, \$length); 319 if ($rv) { 320 if (!defined $exp_length) { 321 # expected 322 return; 323 } 324 325 main::reg_err("Error getting area length for area $area: $rv"); 326 return; 327 } 328 329 if ($length != $exp_length) { 330 main::reg_err("FRU length for area $area was $length, expected $exp_length"); 331 } 332} 333 334sub check_area_used_length { 335 my $fru = shift; 336 my $area = shift; 337 my $exp_length = shift; 338 my $length; 339 my $rv; 340 341 $rv = $fru->area_get_used_length($area, \$length); 342 if ($rv) { 343 if (!defined $exp_length) { 344 # expected 345 return; 346 } 347 348 main::reg_err("Error getting area used length for area $area: $rv"); 349 return; 350 } 351 352 if ($length != $exp_length) { 353 main::reg_err("FRU used length for area $area was $length, expected $exp_length"); 354 } 355} 356 357$tmpfru = undef; 358 359sub check_area { 360 my $fru = shift; 361 my $area = shift; 362 my $exp_offset = shift; 363 my $exp_length = shift; 364 my $exp_used_length = shift; 365 366 check_area_offset($fru, $area, $exp_offset); 367 check_area_length($fru, $area, $exp_length); 368 check_area_used_length($fru, $area, $exp_used_length); 369} 370 371sub dup_fru { 372 my $newfru = shift; 373 my $oldfru = shift; 374 my $i; 375 my $rv; 376 my $str; 377 my $num; 378 my $oldnum; 379 380 for $i (0 .. 4) { 381 my ($offset, $length); 382 $rv = $oldfru->area_get_offset($i, \$offset); 383 if ($rv) { 384 main::reg_err("Error getting old FRU offset: $rv"); 385 $h->close(); 386 return $rv; 387 } 388 $rv = $oldfru->area_get_length($i, \$length); 389 if ($rv) { 390 main::reg_err("Error getting old FRU offset: $rv"); 391 $h->close(); 392 return $rv; 393 } 394 $rv = $newfru->add_area($i, $offset, $length); 395 if ($rv) { 396 main::reg_err("Error adding FRU area: $rv"); 397 $h->close(); 398 return $rv; 399 } 400 } 401 402 $i = 0; 403 $num = 0; 404 $oldnum = $num; 405 $str = $oldfru->get($i, \$num); 406 while (defined $str) { 407 my ($name, $type, $val) = split /\s+/, $str, 3; 408 409 # Make sure to ignore the FRU area things when setting values. 410 if (!($name =~ /.*_length/) && !($name =~ /.*_offset/) && defined $type) { 411 $rv = $newfru->set($i, $oldnum, $type, $val); 412 413 # Check if we didn't have write permissions, that's ok just go on. 414 if ($rv && ($rv != $OpenIPMI::eperm)) { 415 main::reg_err("Error setting fru field $i [$num]: $rv"); 416 $h->close(); 417 return $rv; 418 } 419 } 420 if ($num < 1) { 421 $num = 0; 422 $i++; 423 } 424 $oldnum = $num; 425 $str = $oldfru->get($i, \$num); 426 } 427 428 $num = $oldfru->get_num_multi_records() - 1; 429 for $i (0 .. $num) { 430 my ($type, $ver, $val) = split /\s+/, $oldfru->get_multirecord($i), 3; 431 432 # If the data is empty for the record, val will be undefined by 433 # the split, but we need to define it because undefined means 434 # delete. 435 if (!defined $val) { 436 $val = ""; 437 } 438 439 $rv = $newfru->set_multirecord($i, $type, $ver, $val); 440 if ($rv) { 441 main::reg_err("Error setting multi-record [$i]: $rv"); 442 $h->close(); 443 return $rv; 444 } 445 } 446} 447 448{ 449 package CloseDomain; 450 sub new { 451 my $a = shift; 452 my $b = \$a; 453 $b = bless $b; 454 return $b; 455 } 456 457 sub domain_cb { 458 my $self = shift; 459 my $domain = shift; 460 461 $domain->close($$self); 462 } 463 464 package CheckRead4; 465 466 sub new { 467 my $self = shift; 468 my $a = {}; 469 $a->{handler} = shift; 470 return bless \$a; 471 } 472 473 sub fru_fetched { 474 print "CheckRead4: Fru fetched\n"; 475 476 my $self = shift; 477 my $domain = shift; 478 my $fru = shift; 479 my $err = shift; 480 my $h = $$self->{handler}; 481 my $rv; 482 my $i; 483 my $num; 484 my $str; 485 486 if ($err) { 487 main::reg_err("Error reading the second FRU: $err"); 488 $h->close(); 489 return; 490 } 491 492 print "Second FRU fetched\n"; 493 main::fru_1_data_check($fru, 1); 494 495 # Done with tests 496 $h->close(); 497 } 498 499 package CheckRead3; 500 501 sub new { 502 my $self = shift; 503 my $a = {}; 504 $a->{handler} = shift; 505 return bless \$a; 506 } 507 508 sub fru_written { 509 print "CheckRead3: Fru written\n"; 510 511 my $self = shift; 512 my $domain = shift; 513 my $fru = shift; 514 my $err = shift; 515 my $h = $$self->{handler}; 516 my $rv; 517 518 if ($err) { 519 main::reg_err("Error writing the FRU: $err"); 520 $h->close(); 521 return; 522 } 523 524 print "FRU written\n"; 525 526 # Now re-read the FRU. 527 $rv = $domain->fru_alloc(1, 0x20, 1, 0, 0, 0, CheckRead4->new($h)); 528 if (! defined $rv) { 529 main::reg_err("Error starting fru fetch: $rv"); 530 $self->close(); 531 return; 532 } 533 } 534 535 sub fru_fetched { 536 print "CheckRead3: Fru fetched\n"; 537 538 my $self = shift; 539 my $domain = shift; 540 my $fru = shift; 541 my $err = shift; 542 my $h = $$self->{handler}; 543 my $rv; 544 my $i; 545 my $num; 546 my $str; 547 548 if ($err != $OpenIPMI::enosys) { 549 main::reg_err("Wrong error reading the FRU: $err"); 550 $h->close(); 551 return; 552 } 553 554 print "Bad FRU fetched, copy the prevous FRU to it\n"; 555 main::dup_fru($fru, $main::tmpfru); 556 if (main::get_errcount()) { 557 $h->close(); 558 return; 559 } 560 main::fru_1_data_check($fru, 1); 561 if (main::get_errcount()) { 562 $h->close(); 563 return; 564 } 565 566 $rv = $fru->write($self); 567 if ($rv) { 568 main::reg_err("Error writing FRU: $rv"); 569 $h->close(); 570 } 571 } 572 573 package CheckRead2; 574 575 sub new { 576 my $self = shift; 577 my $a = {}; 578 $a->{handler} = shift; 579 return bless \$a; 580 } 581 582 sub fru_fetched { 583 print "CheckRead2: Fru fetched\n"; 584 585 my $self = shift; 586 my $domain = shift; 587 my $fru = shift; 588 my $err = shift; 589 my $h = $$self->{handler}; 590 my $rv; 591 my $i; 592 my $num; 593 594 if ($err) { 595 main::reg_err("Error reading the FRU: $err"); 596 $main::lanserv->clearlines(); 597 $main::lanserv->cmd("mc_dump_fru_data 20 0"); 598 for ($i=0; $i<128; $i++) { 599 print $main::lanserv->waitnextline(), "\n"; 600 } 601 $h->close(); 602 return; 603 } 604 605 print "FRU refetched\n"; 606 main::fru_1_data_check($fru, 1); 607 main::check_area($fru, 0, 8, 16, 16); 608 main::check_area($fru, 1, 24, 16, 11); 609 main::check_area($fru, 2, 96, 40, 34); 610 main::check_area($fru, 3, 192, 256, 181); 611 main::check_area($fru, 4, 512, 512, 28); 612 613 $main::tmpfru = $fru; 614 615 print "Fetch a bad FRU\n"; 616 $rv = $domain->fru_alloc(1, 0x20, 1, 0, 0, 0, CheckRead3->new($h)); 617 if (! defined $rv) { 618 main::reg_err("Error starting fru fetch: $rv"); 619 $h->close(); 620 return; 621 } 622 } 623 624 package CheckRead1; 625 626 sub new { 627 my $self = shift; 628 my $a = {}; 629 $a->{handler} = shift; 630 return bless \$a; 631 } 632 633 sub fru_written { 634 print "CheckRead1: Fru written\n"; 635 636 my $self = shift; 637 my $domain = shift; 638 my $fru = shift; 639 my $err = shift; 640 my $h = $$self->{handler}; 641 my $rv; 642 643 if ($err) { 644 main::reg_err("Error writing the FRU: $err"); 645 $h->close(); 646 return; 647 } 648 649 print "FRU written\n"; 650 651 # Now re-read the FRU. 652 $rv = $domain->fru_alloc(1, 0x20, 0, 0, 0, 0, CheckRead2->new($h)); 653 if (! defined $rv) { 654 main::reg_err("Error starting fru fetch: $rv"); 655 $self->close(); 656 return; 657 } 658 } 659 660 sub fru_fetched { 661 print "CheckRead1: Fru fetched\n"; 662 663 my $self = shift; 664 my $domain = shift; 665 my $fru = shift; 666 my $err = shift; 667 my $h = $$self->{handler}; 668 my $rv; 669 my $idx; 670 my $num; 671 672 if ($err) { 673 main::reg_err("Error reading the FRU: $err"); 674 $h->close(); 675 return; 676 } 677 678 print "FRU data read, checking\n"; 679 main::check_area($fru, 0, 8, 8, 8); 680 main::check_area($fru, 1, 16, 24, 20); 681 main::check_area($fru, 2, 48, 40, 35); 682 main::check_area($fru, 3, 88, 104, 100); 683 main::check_area($fru, 4, 192, 832, 26); 684 685 main::fru_1_data_check($fru, 0); 686 687 if (main::get_errcount()) { 688 $h->close(); 689 return; 690 } 691 692 print "Fiddle with area offsets and lengths\n"; 693 # Move the chassis info area out by 16. This should fail. 694 $rv = $fru->area_set_offset(1, 32); 695 if (!$rv) { 696 main::reg_err("Setting the FRU offset to a used offset didn't fail"); 697 $h->close(); 698 return; 699 } 700 701 # Move the chassis info area out by 8. This should succeed. 702 $rv = $fru->area_set_offset(1, 24); 703 if ($rv) { 704 main::reg_err("Error setting the FRU offset: $rv"); 705 $h->close(); 706 return; 707 } 708 709 # Increasing the length should fail. 710 $rv = $fru->area_set_length(1, 32); 711 if (!$rv) { 712 main::reg_err("Increasing the FRU length didn't fail"); 713 $h->close(); 714 return; 715 } 716 717 # Decreasing the length should fail. 718 $rv = $fru->area_set_length(1, 16); 719 if (!$rv) { 720 main::reg_err("Decreasing the FRU length didn't fail"); 721 $h->close(); 722 return; 723 } 724 725 # This should just barely fit. 726 $rv = $fru->set($fru_field_table->{chassis_info_part_number}, 727 -1, "ascii", "abcdefg"); 728 if ($rv) { 729 main::reg_err("Error setting chassis info part number to 8: $rv"); 730 $h->close(); 731 return; 732 } 733 main::check_fru_data($fru, "chassis_info_part_number", -1, "ascii", 734 "abcdefg"); 735 736 # This should not fit. 737 $rv = $fru->set($fru_field_table->{chassis_info_part_number}, 738 -1, "ascii", "jjjjjjjjj"); 739 if (!$rv) { 740 main::reg_err("Setting value of chassis info long didn't fail"); 741 $h->close(); 742 return; 743 } 744 main::check_fru_data($fru, "chassis_info_part_number", -1, "ascii", 745 "abcdefg"); 746 747 # Decrease the size of the chassis info area so we are 1 byte 748 # too long to decrease the length. 749 $rv = $fru->set_array($fru_field_table->{chassis_info_part_number}, 750 -1, "binary", [ 0x40 ]); 751 if ($rv) { 752 main::reg_err("Error setting chassis info part number: $rv"); 753 $h->close(); 754 return; 755 } 756 main::check_fru_data($fru, "chassis_info_part_number", -1, "binary", 757 "0x40"); 758 759 # Decreasing the length should fail. 760 $rv = $fru->area_set_length(1, 16); 761 if (!$rv) { 762 main::reg_err("Decreasing the FRU length didn't fail"); 763 $h->close(); 764 return; 765 } 766 767 main::check_area($fru, 0, 8, 8, 8); 768 main::check_area($fru, 1, 24, 24, 17); 769 main::check_area($fru, 2, 48, 40, 35); 770 main::check_area($fru, 3, 88, 104, 100); 771 main::check_area($fru, 4, 192, 832, 26); 772 773 print "Fiddle with area size\n"; 774 # Decrease the size of the chassis info area so we can decrease 775 # the length. 776 $rv = $fru->set($fru_field_table->{chassis_info_serial_number}, 777 -1, "binary", "0x99 0x88 0x77"); 778 if ($rv) { 779 main::reg_err("Error setting chassis info serial number: $rv"); 780 $h->close(); 781 return; 782 } 783 784 # Decreasing the length should succeed. 785 $rv = $fru->area_set_length(1, 16); 786 if ($rv) { 787 main::reg_err("Error decreasing chassis info area length: $rv"); 788 $h->close(); 789 return; 790 } 791 792 main::check_area($fru, 0, 8, 8, 8); 793 main::check_area($fru, 1, 24, 16, 16); 794 main::check_area($fru, 2, 48, 40, 35); 795 main::check_area($fru, 3, 88, 104, 100); 796 main::check_area($fru, 4, 192, 832, 26); 797 798 print "Fiddle with area size some more\n"; 799 # Decreasing the length should succeed. 800 $rv = $fru->area_set_length(1, 16); 801 if ($rv) { 802 main::reg_err("Error decreasing chassis info area length: $rv"); 803 $h->close(); 804 return; 805 } 806 807 print "Move areas around\n"; 808 # Move everything out. 809 $rv = $fru->area_set_offset(4, 512); 810 if ($rv) { 811 main::reg_err("Error setting multi-record offset: $rv"); 812 $h->close(); 813 return; 814 } 815 $rv = $fru->area_set_offset(3, 192); 816 if ($rv) { 817 main::reg_err("Error setting product info offset: $rv"); 818 $h->close(); 819 return; 820 } 821 $rv = $fru->area_set_offset(2, 96); 822 if ($rv) { 823 main::reg_err("Error setting board info offset: $rv"); 824 $h->close(); 825 return; 826 } 827 828 main::check_area($fru, 0, 8, 8, 8); 829 main::check_area($fru, 1, 24, 16, 16); 830 main::check_area($fru, 2, 96, 40, 35); 831 main::check_area($fru, 3, 192, 104, 100); 832 main::check_area($fru, 4, 512, 512, 26); 833 834 print "Increasing length of product info area and adding values\n"; 835 $rv = $fru->area_set_length(3, 256); 836 if ($rv) { 837 main::reg_err("Error increasing product info area length: $rv"); 838 $h->close(); 839 return; 840 } 841 main::check_area($fru, 0, 8, 8, 8); 842 main::check_area($fru, 1, 24, 16, 16); 843 main::check_area($fru, 2, 96, 40, 35); 844 main::check_area($fru, 3, 192, 256, 100); 845 main::check_area($fru, 4, 512, 512, 26); 846 847 # This should truncate 848 $rv = $fru->set($fru_field_table->{product_info_custom}, 7, "ascii", 849 "abcdefghijklmnopqrstuvwxyz012345abcdefghijklmnopqrstuvwxyz012345"); 850 if ($rv) { 851 main::reg_err("Error setting product info custom 1: $rv"); 852 $h->close(); 853 return; 854 } 855 main::check_fru_data($fru, "product_info_custom", 1, "ascii", 856 "abcdefghijklmnopqrstuvwxyz012345abcdefghijklmnopqrstuvwxyz01234"); 857 main::check_area($fru, 3, 192, 256, 164); 858 $rv = $fru->set($fru_field_table->{product_info_custom}, 7, "ascii", 859 "ASDF1234*()"); 860 if ($rv) { 861 main::reg_err("Error setting product info custom 2: $rv"); 862 $h->close(); 863 return; 864 } 865 main::check_fru_data($fru, "product_info_custom", 2, "ascii", 866 "ASDF1234*()"); 867 main::check_area($fru, 3, 192, 256, 174); 868 869 # Convert an 8-bit field to a 6-bit field in board info 870 $rv = $fru->set($fru_field_table->{board_info_board_product_name}, -1, 871 "ascii", "AM4001"); 872 if ($rv) { 873 main::reg_err("Error setting board info board product name: $rv"); 874 $h->close(); 875 return; 876 } 877 878 # Convert an 8-bit field to a 6-bit field 879 $rv = $fru->set($fru_field_table->{product_info_product_name}, -1, "ascii", 880 "TE"); 881 if ($rv) { 882 main::reg_err("Error setting product info product name: $rv"); 883 $h->close(); 884 return; 885 } 886 main::check_fru_data($fru, "product_info_product_name", -1, "ascii", 887 "TE"); 888 889 $rv = $fru->set($fru_field_table->{product_info_custom}, 7, "ascii", 890 "1234567890--."); 891 if ($rv) { 892 main::reg_err("Error setting product info custom 3: $rv"); 893 $h->close(); 894 return; 895 } 896 main::check_fru_data($fru, "product_info_custom", 3, "ascii", 897 "1234567890--."); 898 $rv = $fru->set_multirecord(7, 0xc2, 2, "0x87 0x55 0x23 0x32 0x99"); 899 if ($rv) { 900 main::reg_err("Error setting multirecord 2: $rv"); 901 $h->close(); 902 return; 903 } 904 main::check_fru_mr_data($fru, 2, 0xc2, 2, "0x87 0x55 0x23 0x32 0x99"); 905 main::check_area($fru, 4, 512, 512, 36); 906 $rv = $fru->set_multirecord_array(7, 0xc3, 2, [ 0x87, 0xfe, 0x99 ]); 907 if ($rv) { 908 main::reg_err("Error setting multirecord 3: $rv"); 909 $h->close(); 910 return; 911 } 912 main::check_fru_mr_data($fru, 3, 0xc3, 2, "0x87 0xfe 0x99"); 913 main::check_area($fru, 4, 512, 512, 44); 914 $rv = $fru->set_multirecord_array(7, 0xc4, 2, [ ]); 915 if ($rv) { 916 main::reg_err("Error setting multirecord 3: $rv"); 917 $h->close(); 918 return; 919 } 920 main::check_fru_mr_data($fru, 4, 0xc4, 2, ""); 921 main::check_area($fru, 4, 512, 512, 49); 922 $rv = $fru->set_multirecord(7, 0xc5, 2, ""); 923 if ($rv) { 924 main::reg_err("Error setting multirecord 2: $rv"); 925 $h->close(); 926 return; 927 } 928 main::check_fru_mr_data($fru, 5, 0xc5, 2, ""); 929 main::check_area($fru, 4, 512, 512, 54); 930 931 $rv = $fru->set_multirecord(0, 0, 0, undef); 932 if ($rv) { 933 main::reg_err("Error deleting multirecord 0: $rv"); 934 $h->close(); 935 return; 936 } 937 main::check_area($fru, 4, 512, 512, 33); 938 939 $rv = $fru->set_multirecord(4, 0, 0, undef); 940 if ($rv) { 941 main::reg_err("Error deleting multirecord 4: $rv"); 942 $h->close(); 943 return; 944 } 945 main::check_area($fru, 4, 512, 512, 28); 946 947 $rv = $fru->set($fru_field_table->{chassis_info_custom}, 1, "ascii", 948 undef); 949 if ($rv) { 950 main::reg_err("Error clearing chassis info custom 1: $rv"); 951 $h->close(); 952 return; 953 } 954 main::check_fru_data($fru, "chassis_info_custom", 1, "ascii", undef); 955 main::check_area($fru, 1, 24, 16, 12); 956 $rv = $fru->set($fru_field_table->{chassis_info_custom}, 0, "ascii", 957 undef); 958 if ($rv) { 959 main::reg_err("Error clearing chassis info custom 0: $rv"); 960 $h->close(); 961 return; 962 } 963 main::check_fru_data($fru, "chassis_info_custom", 0, "ascii", undef); 964 main::check_area($fru, 1, 24, 16, 11); 965 966 print "Cleaning up the internal area\n"; 967 $rv = $fru->area_set_length(0, 16); 968 if ($rv) { 969 main::reg_err("Error increasing internal use area length: $rv"); 970 $h->close(); 971 return; 972 } 973 $rv = $fru->set($fru_field_table->{internal_use}, 0, "binary", 974 "0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10"); 975 if ($rv) { 976 main::reg_err("Error clearing chassis info custom 0: $rv"); 977 $h->close(); 978 return; 979 } 980 981 print "Writing out the FRU\n"; 982 # Make sure it's what we want. 983 main::fru_1_data_check($fru, 1); 984 985 $rv = $fru->write($self); 986 if ($rv) { 987 main::reg_err("Error writing FRU: $rv"); 988 $h->close(); 989 } 990 } 991 992 993 package Handlers; 994 995 sub new { 996 my $a = {}; 997 $a->{keepon} = 1; 998 return bless \$a; 999 } 1000 1001 sub log { 1002 my $self = shift; 1003 my $level = shift; 1004 my $log = shift; 1005 1006 print $level, ": ", $log, "\n"; 1007 } 1008 1009 sub conn_change_cb { 1010 my $self = shift; 1011 my $domain = shift; 1012 my $err = shift; 1013 my $conn_num = shift; 1014 my $port_num = shift; 1015 my $still_connected = shift; 1016 my $rv; 1017 1018 if ($err) { 1019 main::reg_err("Error starting up IPMI connection: $err"); 1020 $self->close(); 1021 return; 1022 } 1023 1024 print "Connection up!\n"; 1025 $rv = $domain->fru_alloc(1, 0x20, 0, 0, 0, 0, CheckRead1->new($self)); 1026 if (! defined $rv) { 1027 main::reg_err("Error starting fru fetch: $rv"); 1028 $self->close(); 1029 return; 1030 } 1031 } 1032 1033 sub domain_close_done_cb { 1034 my $self = shift; 1035 1036 $$self->{keepon} = 0; 1037 } 1038 1039 sub close { 1040 my $self = shift; 1041 my $domain = shift; 1042 1043 if (defined $$self->{domain_id}) { 1044 my $v = CloseDomain::new($self); 1045 $$self->{domain_id}->to_domain($v); 1046 } else { 1047 $$self->{keepon} = 0; 1048 } 1049 } 1050 1051} 1052 1053package main; 1054 1055$lanserv = Lanserv->new(); 1056if (! $lanserv) { 1057 main::reg_err("Unable to start lanserv"); 1058 exit(1); 1059} 1060 1061# Add a BMC 1062$lanserv->cmd("mc_add 0x20 0 has-device-sdrs 0x23 9 8 0x1f 0x1291 0xf02"); 1063$lanserv->cmd("main_sdr_add 0x20 0x00 0x00 0x51 0x12 0x0f 0x20 0x00 0x00 0x1f 0x00 0x00 0x00 0x07 0x01 0x00 0xc4 'T 'e 's 't"); 1064 1065# Create some FRU information 1066$lanserv->cmd 1067 ("mc_add_fru_data 0x20 0x0 0x400 data " . 1068 " 0x01 0x01 0x02 0x06 0x0b 0x18 0x00 0xd3" . 1069# Internal Use 1070 " 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08" . 1071# Chassis info 1072 " 0x01 0x03 0x01 0xc4 'A 'T 'C 'A" . 1073 " 0xc4 'T 'e 's '0 0xc0 0xc3 'x" . 1074 " 'y 'z 0xc1 0x00 0x00 0x00 0x00 0x4f" . 1075# Expansion space 1076 " 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00" . 1077# Board info 1078 " 0x01 0x05 0x00 0x00 0x00 0x00 0xc4 'T" . 1079 " 'e 's '1 0xc6 'a 'm '4 '0" . 1080 " '0 '1 0xc4 'T 'e 's '3 0xc4" . 1081 " 'T 'e 's '4 0xc4 'T 'e 's" . 1082 " '5 0xc1 0x00 0x00 0x00 0x00 0x00 0x53" . 1083#Product Info 1084 " 0x01 0x0d 0x00 0xc0 0xc3 'T 'e '6" . 1085 " 0xff 'a 'b 'c 'd 'e 'f 'g" . 1086 " 'h 'i 'j 'k 'l 'm 'n 'o" . 1087 " 'p 'q 'r 's 't 'u 'v 'w" . 1088 " 'x 'y 'z '0 '1 '2 '3 '4" . 1089 " '5 'a 'b 'c 'd 'e 'f 'g" . 1090 " 'h 'i 'j 'k 'l 'm 'n 'o" . 1091 " 'p 'q 'r 's 't 'u 'v 'w" . 1092 " 'x 'y 'z '0 '1 '2 '3 '4" . 1093 " 0x07 0x01 0x02 0x03 0x04 0x05 0x06 0x07" . 1094 " 0xc0 0x48 0x21 0x43 0x65 0x87 0x88 0x53" . 1095 " 0x87 0x99 0x28 0x01 0x88 0xc4 'a 'b" . 1096 " 'c 'd 0xc1 0x00 0x00 0x00 0x00 0xe4" . 1097# Multi-records 1098 " 0xc0 0x02 0x10 0x78 0xb6 0x01 0x02 0x03" . 1099 " 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b" . 1100 " 0x0c 0x0d 0x0e 0x0f 0x10 0xc1 0x82 0x00" . 1101 " 0x00 0xbd" 1102); 1103 1104# Create a dummy FRU that has an error 1105$lanserv->cmd("mc_add_fru_data 0x20 1 0x400 data 0x01"); 1106 1107$lanserv->cmd("mc_enable 0x20"); 1108 1109sleep 1; 1110 1111#OpenIPMI::enable_debug_msg(); 1112OpenIPMI::enable_debug_malloc(); 1113 1114# Now start OpenIPMI 1115$rv = OpenIPMI::init(); 1116if ($rv != 0) { 1117 print "init failed"; 1118 exit 1; 1119} 1120 1121$i = 0; 1122$s = OpenIPMI::fru_index_to_str($i); 1123while (defined $s) { 1124 $fru_field_table->{$s} = $i; 1125 $i++; 1126 $s = OpenIPMI::fru_index_to_str($i); 1127} 1128 1129$h = Handlers::new(); 1130 1131OpenIPMI::set_log_handler($h); 1132 1133@args = ( "-noseteventrcvr", 1134 "lan", "-p", "9000", "-U", "minyard", "-P", "test", "localhost"); 1135$$h->{domain_id} = OpenIPMI::open_domain2("test", \@args, $h, \undef); 1136if (! $$h->{domain_id}) { 1137 $lanserv->close(); 1138 print "IPMI open failed\n"; 1139 exit 1; 1140} 1141 1142while ($$h->{keepon}) { 1143 OpenIPMI::wait_io(1000); 1144} 1145 1146# Make sure our copy of the FRU is destroyed. 1147$main::tmpfru = undef; 1148 1149$lanserv->close(); 1150OpenIPMI::shutdown_everything(); 1151exit main::get_errcount(); 1152