pax_global_header00006660000000000000000000000064131523526430014516gustar00rootroot0000000000000052 comment=2e26d2996789a1e61dd0a872f579dc5768128836 powerpc-utils-1.3.4/000077500000000000000000000000001315235264300143405ustar00rootroot00000000000000powerpc-utils-1.3.4/.gitignore000066400000000000000000000025701315235264300163340ustar00rootroot00000000000000# # NOTE! Don't add files that are generated in specific # subdirectories here. Add them in the ".gitignore" file # in that subdirectory instead. # # NOTE! Please use 'git ls-files -i --exclude-standard' # command after changing this file, to see if there are # any tracked files which get ignored after the change. # # Normal rules # .* *.o *.o.* *.a *.s *.so *.so.dbg *.mod.c *.i *.order *.gz *.bz2 *.lzma *.zip *.lzo *.patch *.gcno # # Build files # /aclocal.m4 /autom4te.cache/ /config/ /config.log /config.status /configure /Makefile /Makefile.in /man/Makefile /man/Makefile.in /powerpc-utils.spec /scripts/Makefile /scripts/Makefile.in /src/Makefile /src/Makefile.in /src/drmgr/Makefile /src/drmgr/Makefile.in /systemd/smt_off.service # # git files that we don't want to ignore even it they are dot-files # !.gitignore # # Generated include files # include/config include/linux/version.h include/generated # stgit generated dirs patches-* # quilt's files patches series # cscope files cscope.* ncscope.* # ctags tags TAGS # gnu global files GPATH GRTAGS GSYMS GTAGS # Executables /src/activate_firmware /src/drmgr/drmgr /src/drmgr/lsslot /src/lparstat /src/lsprop /src/nvram /src/ppc64_cpu /src/rtas_event_decode /src/rtas_ibm_get_vpd /src/serv_config /src/set_poweron_time /src/sys_ident /src/uesensor /src/usysattn /src/usysident /src/errinjct/errinjct /src/rtas_dbg *.orig *~ \#*# powerpc-utils-1.3.4/COPYING000066400000000000000000000432541315235264300154030ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. powerpc-utils-1.3.4/Changelog000066400000000000000000002524021315235264300161570ustar00rootroot00000000000000powerpc-utils-1.3.4 ===================================================================== commit c8083fbc1bfe1548057478ae46543bf58bffc7d4 Author: Michael Bringmann Date: Wed Aug 23 09:06:45 2017 -0500 powerpc-utils.spec: Add "Vendor: IBM Corp." Ensure that "Vendor: IBM Corp." appears in archive for all checkouts and derived builds. Signed-off-by: Michael Bringmann Signed-off-by: Tyrel Datwyler commit 50f11c6c6618e7d59232d67e7446d07714af453b Author: Nathan Fontenot Date: Thu Jul 6 12:31:36 2017 -0400 lsslot: Validate DRC property groups Recently seen on a kvm guest running on a PowerNV system, the lsslot command segfaulted when trying to free the drc information. # gdb -q ./lsslot Reading symbols from ./lsslot...done. (gdb) run -c memory Starting program: ./lsslot -c memory Program received signal SIGSEGV, Segmentation fault. free_drc_info () at src/drmgr/common_ofdt.c:287 287 all_drc_lists = list->all_next; The root cause of this is that the DRC properties in the guest were empty. This caused the lsslot (and likely possible in drmgr since this code is common to both commands) to improperly parse the device tree information. To fix this we need to add a check after gathering information for each of the DRC properties when reading DRC property group data. If there are no entries in any of the DRC properties we cannot continue. Reported-by: Seeteena Thoufeek Signed-off-by: Nathan Fontenot Signed-off-by: Tyrel Datwyler commit c25ae395db914f1137bb8a718277ea4b6f69136b Author: Samuel Mendoza-Jonas Date: Mon Jul 10 11:23:27 2017 +1000 ppc64_cpu: Treat CPUs as online if cpu hotplug not enabled cpu_online() looks for the "online" attribute to decide if a cpu is online, however if the kernel does not have CONFIG_HOTPLUG_CPU enabled the attribute will not exist. get_attribute() calls access() first to check if the attribute exists, which will set errno with ENOENT if it is missing. If get_attribute() fails with this specific error, treat the cpu as online. Signed-off-by: Samuel Mendoza-Jonas [tyreld: removed unnecessary braces from if block] Signed-off-by: Tyrel Datwyler commit 817900edd96c66d6f43f75aaefbe38bba6bab035 Author: Tyrel Datwyler Date: Fri Aug 4 16:24:01 2017 -0700 Revert "ppc64_cpu: Treat CPUs as online if cpu hotplug not enabled" This reverts commit 5f70f6c1af2dd61122acfdbaa6e38be062bb220a. Reverting the commit as further inspection came to show it actually marked a cpu as offline when hotplug was not enabled. Signed-off-by: Tyrel Datwyler commit 136fab970076018bd56aa1aa0c09b8954b89b0b5 Author: Nathan Fontenot Date: Tue Jun 6 12:12:36 2017 -0400 drmgr: Correct some bad formatting in drmig_chrp_pmig.c No functional changes, justy making the code more readable. Signed-off-by: Nathan Fontenot Signed-off-by: Tyrel Datwyler commit 1c5319c76ae8b378bfd59e8c0a08e89f83867dbf Author: Nathan Fontenot Date: Wed Jun 7 16:35:33 2017 -0400 drmgr: Correct errno usage in init_cpu_info() The error message reported if allocaing a dr node fails should not report the errno value. The call to allocate the dr node makes multiple syscalls and there is no way to determine which one last updated errno. Signed-off-by: Nathan Fontenot Reviewed-by: Paul Clarke Signed-off-by: Tyrel Datwyler commit 998933a5185f9c56d1d6bce77301f3e7be6a54cf Author: Nathan Fontenot Date: Wed Jun 7 16:35:28 2017 -0400 drmgr: Correct errno usage use in validate_paltform() For validate_platform(), the call to get_property makes many system calls and there is no way to know what last updated the errno value. This patch drops the output of strerror() due to this reason. Signed-off-by: Nathan Fontenot Reviewed-by: Paul Clarke Signed-off-by: Tyrel Datwyler commit d1c6662d38adeb98a1fd8906cd54031c6fdd653d Author: Nathan Fontenot Date: Wed Jun 7 16:35:22 2017 -0400 drmgr: Stale errno usage corrections Several places in the drmgr code use a stale value of errno either as a return code or when printing an error message. A common example of this is calling the say() routine and then returning the value of errno. The say() routine makes several system calls and the value of errno after a call to say() no longer reflects the original errno value. Several places in the drmgr code were updated to properly handle the return codes from functions such as write() or open() where we should be checking for rc == -1 instead of rc <= 0. This does make a difference as errno won't be set for rc == 0. Note that partial write return codes are not really handled in the drmgr code. The drmgr command is writing to sysfs and /proc files where we know that they will either return success or failure and set errno, no partial writes. Signed-off-by: Nathan Fontenot Reviewed-by: Paul Clarke Signed-off-by: Tyrel Datwyler commit 479f1a1122f7d9025d3a21e60a0431d2eba6ee2f Author: Nathan Fontenot Date: Tue Jun 6 12:12:22 2017 -0400 drmgr: Correct drc type checking in check_kmods() Fixes: f9986ac43011 ("drmgr: Move options.ctype to global usr_drc_type") When the conversion to using the global usr_drc_type was made the logic checking for whic drc types we need to check the rpadlpar_io kernbel module for was broken. This corrects the check. Signed-off-by: Nathan Fontenot Signed-off-by: Tyrel Datwyler commit 27e8d5b8218bc8c8c772080b0d99691bd31d4f0f Author: Chandni Verma Date: Thu Jun 1 19:07:13 2017 +0530 lsslot: Rectify usr_drc_name check This incorrect check refrains lsslot from displaying the slot information. Fixes: e82fb588f573 (lsslot: replace struct options member s_name with usr_drc_name) Signed-off-by: Chandni Verma Signed-off-by: Nathan Fontenot [tyreld: added fixes tag] Signed-off-by: Tyrel Datwyler commit 74715cc0e4db0e2738be7a19c852816c285d8284 Author: Nathan Fontenot Date: Mon May 22 16:40:58 2017 -0400 lsdevinfo: Add support for vNIC devices Add support to dump information about vNIC devices so that device info requests from the HMC can retrieve data about vNIC devices. Signed-off-by: Nathan Fontenot [tyreld: fixed up trailing whitespace] Signed-off-by: Tyrel Datwyler commit 25615a80f3fb5ebcc26d7b00316afce8c46ab2f9 Author: Nathan Fontenot Date: Mon May 22 16:40:50 2017 -0400 ofpathname: Add support for vNIC devices Add 'vnic' to the list of device types for of2l_ethernet so vNIC devices are supported. Signed-off-by: Nathan Fontenot Signed-off-by: Tyrel Datwyler commit 6464f8e96228f7db355f08f270ada1104c3562c3 Author: Amartey Pearson Date: Tue May 16 14:01:30 2017 -0500 Improve perf of drmgr/lsslot with large num of virt. dev. The current algorithm for add_pci_vio_node walks the vdevice bus for every theoretical DRC (1000's of times). The more vdevices you have populated, the worse this algorithm becomes. On a system with 450 devices, this can take over 30 seconds for example. This modifies the algorithm to populate a node list of existing devices (so walks the tree just once), and then uses these nodes when populating the full list instead of walking the device tree for each one. NOTE: This only is changed for virtual devices - a system with large numbers of PCI devices will not be optimized, but that is less of a concern. Signed-off-by: Amartey Pearson Signed-off-by: Bryant G. Ly [tyreld: changed my_drc_index type from u32 to uint32_t] Signed-off-by: Tyrel Datwyler commit 7539330a301ff9ac7d6fd5e1cf974bb9999100b2 Author: Tyrel Datwyler Date: Fri May 19 16:02:51 2017 -0400 Test for zlib presence at configuration time The nvram utility links with zlib and compilation will fail if zlib.h or libz.so are not present. Check and warn at configuration time. Signed-off-by: Tyrel Datwyler commit 3a7b15104fb956aa2e5debababe8536dbd4e8cef Author: Russell Currey Date: Fri May 19 17:36:45 2017 -0400 errinjct: Remove platform check to enable KVM guests qemu/KVM guests can have RTAS as well. There's already a check to see if RTAS is present, there's no need to hardcode the supported platform. Removing this check allows errinjct to work on KVM guests. Signed-off-by: Russell Currey Signed-off-by: Tyrel Datwyler commit 5f70f6c1af2dd61122acfdbaa6e38be062bb220a Author: Samuel Mendoza-Jonas Date: Fri Apr 21 16:47:57 2017 +1000 ppc64_cpu: Treat CPUs as online if cpu hotplug not enabled cpu_online() looks for the "online" attribute to decide if a cpu is online, however if the kernel does not have CONFIG_HOTPLUG_CPU enabled the attribute will not exist. If hotplug is not enabled then the cpu can be assumed to be online - in this case, update cpu_online() to treat the cpu as online. Signed-off-by: Samuel Mendoza-Jonas Acked-by: Stewart Smith Signed-off-by: Tyrel Datwyler commit 4fcc611a09caea70e6bca6a1275211c72ac4bb45 Author: Seeteena Thoufeek Date: Wed Jan 11 15:36:33 2017 +0530 warning: command substitution: ignored null byte in input device Ubuntu 17.04: "command substitution: ignored null byte in input" warning message is displayed while running few RAS commands. The command execution of ls-veth, ls-vscsi, lsdevinfo, and ofpathname returns following output. lsdevinfo /usr/sbin/lsdevinfo: line 233: warning: command substitution: ignored null byte in input device: name="ibmveth2" ls-vscsi /usr/sbin/ls-vscsi: line 72: warning: command substitution: ignored null byte in input host0 U8286.42A.1069B3T-V8-C17-T1 ls-veth /usr/sbin/ls-veth: line 74: warning: command substitution: ignored null byte in input ibmveth2 U8286.42A.1069B3T-V8-C2-T1 ofpathname sda /usr/sbin/ofpathname: line 812: warning: command substitution: ignored null byte in input /usr/sbin/ofpathname: line 865: cd: too many arguments /vdevice/v-scsi@30000011/disk@8100000000000000 Newer versions of bash (Bash 4.4) warn about null bytes in command substitutions. This is fixed. Also fixed /usr/sbin/ofpathname: line 865: cd: too many arguments. Signed-off-by: Seeteena Thoufeek Signed-off-by: Tyrel Datwyler commit 25b8f7d67fb3acee0970cd36f24dc17fac1f6dc3 Author: Pawan K Singh5 Date: Mon Apr 10 15:00:28 2017 +0530 ofpathname : avoid duplicate entries of vFC devices Adding support to avoid the duplicate entries of a Open Firmware device path to logical device path for vfc-client devices. The problem can be reproduced with the bootlist command # bootlist -m normal /dev/sdd /dev/sds /dev/sdf /dev/sdv # bootlist -m normal -r /vdevice/vfc-client@30000899/disk@500507680b2255fe /vdevice/vfc-client@30000899/disk@500507680b2255ff /vdevice/vfc-client@3000089a/disk@500507680b2255fe /vdevice/vfc-client@3000089a/disk@500507680b2255ff # bootlist -m normal -o sda---------------->expected "sdd" sdp---------------->expected "sds" sda---------------->expected "sdf" sdp---------------->expected "sdv" So, this patch check the duplicate entries of logical names of vFC devices at of2l_vfc() and display specified bootlist : # bootlist -m normal -r /vdevice/vfc-client@30000899/disk@500507680b2255fe /vdevice/vfc-client@30000899/disk@500507680b2255ff /vdevice/vfc-client@3000089a/disk@500507680b2255fe /vdevice/vfc-client@3000089a/disk@500507680b2255ff # bootlist -m normal -o sdd sds sdf sdv Signed-off-by: Pawan K Singh5 Signed-off-by: Tyrel Datwyler powerpc-utils-1.3.3 ===================================================================== commit d63e12aa7cd22d5e6c2baf595aacb644311e0217 Author: Mamatha Inamdar Date: Tue Dec 6 11:36:57 2016 -0500 nvram:read list of partion names dynamically This patch is to read "list of partition dynamically and use it rather than having hardcoded partition table list. Test Results: without patch: nvram: ERROR: There is no Open Firmware "ibm,skiboot" partition! with patch: "ibm,skiboot" Partition -------------------------- experimental-fast-reset=feeling-lucky Signed-off-by: Mamatha Inamdar Tested-by: Vasant Hegde commit b54a095e820d0163e29b76b517b57227a358950d Author: Nathan Fontenot Date: Tue Dec 6 11:29:17 2016 -0500 lsslot: Correct formatting fopr printing cpus and caches Minor updates to the field sizes when printing cpus and caches so that the fields no longer run together. Signed-off-by: Nathan Fontenot commit 9d363cd79315f08d00e63674b3608dd3fdd72939 Author: Nathan Fontenot Date: Tue Dec 6 11:16:14 2016 -0500 lsslot: Validate cpu->name when printing When printing the information for all possible CPUs we can possibly print a NULL string pointer. the libc printf code handles this gracefully by printing '(NULL)' but this is not what we should be relying on. This validates the cpu->name pointer before printing it and instead prints '--' if cpu->name is not valid. Signed-off-by: Nathan Fontenot commit b3b35e9a84913f98ab1abf8ac019c8f3a94a5e1d Author: Nathan Fontenot Date: Tue Dec 6 11:12:06 2016 -0500 lsslot: Allow printing information of all possible cpus The lsslot command gathers information about all possible cpus on a system but only prints information about cpus that are present. This patch adds the ability to print information about all possible cpus when the '-d 4' option is used. Signed-off-by: Nathan Fontenot commit 8b229153221416bfdcd06ef67ad3a18fb5bea171 Author: Michel Normand Date: Tue Dec 6 11:03:00 2016 -0500 ofpathname: Avoid infinit loop in get_slave() This is a bypass for a problem raised on openSUSE with bug https://bugzilla.suse.com/show_bug.cgi?id=1011529 Signed-off-by: Michel Normand commit 944cc93ae316edc99bbac1a83f5b0e1aa9401657 Author: Paul A. Clarke Date: Thu Dec 1 11:05:25 2016 -0500 ppc64_cpu: emit error message for invalid core number to on- or offline An off-by-one test is done to detect invalid core numbers for explicit online/offline. For example, on a 16 core system, valid cores are 0-15. However, specifying "16" has no effect, but does not produce an error: -- # ./src/ppc64_cpu --cores-on Number of cores online = 15 # ppc64_cpu --online-cores=16 # ppc64_cpu --online-cores=17 Invalid core to online: 17 -- This change will correctly report an error: -- # ppc64_cpu --online-cores=16 Invalid core to online: 16 -- Signed-off-by: Paul A. Clarke commit be7583177b845b69b7c2e1f21f2652c0545c996d Author: Nathan Fontenot Date: Tue Nov 29 11:42:37 2016 -0500 lsprop: Update and honor recurse option The -R (recurse) option to lsprop is not honored when dumping the contents of a directory. Update the option to also include --recurse and honor this option when specified. Signed-off-by: Nathan Fontenot commit 69b62ea770c6f84f91706d8610a2815fbb19decc Author: Nathan Fontenot Date: Tue Nov 29 11:41:27 2016 -0500 lsprop: Add command version Signed-off-by: Nathan Fontenot commit ab587974c47f3c45929c748a16eee33e875c53f3 Author: Paul A. Clarke Date: Tue Nov 29 11:33:54 2016 -0500 ppc64_cpu: tolerate non-uniform per-core SMT mode If not every core is in the same SMT state, the ppc64_cpu command will report such and no information specific to the command request: -- # ppc64_cpu --cores-on Bad or inconsistent SMT state: use ppc64_cpu --smt=on|off to set all cores to have the same number of online threads to continue. Core 0: 0* 1* 2* 3* Core 1: 4* 5* 6* 7* Core 2: 8* 9* 10* 11* Core 3: 12* 13* 14* 15* Core 4: 16* 17* 18* 19* Core 5: 20* 21* 22* 23* Core 6: 24* 25* 26* 27* Core 7: 28* 29* 30* 31* Core 8: 32* 33 34 35 Core 9: 36* 37 38 39 Core 10: 40* 41* 42* 43* Core 11: 44* 45* 46 47 Core 12: 48* 49* 50* 51* Core 13: 52 53 54* 55* Core 14: 56 57 58 59 Core 15: 60* 61* 62* 63 # ppc64_cpu --online-cores Bad or inconsistent SMT state: use ppc64_cpu --smt=on|off to set all cores to have the same number of online threads to continue. Core 0: 0* 1* 2* 3* Core 1: 4* 5* 6* 7* Core 2: 8* 9* 10* 11* Core 3: 12* 13* 14* 15* Core 4: 16* 17* 18* 19* Core 5: 20* 21* 22* 23* Core 6: 24* 25* 26* 27* Core 7: 28* 29* 30* 31* Core 8: 32* 33 34 35 Core 9: 36* 37 38 39 Core 10: 40* 41* 42* 43* Core 11: 44* 45* 46 47 Core 12: 48* 49* 50* 51* Core 13: 52 53 54* 55* Core 14: 56 57 58 59 Core 15: 60* 61* 62* 63 # ppc64_cpu --offline-cores Bad or inconsistent SMT state: use ppc64_cpu --smt=on|off to set all cores to have the same number of online threads to continue. Core 0: 0* 1* 2* 3* Core 1: 4* 5* 6* 7* Core 2: 8* 9* 10* 11* Core 3: 12* 13* 14* 15* Core 4: 16* 17* 18* 19* Core 5: 20* 21* 22* 23* Core 6: 24* 25* 26* 27* Core 7: 28* 29* 30* 31* Core 8: 32* 33 34 35 Core 9: 36* 37 38 39 Core 10: 40* 41* 42* 43* Core 11: 44* 45* 46 47 Core 12: 48* 49* 50* 51* Core 13: 52 53 54* 55* Core 14: 56 57 58 59 Core 15: 60* 61* 62* 63 # ppc64_cpu --smt Inconsistent state: mix of ST and SMT cores -- This change allows the ppc64_cpu command to properly respond to the above requests: -- # ppc64_cpu --cores-on Number of cores online = 15 # ppc64_cpu --online-cores Cores online = 0,1,2,3,4,5,6,7,8,9,10,11,12,13,15 # ppc64_cpu --offline-cores Cores offline = 14 # ppc64_cpu --smt SMT=1: 8-9 SMT=2: 11,13 SMT=3: 15 SMT=4: 0-7,10,12 -- Note that the output for "--smt" only changes if there is mixed modes. If the mode is uniform, the output will remain as before: # ppc64_cpu --smt=4 # ppc64_cpu --smt SMT=4 Signed-off-by: Paul A. Clarke commit e227a80df7643a1f45e0d2b06e56ef430772c2dd Author: Breno Leitao Date: Tue Nov 22 12:22:45 2016 -0500 ppc64_cpu: add a numeric option when printing SMT Currently, there is not a numeric (non verbose) display of SMT modes, which means that three verbose output is usually generated, as: SMT=X SMT is off Machine is not SMT capable This patch implements a easily machine parsable output for SMT, helping a lot of scripts that needs to read SMT status on a machine. I am considering that if the SMT is off or impossible, then SMT=1 (1 thread per core), thus, always returning SMT=X, where X means thread enabled per core, as 1, 2, 4, 8. Signed-off-by: Breno Leitao commit 09b36b64ec51bd8ce6c0b2b345974cb228064b89 Author: Breno Leitao Date: Tue Nov 22 12:16:35 2016 -0500 Fix man page for ppc64_cpu Currently there is a typo on ppc64_cpu manpage which causes the text to be corrupted, not printing anything after this typo, as showed: --smt Display the current smt setting for the system. The ..... threads online varies per core, or As you can see, there is nothing else after the ", or" expression. This patch simply fixes this typo, which makes the manpage render correctly. Signed-off-by: Breno Leitao Reviewed-by: Vasant Hegde commit 59a17aac4728a3c060f128b315df1324b8df39f5 Author: Nathan Fontenot Date: Tue Nov 22 11:43:20 2016 -0500 lprstat: Add command version Signed-off-by: Nathan Fontenot Reviewed-by: Vasant Hegde commit 4519274c0bdbd781f660a1df8ca41cbe267229e4 Author: Nathan Fontenot Date: Tue Nov 22 11:42:15 2016 -0500 activate_firmware: Remove extraneous comments Signed-off-by: Nathan Fontenot commit 7e9a53937469c451de78d321abe64434ce3e0731 Author: Nathan Fontenot Date: Tue Nov 22 11:41:12 2016 -0500 activate_firmware: Add verbose output option The activate_firmware currently has some debug statements that can only be activated by building the command with DEBUG defined. Instead, we should always have these statements active and control their output with the -v, --verbose option. Signed-off-by: Nathan Fontenot commit 2b0867d3327442fa8bcb42269db3436b5507ac2f Author: Nathan Fontenot Date: Tue Nov 22 11:40:09 2016 -0500 activate_firmware: Update the usage message and option parsing The usage message for activate_firmware should limit itself to 80 characters per line. Additionally the formatting could use a little updating now that we have long options. The new help message appears as: Usage: src/activate_firmware [-e [keyfile]] Without any option, the activate_firmware utility will cause a firmware image that has already been flashed to be activated concurrently. Option summary: -e prints the current Update Access Key expiry date -e applies the provided Update Access key-file to extend the service expiry date -h, --help print this message. -v, --verbose output extra debug information -V, --version print version information. This patch also allows users to specify --help in addition -h for the help option. Signed-off-by: Nathan Fontenot Reviewed-by: Vasant Hegde commit 1c4f7810323f3859f0359250eb3a6f4fab4ff036 Author: Nathan Fontenot Date: Tue Nov 22 11:38:42 2016 -0500 activate_firmware: Add versioning Add versioning to the activate_firmware command. Signed-off-by: Nathan Fontenot Reviewed-by: Vasant Hegde Reviewed-by: Tyrel Datwyler commit 06f2033866b2a991def24354e8657c8146c43b95 Author: Breno Leitao Date: Wed Nov 9 16:24:22 2016 -0500 Fix endian.h header on FreeBSD Unfortunately Linux default endian.h is locaed in sys/endian.h on FreeBSD. This patch simply detect what system you are running and use the proper location on the include. Signed-off-by: Breno Leitao commit 28ec98068a3d06e77d8d3496c26e2f4ff8e61aeb Author: Breno Leitao Date: Wed Nov 9 16:23:10 2016 -0500 Avoid linking with libdl on BSD systems FreeBSD does not have libdl, so, when linking with -ldl fails. This patch simply check if you are running on BSD, and does not invoke -ldl during compilation. Signed-off-by: Breno Leitao commit eca0c56ab6b041c1c90aa213492121d6f0d0c6af Author: Breno Leitao Date: Wed Nov 9 16:20:20 2016 -0500 ppc64_cpu: Fix function method signature If HAVE_LINUX_PERF_EVENT_H is not defined, the code fails to compile, because function do_cpu_frequency() does not have an Argument, as it has if HAVE_LINUX_PERF_EVENT_H is defined. This is the error message: error: too many arguments to function 'do_cpu_frequency' This patch simply adds an argument to the function. Signed-off-by: Breno Leitao commit 741054926742785290ed1cfacac04d8e55409b4a Author: Nathan Fontenot Date: Wed Oct 19 10:40:25 2016 -0400 .gitignore: Add errinjct and rtas_dbg executables Signed-off-by: Nathan Fontenot commit d42164cd2dde616ba51b4143d9c17aa0b9c40b4a Author: Hariharan T.S Date: Wed Oct 19 10:37:51 2016 -0400 hvcsadmin: findtools should be called before is_driver installed scripts/hvcsadmin: is_driver_installed is using systools, where as the same is checked for existence in findtools which is called later. It has to be called before to get the proper error message. The patch will first check for systools before checking for drivers. It will avoid the following situation. hvcsadmin -status Can't exec "systool": No such file or directory at /usr/sbin/hvcsadmin line 272. systool: No such file or directory at /usr/sbin/hvcsadmin line 272. Signed-off-by: Hariharan T.S. commit 0947a3dbaed4fc02e7d2d19cb0cdc6059fb86d5b Author: Nathan Fontenot Date: Wed Oct 19 10:35:09 2016 -0400 drmgr: Cleanup unused progress states in acquiring hotplug resources The progress state that is updated throughout the process of acquiring a hotplug resource is not used anywhere. This patch removes it. Signed-off-by: Nathan Fontenot commit e116eb625c5cb194cb8bd59ddf1564e5268e6b31 Author: Nathan Fontenot Date: Wed Oct 19 10:33:26 2016 -0400 drmgr: Add capability for PCI hotplug only operations We need to provide the capability to do a hotplug only style of operation for some adapters such as nvme adapters behind a bridge that can be owned by more than one partition. These scenarios are used for doing failovers and this update reduces the total drmgr time from 18 seconds per add or remove down to 2-3 seconds per action. Note that this is different from the PAPR notion of hotplug where the device is hotplug removed from the OS, then the slot is powered down, a new card inserted, the slot powered up, and the device hootplug added back into the system. This is the drmgr -R action. This new functionality just does the hotplug to/from the OS, nothing else. This update assumes that when doing an add, the DR indicator already has the proper isolation and allocation state, and the power to the slot is on. For remove operations the indicator and power for the slot is not modified. Signed-off-by: Nathan Fontenot commit 071949595434f68c7ed722b932173d9f69c20c84 Author: Stephen E. Royer Date: Thu Sep 1 10:12:10 2016 -0400 nvsetenv: Fix unitialized variable in 'hvcsadmin' scripts/hvcsadmin: Fix display of distracting perl script warning notice about an unitialized variable during execution. The message is an annoyance during operation. Signed-off-by: Stephen E. Royer Signed-off-by: Michael Bringmann commit 16d7b3126e0c73a1eeb94742559934034667e4c7 Author: Michael Bringmann Date: Thu Sep 1 10:09:15 2016 -0400 nvsetenv: Fix rpmbuild inclusion for nvsetenv Update Makefile.am to add the nvsetenv command to sbin_SCRIPTS so that is is included in generated tarballs from 'make dist'. Signed-off-by: Michael Bringmann commit b071e81d8cd71af496d5c5b36371c30449051def Author: John Allen Date: Fri Aug 26 15:29:58 2016 -0400 lparstat: Ignore whitespace at beginning of /proc/interrupts SPU line In the case that any interrupt number in /proc/interrupts exceeds 3 characters, whitespace will be placed at the beginning of the SPU line in order to keep the columns aligned. In that case, the current code will miss the SPU line. This patch skips any whitespace preceding the SPU line. Signed-off-by: John Allen commit ce767e7a7254e5dd38655b67e31a7b337df5d68e Author: John Allen Date: Fri Aug 26 15:26:12 2016 -0400 drmgr: Include GPL header in prrn.c Add GPL boilerplate to prrn.c for consistency with other files in powerpc-utils. Signed-off-by: John Allen commit 5814722814f876d584f59afdb38e7d3f23e6c7ad Author: Nathan Fontenot Date: Fri Aug 26 15:21:06 2016 -0400 drmgr: Add options.c to Makefile for creating tarballs Previous updates that ctreated the file options.c that is #included instead of built directly for drmgr and lsslot did not update the Makefile to ensure this file is included in tarballs when doing a 'make dist'. Add options.c to the list of NOINST_HEADERS for drmgr and lsslot. Signed-off-by: Nathan Fontenot commit 5799f6f26c34b6e7ac200e50666188279704937c Author: Michael Bringmann Date: Fri Aug 26 15:17:25 2016 -0400 nvsetenv: Add nvsetenv from SUSE distro nvsetenv: Add the nvsetenv script to the package which is normally only present in the SuSE variant of powerpc-utils. The script is a wrapper for the nvram utility. Signed-off-by: Michael Bringmann commit 3c3a53825248e1ef52ee203c968f643c26820cc5 Author: John Allen Date: Tue Aug 23 11:23:31 2016 -0400 lparstat: Fix segfault when parsing /proc/interrupts Fix a bug where we hit a segfault running 'lparstat -i' on machines with a large number of cpus. The 'SPU' line in proc interrupts would exceed the 512B allocated and we would subsequently walk off the end of the array when we attempt to parse the line. This solution uses getline instead of fgets in order to easily handle lines of arbitrary length. Signed-off-by: John Allen commit 0a93eb52603fc8ea77f69ae628f7634054363ad3 Author: Nathan Fontenot Date: Tue Aug 23 10:41:39 2016 -0400 drmgr: kill the options struct Remove the now empty struct options after making all of its members globals. Signed-off-by: Nathan Fontenot commit 64c57c69ed42c4a7af0e4d6b4657f0a52e608dfe Author: Nathan Fontenot Date: Mon Aug 22 16:20:23 2016 -0400 lsslot: Make struct options member delimiter global Make the struct options member delimiter global and re-name it to usr_delimiter. Signed-off-by: Nathan Fontenot commit e82fb588f5738e6d51e7530b894233c190c588b8 Author: Nathan Fontenot Date: Mon Aug 22 16:19:04 2016 -0400 lsslot: replace struct options member s_name with usr_drc_name With moving the option variables to globals we can replace the s_name lsslot variable with the existing usr_drc_name variable. Signed-off-by: Nathan Fontenot commit 4763b5452a120d6e7c98afcd24cc63e20e33f8de Author: Nathan Fontenot Date: Mon Aug 22 16:17:40 2016 -0400 lsslot: make struct options member p_flag global Make the struct options member p_flag global and re-name it to show_caches to make it more descriptive. Signed-off-by: Nathan Fontenot commit 3dde5f36a9c87b9944ad4f46b983ebd2292455d2 Author: Nathan Fontenot Date: Mon Aug 22 16:16:45 2016 -0400 lsslot: make struct options member o_flag global Make the struct options member o_flag global and re-name it to show_occupied_slots to make it more descriptive. Signed-off-by: Nathan Fontenot commit 378acd01a6cc08e4afe27dd2aa102669cdf05f9b Author: Nathan Fontenot Date: Mon Aug 22 16:15:52 2016 -0400 lsslot: make struct options member b_flag global Make the struct options member b_flag global and rename it to show_cpus_and_caches to make it more descriptive of what it represents. Signed-off-by: Nathan Fontenot commit 1d43df2b2c8090073aaafdfdc2d43ff5f2bac1e0 Author: Nathan Fontenot Date: Mon Aug 22 16:14:54 2016 -0400 lsslot: Make the struct options member a_flag global Make the struct options member a_flag a global variable and re-name it to show_available_slots to make it more descriptive of what it represents. Signed-off-by: Nathan Fontenot commit 67e7a1e02aa0b5223df32228311c8083e293ea8a Author: Nathan Fontenot Date: Mon Aug 22 16:13:29 2016 -0400 lsslot: remove struct options slot_type member With the combined options struct and global variables we can re-use the drc_type to replace the lsslot variable slot_type. Signed-off-by: Nathan Fontenot commit 1de7ad4c2952392d151e02f9a67835dcc479ee7c Author: Nathan Fontenot Date: Mon Aug 22 16:10:34 2016 -0400 drmgr: Make struct options member prrn_filename global Make the struct options member prrn_filename global. Signd-off-by: Nathan Fontenot commit 48b5de724e0baf7a74ec01cb983d2cd882510484 Author: Nathan Fontenot Date: Mon Aug 22 16:09:09 2016 -0400 drmgr: Make struct options member pci_virtio global Make the struct options member pci_virtio a global variable. Signed-off-by: Nathan Fontenot commit 213da0d8933835f1ec9466498d1ac800a8c83f0f Author: Nathan Fontenot Date: Mon Aug 22 16:07:25 2016 -0400 drmgr: Make struct options member p_option global Make the struct options member p_option global as the variable usr_p_option. Signed-off-by: Nathan Fontenot commit f9986ac430113c96d0398efb44159c22410bdf5f Author: Nathan Fontenot Date: Mon Aug 22 16:02:09 2016 -0400 drmgr: Move options.ctype to global usr_drc_type Move the ctype member of struct options out to be the global usr_drc_type. This also makes the usr_drc_type an enum drc_type. The type change to the enum allows for checking the type directly instead of the numerous strcmp() operations that are done. Signed-off-by: Nathan Fontenot commit f74a63f87acd08d9391134de50673f0cf22734a4 Author: Nathan Fontenot Date: Mon Aug 22 15:52:56 2016 -0400 drmgr: Make struct options member 'quantity' global Move the quantity member of struct options to be the global usr_drc_count. Signed-off-by: Nathan Fonteot commit 0df871dd765933322ddbb63ff66e158ef81805dd Author: Nathan Fontenot Date: Mon Aug 22 15:49:27 2016 -0400 drmgr: Make options struct no_ident member global Move the no_ident member of struct options to be the global usr_prompt variable. This change also moves the variable to a positive connotation which makes the code slightly easier to read. Signed-off-by: Nathan Fontenot commit 8192b8e6a79d784038ca5fdb1fc7959149e7105b Author: Nathan Fontenot Date: Mon Aug 22 15:45:58 2016 -0400 drmgr: Make struct options member usr_drc_index global Move the usr_drc_index member of struct options to be global. Signed-off-by: Nathan Fontenot commit 669f581f4f65cb9046699ed7a375bc1693cdac92 Author: Nathan Fontenot Date: Mon Aug 22 15:42:48 2016 -0400 drmgr: Make struct options member usr_drc_name global Move the usr_drc_name out of struct options to be global. Signed-off-by: Nathan Fontenot commit d1a1ed2f4349838fa162c1ef0a6b903ed1b2b42a Author: Nathan Fontenot Date: Mon Aug 22 15:37:55 2016 -0400 drmgr: Make struct options member timeout global Move the timeout member of struct options out to be the global usr_timeout. Signed-off-by: Nathan Fontenot commit 552e42d863db093881d58038f27c5d2d72025491 Author: Nathan Fontenot Date: Mon Aug 22 15:35:41 2016 -0400 drmgr: Make struct options member no_ident global Move the no_ident member out of struct options to become the global usr_slot_identification. This change also gives the variable a positive connotation instead of the current negative so we are not checking for not no_ident, this should make the code more readable. Signed-off-by: Nathan Fontenot commit 6b9908f6c59dc2c24bf71f89f809f11b7cdb7fd3 Author: Nathan Fontenot Date: Mon Aug 22 15:33:36 2016 -0400 drmgr: Update various uses of local 'action' variable Update the various locations that use a local action variable and just use the global usr_action variable directly. Signed-off-by: Nathan Fonteot commit 9606e3012efd2eb0c3c7be95ea43f66c517ef3bc Author: Nathan Fontenot Date: Mon Aug 22 15:29:00 2016 -0400 drmgr: Make option struct member 'action' global Move the action member out of struct options to become the global usr_action. Also introduce the enum drmgr_action as the type for usr_action. This patch also introduces the file options.c which will hold the definitions of all of the global variables common to the drmgr and lsslot commands. This file is included in drmgr.c and lsslot.c instead of being built directly. Signed-off-by: Nathan Fontenot commit f3379e4bd9525a914f3e5478858de7425689a778 Author: Nathan Fontenot Date: Mon Aug 22 15:22:42 2016 -0400 drmgr: Merge drmgr and lsslot options structs Merge the lsslot cmd_opts struct in to the drmgr options struct to make a unified options structure for both commands. By also moving the MAX #define to dr.h we can get rid of the lsslot.h header. Signed-off-by: Nathan Fontenot commit c61535c62111d04a886a2b4d7613b7006d5fe209 Author: John Allen Date: Thu Aug 11 16:30:12 2016 -0400 lparstat: Fix bad cast from integer to float Fix a bug where the cpu stats (%user, %sys, %wait, and %idle) do not add up to 100%. The problem was that we were casting the cpu stats and the total cpu time to floats from ints. For large integer values, this would cause the floating point representation to be truncated. This solution avoids the casts and stores the cpu stats as long longs and only casts 'total' to a long double in order to perform floating point division. Additionally, this patch parses the proc stat values as long longs as on systems that have been running for a long time, these values can exceed the maximum 32 bit integer limit. Signed-off-by: John Allen powerpc-utils-1.3.2 ===================================================================== commit 4e5b9dacf7bbddfb58269fc50de6586a9ac6fdfd Author: Ulrich Weigand Date: Mon Jul 11 17:13:17 2016 -0400 lparstat: Fix computation of time used in statistics The routine get_time computes bogus timestap values due to confusing seconds and microseconds. This leads to incorrect return values from elapsed_time and therefore incorrect values for the physc field. Fixed by converting the "time" sysentry field to microseconds (and computing it correctly), and updating the user of elapsed_time. In addition, %entc is supposed to show the ratio of physc to the number of entitled CPUs as *percentage*, so the ratio needs to be multiplied by 100. Signed-off-by: Ulrich Weigand Signed-off-by: Michael Bringmann commit a97c5664f53f9a18dd0b941a842d7884253cf8ed Author: Nathan Fontenot Date: Mon Jul 11 17:06:26 2016 -0400 drmgr: Disable use of in-kernel cpu hotplug After submitting the patch to update drmgr to use the in-kernel hotplug capabilities for memory and cpu, commit (drmgr: Start using in-kernel DLPAR functionality for cpu/memory), I realized there are still distro kernels that do not have the in-kernel cpu hotplug capabilities. Using the latest drmgr with this update breaks cpu dlpar because the cpu dlpar code assumes that if the dlpar sysfs file exists then in-kernel cpu dlpar is possible. this is wrong, the sysfs dlpar file was added with in-kernel memory hotplug, its existence can only guarantee memory hotplug capability. For now, disable using the in-kernel cpu capabilities by drmgr until this can be resolved. Signed-off-by: Nathan Fontenot commit 2bb7599d702d4e1de1ff0f9cbe53329e59c4e120 Author: Ian Neal Date: Mon Jul 11 10:02:45 2016 -0400 lparstat: flush data to stdout The stdout stream is not being flushed after being written to. This means that it doesn't behave properly in shell pipelines as the data isn't visible until the program exits. The fix is to simply flush after writes so the data is immediately available to other processes in the pipeline. Signed-off-by: Ian Neal commit c3269d4e3d4882fd931d1df6aece0bec86fb6734 Author: Vasant Hegde Date: Thu Jun 30 10:26:58 2016 -0400 update_flash: Fix bashism issue in opp_display_current_fw_version() Ubuntu uses dash, not bash. We hit below warning on Ubuntu system. root@abc:/sys/firmware/devicetree/base/ibm,opal/sensors# update_flash -d /usr/sbin/update_flash_nv: 595: [: x43: unexpected operator Firmware version: .... .... == is a bashism. Replace it with =. Fixes: 767e3dd7 (update_flash: Add support for OpenPower system) Signed-off-by: Vasant Hegde commit 386a07c4dc6c09d35116dc6064f7a83d76f4415b Author: Nathan Fontenot Date: Tue May 24 16:32:39 2016 -0400 errinjct: Correct read_file() error checking When reading files from syfs the file length returned from a stat() call does not always match the actual length of the file. The read_file() routine should be checking for an error return from the read() call instead of checking that the amount read matches the file length returned from a stat() call. Signed-off-by: Nathan Fontenot commit 42b83884bfb51c0c8b23bf2949157430f8468caa Author: Nathan Fontenot Date: Tue May 24 16:31:37 2016 -0400 errinjct: Recognize -5 return from rtas Update the errinjct command to recognize the rturn code of -5 from rtas indicating that PCI error injection is not enabled. Signed-off-by: Nathan Fontenot commit ab848a8d5cc4c4b9f5faef1b31be3982fb7d4bf2 Author: Nathan Fontenot Date: Tue May 24 16:30:33 2016 -0400 errinjct: Correct config_addr parsing A recent patch (commit id: ccc9c72cec2a4) to move the errinjct function to using a common read_file() routine did not correctly update the get_config_addr_from_reg() function. This patch corrects this to return the proper config address. Signed-off-by: Nathan Fontenot commit 9fc079cf39d999040483a00d3b41000ca3e43013 Author: John Allen Date: Tue May 24 16:28:27 2016 -0400 drmgr: Workaround for concurrent PRRN collisions Proposed workaround for issues with current PRRN event handling mechanism. Currently, the mechanism works by kicking off a script that calls a drmgr remove followed by a drmgr add for each effected device. With this method, problems can occur when multiple prrn events arrive in a short time span or when other dlpar operations are happening while the script is running. What can happen is that these other dlpar operations can jump in inbetween when the script calls the remove and the add and take the drmgr lock. Then when we try to add the memory back from the script, we are unable to take the drmgr lock and the add fails. This patch fixes this issue by creating a new -P flag for drmgr which will perform the necessary removes/adds from within the drmgr lock. The new option will be invoked as follows: drmgr -P On the rtas_errd side, we will begin by creating a log file for the PRRN event which will contain a list of the type and the drc index for each effected device. Then instead of invoking the script, we will call the above drmgr command with the path to the prrn log file. Then, on the drmgr side, we parse the list and perform the necessary removes/adds and then delete the prrn log file. Signed-off-by: John Allen commit bbc5fc07c54dd53f4ceac3552ea12717cc86cba2 Author: Nathan Fontenot Date: Wed May 11 13:16:19 2016 -0400 drmgr: Start using in-kernel DLPAR functionality for cpu/memory Now that the capability to do DLPAR of cpus and memory can be done completely in the kernel, update the drmgr command to use this functionality. The kernel updates provided a sysfs file (/sys/kernel/dlpar) that will allow the drmgr command invoke DLPAR of cpus and memory by writing to this file. There are some exisitng behaviors of drmgr on the PowerVM platforms that require cpu and memory to be done slightly differently. For memory drmgr only needs to report the number of LMBs that were added or removed so drmgr can just pass all requests straight to the kernel. This patch also makes a common routine for reporting memory resources to ensure the format is kept constant. For cpu DLPAR the drmgr command has to report the drc name of each cpu that is added/removed. To do this the command uses much of the same device tree parsing that is currently used and make a request to the kernel to remove a specific cpu (by drc index) where a write to the sysfs probe file was previously done. Signed-off-by: Nathan Fontenot commit 4dafa57ec7c1498f94b324e671625b0794b92f2f Author: Thomas Falcon Date: Tue Apr 19 15:01:13 2016 -0400 ppc64_cpu: display error message after set_smt_state_one failure This avoids a silent error if threads are unable to be onlined or offlined. Signed-off-by: Thomas Falcon commit 96745e9e1cb560af6f900b1dac920e36db750ee5 Author: John Allen Date: Tue Apr 19 14:52:35 2016 -0400 lparstat: Check return value of fopen/popen before dereferencing Checks the return value of fopen and popen in several locations to make sure it's not null. If we pass a null file descriptor to fgets, we will hit a segfault. Signed-off-by: John Allen Reviewed-by: Vasant Hegde commit 6855b92b3f9f3ed9c02065344cc98b965c3f03ef Author: Michael Roth Date: Tue Apr 19 14:49:43 2016 -0400 drmgr: avoid loading rpadlpar_io/rpaphp when -v flags is used The -v / opts->pci_virtio flag was added to provide an alternative way to scan/remove PCI devices which doesn't rely on rpaphp. That was a workaround for a bug induced by QEMU emulating PHBs with multiple hotpluggable slots, which fails to register slots beyond the first due to rpaphp no longer accounting for the possibility of there being more than 1 slot per PHB. This leads to warnings of the form: kernel: rpaphp: pci_hp_register failed with error -16 kernel: rpaphp: pci_hp_register failed with error -16 ... For most guest distros this has resulted in the module not being loaded by default to avoid the errors showing up. However, as of a9b4e4e, we now load automatically load the module as needed, but we don't take opts->pci_virtio into account when determining if it's needed, leading to PCI hotplug operations to KVM guests now resulting into rpaphp being loaded and generating the errors above when drmgr is invoked. Fix this by avoiding modprobe of rpadlpar_io/rpaphp when opts->pci_virtio is set. Signed-off-by: Michael Roth commit efa87d93231eb0fe4f406bf58e7d5aa783ee4f13 Author: Michael Bringmann Date: Tue Apr 19 14:47:32 2016 -0400 lparstat: Correct presentation of some stats lparstat.c: Currently there are several problems with the presentation of statistics by lparstat's default output mode. These issues include: * Showing negative values for certain fields e.g. %user, %sys, %wait, %lbusy. * Showing zero values for certain fields e.g. physc, %entc * Identifying systems with 'Shared' or 'Dedicated' Memory Mode * Calculating the number if logical CPUs used by a system This patch looks to correct these issues. It also changes the widths of the physc, %entc fields which had too little precision available to show the value change on some systems. Signed-off-by: Michael Bringmann commit a27c639aca69271aabe7cac287f998b29b82f333 Author: Michael Roth Date: Tue Apr 19 14:37:36 2016 -0400 drmgr: ensure PCI cleanup is done before offlining dev As part of 4f542616, functionality was added to support add/remove PCI devices without relying on rpaphp hotplug module. The sysfs write used in the remove path initiates an asynchronous removal of PCI device from kernel PCI subsystem, and eventually from the sysfs tree. Afterward, we set the corresponding DRC for the device to ISOLATED state so host can complete device removal. To avoid the situation where the asychronous removal has not yet completed by the time drmgr sets the state to ISOLATED, and simple sleep of 3 seconds was added. This seems to have worked out okay for virtio devices, but in the case of other devices, like PCI passthrough of a Mellanox CX4 virtual function, the removal can take up to 20 seconds. When this happens, we hit a situation where the host reclaims the devices while the guest is still attempting to access it in it's cleanup path, which leads to guest crashes. Fix this by polling the PCI devices sysfs path and not completing the removal until the sysfs path is removed as part of device cleanup. Signed-off-by: Michael Roth powerpc-utils-1.3.1 ===================================================================== commit dccad2d1dc5c84571f31af3117095bd9ec6e34c4 Author: Brahadambal Srinivasan Date: Fri Mar 25 07:46:56 2016 -0400 snap: PowerNV platform is not correctly checked Recent patches to change from PowerKVM to PowerNV missed a simple change to the /usr/sbin/snap script. This patch is to fix that. Signed-off-by: Brahadambal Srinivasan commit a9b4e4ed7c6a908feb04f5b066f214ad14c76745 Author: Nathan Fontenot Date: Fri Mar 25 07:45:20 2016 -0400 drmgr: Load kernel modules for pci hotplug For PHB DLPAR, slot DLPAR, and PCI hotplug operations we need to ensure that the rpadlpar_io and rpaphp kernel modules are loaded or have been built into the kernel. A check for this is currently done for PHB and slot DLPAR when determining if the system is capable of these operations. This patch moves the code to validate the presence of these modules to be called from dr_init() for PHB/SLOT/PCI operations. In order to do this the parsing of args has to be done prior to calling dr_init. This should not cause an issue since we can parse args without holding the dr_lock and any errors are written to stderr. Signed-off-by: Nathan Fontenot commit c66dfa6338e6bb889f4806df1518642a800992ea Author: John Allen Date: Fri Mar 25 07:43:39 2016 -0400 lsslot: Update man page/usage statement to document required argument Update man page and usage statement for lsslot to reflect the fact that the -d flag requires an argument. Signed-off-by: John Allen commit bd7e19a9ff5aebe741b0520906660dac1ecf4a2a Author: Nathan Fontenot Date: Fri Mar 25 07:27:58 2016 -0400 nvram: Correct valid partition name checking A recent update to not allow long names had a bug in that it did not correctly check the return value when verifying a partition name. Fixes: b15b0a7f9ffc (nvram: don't allow long names) Signed-off-by: Nathan Fontenot CC: Joel Stanley commit 63a362d28253e32552ff3e1e4358bfb47d69c78b Author: Mauricio Faria de Oliveira Date: Thu Mar 17 20:01:06 2016 -0400 ofpathname: Convert OF device path to logical device path for NVMe devices Add support to convert a Open Firmware device path to logical device path for NVMe devices (with namespace id). Signed-off-by: Mauricio Faria de Oliveira commit bd0a574f70f2b2af39020440e6e3ed61ab5afe35 Author: Mauricio Faria de Oliveira Date: Thu Mar 17 19:59:51 2016 -0400 ofpathanme: Convert logical device path to OF device path for NVMe devices Add support to convert logical device path to Open firmware device path for NVMe devices. Signed-off-by: Mauricio Faria de Oliveira commit e4af95a7da425d37a6762b81d1614e648129b36a Author: Nathan Fontenot Date: Tue Feb 23 14:43:35 2016 -0500 drmgr: free allocated hpdev in error path In error paths while allocating hpdevs in get_os_hp_devices() we can exit without free'ing an allocated hpdev. Move up the addition of the hpdev to the hpdev_list to ensure it is free'ed if an error occurs. Signed-off-by: Nathan Fontenot commit 6fcff4b41726784d9f13bdc905d7eb85f84a3248 Author: Nathan Fontenot Date: Tue Feb 23 12:18:12 2016 -0500 drmgr: close opened dir Close the directory we are traversing before returning. Signed-off-by: Nathan Fontenot commit faa441c184dfa28bd5793adbd17faa7f696fc49d Author: Nathan Fontenot Date: Tue Feb 23 12:17:03 2016 -0500 rtas_dbg: Do not exit on failure to read rtas token When gathering a list of the available rtas tokens if we are not able to determine the rtas token value for a token in the device tree we should print an error message and continue instead of exiting. Signed-off-by: Nathan Fontenot commit 64dd69fdc6242ec22519f1d2a18f1328825add3e Author: Nathan Fontenot Date: Tue Feb 23 12:15:53 2016 -0500 rtas_dbg: Ensure we NULL terminate token names The current code to look up rtas tokens writes the token name to a static buffer size, this runs the risk of not having the string null terminated if the string length matches the buffer length. Update the code to use strdup so we can ensure the strings are null terminated. This also updates the free_rtas_tokens() routine to free the token name. Signed-off-by: Nathan Fontenot commit ccc9c72cec2a4885a219958c69c35abae6cef9c4 Author: Nathan Fontenot Date: Tue Feb 23 12:14:16 2016 -0500 errinjct: Correct possible buffer overflow In multiple places in the errinjct command we read the contents of a file into a local buffer. This presents a possible issue if the file we are reading ever exceeds the size of the buffer. To prevent this issue a new read_file() routine is introduced that will allocate a buffer large enough to hold the contents of the file and read the file into the buffer. Signed-off-by: Nathan Fontenot commit fa50467bbf0f83207055124e7bee866cbc1b612c Merge: 39dbb91 61558c9 Author: Nathan Fontenot Date: Mon Feb 15 09:03:26 2016 -0500 Merge branch 'cyphermox-mpath' into next commit 61558c9df4571b79c435e2d7b1157f40ae7565a3 Merge: 39dbb91 2d27304 Author: Mathieu Trudel-Lapierre Date: Mon Feb 15 08:51:37 2016 -0500 ofpathanme: map mpath* devices to the appropriate dm-* generic dm device Signed-off-by: Mathieu Trudel-Lapierre Date: Mon Feb 1 11:59:27 2016 -0500 errinjct: Close file descriptors Properly handle file descriptors opened by ensuring they are closed prior to returning. Reported as a leaked resource by Coverity scans. Signed-off-by: Nathan Fontenot Reviewed-by: Vasant Hegde commit 07c190715a730dc98823691f18aa3b262a2bf432 Author: Nathan Fontenot Date: Mon Feb 1 11:57:49 2016 -0500 errinjct: Null terminate buffer from read() Null terminate buffers filled when calling read(). Issue uncovered with Coverity Scans. Signed-off-by: Nathan Fontenot commit 3153111b0ab6e6ae2b83c448443a3b6e3e8fe6e5 Author: Nathan Fontenot Date: Mon Feb 1 11:56:02 2016 -0500 activate_firmware: Remove use of strcat Resolve uninitialized scalar variable reported by Coverity scan. The 'msg' buffer was being used uninitialized in calls to strcat, this patch removes the use of the local 'msg' variable and puts the message string directly in the warnx() call. Signed-off-by: Nathan Fontenot Reviewed-by: Vasant Hegde commit f3f25d4aee3f12f0dfc6611aaab6f0819d58fe33 Author: Nathan Fontenot Date: Mon Feb 1 11:53:13 2016 -0500 ppc64_cpu: free core_state on error Make sure we free the allocated 'core_state', issue found with Coverity. Signed-off-by: Nathan Fontenot commit e6f476d32c33f5b8e364f930c467785495eeb0ce Author: Nathan Fontenot Date: Mon Feb 1 11:51:55 2016 -0500 lsslot: free lmb_list on error Free the lmb resources allocated by lsslot, Issue discovered with Coverity scan. Signed-off-by: Nathan Fontenot commit 2d27304b9e8f69619927cd2f55fb1c11c3dc5f09 Author: Mathieu Trudel-Lapierre Date: Tue Jan 12 16:46:12 2016 -0500 ofpathname: map mpath* devices to the appropriate dm-* generic dm device. Signed-off-by: Mathieu Trudel-Lapierre powerpc-utils-1.3.0 ===================================================================== commit ad4cf85f4bc80f6f5cbf4ce0b71eada696848081 Author: Nathan Fontenot Date: Thu Jan 7 15:17:41 2016 -0500 Move the powerpc-utils package from the IBM license to the GNU GPL license. Signed-off-by: Nathan Fontenot commit f037afe3bcece02ca3a3b1711a57c66db088cfa1 Author: Nathan Fontenot Date: Tue Dec 1 16:36:11 2015 -0500 drmgr: Correct checking for display adapters when adding PHB A previous commit (c2091227) added formalization for checking for display adapters. Unfortunately the update tries to verify if there is a display adapter for a NULL phb pointer when trying to add a PHB resulting in a segfault on phb add requests. Signed-off-by: Nathan Fontenot commit 85a5037cb01c1aaa5ad3dbd91f74dbcdd823dbb1 Author: Nathan Fontenot Date: Tue Dec 1 16:35:04 2015 -0500 drmgr: Remove extraneous debug output Remove extra debug statements for allocating and free'ing drc information. These were mistakenly left in during debug of a previous patch. Signed-off-by: Nathan Fontenot commit 33aa48a0c4ebc4e660080514939232ad2912cb6d Author: Nathan Fontenot Date: Tue Dec 1 16:33:45 2015 -0500 drmgr: Fix node add buffer overflow When adding a node to the device tree, the drmgr command writes a terminatin null in the first character past the end of the allocated buffer. This results in a SIGABRT being generated by libc when the buffer is free'ed. The fix is to move the writing of the space between properties to the beginning of the loop instead of at the end of the loop. Signed-off-by: Nathan Fontenot commit 55544a975f87e9d76366e6fefcf571ae01f3e7eb Author: Nathan Fontenot Date: Mon Nov 23 21:10:27 2015 -0500 drmgr: Remove extraneous "d" in buffer Remove an erroneous character left in a print statement used to update the drconf property. Signed-off-by: Nathan Fontenot commit f4006893d84c85bbf5b86919c28ba56047001204 Author: Nathan Fontenot Date: Mon Nov 23 21:09:47 2015 -0500 drmgr: Correct return code from set_mem_scn_state() The set_mem_scn_state() routine incorrectly returns the number of chars written in the case of success instead of returning 0. This results in the caller assuming a failure occurred when setting the memroy section state and fails the memory online/offline operation. Signed-off-by: Nathan Fontenot commit 4f515ea179cb36f26adb53c93b79f834e32c2abe Author: Nathan Fontenot Date: Mon Nov 23 21:08:54 2015 -0500 drmgr: Correct LMB counting when discovering LMBs Recent updates to how drmgr counted the number of LMBs found did not save the count value correctly and in the case of LMBs found in the ibm,dynamic-reconfiguration-memory property only counted LMBs that were present. This caused havoc when trying to shuffle the LMBs. Save the LMB count in the lmb_list_head struct so we have it across function calls. Also update the shuffle_lmbs to just take a pointer to the lmb_list_head and make changes locally in the routine. Signed-off-by: Nathan Fontenot commit 9a1957588b040db0dddfa284dbb96a817e699792 Author: Cédric Le Goater Date: Mon Nov 23 21:07:17 2015 -0500 update_flash_nv: improve check_ipmitool This patch adds a quick test in check_ipmitool to make sure the BMC is alive Signed-off-by: Cédric Le Goater commit 4e4e5f9f8d16a2ad196d1fd5388de23aa2e1fdbc Author: Cédric Le Goater Date: Mon Nov 23 21:06:52 2015 -0500 update_flash_nv: fix firmware update sequence for powernv This patch modifies the way the firmware update is performed from the host. It adds a cold reset of the BMC before and after the update. Signed-off-by: Cédric Le Goater commit 1f25105c1c7f1384be4aef03f2aa6d5bd065eb11 Author: Cédric Le Goater Date: Mon Nov 23 21:06:22 2015 -0500 update_flash_nv: force the use of the ipmitool usb backend Signed-off-by: Cédric Le Goater commit b0e5ba4f55dcf1a5d013eddbb95b660c65504b3c Author: Nishanth Aravamudan Date: Mon Nov 23 21:04:45 2015 -0500 ppc64_cpu: output to user if the requested number of cores are not brought o Now that we check the return code from set_one_core, we should ensure that the requested number of cores in --cores-on is achieved, or return -1 intead. Also add a slightly verbose message in that case. Signed-off-by: Nishanth Aravamudan commit 1a1bb7167a3946712a5b59b5566bac6ced46cdc9 Author: Nishanth Aravamudan Date: Mon Nov 23 21:03:37 2015 -0500 ppc64_cpu: use rc instead of boolean flag We can overload the rc variable, reducing the number of local variables in do_online_cores. Signed-off-by: Nishanth Aravamudan commit 37eeba5583d48558f2ca1de6096df83494005e6f Author: Nishanth Aravamudan Date: Mon Nov 23 21:00:14 2015 -0500 ppc64_cpu: check return code from set_one_core In both --cores-on and --online-cores, the return code from the helper function set_one_core is not checked. This can lead to ppc64_cpu returning 0 even though the command technically failed to do what was requested. After this patch, --cores-on still doesn't return a proper error code (fixing in a follow-on). Signed-off-by: Nishanth Aravamudan commit 9711ee00b604a39d47dfced7f0c49cf40600131f Author: Nishanth Aravamudan Date: Tue Nov 17 16:24:37 2015 -0500 ppc64_cpu: add --{on,off}line-cores to {on,off}line specific cores We currently have support for a mechanism to ensure an exact number of cores (or all cores after a recent patch submission) are online. However, there is no control over which cores are selected. Add two new options to ppc64_cpu, --online-cores and --offline-cores to support specifying which cores to bring online or offline, respectively. Both options take either no parameters, in which case they output a comma-separated list of cores that are online/offline, or a comma-separated list of cores, in which case the command sets those cores' states to online/offline. Signed-off-by: Nishanth Aravamudan commit 2239dd005e00d63c6e68fe962928b5f0b08ef6cb Author: Nishanth Aravamudan Date: Tue Nov 17 09:33:55 2015 -0500 ppc64_cpu: rename do_cores_online to do_cores_on This matches the other function names more closely. Signed-off-by: Nishanth Aravamudan commit bb8472f0658565e5188150a141fa8856b55000ca Author: Nishanth Aravamudan Date: Tue Nov 17 09:31:57 2015 -0500 ppc64_cpu: add all parameter to --cores-on to online all cores Rather than finding out how many cores are in a system, and then passing that value to --cores-on, it can be handy to have a shortcut to just online all cores. Signed-off-by: Nishanth Aravamudan commit 17cd4bbf7c20d8096523c765c1157e4a58d31363 Author: Nishanth Aravamudan Date: Tue Nov 17 09:29:06 2015 -0500 ppc64_cpu: handle errors from strtol in --cores-on parsing Currently, on a 24-core system, passing certain values to `ppc64_cpu --cores-on` leads to some surprising results: ppc64_cpu --cores-on=all ppc64_cpu --cores-on=adfd offlines all but one core This is because we are not using the endptr parameter of strtol to determine if any of the string is consumed (and if none of the string is consumed, strtol still returns a valid long value, namely 0). ppc64_cpu --cores-on=12df onlines 12 cores This is because we are not using the endptr parameter to strtol to determine if the entire string is consumed (checking for trailing characters). Add both these checks. After this patch: ppc64_cpu --cores-on=all Invalid number of cores to online: all ppc64_cpu --cores-on=adfd Invalid number of cores to online: adfd ppc64_cpu --cores-on=12fd Invalid number of cores to online: 12fd Signed-off-by: Nishanth Aravamudan commit 475919d4294819e5f890f000ccadf5b13280a0a9 Author: Chandni Verma Date: Mon Nov 16 16:50:11 2015 -0500 powerpc-utils.spec: Fix typo in spec-file In line: %{__rm} -rf $RPM_BULD_ROOT The directory should be RPM_BUILD_ROOT not RPM_BULD_ROOT Signed-off-by: Chandni Verma commit b1d909378cf8a9502c7207f4f51a2cf3931d5263 Author: Michael Bringmann Date: Mon Nov 16 16:48:30 2015 -0500 errinjct/rtas_debug: Update RPM packaging specs This patch updates the powerpc-utils.spec.in file to install the binaries associated with errinjct and rtas_dbg. Signed-off-by: Michael Bringmann commit 03704771a36c025eb8636a90f67eaa77acd5880d Author: Nathan Fontenot Date: Mon Nov 16 16:40:47 2015 -0500 lsslot/drmgr: Performance enhancement for parsing LMBs Signed-off-by: Nathan Fontenot commit 268116acde0d5f98efa150044b68d977d578ccb4 Author: Vasant Hegde Date: Mon Nov 16 16:39:15 2015 -0500 errinjct: Add format specificer We hit below build warning with "-Werror=format-security" compilation option CC src/errinjct/icache.o src/errinjct/errinjct.c: In function 'perr': src/errinjct/errinjct.c:240:18: error: format not a string literal and no f fprintf(stderr, buf); ^ Signed-off-by: Vasant Hegde commit c2091227bdf40192a37456445a6dedf3f3da8cda Author: Nathan Fontenot Date: Mon Nov 16 16:27:08 2015 -0500 drmgr: Do not allow DLPAR of display adapters The DLPAR of display adapters has never been supported but that support has not ever been enforced in drmgr. Recent tests show that trying to DLPAR remove a display adapter causes the drmngr command to appear hung as it waits for display adapters to power down. Add the ability to check for a drc-type of 'display' when trying to add or remove a pci or slot, and verify that none of the children under a PHB are display adapters when trying to add or remove a PHB. Signed-off-by: Nathan Fontenot commit aef0c5daa20f38b66e5fa0255ecf5a53ba202138 Author: Nathan Fontenot Date: Mon Nov 16 16:26:01 2015 -0500 drmgr: Move check for non-hotplug children to common routine In more than one place we check to see if a PHB has any children that are not hotplug capable. Move this code to common routine. Signed-off-by: Nathan Fontenot commit 2d8ad5ef33948f07e3022c601ee99cd8efc85a76 Author: Chandni Verma Date: Mon Nov 16 16:22:19 2015 -0500 activate_firmware: Have man page reflect the changes made in this branch -Edited description -added Option section -Added 2 new return codes 7 and 8 Signed-off-by: Chandni Verma commit 11041ab9e8f0e75b58d2c1a593c9c410d7a82f00 Author: Chandni Verma Date: Mon Nov 16 16:21:02 2015 -0500 activate_fw: Return code 8, to report a parameter error when activating firm This is a new return code mapped from rtas return code -3 which is returned case of parameter error, when the utility is used without options. Signed-off-by: Chandni Verma commit d1217de2906f22dbeed54f52c683f28ffcfe90c9 Author: Chandni Verma Date: Mon Nov 16 16:19:56 2015 -0500 activate_fw: get update access key expiry date, set update access key This patch provides two feature extensions: 1. activate_firmware -e (with only -e, fetches the update access key expiry date) 2. activate_firmware -e /path/to/keyfile (with an argument to -e applies the provided update access key-file to extend the update access key expiry date) These are required to provide an interface to check validity of and update the Update Access Key. ESA will be one of the users of this tool. Signed-off-by: Chandni Verma commit 097c16987a65aceb0be6d66befaa0104b518abbd Author: Chandni Verma Date: Mon Nov 16 16:18:09 2015 -0500 activate_fw.c: Make use of errx() to print error messages to stderr and exit This is a more compact way to do it compared to using fprintf and explicitly exiting in main() Signed-off-by: Chandni Verma commit c2dc2191bb5963b09e781b78cbf2a152520c8e87 Author: Chandni Verma Date: Mon Nov 16 16:17:21 2015 -0500 activate_fw.c: Factor out activate_firmware() from main() This is done to reserve main solely for option processing and to abstract out rtas calling function. Signed-off-by: Chandni Verma commit 72bc893a5f4b59d0e7742726e85f3cffab65ebd3 Author: Chandni Verma Date: Mon Nov 16 16:14:46 2015 -0500 activate_fw: fix typo The default case in error handler should return code 6, not 4. Signed-off-by: Chandni Verma commit 782445384c165ea28f00c9cb233e41bdeef7a962 Author: Chandni Verma Date: Mon Nov 16 15:53:42 2015 -0500 activate_fw: Coding style fixes This patch fixes trailing white spaces and indentation issues and in general makes to code confirm to linux's checkpatch.pl Signed-off-by: Chandni Verma commit ad93027170afe3b7bc760fed0ab3e078390ba088 Author: Nathan Fontenot Date: Tue Oct 27 16:58:44 2015 -0400 serv_config: Compile warning cleanups Correct several compile warnings. Remove unchecked return code from execv(). Remove unused variables. Correct de-reference of type punned pointers. Signed-off-by: Nathan Fontenot commit 8ad7081b5f1d98593c8192d4d46c10050e5b8d88 Author: Nathan Fontenot Date: Tue Oct 27 16:57:34 2015 -0400 rtas_ibm_get_vpd: Compile warning cleanups Clean up compile warning by removing the unused lflag variable. Signed-off-by: Nathan Fontenot commit 28aeacd59e0e35753bae243cf63150f6ecc2a10b Author: Nathan Fontenot Date: Tue Oct 27 16:56:32 2015 -0400 rtas_dbg: Compile warning cleanups Correct compile errors to check the return value from a fread() call and add an appropriate error message, and ensuring we do not use an uninitialized 'rc' variable. Signed-off-by: Nathan Fontenot commit dfab2e6f11a11e25da342b703bd054aaf906d818 Author: Nathan Fontenot Date: Tue Oct 27 16:55:33 2015 -0400 ppc64_cpu: Compile warning cleanups Correct compile warning for dereference of type punned pointer. Signed-off-by: Nathan Fontenot commit 92fd02382fbec464562e2a84841391f09cf1e2ea Author: Nathan Fontenot Date: Tue Oct 27 16:54:34 2015 -0400 nvram: Compile warning cleanups Correct compile warning by removing the unused variable memctrl_data. Signed-off-by: Nathan Fontenot commit f069a159755b70bf4596b2bcce5b3fb4f8c3831f Author: Nathan Fontenot Date: Tue Oct 27 16:53:35 2015 -0400 lparstat: Compile warning cleanups Clean up compile warnings by adding checks for the return codes from fgets() calls and adding appropriate error messages. Signed-off-by: Nathan Fontenot commit 2cc2e6590a43a367ee6ca6474bc98cc0a7245caf Author: Nathan Fontenot Date: Tue Oct 27 16:51:59 2015 -0400 drmgr: Compile warning cleanups Fix multiple warnings generated when compiling drmgr code. These include not checking return codes of fread() and write() calls where a check is added and appropriate error messages. Updating print formats to use the appropriate type of value being printed. Correcting the use of rc values to ensure the rc variable is set. Signed-off-by: Nathan Fontenot commit 0e8d1534f5bf57798b74584b6f2b42bad57ddf89 Author: Nathan Fontenot Date: Tue Oct 27 16:49:57 2015 -0400 drmgr: Validate the status of a CPU before adding or removing it When asked to perform a CPU DLPAR operation we should verify the current status of the CPU before performing the operation. Failure to verify the status has caused the kernel to oops in cases where we try to add a CPU that is already owned, namely in a kvm guest the following is seen. Signed-off-by: Nathan Fontenot commit dabc0264a9f3b64226da63421378ed02f2f1b201 Author: Nathan Fontenot Date: Tue Oct 27 16:48:25 2015 -0400 drmgr: Add missing free's of allocated memory Using valgrind to do analysis of the memory usage of the drmgr command revealed multiple instances of memory not being free'ed. Correct this by adding appropriate calls to free commands. Note that the analysis done, and this patch, does not cover all of the code paths in drmgr. There may be additional patches as testing continues. Signed-off-by: Nathan Fontenot commit d5a1c1bfae839e159ba049736a9719835e2a42e6 Author: Nathan Fontenot Date: Tue Oct 27 16:45:26 2015 -0400 drmgr: Add EXTRA_DEBUG output level Introduce a new internal developer debug output level. In some cases the drmgr command dumps all the information about slots/adapters it gathers from the device tree, this is really meant for internal debugging purposes. Additionally, one large systems this information can easily overwhelm the output seen from drmgr. This patches introduces a debug level for the say() command, EXTRA_DEBUG. Developers can get this output by using the option '-d 5'. Several instances of debug output are also updated to use this new option. Signed-off-by: Nathan Fontenot commit a7ebbd4bbc61cd0c7d6c3c3eea9f7ea9724558d9 Author: Nathan Fontenot Date: Tue Oct 27 16:43:25 2015 -0400 drmgr: free slot nodes before adding slots When handling a request for slot dlpar add the device tree is parsed twice, once prior to the add and again after adding the slot. On systems with a large number of slot devices, 200+, we are seeing that the drmgr command segfaults when trying to parse the device tree the second time. To avoid crashing here we need to free the parsed information from the device tree prior to adding the new slot. While this isn't really a true root cause fix it does alloow drmgr to run without segfaulting. Signed-off-by: Nathan Fontenot commit 767e3dd780f1a18b2c832b5d8db82a5aac9a9818 Author: Vasant Hegde Date: Fri Oct 16 10:01:50 2015 -0400 update_flash: Add support for OpenPower system On OpenPower system we use IPMI interface to pass image to service processor (BMC) and it will take care of updating FW. This patch adds wrapper around ipmitool so that we can use update_flash command to update FW. Validation: BMC take care of validating image. We just pass the image to BMC. Commit/Reject operation: Like FSP system, BMC has two sides. Golden and boot side. Golden side is permanent and is never updated in the field. So commit/reject operations are not allowed on BMC based system. FW update: OpenPower system has two components (BMC FW and host FW). We send all the component to BMC in one command. BMC will take care of updating all the components. Note that we are not using "force" option. So BMC will skip the component which are not changed. FW version display: We display host FW version using ipmitool fru command. like below: Product Name : OpenPOWER Firmware Product Version : IBM-firestone-ibm-OP8_PFD_v1.6_0.29 Product Extra : hostboot-6847d73-b8d7c0a Product Extra : occ-0726e69 Product Extra : skiboot-5.1.3-6221bd2 Product Extra : hostboot-binaries-43d5a59 Product Extra : firestone-xml-db1a93e-4ae8032 Product Extra : capp-ucode-105cb8f Signed-off-by: Vasant Hegde commit 1422abed03f78866339a7b29e3eba4b2d29cb468 Author: Vasant Hegde Date: Fri Oct 16 10:01:04 2015 -0400 update_flash_nv: Add platform check Presently we assume this script is running on FSP based PowerNV platform. Lets add platform check to validate platform before running. That way adding new platform support (like OpenPower) becomes easy. Signed-off-by: Vasant Hegde Reviewed-by: Kamalesh Babulal commit b7d4678e0963ff4956d02188fae33cb8d5a7fe11 Author: Vasant Hegde Date: Fri Oct 16 10:00:28 2015 -0400 update_flash_nv: Rename function name to reflect platform Presently update_flash_nv supports code update on FSP based PowerNV (Non-Virtualized) platform. We want to support code update on OpenPower (BMC based) platform. Code update procedure on OpenPower system is different than FSP based machine. Hence rename FSP specific function in this script as fsp_*. Signed-off-by: Vasant Hegde Reviewed-by: Kamalesh Babulal commit a3e1c3eddb6e3486ae48dfd23f0c95c4b714322d Author: Kamalesh Babulal Date: Fri Oct 16 09:59:06 2015 -0400 snap: Warn users about deprecated support for SLES 12 onwards This patch introduce deprecated warning on SLES 12 onwards to use supportconfig. supportconfig captures all the information collected by snap, so it safe to deprecate snap. It also rearranges check for distribution (RHEL/SLES/Ubuntu) into common function check_distro_support(). Signed-off-by: Kamalesh Babulal Cc: Vasant Hegde Cc: Nathan Fontenot powerpc-utils-1.3.4/Makefile.am000066400000000000000000000113441315235264300163770ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 noinst_HEADERS = sbin_PROGRAMS = EXTRA_DIST = docdir = $(datadir)/doc/packages/@PACKAGE@ doc_DATA = README COPYING bin_SCRIPTS = scripts/amsstat sbin_SCRIPTS = \ scripts/update_flash \ scripts/update_flash_nv \ scripts/hvcsadmin \ scripts/rtas_dump \ scripts/snap \ scripts/bootlist \ scripts/ofpathname \ scripts/lsdevinfo \ scripts/ls-veth \ scripts/ls-vscsi \ scripts/ls-vdev \ scripts/nvsetenv \ scripts/pseries_platform man_MANS = \ man/activate_firmware.8 \ man/rtas_ibm_get_vpd.8 \ man/uesensor.8 \ man/amsstat.1 \ man/serv_config.8 \ man/update_flash.8 \ man/nvram.8 \ man/set_poweron_time.8 \ man/bootlist.8 \ man/ofpathname.8 \ man/snap.8 \ man/hvcsadmin.8 \ man/rtas_dump.8 \ man/sys_ident.8 \ man/lparcfg.5 \ man/lparstat.8 \ man/lsslot.8 \ man/ppc64_cpu.8 \ man/errinjct.8 \ man/rtas_dbg.8 EXTRA_DIST += $(bin_SCRIPTS) $(sbin_SCRIPTS) $(man_MANS) EXTRA_DIST += COPYING Changelog powerpc-utils.spec.in doc/activate_firmware.doxycfg \ doc/nvram.doxycfg doc/rtas_ibm_get_vpd.doxycfg doc/serv_config.doxycfg \ doc/set_poweron_time.doxycfg doc/uesensor.doxycfg if WITH_SYSTEMD EXTRA_DIST += systemd/smt_off.service.in endif sbin_PROGRAMS += src/nvram src/lsprop src/lparstat src/ppc64_cpu pseries_platform_SOURCES = src/common/pseries_platform.c src/common/pseries_platform.h librtas_error_SOURCES = src/common/librtas_error.c src/common/librtas_error.h src_nvram_SOURCES = src/nvram.c src/nvram.h $(pseries_platform_SOURCES) src_nvram_LDADD = -lz @LIBDL@ src_lsprop_SOURCES = src/lsprop.c $(pseries_platform_SOURCES) src_lparstat_SOURCES = src/lparstat.c src/lparstat.h $(pseries_platform_SOURCES) src_ppc64_cpu_SOURCES = src/ppc64_cpu.c $(pseries_platform_SOURCES) src_ppc64_cpu_LDADD = -lpthread AM_CFLAGS = -Wall -g -I $(top_srcdir)/src/common/ if WITH_LIBRTAS sbin_PROGRAMS += \ src/activate_firmware \ src/set_poweron_time \ src/rtas_ibm_get_vpd \ src/serv_config \ src/uesensor \ src/rtas_event_decode \ src/sys_ident src_activate_firmware_SOURCES = src/activate_fw.c $(librtas_error_SOURCES) $(pseries_platform_SOURCES) src_activate_firmware_LDADD = -lrtas -lm src_set_poweron_time_SOURCES = src/set_poweron_time.c $(librtas_error_SOURCES) $(pseries_platform_SOURCES) src_set_poweron_time_LDADD = -lrtas src_rtas_ibm_get_vpd_SOURCES = src/rtas_ibm_get_vpd.c $(librtas_error_SOURCES) $(pseries_platform_SOURCES) src_rtas_ibm_get_vpd_LDADD = -lrtas src_serv_config_SOURCES = src/serv_config.c $(librtas_error_SOURCES) $(pseries_platform_SOURCES) src_serv_config_LDADD = -lrtas src_uesensor_SOURCES = src/uesensor.c $(librtas_error_SOURCES) $(pseries_platform_SOURCES) src_uesensor_LDADD = -lrtas src_rtas_event_decode_SOURCES = src/rtas_event_decode.c $(pseries_platform_SOURCES) src_rtas_event_decode_LDADD = -lrtasevent src_sys_ident_SOURCES = src/sys_ident.c $(pseries_platform_SOURCES) src_sys_ident_LDADD = -lrtas src_ppc64_cpu_SOURCES += $(librtas_error_SOURCES) src_ppc64_cpu_LDADD += -lrtas sbin_PROGRAMS += src/errinjct/errinjct src/rtas_dbg src_errinjct_errinjct_SOURCES = \ src/errinjct/dcache.c \ src/errinjct/errinjct.c \ src/errinjct/icache.c \ src/errinjct/ioa_bus_error.c \ src/errinjct/open_close.c \ src/errinjct/platform.c \ src/errinjct/slb.c \ src/errinjct/tlb.c \ $(pseries_platform_SOURCES) noinst_HEADERS += src/errinjct/errinjct.h src_errinjct_errinjct_LDADD = -lrtas src_rtas_dbg_SOURCES = src/rtas_dbg.c $(pseries_platform_SOURCES) src_rtas_dbg_LDADD = -lrtas sbin_PROGRAMS += src/drmgr/drmgr src/drmgr/lsslot endif src_drmgr_drmgr_SOURCES = \ src/drmgr/common.c \ src/drmgr/common_cpu.c \ src/drmgr/common_ofdt.c \ src/drmgr/common_pci.c \ src/drmgr/drmgr.c \ src/drmgr/drmig_chrp_pmig.c \ src/drmgr/drslot_chrp_cpu.c \ src/drmgr/drslot_chrp_hea.c \ src/drmgr/drslot_chrp_mem.c \ src/drmgr/drslot_chrp_pci.c \ src/drmgr/drslot_chrp_phb.c \ src/drmgr/drslot_chrp_slot.c \ src/drmgr/rtas_calls.c \ src/drmgr/prrn.c \ $(pseries_platform_SOURCES) noinst_HEADERS += \ src/drmgr/drcpu.h \ src/drmgr/dr.h \ src/drmgr/drmem.h \ src/drmgr/drpci.h \ src/drmgr/rtas_calls.h \ src/drmgr/ofdt.h \ src/drmgr/rtas_calls.h \ src/drmgr/options.c src_drmgr_drmgr_LDADD = -lrtas src_drmgr_lsslot_SOURCES = \ src/drmgr/lsslot.c \ src/drmgr/lsslot_chrp_cpu.c \ src/drmgr/common.c \ src/drmgr/common_cpu.c \ src/drmgr/common_pci.c \ src/drmgr/common_ofdt.c \ src/drmgr/rtas_calls.c \ src/drmgr/drslot_chrp_mem.c \ $(pseries_platform_SOURCES) noinst_HEADERS += \ src/drmgr/options.c src_drmgr_lsslot_LDADD = -lrtas if WITH_SYSTEMD install-data-hook: systemd/smt_off.service $(MKDIR_P) @prefix@${systemd_unit_dir} $(INSTALL_SCRIPT) $< @prefix@${systemd_unit_dir}/ sed -i -e 's,$${exec_prefix},@sbindir@,g' @prefix@${systemd_unit_dir}/smt_off.service endif powerpc-utils-1.3.4/README000066400000000000000000000075261315235264300152320ustar00rootroot00000000000000powerpc-utils package ========================== This package contains utilities which are intended for maintenance of IBM powerpc platforms that follow the POWER Architecture Platform Reference (PAPR), This package requires the librtas package in order to function properly. All of these utilities must be run as root. The virtual IO administration utilities included in this package require the systool application. Further documentation for each of these utilities is available in their corresponding man pages. update_flash: system firmware update utility ------------ A script that uses the rtas_flash kernel module to flash firmware. set_poweron_time: configure time for system power-on ---------------- A utility to set a time in the future for the system to automatically power on, if the system is powered off at that time. serv_config: configure serviceability settings ----------- A series of menus that can be used to update system service settings stored in NVRAM, which are used by the system's service processor. These settings include surveillance, boot, and remote maintenance policies. Different system configurations may expose different kinds of serviceability parameters. hvcsadmin: HVCS driver administration utility ------- This is the hvcs driver administration utility which simplifies hvcs administration by providing a set of options for such functions as closing adapter targets using device mapping, querying console adapters, querying adapters based upon device node, gathering status, and closing all open adapters. Documentation is provided in man page hvcsadmin (8). ibmvscsis.sh: IBMVSCSIS driver init script ------- When symlinked into start and stop run levels this script can provide vscsi server operation automation. It supports the standard array of init script options {start|stop|status|restart}. By design this script executes operations in silent mode. For extended vscsi server operations the vscsisadmin script should be used instead. Documentation is provided in man page ibmvscsis.sh (8). vscsisadmin: IBM Virtual SCSI Server (ibmvscsis) administration utilities ------- This is the virtual scsi server administration utility which simplifies configuration, starting, and stopping of an IBM virtual SCSI server. This script can be run standalone or it can be invoked via the ibmvscsis.sh init script. Documentation is provided in man page vscsisadmin (8). Configuration script documentation is provided in ibmvscsis.conf (8) and outlines the proper method for writing a well formed ibmvscsis configuration file. drmgr: ----- Dynamic reconfiguration manager. This isn't neccessarily meant to be invoked from the command line, but rather is the command invoked via the RMC connection from an HMC. lsslot: ------ Tool used to determine dyanmic reconfiguration capable slots/cpus/memory on a partition. ppc64_cpu: --------- This allows users to set the smt state, smt-snooze-delay and other settings on ppc64 processors. It also allows users to control the number of processor cores which are online (not in the sleep state). lsdevinfo: --------- This utility provides the HMC or IVM with name information for virtual devices so they can be matched against the VIOS names. usysident, usysattn, usysfault: ------------------------------- Deprecated. Moved to ppc64-diag package. http://sourceforge.net/projects/linux-diag/files/ppc64-diag/ =================== The following tools are used by other maintenance utilities to gather necessary information. These tools are not typically invoked on the command line. activate_firmware: concurrent firmware activation ----------------- Used during concurrent firmware update operations to activate the new firmware image locally. This utility is invoked automatically when necessary. rtas_ibm_get_vpd: ---------------- Used by the lsvpd utility to gather Vital Product Data that changes dynamically. powerpc-utils-1.3.4/addon/000077500000000000000000000000001315235264300154255ustar00rootroot00000000000000powerpc-utils-1.3.4/addon/Makefile000066400000000000000000000022171315235264300170670ustar00rootroot00000000000000## Makefile for powerpc-utils-sles10-addons PPU_ADDONS_NAME = powerpc-utils-sles10-addons VERSION = 1.0.2 SCRIPTS = ../scripts/lsdevinfo ../scripts/ls-vdev ../scripts/ls-veth ../scripts/ls-vscsi UTILS = ../src/drmgr/drmgr ../src/drmgr/lsslot DOCS = ../COPYRIGHT README INSTALL = /usr/bin/install SBIN_DIR = /usr/sbin DOC_DIR = /usr/share/doc/packages/$(PPU_ADDONS_NAME) PPU_TARNAME = powerpc-utils-1.2.8 PPU_ADDONS_TARNAME = $(PPU_ADDONS_NAME)-$(VERSION) all: install: $(INSTALL) -d -m 755 $(DESTDIR)$(SBIN_DIR) $(foreach f,$(SCRIPTS),$(INSTALL) -m 744 $f $(DESTDIR)$(SBIN_DIR);) $(foreach f,$(UTILS),$(INSTALL) -m 744 $f $(DESTDIR)$(SBIN_DIR);) $(INSTALL) -d -m 755 $(DESTDIR)$(DOC_DIR) $(foreach f,$(DOCS),$(INSTALL) -m 744 $f $(DESTDIR)$(DOC_DIR);) dist: $(MAKE) -C .. dist tar -xzf ../$(PPU_TARNAME).tar.gz mv $(PPU_TARNAME) $(PPU_ADDONS_TARNAME) mkdir $(PPU_ADDONS_TARNAME)/addon cp Makefile $(PPU_ADDONS_TARNAME)/addon cp README $(PPU_ADDONS_TARNAME)/addon cp powerpc-utils-sles10-addons.spec $(PPU_ADDONS_TARNAME)/addon tar -chof $(PPU_ADDONS_TARNAME).tar $(PPU_ADDONS_TARNAME) gzip $(PPU_ADDONS_TARNAME).tar rm -rf $(PPU_ADDONS_TARNAME) powerpc-utils-1.3.4/addon/README000066400000000000000000000020721315235264300163060ustar00rootroot00000000000000powerpc-utils-sles10-addons package =================================== This package is meant as an addon for the SLES 10 SP3 release to bring the installed powerpc-utilities up to par with the latest ppowerpc-utils release. the packages installed are those that are not installed with the version of powerpc-utils shipped with SLES 10 SP3. This package contains utilities which are intended for maintenance of IBM powerpc platforms that follow the POWER Architecture Platform Reference (PAPR), This package requires the librtas package in order to function properly. All of these utilities must be run as root. drmgr ----- Dynamic reconfiguration manager. This isn't neccessarily meant to be invoked from the command line, but rather is the command invoked via the RMC connection from an HMC. lsslot: ------ Tool used to determine dyanmic reconfiguration capable slots/cpus/memory on a partition. lsdevinfo, ls-vdev, ls-veth, ls-vscsi: --------- These utilities provides the HMC or IVM with name information for virtual devices so they can be matched against the VIOS names. powerpc-utils-1.3.4/addon/powerpc-utils-sles10-addons.spec000066400000000000000000000032761315235264300235010ustar00rootroot00000000000000%define name powerpc-utils-sles10-addons %define version 1.0.2 %define release 0 Summary: Powerpc-utils Add-ons for SLES10 SP3 Name: %{name} Version: %{version} Release: %{release} License: IBM Common Public License (CPL) Group: System Environment Source: powerpc-utils-sles10-addons-%{version}.tar.gz BuildRoot: /tmp/%{name}-buildroot/ Requires: /bin/bash, /bin/sh, /bin/sed, /usr/bin/perl, librtas >= 1.3.0 %description Additional utilities for maintaining and servicing PowerPC systems on SLES10 SP3 releases. %prep %setup -q %build %configure %{__make} %{?_smp_mflags} %install %{__rm} -rf $RPM_BULD_ROOT %{__make} install -C addon DESTDIR=$RPM_BUILD_ROOT %files %defattr(-,root,root) /usr/share/doc/packages/powerpc-utils-sles10-addons/README /usr/share/doc/packages/powerpc-utils-sles10-addons/COPYRIGHT /usr/sbin/drmgr /usr/sbin/lsslot /usr/sbin/lsdevinfo /usr/sbin/ls-veth /usr/sbin/ls-vdev /usr/sbin/ls-vscsi %post # Post-install script ----------------------------------------------- ln -sf /usr/sbin/drmgr /usr/sbin/drslot_chrp_slot ln -sf /usr/sbin/drmgr /usr/sbin/drslot_chrp_pci ln -sf /usr/sbin/drmgr /usr/sbin/drslot_chrp_cpu ln -sf /usr/sbin/drmgr /usr/sbin/drslot_chrp_phb ln -sf /usr/sbin/drmgr /usr/sbin/drslot_chrp_mem ln -sf /usr/sbin/drmgr /usr/sbin/drslot_chrp_hea ln -sf /usr/sbin/drmgr /usr/sbin/drmig_chrp_pmig %postun # Post-uninstall script --------------------------------------------- if [ "$1" = "0" ]; then # last uninstall rm /usr/sbin/drslot_chrp_slot rm /usr/sbin/drslot_chrp_pci rm /usr/sbin/drslot_chrp_cpu rm /usr/sbin/drslot_chrp_phb rm /usr/sbin/drslot_chrp_mem rm /usr/sbin/drslot_chrp_hea rm /usr/sbin/drmig_chrp_pmig fi powerpc-utils-1.3.4/autogen.sh000077500000000000000000000001461315235264300163420ustar00rootroot00000000000000#!/bin/sh set -e if [ ! -d config ]; then mkdir config; fi autoreconf --install --verbose --force powerpc-utils-1.3.4/configure.ac000066400000000000000000000060151315235264300166300ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. m4_define([ppu_version], 1.3.4) AC_PREREQ([2.63]) AC_INIT([powerpc-utils], ppu_version, [nfont@linux.vnet.ibm.com]) AC_CONFIG_AUX_DIR([config]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE([1.10 -Wall subdir-objects -Werror foreign]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_CONFIG_SRCDIR([src/rtas_ibm_get_vpd.c]) # Checks for programs. AC_PROG_CC AC_PROG_INSTALL AM_PROG_CC_C_O # Checks for header files. AC_CHECK_HEADERS([fcntl.h inttypes.h limits.h locale.h memory.h netinet/in.h nl_types.h stdint.h stdlib.h string.h sys/ioctl.h syslog.h unistd.h linux/perf_event.h sys/time.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_TYPE_INT8_T AC_TYPE_MODE_T AC_TYPE_PID_T AC_TYPE_SIZE_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_UINT8_T # Checks for library functions. AC_FUNC_FORK AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK AC_FUNC_MALLOC AC_FUNC_MKTIME AC_CHECK_FUNCS([memset strchr strcspn strdup strerror strrchr strstr strtol strtoul strtoull gettimeofday]) # check for zlib AC_CHECK_HEADER(zlib.h, [AC_CHECK_LIB(z, inflate, [], [AC_MSG_FAILURE([zlib library is required for compilation])])], [AC_MSG_FAILURE([zlib.h is required for compiliation])]) # check for librtas AC_ARG_WITH([librtas], [AS_HELP_STRING([--without-librtas], [disable building utilities that require librtas])], [], [with_librtas=yes] ) AS_IF([test "x$with_librtas" != "xno"], [AC_CHECK_HEADER([librtas.h], [ with_libtras=yes AC_DEFINE(WITH_LIBRTAS) ], [AC_MSG_FAILURE( [librtas test failed (--without-librtas to disable)])] )] ) AM_CONDITIONAL([WITH_LIBRTAS], [test "x$with_librtas" = "xyes"]) # Check what OS you are running AC_CANONICAL_HOST case $host_os in linux*) LIBDL="-ldl" ;; *freebsd*) LIBDL="" ;; *) #Default Case AC_MSG_ERROR([Your platform is not currently supported]) ;; esac AC_SUBST(LIBDL) # check for systemd systemd_unit_dir=/usr/lib/systemd/system AC_ARG_WITH([systemd], [AC_HELP_STRING([--with-systemd@<:@=DIR@:>@], [install systemd unit files (not default and unit dir is /usr/lib/systemd/system)])], [if test "$withval" = "no"; then with_systemd=0 else with_systemd=1 test $withval != "yes" && systemd_unit_dir=$withval fi], with_systemd=0 ) AM_CONDITIONAL(WITH_SYSTEMD, [test "$with_systemd" = 1]) AC_SUBST(systemd_unit_dir) AC_DEFUN([LOCAL_CHECK_FLAGS],[ AC_REQUIRE([AX_CHECK_LINK_FLAG]) AC_REQUIRE([AX_APPEND_COMPILE_FLAGS]) AC_LANG_PUSH([C]) AX_APPEND_COMPILE_FLAGS([-Wall]) AX_APPEND_COMPILE_FLAGS([-D_FORTIFY_SOURCE=2 -fstack-protector-all]) AX_APPEND_COMPILE_FLAGS([-fwrapv -fPIE -Wstack-protector]) AX_APPEND_COMPILE_FLAGS([--param=ssp-buffer-size=1]) AX_CHECK_LINK_FLAG([-z relro -z now]) AX_CHECK_LINK_FLAG([-pie]) AC_LANG_POP ]) LOCAL_CHECK_FLAGS AC_CONFIG_FILES([Makefile powerpc-utils.spec systemd/smt_off.service]) AC_OUTPUT powerpc-utils-1.3.4/doc/000077500000000000000000000000001315235264300151055ustar00rootroot00000000000000powerpc-utils-1.3.4/doc/activate_firmware.doxycfg000066400000000000000000001343071315235264300221760ustar00rootroot00000000000000# Doxyfile 1.3.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = activate_firmware # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = . # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of source # files, where putting all generated files in the same directory would otherwise # cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, # Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, # Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, # Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, # Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = NO # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is used # as the annotated text. Otherwise, the brief description is used as-is. If left # blank, the following values are used ("$name" is automatically replaced with the # name of the entity): "The $name class" "The $name widget" "The $name file" # "is" "provides" "specifies" "contains" "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited # members of a class in the documentation of that class as if those members were # ordinary class members. Constructors, destructors and assignment operators of # the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources # only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../../cmds/activate_fw.c # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp # *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories # that are symbolic links (a Unix filesystem feature) are excluded from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_PREDEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse the # parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or # super classes. Setting the tag to NO turns the diagrams off. Note that this # option is superseded by the HAVE_DOT option below. This is only a fallback. It is # recommended to install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes that # lay further from the root node will be omitted. Note that setting this option to # 1 or 2 may greatly reduce the computation time needed for large code bases. Also # note that a graph may be further truncated if the graph's image dimensions are # not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). # If 0 is used for the depth value (the default), the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO powerpc-utils-1.3.4/doc/nvram.doxycfg000066400000000000000000001343101315235264300176170ustar00rootroot00000000000000# Doxyfile 1.3.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = nvram # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = . # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of source # files, where putting all generated files in the same directory would otherwise # cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, # Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, # Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, # Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, # Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = NO # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is used # as the annotated text. Otherwise, the brief description is used as-is. If left # blank, the following values are used ("$name" is automatically replaced with the # name of the entity): "The $name class" "The $name widget" "The $name file" # "is" "provides" "specifies" "contains" "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited # members of a class in the documentation of that class as if those members were # ordinary class members. Constructors, destructors and assignment operators of # the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources # only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../../cmds/nvram.c ../../cmds/nvram.h # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp # *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories # that are symbolic links (a Unix filesystem feature) are excluded from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_PREDEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse the # parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or # super classes. Setting the tag to NO turns the diagrams off. Note that this # option is superseded by the HAVE_DOT option below. This is only a fallback. It is # recommended to install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes that # lay further from the root node will be omitted. Note that setting this option to # 1 or 2 may greatly reduce the computation time needed for large code bases. Also # note that a graph may be further truncated if the graph's image dimensions are # not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). # If 0 is used for the depth value (the default), the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO powerpc-utils-1.3.4/doc/rtas_ibm_get_vpd.doxycfg000066400000000000000000001343131315235264300220070ustar00rootroot00000000000000# Doxyfile 1.3.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = rtas_ibm_get_vpd # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = . # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of source # files, where putting all generated files in the same directory would otherwise # cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, # Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, # Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, # Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, # Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = NO # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is used # as the annotated text. Otherwise, the brief description is used as-is. If left # blank, the following values are used ("$name" is automatically replaced with the # name of the entity): "The $name class" "The $name widget" "The $name file" # "is" "provides" "specifies" "contains" "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited # members of a class in the documentation of that class as if those members were # ordinary class members. Constructors, destructors and assignment operators of # the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources # only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../../cmds/rtas_ibm_get_vpd.c # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp # *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories # that are symbolic links (a Unix filesystem feature) are excluded from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_PREDEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse the # parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or # super classes. Setting the tag to NO turns the diagrams off. Note that this # option is superseded by the HAVE_DOT option below. This is only a fallback. It is # recommended to install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes that # lay further from the root node will be omitted. Note that setting this option to # 1 or 2 may greatly reduce the computation time needed for large code bases. Also # note that a graph may be further truncated if the graph's image dimensions are # not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). # If 0 is used for the depth value (the default), the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO powerpc-utils-1.3.4/doc/serv_config.doxycfg000066400000000000000000001343341315235264300210060ustar00rootroot00000000000000# Doxyfile 1.3.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = serv_config # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = . # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of source # files, where putting all generated files in the same directory would otherwise # cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, # Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, # Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, # Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, # Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = NO # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is used # as the annotated text. Otherwise, the brief description is used as-is. If left # blank, the following values are used ("$name" is automatically replaced with the # name of the entity): "The $name class" "The $name widget" "The $name file" # "is" "provides" "specifies" "contains" "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited # members of a class in the documentation of that class as if those members were # ordinary class members. Constructors, destructors and assignment operators of # the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources # only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../../cmds/serv_config.c ../../cmds/librtas_error.c # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp # *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories # that are symbolic links (a Unix filesystem feature) are excluded from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_PREDEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse the # parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or # super classes. Setting the tag to NO turns the diagrams off. Note that this # option is superseded by the HAVE_DOT option below. This is only a fallback. It is # recommended to install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes that # lay further from the root node will be omitted. Note that setting this option to # 1 or 2 may greatly reduce the computation time needed for large code bases. Also # note that a graph may be further truncated if the graph's image dimensions are # not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). # If 0 is used for the depth value (the default), the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO powerpc-utils-1.3.4/doc/set_poweron_time.doxycfg000066400000000000000000001343131315235264300220610ustar00rootroot00000000000000# Doxyfile 1.3.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = set_poweron_time # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = . # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of source # files, where putting all generated files in the same directory would otherwise # cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, # Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, # Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, # Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, # Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = NO # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is used # as the annotated text. Otherwise, the brief description is used as-is. If left # blank, the following values are used ("$name" is automatically replaced with the # name of the entity): "The $name class" "The $name widget" "The $name file" # "is" "provides" "specifies" "contains" "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited # members of a class in the documentation of that class as if those members were # ordinary class members. Constructors, destructors and assignment operators of # the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources # only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../../cmds/set_poweron_time.c # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp # *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories # that are symbolic links (a Unix filesystem feature) are excluded from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_PREDEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse the # parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or # super classes. Setting the tag to NO turns the diagrams off. Note that this # option is superseded by the HAVE_DOT option below. This is only a fallback. It is # recommended to install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes that # lay further from the root node will be omitted. Note that setting this option to # 1 or 2 may greatly reduce the computation time needed for large code bases. Also # note that a graph may be further truncated if the graph's image dimensions are # not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). # If 0 is used for the depth value (the default), the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO powerpc-utils-1.3.4/doc/uesensor.doxycfg000066400000000000000000001343261315235264300203460ustar00rootroot00000000000000# Doxyfile 1.3.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = uesensor # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = . # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of source # files, where putting all generated files in the same directory would otherwise # cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, # Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, # Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, # Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, # Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = NO # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is used # as the annotated text. Otherwise, the brief description is used as-is. If left # blank, the following values are used ("$name" is automatically replaced with the # name of the entity): "The $name class" "The $name widget" "The $name file" # "is" "provides" "specifies" "contains" "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited # members of a class in the documentation of that class as if those members were # ordinary class members. Constructors, destructors and assignment operators of # the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources # only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../../cmds/uesensor.c ../../cmds/librtas_error.c # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp # *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories # that are symbolic links (a Unix filesystem feature) are excluded from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_PREDEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse the # parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or # super classes. Setting the tag to NO turns the diagrams off. Note that this # option is superseded by the HAVE_DOT option below. This is only a fallback. It is # recommended to install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes that # lay further from the root node will be omitted. Note that setting this option to # 1 or 2 may greatly reduce the computation time needed for large code bases. Also # note that a graph may be further truncated if the graph's image dimensions are # not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). # If 0 is used for the depth value (the default), the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO powerpc-utils-1.3.4/m4/000077500000000000000000000000001315235264300146605ustar00rootroot00000000000000powerpc-utils-1.3.4/m4/ax_append_compile_flags.m4000066400000000000000000000055311315235264300217510ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html # =========================================================================== # # SYNOPSIS # # AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS]) # # DESCRIPTION # # For every FLAG1, FLAG2 it is checked whether the compiler works with the # flag. If it does, the flag is added FLAGS-VARIABLE # # If FLAGS-VARIABLE is not specified, the current language's flags (e.g. # CFLAGS) is used. During the check the flag is always added to the # current language's flags. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # NOTE: This macro depends on the AX_APPEND_FLAG and # AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with # AX_APPEND_LINK_FLAGS. # # LICENSE # # Copyright (c) 2011 Maarten Bosmans # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 4 AC_DEFUN([AX_APPEND_COMPILE_FLAGS], [AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG]) AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) for flag in $1; do AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3]) done ])dnl AX_APPEND_COMPILE_FLAGS powerpc-utils-1.3.4/m4/ax_append_flag.m4000066400000000000000000000053041315235264300200540ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_append_flag.html # =========================================================================== # # SYNOPSIS # # AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) # # DESCRIPTION # # FLAG is appended to the FLAGS-VARIABLE shell variable, with a space # added in between. # # If FLAGS-VARIABLE is not specified, the current language's flags (e.g. # CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains # FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly # FLAG. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 2 AC_DEFUN([AX_APPEND_FLAG], [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])dnl AS_VAR_SET_IF(FLAGS, [case " AS_VAR_GET(FLAGS) " in *" $1 "*) AC_RUN_LOG([: FLAGS already contains $1]) ;; *) AC_RUN_LOG([: FLAGS="$FLAGS $1"]) AS_VAR_SET(FLAGS, ["AS_VAR_GET(FLAGS) $1"]) ;; esac], [AS_VAR_SET(FLAGS,["$1"])]) AS_VAR_POPDEF([FLAGS])dnl ])dnl AX_APPEND_FLAG powerpc-utils-1.3.4/m4/ax_check_compile_flag.m4000066400000000000000000000064111315235264300213720ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 3 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS powerpc-utils-1.3.4/m4/ax_check_link_flag.m4000066400000000000000000000061151315235264300207000ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the linker or gives an error. # (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the linker's default flags # when the check is done. The check is thus made with the flags: "LDFLAGS # EXTRA-FLAGS FLAG". This can for example be used to force the linker to # issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_LINK_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 3 AC_DEFUN([AX_CHECK_LINK_FLAG], [AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ ax_check_save_flags=$LDFLAGS LDFLAGS="$LDFLAGS $4 $1" AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) LDFLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_LINK_FLAGS powerpc-utils-1.3.4/m4/ax_require_defined.m4000066400000000000000000000023011315235264300207400ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_require_defined.html # =========================================================================== # # SYNOPSIS # # AX_REQUIRE_DEFINED(MACRO) # # DESCRIPTION # # AX_REQUIRE_DEFINED is a simple helper for making sure other macros have # been defined and thus are available for use. This avoids random issues # where a macro isn't expanded. Instead the configure script emits a # non-fatal: # # ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found # # It's like AC_REQUIRE except it doesn't expand the required macro. # # Here's an example: # # AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) # # LICENSE # # Copyright (c) 2014 Mike Frysinger # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 1 AC_DEFUN([AX_REQUIRE_DEFINED], [dnl m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])]) ])dnl AX_REQUIRE_DEFINED powerpc-utils-1.3.4/man/000077500000000000000000000000001315235264300151135ustar00rootroot00000000000000powerpc-utils-1.3.4/man/activate_firmware.8000066400000000000000000000023251315235264300207020ustar00rootroot00000000000000.\" .\" Copyright (C) 2004 International Business Machines .\" .TH ACTIVATE_FIRMWARE 8 "May 2004" Linux "Power Service Tools" .SH NAME activate_firmware - activate a firmware image that has been updated concurrently .SH SYNOPSIS \fB/usr/sbin/activate_firmware [-e [keyfile]] .SH DESCRIPTION When used without options, the activate_firmware utility will cause a firmware image that has already been flashed to be activated concurrently. This utility will be invoked automatically when necessary, and as such should not be manually invoked at the command line. .SH OPTIONS .TP .B \-e [keyfile] When used with this option, the command either fetches the current Update Access Key expiry date or sets the Update Access Key expiry date if is provided. .SH "EXIT STATUS" .TP .B 0 Success. .TP .B 1 This platform does not support concurrent activation of firmware. .TP .B 2 There is no new firmware ready to activate. .TP .B 3 You must have root authority to run this command. .TP .B 4 Hardware failure. .TP .B 5 Memory/resource allocation error. .TP .B 6 General error. .TP .B 7 Error in case of getting UAK expiry date or setting UAK. Exact error description is written to stderr. .TP .B 8 Parameter error when activating firmware. powerpc-utils-1.3.4/man/amsstat.1000066400000000000000000000273511315235264300166610ustar00rootroot00000000000000.\" Copyright (C) 2009 International Business Machines. .\" Common Public License Version 1.0 (see COPYRIGHT) .\" .\" Author(s) .\" Robert Jennings .\" .TH AMSSTAT 1 "March 2009" Linux "Linux on Power Service Tools" .SH NAME amsstat \- display a list of Active Memory Sharing (AMS) statistics. .SH SYNOPSIS .B /usr/bin/amsstat [\fISECONDS\fP] .SH DESCRIPTION This program captures memory statistics relevant in an Active Memory Sharing (AMS) environment. This tool can run once or be set to run repeatedly with a specified timeout, in seconds, between instances of data collection. Several sections are displayed for the partition, they are as follows: .SS System Memory Statistics In an AMS environment, the amount of memory available will change as memory is loaned to other partitions by the Cooperative Memory Manager (CMM) module. This section will show how the total amount of memory provided to the partition is being utilized. .P The fields here are taken from \fI/proc/meminfo\fP. .TP MemTotal This value, expressed in kilobytes, is the maximum amount of memory available to the operating system. .TP MemFree This value, displayed in kilobytes, is the amount of memory which is unused. .TP Buffers The amount of memory, in kilobytes, used for file buffers. .TP Cached The amount of memory, in kilobytes, used as cache memory. .TP Inactive The total amount of buffer or page cache memory, in kilobytes, that are free and available. This is memory that has not been recently used and can be reclaimed for other purposes. .TP SwapTotal The total amount of swap available, in kilobytes. .TP SwapFree The total amount of swap free, in kilobytes. .TP DesMem The desired memory field shows the amount of memory that firmware would like to to have currently assigned to the partition. This relates to the amount of assigned memory specified in the HMC or IVM however this value can be out-of-sync withe current amount of memory assigned to the operating system if dynamic memory add or remove operations have failed. .SS Entitlement Information This information is specific to an AMS environment, the fields are taken from \fI/proc/ppc64/lparcfg\fP. .TP entitled_memory The \fIentitled_memory\fP is a specific amount of memory given to the operating system that will be available to be mapped for IO operations; this guarantee is maintained by the platform firmware and can be tuned through the HMC or IVM depending on the particular environment. This value is displayed in kilobytes. The amount of \fIentitled memory\fP is changed by the HMC or IVM in response to hot-plug events or explicit tuning. .TP mapped_entitled_memory The number of bytes of \fIentitled_memory\fP currently mapped for IO operations according to firmware. .TP entitled_memory_group_number This value is assigned to the partition by firmware and can be used by support to help correlate operating system data with firmware data. It is not of use to the end user but is displayed for debug support. .TP entitled_memory_pool_number This is the identification number of the shared memory pool to which this partition belongs. .TP entitled_memory_weight This is the weighting that is used by firmware to help prioritize partitions for memory loaning. .TP entitled_memory_pool_size This is the total size of the physical memory in the memory pool to which this partition belongs and includes memory that may not presently be accessible to the operating system. .TP entitled_memory_loan_request The number of bytes which firmware would like the partition to give or take via the Cooperative Memory Manager (CMM). Positive values denote a request of how much memory, in bytes, it would like the operating system to loan to firmware. Negative values denote that the operating system may take back that number of bytes of memory for its own use. .TP backing_memory This is the amount of physical memory, in bytes, that is currently reserved for access by this partition. This value does change over time based on load of all of the partitions in the shared memory pool. Use of memory in excess of this amount incurs performance penalties as loaning and paging will need to occur. .TP coalesced_bytes The number of bytes of memory assigned to the logical partition which have been coalesced with identical pages either within the logical partition, or with another logical partition. .TP pool_coalesced_bytes The number of bytes of memory in the shared memory pool which have been coalesced with identical pages. .TP cmo_enabled When this value is \fI1\fP the partition is running in shared memory mode. A \fI0\fP in this field indicates that dedicated memory mode is enabled and the AMS kernel code will not be active. .TP cmo_faults A fault occurs when an attempt to access memory is made where the platform firmware must suspend the partition and request data from disk. This value is a sum of the number of faults since the operating system was booted. Increases in this value indicate contention for memory between partitions in the AMS environment. .TP cmo_fault_time_usec This value is a running sum of the amount of time, since boot time, that the operating system has been suspended by platform firmware to process \fIcmo_faults\fP. This value is given is microseconds (10^-6 or 0.0000001 seconds). .TP cmo_primary_psp This is the identification number of the primary paging storage pool (psp). .TP cmo_secondary_psp This is the identification number of the secondary paging storage pool (psp). .SS CMM Statistics The Cooperative Memory Manager (CMM) module loans unused memory to firmware to be used by other partitions within the shared memory pool. The fields here are taken from \fI/sys/module/cmm/parameters\fP and \fI/sys/devices/system/cmm/cmm0\fP. .TP disable The CMM code is disabled when this is set to 1 and is enabled when this value is 0. If CMM is disabled no loaning will occur. .TP debug Set to 1, CMM will print debug information regarding the number of pages loaned, the loan request from firmware, etc to the console or system log. .TP min_mem_mb This the amount of partition memory, in megabytes, which will be reserved from loaning. .TP oom_kb The number of kilobytes of memory taken back from firmware by the CMM module for the operating system when an out of memory signal from the kernel is caught by CMM. .TP delay This is the number of seconds that CMM waits between requests to firmware for the number of pages that firmware would like the operating system to loan. .TP loaned_kb This is the amount of memory, in kilobytes, that the operating system has given back to the platform firmware to be used by other partitions. This value fluctuates to meet the demands of all of the partitions in the shared memory pool of an AMS environment. .TP loaned_target_kb This is the amount of memory, in kilobytes, that the firmware would like the operating system to loan for use by other partitions. This value may be greater than \fIloaned_kb\fP if firmware would like additional pages to be loaned or it may be less than \fIloaned_kb\fP if firmware is providing additional pages to the operating system. .TP oom_freed_kb The amount of memory, in kilobytes, that is no longer being loaned by CMM as a result of out-or-memory kernel signals. .SS VIO Bus Statistics The VIO Bus manages the operating system's \fIentitled memory\fP for devices which may perform DMA operations. The data here is found in the \fI/sys/bus/vio/\fP directory. The use of \fIcmo\fP is a historical reference to the \fIAMS\fP feature and is used interchangeably. .TP cmo_entitled The \fIentitled\fP memory is a specific amount of memory given to the operating system that will be available to be mapped for IO operations; this guarantee is maintained by the platform firmware and can be tuned through the HMC or IVM depending on the particular environment. This value is displayed in kilobytes. The amount of \fIentitled\fP memory is changed by the HMC or IVM in response to hot-plug events or explicit tuning. .TP cmo_reserve_size The \fIentitled\fP memory is split into two pools, the first of which is the \fIreserve pool\fP. This value, expressed in kilobytes, represents the amount of memory guaranteed to individual devices on the bus. .TP cmo_excess_size This pool contains any amount of \fIentitled\fP memory not placed in the \fIreserve pool\fP; the value is displayed in kilobytes. Any device can map memory from this pool for IO operations, after having used up its own allocation from the \fIreserve pool\fP, until the \fIexcess pool\fP is exhausted. .TP cmo_excess_free This value represents the amount of memory, in kilobytes, currently available for devices to use from the \fIexcess pool\fP. .TP cmo_spare This value represents the amount of memory, in kilobytes, kept unused to handle hot-plug events, entitlement rebalancing between devices, and module loading. .TP cmo_min This value represents the current minimum amount of entitlement that the operating system could function with based on the ideal size of the \fIspare\fP allocation plus a small allocation for each device present in the system. Requests to change system entitlement below this value will fail. Setting entitlement to this value may impact performance, but should allow the system to make forward progress, the ideal value is displayed in \fIcmo_desired\fP below. .TP cmo_desired Each device in the system that requires memory for mapping IO operations will specify an amount of memory which is desired for optimal performance. This value is the sum of the requests made by individual devices on the bus and is measured in kilobytes. .TP cmo_curr This value represents the amount of memory, in kilobytes, that is currently mapped by device drivers for IO operations. .TP cmo_high This value, measured in kilobytes, represents the largest amount of memory mapped at any one point in time since the system was booted or the field was last reset. This value can be reset by writing a '0' to the file \fI/sys/bus/vio/cmo_high\fP. .SS VIO Device Statistics Each device that is configured and performs DMA operations will appear listed beneath this heading. The devices are displayed by their location on the VIO bus nd the data is pulled from \fI/sys/bus/vio/devices/\fP\fB\fP\fI/*\fP. For each device the following are shown: .TP cmo_desired The amount of memory, in kilobytes, that the device has requested from the bus to provide optimal performance. The amount of \fIcmo_entitled\fP memory will not exceed this amount. The device may receive a memory entitlement less than its desired level in cases where resources are limited. .TP cmo_entitled The amount of memory, in kilobytes, that the device is guaranteed that it may map for IO operations. The allocation of this entitled memory is made to the device from the bus' \fIcmo_reserve_pool\fP. .TP cmo_allocated The amount of memory, in kilobytes, that the device has currently mapped for IO operations. .TP cmo_allocs_failed When the amount of memory allocated (\fIcmo_allocated\fP) has exhausted both the entitled memory (\fIcmo_entitled\fP) and the bus' excess pool, memory mapping failures will occur. For each failed attempt, the value displayed here will increase by 1. Large changes in this value would indicate resource contention that may require system tuning. The device drivers are written such that these failures, while impacting performance, do not impede functionality. To reset this counter, the value '0' can be written to the file \fI/sys/bus/vio/devices/\fP\fI/cmo_allocs_failed\fP. .SH EXAMPLES .TP .B amsstat Display the AMS data for the local system, providing an update every 10 seconds. .P .TP .BI amsstat " 10" Display a list of AMS statistics and repeat every 10 seconds thereafter. .SH FILES .I /proc/sys/meminfo .br .I /proc/ppc64/lparcfg .br .I /sys/module/cmm/parameters/* .br .I /sys/devices/system/cmm/cmm0/ .br .I /sys/bus/vio/cmo_* .br .I /sys/bus/vio/devices/*/cmo_* powerpc-utils-1.3.4/man/bootlist.8000066400000000000000000000041421315235264300170440ustar00rootroot00000000000000.\" .\" Copyright (C) 2004 International Business Machines .\" Nathan Fontenot .\" .TH BOOTLIST 8 "May 2013" Linux "Linux on Power Service Tools" .SH NAME bootlist - update and view the bootlist .SH SYNOPSIS .nf \fB/usr/sbin/bootlist \-m \fR{\fBnormal\fR|\fBservice\fR|\fBboth\fR}\fB -o\fR|\fB-r\fR \fB/usr/sbin/bootlist \-m \fR{\fBnormal\fR|\fBservice\fR|\fBboth\fR} [\fB-o\fR|\fB-r\fR] \fB-f \fIfile \fB/usr/sbin/bootlist \-m \fR{\fBnormal\fR|\fBservice\fR|\fBboth\fR} [\fB-o\fR|\fB-r\fR] <\fIdev_list\fR> .fi .SH DESCRIPTION The bootlist command allows users to view and update the system bootlist stored in NVRAM for PowerPC-64 machines. To update the list of boot devices one or more boot devices can be specified directly or read from a file. This list of devices may be specified as either logical device names or the full Open Firmware device path. The bootlist command uses the \fIofpathanme\fR script to convert between logical device names and Open Firmware device paths, and the \fInvram\fR command to update the stored boot list. If a list of devices is not specified, or the -o or -r options are specified, the current boot list stored in nvram is displayed. .SH OPTIONS .TP \fB\-m normal\fR|\fBservice\fR|\fBboth Required; specify whether the normal or service mode boot list should be viewed/updated. Specifying "both" will update the normal and service mode boot lists. .TP \fB\-o Display the current boot list entries as logical device names. .TP \fB\-r Display the current boot list entries as Open Firmware device path names (default). .TP \fB\-f \fIfile Read the bootlist device names from \fIfile\fR, one entry per line. .TP \fIdev_list A space-separated list of devices, specified as logical device names or OF device path names, depending on whether the \fB-o\fR or \fB-r\fR option is specified. .SH EXAMPLES .nf View the normal mode boot list as logical device names: /usr/sbin/bootlist -o -m normal Update the service mode boot list: /usr/sbin/bootlist -o -m service /dev/sda3 /dev/cdrom .fi .SH AUTHOR Written by Nathan Fontenot .SH "SEE ALSO" .BR ofpathname (8), .BR nvram (8) powerpc-utils-1.3.4/man/errinjct.8000066400000000000000000000242721315235264300170330ustar00rootroot00000000000000\." \." Copyright (C) 2004 International Business Machines \." .TH ERRINJCT 8 "June 2007" Linux "Linux on Power Service Tools" .SH NAME errinjct \- inject errors into a system via RTAS. .SH SYNOPSIS .B /usr/local/sbin/errinjct [ OPTIONS ] .SH DESCRIPTION The \fIerrinjct\fR tool enables RTAS to inject errors on a Power system. This tool is for IBM internal use only. Currently, errinjct is only supported on PowerVM systems. .SH OPTIONS The options to the \fIerrinjct\fR tool change depending on the functionality requested. Run \fIerrinjct\fR without any arguments to see a list of supported functions. See the explanations of the individual functions below for more information. .SH FUNCTIONS .TP \fBopen\fR Open the RTAS error injection facility. .TP \fBclose\fR Close the RTAS error injection facility .TP \fBcorrupted-dcache-start\fR Start causing LI data cache errors .TP \fBcorrupted-dcache-end\fR Stop causing LI data cache errors .TP \fBcorrupted-icache-start\fR Start causing instruction cache errors .TP \fBcorrupted-icache-end\fR Stop causing instruction cache errors .TP \fBcorrupted-slb\fR Corrupt the SLB entry associated with a specific effective address .TP \fBioa-bus-error\fR Simulate an error on the IOA bus .TP \fBplatform-specific\fR Request the firmware perform a specific platform specific injection .TP \fBcorrupted-tlb-start\fR Start corrupting TLB .TP \fBcorrupted-tlb-end\fR Stop corrupting TLB .SH open Open the RTAS error injection facility Usage: errinjct open [options] Optional arguments: --dry-run don't perform the action, just print what would have been done -H --help print usage information for a particular function -v --verbose be more verbose with messages -q --quiet shhhh.... only report errors .SH close Close the RTAS error injection facility Usage: errinjct close [optioons] Mandatory argument: -k token token returned from error inject open Optional arguments: --dry-run don't perform the action, just print what would have been done -H --help print usage information for a particular function -v --verbose be more verbose with messages -q --quiet shhhh.... only report errors -C cpu cpu to inject errors on .SH corrupted-dcache-start / corrupted-dcache-end Inject errors onto the L1 data cache. Before using this option you need to open the RTAS error injection facility via "errinjct open". Afterwards pass this parameter in with the -k option and specify a cpu to run on with the -C option. Please note that you need to specify the same cpu number to the dcache-start and dcache-end errinjct calls. Usage: errinjct corrupted-dcache-start [options] errinjct dcache-start [options] errinjct corrupted-dcache-end [options] errinjct dcache-end [options] Mandatory Arguments: -a action type of D-cache error to inject 0: parity error 1: D-ERAT parity error 2: tag parity error -C cpu cpu to inject errors on -k token token returned from error inject open Optional arguments: --dry-run don't perform the action, just print what would have been done -H --help print usage information for a particular function -v --verbose be more verbose with messages -q --quiet shhhh.... only report errors Example: > errinjct open Error inject token = 2 > errinjct corrupted-dcache-start -a 1 -k 2 -C 0 . . . > errinjct corrupted-dcache-end -a 1 -k 2 -C 0 > errinjct close -k 2 .SH corrupted-icache-start / corrupted-icache-end Inject errors into the instruction cache. Before using this option you need to open the RTAS error injection facility via "errinjct open". Afterwards pass this parameter in with the -k option and specify a cpu to run on with the -C option. Please note that you need to specify the same cpu number to the icache-start and icache-end errinjct calls. Usage: errinjct corrupted-icache-start [options] errinjct icache-start [options] errinjct corrupted-icache-end [options] errinjct icache-end [options] Mandatory Arguments: -a action type of I-cache error to inject 0: Parity error 1: I-ERAT partiy error 2: Cache directory 0 parity error 3: Cache directory 1 parity error -n nature nature of I-cache error to inject 0: Single 1: Solid 2: Hang -C cpu cpu to inject errors on -k token token returned from error inject open Optional arguments: --dry-run don't perform the action, just print what would have been done -H --help print usage information for a particular function -v --verbose be more verbose with messages -q --quiet shhhh.... only report errors Example: > errinjct open Error inject token = 2 > errinjct corrupted-icache-start -a 1 -n 0 -k 2 -C 0 . . . > errinjct corrupted-icache-end -a 1 -n 0 -k 2 -C 0 > errinjct close -k 2 .SH corrupted-slb Corrupt the SLB entry associated with the specified effective address. Usage: errinjct corrupted-slb [options] errinjct slb [options] Mandatory Argument: -a addr effective address associated with the SLB entry to corrupt Optional arguments: --dry-run don't perform the action, just print what would have been done -H --help print usage information for a particular function -v --verbose be more verbose with messages -q --quiet shhhh.... only report errors -C cpu cpu to inject errors on -k token token returned from error inject open .SH ioa-bus-error Inject errors onto an IO adapter (PCI) bus slot. Usage: errinjct ioa-bus-error [options] errinjct eeh [options] Mandatory arguments: -f function IOA bus error to inject Specify a device either with the -s flag, the -p flag, or use the explicit BUID/config address flags. -s classpath look up device by sysfs classpath for example -s net/eth3 or -s scsi_host/host0 -p loc-code look up device by location code for example -p "U0.1-P2-I1" Explicit BUID/config mandatory arguments: -c config_addr configure address of the IOA -h high_bits high bits of PHB unit id -l lo_bits lo bits of PHB unit id Optional arguments: --dry-run don't perform the action, just print what would have been done -H --help print usage information for a particular function -v --verbose be more verbose with messages -q --quiet shhhh.... only report errors -a addr address at which to report the error -m mask address mask (defaults to 0x00000000) -C cpu cpu to inject errors on -k token token returned from error inject open Functions for ioa-bus-error: 0 - Load to PCI Memory Address Space inject an Address Parity Error 1 - Load to PCI Memory Address Space inject a Data Parity Error 2 - Load to PCI I/O Address Space inject an Address Parity Error 3 - Load to PCI I/O Address Space inject a Data Parity Error 4 - Load to PCI Configuration Space inject an Address Parity Error 5 - Load to PCI Configuration Space inject a Data Parity Error 6 - Store to PCI Memory Address Space inject an Address Parity Error 7 - Store to PCI Memory Address Space inject a Data Parity Error 8 - Store to PCI I/O Address Space inject an Address Parity Error 9 - Store to PCI I/O Address Space inject a Data Parity Error 10 - Store to PCI Configuration Space inject an Address Parity Error 11 - Store to PCI Configuration Space inject a Data Parity Error 12 - DMA read to PCI Memory Address Space inject an Address Parity Error 13 - DMA read to PCI Memory Address Space inject a Data Parity Error 14 - DMA read to PCI Memory Address Space inject a Master Abort Error 15 - DMA read to PCI Memory Address Space inject a Target Abort Error 16 - DMA write to PCI Memory Address Space inject an Address Parity Error 17 - DMA write to PCI Memory Address Space inject a Data Parity Error 18 - DMA write to PCI Memory Address Space inject a Master Abort Error 19 - DMA write to PCI Memory Address Space inject a Target Abort Error .SH platform-specific Request the firmware perform a platform specific error injection. Usage: errinjct platform-specific [options] Mandatory argument: -f fname file name to read platform specific error injection data from Optional arguments: --dry-run don't perform the action, just print what would have been done -H --help print usage information for a particular function -v --verbose be more verbose with messages -q --quiet shhhh.... only report errors -C cpu cpu to inject errors on -k token token returned from error inject open .SH corrupted-tlb-start / corrupted-tlb-end Inject errors into the TLB. Before using this option you need to open the RTAS error injection facility via "errinjct open". Afterwards pass this parameter in with the -k option and specify a cpu to run on with the -C option. Please note that you need to specify the same cpu number to the tlb-start and tlb-end errinjct calls. Usage: errinjct corrupted-tlb-start [options] errinjct tlb-start [options] errinjct corrupted-tlb-end [options] errinjct tlb-end [options] Mandatory arguments: -C cpu cpu to inject errors on -k token token returned from error inject open Optional arguments: --dry-run don't perform the action, just print what would have been done -H --help print usage information for a particular function -v --verbose be more verbose with messages -q --quiet shhhh.... only report errors Example: > errinjct open Error inject token = 2 > errinjct corrupted-tlb-start -k 2 -C 0 . . . > errinjct corrupted-tlb-end -k 2 -C 0 > errinjct close -k 2 .SH Authors Written by Nathan Fontenot and Linas Vepstas powerpc-utils-1.3.4/man/hvcsadmin.8000066400000000000000000000072431315235264300171660ustar00rootroot00000000000000.\" Copyright (c) 2005 International Business Machines. .\" Common Public License Version 1.0 (see COPYRIGHT) .\" .\" Author(s) .\" Ryan S. Arnold .\" Original version: January 14, 2005. .\" .Dd January 18, 2005 .Os LINUX .Dt HVCSADMIN 8 .Sh NAME .Nm hvcsadmin .Nd hypervisor virtual console server administration utility .Sh SYNOPSIS .Nm Fl all Op Fl noisy .Op Fl noisy .Pp .Nm Fl close Ar hvcs Op Fl noisy .Op Fl noisy .Pp .Nm Fl console Ar partition Op Fl noisy .Op Fl noisy .Pp .Nm Fl help .Pp .Nm Fl node Ar hvcs Op Fl noisy .Op Fl noisy .Pp .Nm Fl rescan Op Fl noisy .Op Fl noisy .Pp .Nm Fl status Op Fl noisy .Op Fl noisy .Pp .Nm Fl version .Pp .Sh DESCRIPTION This is the IBM hypervisor virtual console server .Pq \fBhvcs\fR administration utility. .Sh OPTIONS .Bl -tag -width -indent .It Fl all Close all open vty-server adapter connections. .Pp Inclusion of a single .Sq Fl noisy flag will direct the utility to output a list of all the adapters that were closed. .It Fl close Ar hvcs Close the vty-server adapter connection that maps to the hvcs device node specified in the option. .Pp By default this operation only exhibits output on error. It is silent on success and silent if the adapter is already closed. When accompanied by a .Sq Fl noisy flag this option will output the device to adapter mapping and a message indicating that the adapter has been closed. .It Fl console Ar partition Which /dev/hvcs node provides the console for the option specified partition? This option takes a partition number and returns a status string which contains the device node that maps to the target partition's slot zero vty-server adapter [A console adapter is always in slot zero]. .Pp Inclusion of a single .Sq Fl noisy flag does not change the default output of this option. .It Fl help Output the utility help text. .It Fl node Ar hvcs Which vty-server adapter is mapped to the option specified /dev/hvcs node? This option takes a device node and returns a status string which contains the vty-server adapter mapped to that node. .Pp Inclusion of a single .Sq Fl noisy flag does not change the default output of this option. .It Fl noisy This directive is optional. Without a .Sq Fl noisy directive the hvcsadmin utility is in \fBsilent\fR mode by default (except in the case of errors and output requests). The output verbosity of the utility is managed by stacking .Sq Fl noisy directives. A single instance of .Sq Fl noisy indicates that the utility should output in \fBstatus\fR mode. A second instance of .Sq Fl noisy indicates that the utility should output in \fBverbose\fR mode. Verbose mode is generally used for script tracing and won't be used by a casual user unless problems arise. .It Fl rescan Direct the hvcs driver to rescan partner information for all vty-server adapters it manages. This may expose additional adapters and partners. .It Fl status Outputs a table with each row containing a vty-server, adapter, its /dev/hvcs device node mapping, and the adapter connection status. "vterm_state:0" means it is free/disconnected and "vterm_state:0" means the vty-server is connected to its vty partner adapter. .Pp An example of \fBhvcsadmin -status\fR output follows: .Pp .Bd -literal \fBvty-server@30000003 partition:1 slot:2 /dev/hvcs0 vterm-state:0 vty-server@30000004 partition:15 slot:0 /dev/hvcs1 vterm-state:0\fR .Ed .Pp When this option is accompanied by a .Sq Fl noisy flag it will output a line for each hvcs device node which doesn't have a current vty-server adapter mapping as well as the status demonstrated above. .It Fl version Out the hvcsadmin script's version number. .El .Sh AUTHOR(S) .An Ryan S. Arnold Aq rsa@us.ibm.com powerpc-utils-1.3.4/man/ibmvscsis.conf.8000066400000000000000000000216021315235264300201330ustar00rootroot00000000000000.\" Copyright (c) 2005 International Business Machines. .\" Common Public License Version 1.0 (see COPYRIGHT) .\" .\" Author(s) .\" Ryan S. Arnold .\" Original version: January 14, 2005. .\" .Dd January 14, 2005 .Os LINUX .Dt IBMVSCSIS.CONF 8 .Sh NAME .Nm ibmvscsis.conf .Nd virtual SCSI server configuration file .Sh DESCRIPTION This is the manual page for \fBibmvscsis.conf\fR which is the IBM virtual SCSI server configuration file. This file denotes the SCSI bus and SCSI target configurations for each vscsis host adapter that the IBM virtual SCSI server manages. This configuration is read by the \fBvscsisadmin\fR utility which interacts with the \fBibmvscsis\fR driver to create, configure, active, and deactivate properly configured targets. .Pp This manual page serves as documentation on the configuration options supported by the \fBvscsisadmin\fR utility and how they must be presented in the \fBibmvscsis.conf\fR configuration file to exhibit well-formed-ness. .Sh FILES The configuration file should be located in the following location on the file system: .Bl -tag -width -indent .It \fI/etc/ibmvscsis.conf\fR .El .Pp If this file doesn't exist, it should be created manually and contain entries for every vscsis adapter exposed by firmware to the \fBibmvscsis\fR driver. .Sh CONFIGURATION The \fBibmvscsis.conf\fR configuration file is built upon \fBadapter:bus:target\fR headers which describe SCSI target entries and a corresponding entry body built of elements. These elements denote the entry validity state, the entry activity state, the entry type, the device path and an optional loop file path. .Pp .Ss ENTRY HEADER The following is an example of a config file entry header:\fB .Bd -literal ibmvscsis:30000005:bus0:target0 .Ed .Pp \fRThis header is made up of the ibmvscsis identifier followed by a hexadecimal adapter number. Following the adapter number is a bus and target number. .Pp The adapter number must correspond to a vscsis adapter found at .Pa /sys/bus/vio/drivers/ibmvscsis in sysfs. To verify that the adapter number is indeed a vscsis adapter the string, .Sq \fBv-scsi-host\fR will appear under the \fBname\fR attribute in the adapter entry. .Pp The bus and target numbers that appear in entry headers define the bus and targets that the \fBvscsisadmin\fR utility will create when the vscsi server is configured. Each header entry defines the configuration settings for a single target. .Pp If the adapter specified in the configuration file doesn't exist in sysfs when the vscsi server is configured all of the elements in the entry body will be ignored. .Ss VALIDITY STATES A SCSI target entry can be configured to demonstrate one of two possible visibility states. It can be either a valid entry or a placeholder entry. A placeholder entry contains the .Sq \fBnone\fR element as the only element in the entry body as the following example demonstrates: \fB .Pp .Bd -literal ibmvscsis:30000005:bus0:target0 none .Ed .Pp \fRA valid entry contains at least the \fBdevice_path\fR element. Any entry which doesn't contain a \fBdevice_path\fR element is considered invalid and is ignored when the vscsi server is configured. A minimally configured valid entry example follows: .Pp .Bd -literal \fBibmvscsis:30000005:bus0:target0 device_path="/dev/sdd1"\fR .Ed .Pp The \fBdevice_path\fR element in this example indicates that the vscsi server is providing partition .Sq sdd1 as the block device managed by said target. .Ss DEFAULT ASSUMPTIONS The \fBvscsisadmin\fR script assumes two default settings which are automatically configured in lieu of omitted elements. .Pp The first is that all targets are activated by default unless an "\fBinactive\fR" element indicates otherwise. Please reference the \fBACTIVITY STATE\fR sub section for further details on the activity state default and the method to override it. .Pp The second default assumption is that the target device \fBtype\fR is a \fBblock\fR device. Excluding the "\fBtype\fR" element from the entry is tantamount to declaring it a block device as the following example indicates: .Bd -literal \fBibmvscsis:30000005:bus0:target0 device_path="/dev/sdb1" #defaults to type="b"\fR .Ed .Pp It is strongly recommended that \fBtype="b"\fR element be included in the entry body anyway, for clarity as the following example shows: .Bd -literal \fBibmvscsis:30000005:bus0:target0 device_path="/dev/sdb1" type="b"\fR .Ed .Pp In the future when other device types are supported the type element will indicate which type to set for each target. .Ss ACTIVITY STATES An entry can be either \fBactive\fR or \fBinactive\fR. The activity state dictates whether the \fBvscsisadmin\fR utility activates the target once it has been configured. By default every entry is in the \fBactive\fR state. In order to tell the vscsisadmin script to configure the target but \fBnot\fR activate it the .Sq \fBinactive\fR element must be included in the entry body as indicated by the following example: .Pp .Bd -literal \fBibmvscsis:30000005:bus0:target0 device_path="/dev/sdb1" type="b" inactive\fR .Ed .Pp The .Sq \fBinactive\fR element can be placed anywhere within the entry body, though placing it as the last element is customary. .Ss LOOP DEVICE CONFIGURATION In order to direct the vscsi server to use a flat file as a SCSI target the file must be set up as a loop file and a special device called a loop device must be mapped by the file system as the device point attachment for the loop file. The \fBvscsisadmin\fR utility can create the loop file-to-device mapping automatically if the configuration file entry contains the \fBloop_file\fR element. The following example demonstrates the required elements where .Sq vdisk is a large flat file created especially for this purpose: .Pp .Bd -literal \fBibmvscsis:30000005:bus0:target1 loop_file="var/vscsis/vdisk/" device_path="/dev/loop1" type="b"\fR .Ed .Pp The \fBloop_file\fR element may be placed anywhere in the entry though it is customary to place it preceding the \fBdevice_path\fR element. When the vscsi server is stopped the \fBvscsisadmin\fR utility will automatically detach any loop file-to-device mappings which match a target's \fBdevice_path\fR element. .Pp The \fBvscsisadmin\fR script will check for the loop file on the file system before it attempts to configure target. If the loop file doesn't exist the target entry is ignored and the target will remain unconfigured. .Ss ELEMENT ORDERING Configuration elements may be placed in any order in the entry body though there are customary places for certain elements that facilitate visual clarity. .Ss ENTRY ORDERING The \fBvscsisadmin\fR utility should be smart enough to create the proper \fBibmvscsis\fR configuration regardless of the order that the entries appear in the configuration file. It is still recommended that entries follow a least-to-greatest pattern. .Pp Since each entry represents a target under a bus and adapter, targets are always listed in ascending order under their own bus. Each successive bus (and its target entries) should be listed in ascending order under its adapter. Finally each successive adapter (and its bus:target entries) should be listed in ascending order. The following ordering, sans entry elements, demonstrates the ordering criteria. .Pp .Bd -literal \fB#same adapter, targets on the same bus ibmvscsis:30000003:bus0:target0 ibmvscsis:30000003:bus0:target1 ibmvscsis:30000003:bus0:target2 #same adapter as previous, each target on a different bus ibmvscsis:30000003:bus1:target0 ibmvscsis:30000003:bus2:target0 #new adapter, each target on the same bus. ibmvscsis:30000004:bus0:target1 ibmvscsis:30000004:bus0:target2 #new adapter and each target on a different bus ibmvscsis:30000005:bus0:target0 ibmvscsis:30000005:bus1:target0 ibmvscsis:30000005:bus2:target0\fR .Ed .Pp .Sh EXAMPLES An example, well-formed .Cd /etc/ibmvscsis.conf configuration follows: .Pp .Bd -literal \fBibmvscsis:30000003:bus0:target0 device_path="/dev/sdd1" type="b" ibmvscsis:30000004:bus0:target0 device_path="/dev/sdd2" #you can exclude the 'type="b"' as well ibmvscsis:30000005:bus0:target0 device_path="/dev/sdd3" type="b" ibmvscsis:30000006:bus0:target0 device_path="/dev/sdd5" type="b" ibmvscsis:30000006:bus0:target1 device_path="/dev/sdd6" type="b" ibmvscsis:30000007:bus0:target0 none ibmvscsis:30000008:bus0:target0 device_path="/dev/sdd7" type="b" inactive ibmvscsis:30000008:bus1:target0 loop_file="/var/vscsi/vdisk1" device_path="/dev/loop0" type="b" ibmvscsis:30000009:bus0:target0 none ibmvscsis:3000000a:bus0:target0 loop_file="/var/vscsi/vdisk2" device_path="/dev/loop1" type="b" inactive ibmvscsis:3000000b:bus0:target0 loop_file="/var/vscsi/vdisk3" device_path="/dev/loop2" type="b" ibmvscsis:3000000c:bus0:target0 loop_file="/var/vscsi/vdisk4" device_path="/dev/loop3" type="b" .Ed .Sh SEE ALSO .Xr ibmvscsis.sh 8 , .Xr vscsisadmin 8 .Sh AUTHOR(S) .An Ryan S. Arnold Aq rsa@us.ibm.com powerpc-utils-1.3.4/man/ibmvscsis.sh.8000066400000000000000000000024651315235264300176260ustar00rootroot00000000000000.\" Copyright (c) 2005 International Business Machines. .\" Common Public License Version 1.0 (see COPYRIGHT) .\" .\" Author(s) .\" Ryan S. Arnold .\" Original version: January 14, 2005. .\" .Dd January 14, 2005 .Os LINUX .Dt IBMVSCSIS.SH 8 .Sh NAME .Nm /etc/init.d/ibmvscsis.sh .Nd virtual SCSI server init script .Sh SYNOPSIS .Nm /etc/init.d/ibmvscsis.sh restart .Pp .Nm /etc/init.d/ibmvscsis.sh start .Pp .Nm /etc/init.d/ibmvscsis.sh status .Pp .Nm /etc/init.d/ibmvscsis.sh stop .Pp .Sh DESCRIPTION This is the init script which can be configured to automatically configure, start, and stop the IBM virtual SCSI server \fBibmvscsis\fR. .Sh OPTIONS .Bl -tag -width -indent .It \fBrestart\fR Restart the vscsi server. .It \fBstart\fR Start the vscsi server if it is not already in operation. .It \fBstatus\fR Output status on the vscsi server. .It \fBstop\fR Stop the running vscsi server. .El .Sh CONFIGURATION Use symlinks to start and stop run levels to automate vscsis configuration, start, and stop. .Sh FILES This init script should exist in the following location: .Pp .Cd /etc/init.d/ibmvscsis.sh .Pp .Sh DEPENDENCIES This init script requires the existence of the \fBvscsisadmin\fR utility. .Sh SEE ALSO .Xr vscsisadmin 8 .Xr ibmvscsis.conf 8 .Sh AUTHOR(S) .An Ryan S. Arnold Aq rsa@us.ibm.com powerpc-utils-1.3.4/man/lparcfg.5000066400000000000000000000532661315235264300166330ustar00rootroot00000000000000.TH LPARCFG 5 "August 2010" .SH NAME /proc/ppc64/lparcfg - IBM Power LPAR Configuration Data .SH SYNOPSIS .BI "/proc/ppc64/lparcfg" .sp .BI "cat /proc/ppc64/lparcfg" .SH DESCRIPTION The .B lparcfg file is a virtual file which contains information related to an IBM Power Logical Partition. .SH OPTIONS The fields displayed in the .B lparcfg file are sorted below according to the version of the .B lparcfg file. Generally, fields are only added and not removed (unless otherwise noted), so the latest version of .B lparcfg contains all fields in all previous versions of the file as well. .PP .B lparcfg 1.6 based values .br (Values added in lparcfg 1.7, 1.8, 1.9 are listed below) .PP .B serial_number .br The serial number of the physical system in which the partition resides .PP .B system_type .br The machine,type-model of the physical system in which the partition resides .PP .B partition_id .br The numeric partition ID. .PP .B R4 .br The hexadecimal representation of partition_entitled_capacity. This field is deprecated and not displayed on more recent versions of the Linux kernel ( .B lparcfg 1.8 or greater). The definition is only provided for historical purposes. .PP .B R5 .br The hexadecimal representation of unallocated_capacity. Not displayed on more recent versions of the Linux kernel. This field is deprecated and not displayed on more recent versions of the Linux kernel ( .B lparcfg 1.8 or greater). The definition is only provided for historical purposes. .PP .B R6 .br This is a hexadecimal value representing both the group and pool. This field is deprecated and not displayed on more recent versions of the Linux kernel ( .B lparcfg 1.8 or greater). The definition is only provided for historical purposes. .PP .B R7 .br This is a hexadecimal value representing capped, capacity_weight, unallocated_capacity_weight, pool_capacity, and system_active_processors. This field is deprecated and not displayed on more recent versions of the Linux kernel ( .B lparcfg 1.8 or greater). The definition is only provided for historical purposes. .PP .B BoundThrds .br For virtual processor dispatches, if the hypervisor always dispatches a set of virtual threads together on a physical processor, the threads are said to be bound. This allows an operating system to make scheduling decisions based on cache affinity and work load. Set to 1 if threads are bound, 0 otherwise. This value is informational and is not a tunable value. .\" A change in this characteristic takes effect on the next reboot of the partition. .PP .B CapInc .br This defines the delta by which the entitled capacity of a partition can be incremented or decremented by DLPAR/WLM. The capacity increment is expressed as a percentage of a physical processor. This value is informational and is not a tunable value. .\" A change in the capacity increment takes effect on the next reboot of the partition. This does not affect the number of virtual processors defined for the partition. .PP .B DisWheRotPer .br The duration of the hypervisor's scheduling window. The time over which the entitled capacity of a virtual processor has to be utilized by the partition. At the start of a dispatch wheel rotation period, each virtual processor is eligible for CPU time corresponding to its entitled capacity. If the entire entitled capacity of a virtual processor is not utilized during a dispatch wheel rotation period, the unused entitled capacity is lost. The dispatch wheel rotation period is expressed as N number of time base ticks. The dispatch wheel duration of a partition with a capacity increment of 100 is 0. This value is informational and is not a tunable value. .PP .B MinEntCap .br The minimum entitled capacity that is needed to boot the partition. The capacity is expressed as a percentage of a physical processor. The minimum entitled capacity is set by the system administrator in the partition definition. DLPAR cannot take the entitled capacity below the minimum entitled capacity. A change in the minimum entitled capacity takes effect on the next reboot of the partition. Linux running in a partition can give up its entitled capacity to be below the minimum entitled capacity, but this is generally not recommended. .PP .B MinEntCapPerVP .br The minimum entitled capacity that the platform requires for a virtual processor of any partition on the platform. The minimum capacity per virtual processor is enforced by the HMC in the partition definition and by the hypervisor. A change in the minimum entitled capacity per virtual processor takes effect on the next reboot of the partition. This is a physical system setting and is not considered a Linux partition tunable. .PP .B MinMem .br The minimum amount of main store that is needed to boot the partition. Minimum memory is expressed in MB of storage. The minimum memory is set by the system administrator in the partition definition. DLPAR cannot take the partition memory below the minimum memory. A change in the minimum memory takes effect on the next reboot of the partition. Linux running in a partition can always give up its memory to go below the minimum memory. .PP .B MinProcs .br The minimum number of virtual processors that are needed to boot the partition. The minimum number of virtual processors is set by the system administrator in the partition definition. DLPAR cannot take the number of virtual processors below the minimum number of processors. A change in the minimum number of processors takes effect on the next reboot of the partition. A partition can always give up its virtual processors to go below the minimum number of processors. The number of virtual processors is a simulated physical core view. Additional logical CPUs are defined in the Linux partition to account for the possible hardware threads. .PP .B partition_max_entitled_capacity .br The maximum entitled capacity currently that can be assigned to the partition through DLPAR/WLM. The capacity is expressed as a percentage of a physical processor. The Maximum entitled capacity is set up by the system administrator in the partition definition. A change in the maximum entitled capacity maximum takes effect on the next reboot of the partition. .PP .B system_potential_processors .br The maximum number of physical processors that can be active on the platform. A change in the maximum platform processors takes effect on the next reboot of the partition. .PP .B DesEntCap .br The desired entitled capacity is the number of processing units, expressed as a percentage of a physical processor, which is desired for a logical partition. The desired entitled capacity is the same as the desired processing units on the HMC. If the system has at least the desired number of processing units available when you activate the partition, then the system commits the desired number of processing units to the logical partition. If the desired number of processing units is not available, but at least the minimum number of processing units is available, then the system activates the logical partition with the processing units it has. .PP .B DesMem .br The desired memory set by the system administrator in the partition definition. The desired memory is expressed in MB of storage. The desired memory can change without a reboot of the partition. The desired memory that the partition is currently using may differ from the desired memory because of WLM actions or because of failed system memory. .PP .B DesProcs .br The desired number of virtual processors set by the system administrator in the partition definition. The desired number of processors can change without a reboot of the partition. The number of processors that the partition is currently using may differ from the desired number of processors because of WLM actions or because of failed system processors. .PP .B DesVarCapWt .br The desired variable capacity weight set by the system administrator in the partition definition. The desired variable capacity weight is a number between 0 and 255. The desired variable capacity weight can change without a reboot of the partition. The variable capacity weight that the partition is currently using may differ from the desired variable capacity because of WLM actions. .PP .B DedDonMode .br For a partition with a capacity increment of 100, the platform uses a dedicated CPU to actualize a virtual processor of the partition. For such a partition, the platform can increase the capacity of the shared processor pool by utilizing the unused processor capacity of the partition. If the platform supports the dedicated donate function, it can be enabled by the system administrator in the partition definition. The value of this characteristic can change without a reboot of the partition. The values for this field are 0 and 1. .PP .B partition_entitled_capacity .br Entitled Processor Capacity Percentage. The percentage of a physical processor that the hypervisor guarantees to be available to the partition's virtual processors (distributed in a uniform manner among the partition's virtual processors -- thus the number of virtual processors affects the time slice size) each dispatch cycle. Capacity ceded or conferred from one partition virtual processor extends the time slices offered to other partition processors. Capacity ceded or conferred after all of the partition's virtual processors have been dispatched is added to the variable capacity kitty. The initial, minimum and maximum constraint values of this parameter are determined by the partition configuration definition. The OS can set this parameter within the constraints imposed by the partition configuration definition minimum and maximums plus constraints imposed by partition aggregation. To change this value, echo the new partition_entitled_capacity into .B /proc/ppc64/lparcfg like this: .br .IP "" 7 .B echo """partition_entitled_capacity=40"" > /proc/ppc64/lparcfg .PP .B group .br LPAR group number of the partition .PP .B system_active_processors .br The number of processors active on the underlying physical system. .PP .B pool .br The pool number of the shared processor pool for the partition. This field is not displayed in the case of a dedicated processor partition. .PP .B pool_capacity .br The number of physical processors active in the partition's processor pool. This field is not displayed in the case of a dedicated processor partition. This value is expressed as a percentage so is 100* the number of active physical processors. .PP .B pool_idle_time .br If no virtual processor is ready to run, the pool_idle_count is incremented the total number of idle processor cycles in the physical processor pool. This field contains the total number of idle processor cycles up to the current point in time. If unsupported or if performance information collection is not enabled for the partition on the HMC, this will report 0. This field is not displayed in the case of a dedicated processor partition. For more information, see the NOTES section below on PURR/PIC. .PP .B pool_num_procs .br The number of physical processors in the partition's processing pool. This field is not displayed in the case of a dedicated processor partition. .PP .B unallocated_capacity_weight .br Unallocated Variable Processor Capacity Weight. The amount of variable processor capacity weight that is currently available within the constraints of the partition's current environment for allocation to the partition's variable processor capacity weight. .PP .B capacity_weight .br Variable Processor Capacity Weight. The unitless factor that the hypervisor uses to assign processor capacity in addition to the Entitled Processor Capacity Percentage. This factor may take the values 0 to 255. In the case of a dedicated processor partition this value is 0. A virtual processor's time slice may be extended to allow it to use capacity unused by other partitions, or not needed to meet the Entitled Processor Capacity Percentage of the active partitions. A partition is offered a portion of this variable capacity kitty equal to: (Variable Processor Capacity Weight for the partition) / (summation of Variable Processor Capacity Weights for all competing partitions). The initial value of this parameter is determined by the partition configuration definition. The OS can set this parameter within the constraints imposed by the partition configuration definition maximum. Certain partition definitions may not allow any variable processor capacity allocation. To change this value, echo the new capacity_weight into .B /proc/ppc64/lparcfg like this: .br .IP "" 7 .B echo """capacity_weight=128"" > /proc/ppc64/lparcfg .PP .B capped .br The partition's virtual processor(s) are capped at their entitled processor capacity percentage if this is 1. If capped=0, the partition is uncapped, and can use processor capacity from the uncapped pool, if available and according to the weighted values. In the case of dedicated processors this bit is set. .PP .B unallocated_capacity .br Unallocated Processor Capacity Percentage. The amount of processor capacity that is currently available within the constraints of the partition's current environment for allocation to Entitled Processor Capacity Percentage. .PP .B purr .br The Processor Utilization of Resources Register. Summation of the PURR value for all of the partition's virtual processors. See the NOTES section below for more information on PURR and PIC. This value is typically not a metric used. .PP .B partition_active_processors .br The total number of virtual processors assigned to the partition. This does not include the potential SMT threads. For dedicated processor partitions, this is the number of physical processors assigned to the partition. Linux will define virtual CPUs for the possible SMT threads across all of the virtual processors defined here. .PP .B partition_potential_processors .br The maximum number of virtual processors that can be assigned to the partition. This does not include SMT threads. For dedicated processor partitions, this is the maximum number of physical processors that can be assigned to the partition. .PP .B shared_processor_mode .br This is set to 1 if the partition is running with shared processors. This is set to 0 for dedicated processor partitions. .PP .B lparcfg 1.7 additional fields .PP .B slb_size .br The total number of entries in the Segment Lookaside Buffer (SLB). This is an attribute of the underlying processor architecture and is provided for informational purposes. The Linux OS uses this when determining the ability to perform Live Partition Migration with differing processor families. .PP .B lparcfg 1.8 .PP .B entitled_memory .br The number of bytes of main storage that the partition is entitled to DMA map for virtual I/O devices. In the case of a dedicated memory partition this is the size of the partition's logical address space. To change this value, echo the new entitled_memory value into .B /proc/ppc64/lparcfg like this: .br .IP "" 7 .B echo """entitled_memory=80740352"" > /proc/ppc64/lparcfg .PP .B mapped_entitled_memory .br The number of bytes of main storage that the partition has DMA mapped. In the case of a dedicated memory partition this is not displayed. .PP .B entitled_memory_group_number .br Entitled Memory Group Number .PP .B entitled_memory_pool_number .br Entitled memory pool number. In the case of a dedicated memory partition, this is 65535. .PP .B entitled_memory_weight .br The partition's shared memory weight. In the case of a dedicated memory partition this is 0. To change this value, echo the new entitled_memory_weight value into .B /proc/ppc64/lparcfg like this: .br .IP "" 7 .B echo """entitled_memory_weight=128"" > /proc/ppc64/lparcfg .PP .B unallocated_entitled_memory_weight .br The unallocated shared memory weight for the calling partition's aggregation. In the case of a dedicated memory partition this is 0. .PP .B unallocated_io_mapping_entitlement .br The unallocated I/O mapping entitlement for the calling partition's aggregation divided by 4096. In the case of a dedicated memory partition this is 0. .PP .B entitled_memory_loan_request .br The signed difference between the number of bytes of logical storage that are currently on loan from the calling partition and the partition's overage allotment (a positive number indicates a request to the partition to loan the indicated number of bytes else they will be expropriated as needed). In the case of a dedicated memory partition this is 0. In the case of a shared memory partition, when running the Collaborative Memory Manager (cmm module), this will typically be 0, as the CMM will monitor and fulfill the hypervisor's loan requests. .PP .B backing_memory .br The number of bytes of main storage that is backing the partition logical address space. In the case of a dedicated memory partition this is the size of the partition's logical address space. .PP .B cmo_enabled .br If Active Memory Sharing is enabled for the partition, this is set to 1. For dedicated memory partitions, this is 0. .PP .B cmo_faults .br Displayed only for shared memory partitions. Indicates the total number of times the partition has accessed a page in memory which was paged out to disk by firmware, requiring it to be paged back in. If the Collaborative Memory Manager is disabled, this value may be large. If it is enabled (default setting for most Linux distributions), this number is typically small. If this value is large and is increasing, it may be an indication that the partition's shared memory pool has too high of an overcommit ratio, in which case you may need to assign additional physical memory to the shared memory pool. .PP .B cmo_fault_time_usec .br Displayed only for shared memory partitions. Indicates the total amount of time in microseconds the partition has had a virtual processor blocked in order for firmware to page in data. Directly related to cmo_faults. .PP .B cmo_primary_psp .br Displayed only for shared memory partitions. Partition ID of the primary paging VIOS. .PP .B cmo_secondary_psp .br Displayed only for shared memory partitions. Partition ID of the secondary paging VIOS. If there is no secondary paging VIOS, this will be set to 65535. .PP .B cmo_page_size .br Displayed only for shared memory partitions. Physical page size in bytes. .PP .B lparcfg 1.9 additional fields .PP .B physical_procs_allocated_to_virtualization .br The number of physical platform processors allocated to processor virtualization. This is a physical system attribute and has no bearing on the Linux partition. .PP .B max_proc_capacity_available .br The maximum processor capacity percentage that is available to the partition's shared processor pool. .PP .B entitled_proc_capacity_available .br The entitled processor capacity percentage available to the partition's pool. .PP .B dispatches .br Virtual Processor Dispatch Counter. Counter that is incremented each time a virtual processor is dispatched/preempted. .PP .B dispatch_dispersions .br Virtual Processor Dispatch Dispersion Accumulator. Incremented on each virtual processor dispatch if the physical processor differs from that of the last dispatch. .PP .B coalesced_bytes .br The number of bytes of memory assigned to the logical partition which have been coalesced with identical pages either within the logical partition, or with another logical partition. .PP .B pool_coalesced_bytes .br The number of bytes of memory in the shared memory pool which have been coalesced with identical pages. .PP .B coalesce_pool_purr .br The number of PURR cycles which have been consumed to coalesce pages of data. .PP .B coalesce_pool_spurr .br The number of SPURR cycles which have been consumed to coalesce pages of data. .SH NOTES .PP .B PURR/PIC .br These two statistics are counts in the same units as counted by the processor time base. Like the time base, the PUR and PIC are 64 bit values that are set to a numerically low value during system initialization. The difference between their values at the end and beginning of monitored operations provides data on virtual processor performance. The value of the PUR is a count of processor cycles used by the calling virtual processor. The PUR count is intended to provide an indication to the partition software of the computation load supported by the virtual processor. Shared processor virtual processors are created by dispatching the virtual processor's architectural state on one of the physical processors from a pool of physical processors. The value of the PIC is the summation of the physical processor pool idle cycles, that is the number of time base counts when the pool could not dispatch a virtual processor. The PIC count is intended to provide an indication to platform management software of the pool capacity to perform more work. .PP .B Processors vs. SMT threads .br The Power processors support Simultaneous Multi-Threading (SMT). SMT is generally enabled by default on most Linux distributions that support Power. When enabled, a single Power 5 or Power 6 CPU will be seen as up to two logical CPUs in the Linux operating system. A single Power 7 CPU will be seen as four logical CPUs. SMT can be disabled with the .B ppc64_cpu utility, which is packaged in powerpc-utils. When SMT is disabled, the logical CPUs seen by Linux will not be contiguous. For example, a four core Power 7 partition with SMT disabled will show CPUs 0, 4, 8, and 12 in /proc/cpuinfo. A Power7 CPU/processor/core can also be set to SMT=2 mode. .SH VERSIONS .PP .B Linux Distribution Version Mapping The following is a brief list of the mapping of some enterprise versions of Linux for Power to the version of the .B lparcfg file. .br SLES 9: lparcfg 1.6 .br SLES 10: lparcfg 1.7 .br SLES 11: lparcfg 1.8 .br SLES 11 SP1: lparcfg 1.9 .br RHEL 4: lparcfg 1.6 .br RHEL 5: lparcfg 1.7 .br RHEL 6: lparcfg 1.9 .SH FILES .TP .B /proc/ppc64/lparcfg .SH AUTHOR Written by Brian King . .br Comments and questions on this document should be posted on the .B Linux for Power Architecture forum: .br .B http://www.ibm.com/developerworks/forums/forum.jspa?forumID=375&start=0. powerpc-utils-1.3.4/man/lparstat.8000066400000000000000000000212661315235264300170450ustar00rootroot00000000000000.\" Copyright (C) 2011 International Business Machines. .\" .\" Author(s) .\" Santiago Leon .\" Text extracted from AIX 6.1 Information Document. .\" Copyright International Business Machines Corporation 1997, 2010. .\" .TH LPARSTAT 8 "May 2011" Linux "Linux on Power Service Tools" .SH NAME lparstat \- Reports logical partition ( LPAR ) related information and statistics. .SH SYNOPSIS .B /usr/sbin/lparstat [ -i ] [ interval [ count ] ] .SH DESCRIPTION The \fIlparstat\fR command provides a report of LPAR related information and utilization statistics. This command provides a display of current LPAR related parameters and Hypervisor information, as well as utilization statistics for the LPAR. The \fIlparstat\fR command with no options will generate a single report containing utilization statistics related to the LPAR since boot time. The following information is displayed in the system configuration row: .TP type Partition Type. Can be either dedicated or shared. .TP mode Indicates whether the partition processor capacity is capped or uncapped allowing it to consume idle cycles from the shared pool. Dedicated LPAR is capped or donating. .TP smt Indicates whether simultaneous multi-threading is enabled or disabled in the partition. If SMT is enabled, the number of SMT threads is displayed. .TP lcpu Number of online logical processors. .TP mem Online Memory Capacity. .TP cpus Number of online physical processors in the pool. .TP ent Entitled processing capacity in processor units. This information is displayed only if the partition type is shared. .P The following information is displayed in the utilization row: .TP %user Shows the percentage of the entitled processing capacity used while executing at the user level (application). For dedicated partitions, the entitled processing capacity is the number of physical processors. For uncapped partitions with a current physical processor consumption above their entitled capacity, the percentage becomes relative to the number of physical processor consumed (physc). .TP %sys Shows the percentage of the entitled processing capacity used while executing at the system level (kernel). For dedicated partitions, the entitled processing capacity is the number of physical processors. For uncapped partitions with a current physical processor consumption above their entitled capacity, the percentage becomes relative to the number of physical processor consumed (physc). .TP %wait Shows the percentage of the entitled processing capacity unused while the partition was idle and had outstanding disk I/O requests. For dedicated partitions, the entitled processing capacity is the number of physical processors. For uncapped partitions with a current physical processor consumption above their entitled capacity, the percentage becomes relative to the number of physical processor consumed (physc). .TP %idle Shows the percentage of the entitled processing capacity unused while the partition was idle and did not have any outstanding disk I/O request. For dedicated partitions, the entitled processing capacity is the number of physical processors. For uncapped partitions with a current physical processor consumption above their entitled capacity, the percentage becomes relative to the number of physical processor consumed (physc). .P The following statistics are displayed when the partition type is shared or dedicated-donating: .TP physc Shows the number of physical processors consumed. .TP vcsw Shows the number of virtual context switches that are virtual processor hardware preemptions. .P The following statistics are displayed only when the partition type is shared: .TP %entc Shows the percentage of the entitled capacity consumed. Because the time base over which this data is computed can vary, the entitled capacity percentage can sometimes exceed 100%. This excess is noticeable only with small sampling intervals. .TP lbusy Shows the percentage of logical processor(s) utilization that occurred while executing at the user and system level. .TP phint Shows the number of phantom (targeted to another shared partition in this pool) interruptions received. .SH OPTIONS .TP \fB\-i\fR Lists details on the LPAR configuration. The various details displayed by the -i option are listed below: .RS .TP Node Name Description .TP Partition Name Logical partition name as assigned at the HMC. .TP Partition Number Number of this Logical Partition. .TP Type Indicates whether the LPAR is using dedicated or shared CPU resource and if the SMT is turned ON. The Type is displayed in the format [Shared | Dedicated] [ -SMT ] [ -# ] The following list explains the different Type formats: .RS .TP Shared - Indicates that the LPAR is running in the Shared processor mode. .TP Dedicated - Indicates that the LPAR is running in the dedicated processor mode. .TP SMT[-#] - Indicates that the LPAR has SMT mode turned ON and the number of SMT threads is 2. If the number of threads is greater than 2, then the number of threads is also displayed. .RE .TP Mode Indicates whether the LPAR processor capacity is capped, or if it is uncapped and allowed to consume idle cycles from the shared pool. Dedicated LPAR is capped or donating. .TP Entitled Capacity The number of processing units this LPAR is entitled to receive. .TP Partition Group-ID LPAR group that this LPAR is a member of. .TP Shared Pool ID Identifier of Shared Pool of Physical processors that this LPAR is a member. .TP Online Virtual CPUs Number of CPUs (virtual engines) currently online. .TP Maximum Virtual CPUs Maximum possible number of CPUs (virtual engines). .TP Minimum Virtual CPUs Minimum number of virtual CPUs this LPAR was defined to ever have. .TP Online Memory Amount of memory currently online. .TP Minimum Memory Minimum memory this LPAR was defined to ever have. .TP Variable Capacity Weight The priority weight assigned to this LPAR which controls how extra (idle) capacity is allocated to it. A weight of -1 indicates a soft cap is in place. .TP Minimum Capacity The minimum number of processing units this LPAR was defined to ever have. Entitled capacity can be reduced down to this value. .TP Maximum Capacity The maximum number of processing units this LPAR was defined to ever have. Entitled capacity can be increased up to this value. .TP Capacity Increment The granule at which changes to Entitled Capacity can be made. A value in whole multiples indicates a Dedicated LPAR. .TP Active Physical CPUs in System The current number of active physical CPUs in the system containing this LPAR. .TP Active CPUs in Pool The maximum number of CPUs available to this LPAR's shared processor pool. .TP Maximum Capacity of Pool The maximum number of processing units available to this LPAR's shared processor pool. .TP Entitled Capacity of Pool The number of processing units that this LPAR's shared processor pool is entitled to receive. .TP Unallocated Capacity The sum of the number of processor units unallocated from shared LPARs in an LPAR group. This sum does not include the processor units unallocated from a dedicated LPAR, which can also belong to the group. The unallocated processor units can be allocated to any dedicated LPAR (if it is greater than or equal to 1.0 ) or shared LPAR of the group. .TP Physical CPU Percentage Fractional representation relative to whole physical CPUs that these LPARs virtual CPUs equate to. This is a function of Entitled Capacity / Online CPUs. Dedicated LPARs would have 100% Physical CPU Percentage. A 4-way virtual with Entitled Capacity of 2 processor units would have a 50% physical CPU Percentage. .TP Unallocated Weight Number of variable processor capacity weight units currently unallocated within the LPAR group. .TP Memory Mode Indicates whether the memory mode is shared or dedicated. If Active Memory Expansion is enabled, the memory mode also includes a new mode called Expanded. .TP Total I/O Memory Entitlement The I/O memory entitlement of the LPAR. .TP Variable Memory Capacity Weight .TP Memory Pool ID The memory pool ID of the pool that the LPAR belongs to. .TP Physical Memory in the Pool The physical memory present in the pool that the LPAR belongs to. .TP Unallocated Variable Memory Capacity Weight he unallocated variable memory-capacity weight of the LPAR. .TP Unallocated I/O Memory Entitlement The unallocated I/O memory entitlement of the LPAR. .TP Memory Group ID of LPAR The memory group ID of the Workload Manager group that the LPAR belongs to. .TP Desired Variable Capacity Weight The variable memory capacity weight of the LPAR. .TP .SH interval The .B interval parameter specifies the amount of time between each report. .TP .SH count The .B count parameter specifies how many reports will be displayed. .TP powerpc-utils-1.3.4/man/lsslot.8000066400000000000000000000033171315235264300165300ustar00rootroot00000000000000.\" .\" Copyright (C) 2011 International Business Machines .\" Brian King .\" .TH LSSLOT 8 "December 2011" Linux "Linux on Power Service Tools" .SH NAME lsslot \- display hot plug capable slots and resources .SH SYNOPSIS .BI "lsslot [-c | -a | -b | -p | -o | -s | -F | -d | -w]" .SH DESCRIPTION The .B lsslot command can be used to display hot plug capable I/O slots, CPUs and caches. Please note that this command does not display all I/O slots, only slots which are physically capable of hot plug. Slots which are capable of DLPAR but not hot plug capable will not be listed. .SH OPTIONS .TP .B \-c Display the slots of the specified connector type. The valid connector types are "pci" for hotplug PCI slots, "slot" for logical slots, "phb" for PHB's, "port" for LHEA ports, "mem" for memory, and "cpu" for cpu's. The default is "slot" if no -c option is specified. .TP .B \-a Display available slots, valid for "pci" slots only. .TP .B \-b Display cpu's and caches, valid for "cpu" only. .TP .B \-o Display occupied slots, valid for "pci" slots only. .TP .B \-p Display caches, valid for "cpu" slots only. .TP .B \-s [ | ] Display characteristics of the specified slot or the LMB with the specified drc index. .TP .B \-F Specified a single character to delimit the output. The heading is not displayed and the columns are delimited by the specified character. .TP .B \-d Enable debugging output. When displaying memory information this flag will also enable printing information about LMBs not currently owned by the system. .TP .B \-w Specify a timeout when attempting to acquire locks. .SH AUTHOR Brian King powerpc-utils-1.3.4/man/nvram.8000066400000000000000000000043031315235264300163270ustar00rootroot00000000000000.\" .\" Copyright (C) 2002 - 2004 International Business Machines .\" .TH NVRAM 8 "May 2004" Linux "Linux on Power Service Tools" .SH NAME nvram \- format data stored in non-volatile RAM .SH SYNOPSIS .B /usr/sbin/nvram [ options ] .SH DESCRIPTION .I Nvram is used to print and modify data stored in the non-volatile RAM (NVRAM) on a PowerPC-64 system. NVRAM on these systems is partitioned into data sections that each have their own format. The print options to this command selects what to print and how to format it. .P The .I nvram utility can also be used to update the data in certain NVRAM partitions of PowerPC-64 systems. .I Nvram can update the value of a name/value pair for NVRAM partitions formatted as a set of name=value pairs. On many systems, the following NVRAM partitions contain data formatted as name=value pairs: common, of-config, and ibm,setupcfg. .SH OPTIONS .TP \fB\--print-config\fR[=\fIvar\fR] print value of a config variable, or print all variables in the specified (or all) partitions. .TP \fB\--update-config \fIname\fR=\fIvalue update the config variable in the specified partition; the -p option must also be specified.. .TP \fB\-p \fIpartition specify a partition; required with the --update-config option, optional with the --print-config option. .TP \fB\--print-vpd print vital product data (VPD) collected by the system in NVRAM. This data may also be viewed with the lscfg(1) command directly from the devices. .TP \fB\--print-all-vpd print viral product data (VPD) collected by the system in NVRAM including vendor specific data. .TP \fB\--print-err-log print the checkstop error log generated by the service processor whenever the system checkstops. .TP \fB\--print-event-scan print the event scan log stored in NVRAM. .TP \fB\--partitions print the contents of all the NVRAM partition headers. .TP \fB\--nvram-file \fIpath read nvram data from a given file rather than /dev/nvram. To capture NVRAM for later use, simply copy /dev/nvram into a file. .TP \fB\--verbose \fR(\fB-v\fR) be more verbose. .TP \fB\--help print usage information including other low level options useful for debugging nvram. .SH FILES /dev/nvram .SH AUTHOR Writtem by Todd Inglett, Nathan Fontenot, and Michael Strosaker powerpc-utils-1.3.4/man/ofpathname.8000066400000000000000000000017661315235264300173400ustar00rootroot00000000000000.\" .\" Copyright (C) 2004 International Business Machines .\" Nathan Fontenot .\" .TH OFPATHNAME 8 "April 2004" Linux "Linux on Power Service Tools" .SH NAME ofpathname \- translate between Open Firmware and logical device names .SH SYNOPSIS \fB/usr/sbin/ofpathname \fR[\fB-laqVh\fR] \fIname .SH DESCRIPTION .I Ofpathname provides the ability to translate logical device names to their Open Firmware device path names for PowerPC-64 systems. It can also translate an Open Firmware device path to its logical device name using the -l option. .SH OPTIONS .TP \fB\-l Translate the \fIname \fRparameter to the corresponding logical device name. .TP \fB\-a Find a matching Open Firmware device alias[es]. .TP \fB\--quiet \fR(\fB\-q\fR) Do not report any failures, exit quietly. .TP \fB\--version \fR(\fB\-V\fR) Display version information and exit. .TP \fB\--help \fR(\fB\-h\fR) print usage information. .SH AUTHOR Written by Nathan Fontenot .SH "SEE ALSO" .BR bootlist (8), .BR nvram (8) powerpc-utils-1.3.4/man/ppc64_cpu.8000066400000000000000000000055521315235264300170160ustar00rootroot00000000000000.\" .\" Copyright (C) 2015 International Business Machines .\" .TH PPC64_CPU 8 "January 2015" Linux "Linux on Power Service Tools" .SH NAME ppc64_cpu \- Display cpu characteristics of PowerPC systems .SH SYNOPSIS .B /usr/sbin/ppc64_cpu [ command ] [ options ] .SH DESCRIPTION The .I ppc64_cpu command is used to display and set cpu characteristics on PowerPC platforms. .SH OPTIONS .TP \fB\-\-smt\fR [-n] Display the current smt setting for the system. The output will state whether smt is off indicating there is only one thread per core online, smt is on indicating that all threads of every core is online, the smt is in a mixed state indicating that the number of threads online varies per core, or \fISMT=X\fR indicating a specific smt state. Option -n dumps a numeric output instead of a verbose output. .TP \fB\-\-smt\fR={\fIon\fR|\fIoff\fR} Set the current smt state for the system to either \fIon\fR, which will online every thread in every core on the system, or \fIoff\fR which will leave each core on the system with only one thread online. .TP \fB\-\-smt\fR=\fIvalue\fR Set the smt state for each core to the specified \fIvalue\fR. .TP \fB\-\-cores\-present\fR Display the number of cores present. .TP \fB\-\-cores\-on\fR Display the number of cores online. .TP \fB\-\-cores\-on\fR=\fIvalue\fR Put exactly \fIvalue\fR number of cores online. Note that this will either online or offline cores to achieve the desired result. .TP \fB\-\-dscr\fR Display the current Data Stream Control Register (DSCR) setting for the system. .TP \fB\-\-dscr\fR=\fIvalue\fR Set the DSCR setting for the system to \fIvalue\fr. .TP \fB\-\-dscr\fR [\fIpid\fR] Display the DSCR setting for process \fIpid\fR. .TP \fB\-\-dscr\fR=\fIvalue\fR [\fIpid\fR] Set the DSCR to the specified \fIvalue\fR for process \fIpid\fR. .TP \fB\-\-smt\-snooze\-delay\fR Display the current smt\-snooze\-delay setting. .TP \fB\-\-smt\-snooze\-delay\fR=\fIvalue\fR Set the smt\-snooze\-delay to the specified \fIvalue\fR. .TP \fB\-\-run-mode\fR Display the current diagnostics run mode. .TP \fB\-\-run\-mode\fR=\fIvalue\fR Set the current diagnostics run mode to \fIvalue\fR. .TP \fB\-\-frequency\fR [\-t \fItime\fR] Determine the cpu frequency. The default sampling period is one second unless a time is specified with the \fB\-t \fItime\fR option. .TP \fB\-\-subcores\-per\-core\fR Display the number of subcores per core. .TP \fB\-\-subcores\-per\-core\fR=\fIvalue\fR Set the number of subcores per core to \fIvalue\fR. .TP \fB\-\-threads\-per\-core\fR Display the number of threads per core. .TP \fB\-\-info\fR Display system state information. The output will print a line for each core and possible sub\-core along with the thread numbers for each thread in the core with an asterick next to it if the thread is online. .TP \fB\-\-version\fR Print the version number. .SH AUTHOR Written by Anton Blanchard and Nathan Fontenot powerpc-utils-1.3.4/man/rtas_dbg.8000066400000000000000000000012351315235264300167720ustar00rootroot00000000000000.\" .\" Copyright (C) 2015 International Business Machines .\" .TH RTAS_DBG 8 "September 2015" Linux "Linux on Power Service Tools" .SH NAME rtas_dbg \- enable debug output for a particular rtas call .SH SYNOPSIS .B /usr/local/sbin/rtas_dbg -l | \fIfunction\fR | \fItoken\fR .SH DESCRIPTION The \fIrtas_dbg\fR tool enables RTAS debug output for a particular RTAS call. Users can either supply the -l option to list the available functions or supply the function name or token value to enable RTAS debug output for that function. Currently, this tool is only supported on PowerVM systems. .SH OPTIONS .TP \fB\-l\fR list the rtas calls available to display debug output powerpc-utils-1.3.4/man/rtas_dump.8000066400000000000000000000024301315235264300172010ustar00rootroot00000000000000.\" Copyright (C) 2005 International Business Machines. .\" Common Public License Version 1.0 (see COPYRIGHT) .\" .\" Author(s) .\" Nathan Fontenot .\" .TH RTAS_DUMP 8 "May 2005" Linux "Linux on Power Service Tools" .SH NAME rtas_dump \- dump the contents of an RTAS event. .SH SYNOPSIS .B /usr/sbin/rtas_dump [ options ] .SH DESCRIPTION The \fIrtas_dump\fR icommand is used to dump the contents of an RTAS event into a human readable form. The tool is able to parse the contents of /var/log/messages, /var/log/platform and /var/log/boot.msg to extract dump the contents of RTAS events. RTAS events can also be read in from a specified file or stdin. The real work of de-coding RTAS events is handled by \fI/usr/sbin/rtas_event_decode\fR, the rtas_dump command simply parses the input and files and passes on the data to \fIrtas_event_decode\fR. .SH OPTIONS .TP \fB\-d\fR debug flag, passed through to rtas_event_decode .TP \fB\-f\fI file\fR dump the RTAS event(s) from \fIfile\fR .TP \fB\-h\fI print the usage message and exit .TP \fB\-n\fI num\fR Only dump RTAS event number \fInum\fR .TP \fB\-v\fR dump the entire contents of the RTAS event(s), not just the header .TP \fB\-w\fR set the output character width .SH AUTHOR Nathan Fontenot powerpc-utils-1.3.4/man/rtas_ibm_get_vpd.8000066400000000000000000000024611315235264300205170ustar00rootroot00000000000000.\" .\" Copyright (C) 2004 International Business Machines .\" Michael Strosaker .\" .TH RTAS_IBM_GET_VPD 8 "May 2004" Linux "Power Service Tools" .SH NAME rtas_ibm_get_vpd \- retrieve dynamically changing Vital Product Data .SH SYNOPSIS .nf \fB/usr/sbin/rtas_ibm_get_vpd \-h \fB/usr/sbin/rtas_ibm_get_vpd \fR[\fB\-l \fIlocation_code\fR] .fi .SH DESCRIPTION .P The .I rtas_ibm_get_vpd utility is a utility to assist inventory retrieval applications by gathering dynamically changing vital product data on IBM ppc64 systems. The output of this utility is formatted to be parsed by other applications; as such, it is not intended for general command-line usage, though there is no reason that it should not be used in that manner. .SH OPTIONS .TP .B \-l \fIlocation_code Specify the location code of the device from which dynamic VPD should be gathered. If this option is not specified, dynamic VPD for all appropriate devices will be gathered. .TP .B \-h Print a usage message. .SH EXIT STATUS .TP .B 0 Success. .TP .B 1 Usage or parameter error. .TP .B 2 Hardware error. .TP .B 3 The library used to invoke firmware routines, librtas, has experienced an error. .TP .B 4 The necessary firmware routine is not available on this system. .TP .B 5 Out of memory. .SH "SEE ALSO" .BR lsvpd (8), .BR lscfg (8) powerpc-utils-1.3.4/man/serv_config.8000066400000000000000000000117141315235264300175140ustar00rootroot00000000000000.\" .\" Copyright (C) 2004 International Business Machines .\" Michael Strosaker .\" .TH SERV_CONFIG 8 "May 2004" Linux "Linux on Power Service Tools" .SH NAME serv_config \- view and configure system service policies and settings on IBM ppc64 platforms .SH SYNOPSIS .nf \fB/usr/sbin/serv_config \fR[\fB-b\fR] [\fB-s\fR] [\fB-r\fR] [\fB-m\fR] \fB/usr/sbin/serv_config -l \fB/usr/sbin/serv_config -z \fIfilename \fB/usr/sbin/serv_config -e \fIvar\fR[\fB=\fIvalue\fR] \fB/usr/sbin/serv_config \fR[\fB--surveillance\fR[\fB=\fIsettings\fR]] \fR[\fB--reboot-policy\fR[\fB=\fIsettings\fR]] \fR[\fB--ring-indicate\fR[\fB=\fIsettings\fR]] \fR[\fB--remote-maint\fR[\fB=\fIsettings\fR]] \fR[\fB--force\fR] .fi .SH DESCRIPTION .P The .I serv_config utility is used to view and manipulate various system service policies and settings on PAPR-compliant PowerPC-64 machines, such as IBM pSeries, iSeries, System p or System i machines. .P .I serv_config can be run in one of two modes; interactive mode, in which the user will be prompted for the value of each variable in the specified category, or macro mode, in which the string provided on the command line will be parsed for the values of the variables in the category. Macro mode is for expert use only; most users should be utilizing the interactive options (\fB\-s\fR, \fB\-b\fR, \fB\-r\fR, and \fB\-m\fR). .P .B NOTE: It is recommended that the current service settings are backed up with the \fB\-l\fR option before the settings are manipulated with this utility. Should a value be mistakenly updated to an incorrect value, all the settings can be restored to the backed up values with the \fB\-z\fR option. .SH OPTIONS .TP .B \-l List all of the current service settings. If this output is stored to a file, these settings can be later restored with the \fB\-z\fR option. .TP \fB\-e \fIvar\fR[\fB=\fIvalue\fR] If only \fIvar\fR is specified, the value of the specified service setting is displayed; if a \fIvalue\fR is also specified, the value of the specified service setting is updated to the specified value. .TP .B \-s Interactively update the Surveillance settings. .TP .B \-b Interactively update the Reboot policies. .TP .B \-r Interactively update the Remote Power-On settings (either Ring Indicate Power-On or Wake On LAN). .TP .B \-m Interactively update the Remote Maintenance settings. .TP .B \-z \fIfilename Restore the service settings that were previously stored to \fIfilename\fR (using the \fB\-a\fR option). .SH ADVANCED OPTIONS .P The following options are for expert users only. They are intended to be used by scripts and utilities which have been designed to automate the retrieval/manipulation of service settings. .TP \fB\-\-surveillance\fR[\fB=\fIsettings\fR] View or update the Surveillance settings in macro mode. If the \fIsettings\fR argument is not specified, all of the Surveillance variables are printed along with their corresponding values. If the \fIsettings\fR argument is specified, the Surveillance settings are updated to the specified values. The \fIsettings\fR argument should be in the following format: .nf \fIsp-sen\fB,\fIsp-sti\fB,\fIsp-del\fB,\fIimmediate .fi .TP \fB\-\-reboot\-policy\fR[\fB=\fIsettings\fR] View or update the Reboot policies in macro mode. If the \fIsettings\fR argument is not specified, all of the Reboot policy variables are printed along with their corresponding values. If the \fIsettings\fR argument is specified, the Reboot policies are updated to the specified values. The \fIsettings\fR argument should be in the following format on legacy systems: .nf \fIsp-bootrt-limit\fB,\fIsp-os-plt-reboot\fB,\fIsp-plt-reboot\fB, \fIsp-dookc\fB,\fIsp-ac-reboot\fR On recent systems, the following format is used: \fIpartition_auto_restart\fB,\fIplatform_auto_power_restart .fi .TP \fB\-\-remote\-pon\fR[\fB=\fIsettings\fR] View or update the Remote Power-On settings in macro mode. If the \fIsettings\fR argument is not specified, all of the Remote Power-On variables are printed along with their corresponding values. If the \fIsettings\fR argument is specified, the Remote Power-On settings are updated to the specified values. The \fIsettings\fR argument should be in the following format for systems with support for Ring Indicate Power-On: .nf \fIsp-ri-pon\fB,\fIsp-rb4-pon\fR On systems with support for Wake On LAN, the format is as follows: \fIsp-remote-pon .fi .TP \fB\-\-remote\-maint\fR[\fB=\fIsettings\fR] View or update the Remote Maintenance settings in macro mode. If the \fIsettings\fR argument is not specified, all of the Remote Maintenance variables are printed along with their corresponding values. If the \fIsettings\fR argument is specified, the Remote Maintenance settings are updated to the specified values. .TP .B \-\-force Do not prompt for confirmation before modifying system settings; only valid in macro mode (ignored in interactive mode). .SH "SEE ALSO" .BR bootlist (8), .BR lscfg (8), .BR nvram (8) powerpc-utils-1.3.4/man/set_poweron_time.8000066400000000000000000000054741315235264300206000ustar00rootroot00000000000000.\" .\" Copyright (C) 2004 International Business Machines .\" Michael Strosaker .\" .TH SET_POWERON_TIME 8 "May 2004" Linux "Power Service Tools" .SH NAME set_poweron_time \- set a time in the future for the system to be powered on .SH SYNOPSIS .nf \fB/usr/sbin/set_poweron_time \fR[\fB-s\fR] \fB-t \fIabsolute_time \fB/usr/sbin/set_poweron_time \fR[\fB-s\fR] \fB-d \fIdelta_time .B /usr/sbin/set_poweron_time -m .B /usr/sbin/set_poweron_time -h .fi .SH DESCRIPTION .P The .I set_poweron_time utility is used to set a time in the future to power on the system. The utility uses firmware interfaces provided by IBM ppc64 systems to provide this functionality. .P When used with the .B -t option, the utility will configure the system to power-on at the specified date and time. This is usefule for specifying that the sysetm should be restarted at 6 AM on Monday morning, for example. When used with the .B -d option, the utility will treat the specified time as a delta from the present. This is useful for specifying that the system should be restarted in 2 days, for example. Times for the .B -t and .B -d options should be specified in the following format: .P \fBY\fR\fBM\fR\fBD\fR\fBh\fR\fBm\fR\fBs\fR .P The month, if specified, should be in the range of 1-12. The day, if specified, should be in the range of 1-31. The hour, if specified, should be in the range of 0-23. The minute and second, if specified, should be in the range of 0-59. .TP For the -t option: Year, month, and day default to the current date if not specified. Hour, minute, and second default to 0 if not specified. .TP For the -d option: Year, month, day, hour, minute, and second default to 0 if not specified. .P When used with the .B -m option, the utility will print the maximum amount of time in the future that the power-on time can be set (in days). This option cannot be used with any others. When used with the .B -s option, the utility will shut down the system with .B shutdown -h now after the power-on time has been set. If the utility is unable to set the power-on time for any reason, the system will not be shut down. .SH OPTIONS .TP \fB\-t \fIabsolute_time specify the power-on time .TP \fB\-d \fIdelta_time specify the power-on time as a delta from the current time .TP .B \-m print the maximum amount of time in the future that the power-on time can be set (in days) .TP .B \-s shut down the system after setting the power-on time. The system will not be shut down if the power-on time cannot be set for any reason. .TP .B \-h print a usage message with examples .SH EXAMPLES .nf Shut down the system and schedule it to restart in 12 hours and 10 minutes: set_poweron_time -d h12m10 -s Schedule the system to restart at noon on June 15th of this year: set_poweron_time -t M6D15h12 .fi powerpc-utils-1.3.4/man/snap.8000066400000000000000000000023541315235264300161510ustar00rootroot00000000000000.\" .\" Copyright (C) 2002 - 2012 International Business Machines .\" Todd Inglett .\" Michael Strosaker .\" Vasant Hegde .\" .TH SNAP 8 "30 May 2012" Linux "Linux on Power Service Tools" .SH NAME snap \- generate a configuration snapshot for service .SH SYNOPSIS \fB/usr/sbin/snap \fR[\fB-athv\fR] [\fB-d \fIdir\fR] [\fB-o \fIfile\fR] .SH DESCRIPTION The .I snap script copies several system status and config files and the output of several commands from the system into snap.tar.gz in the current directory. System servicers may ask that this be run in order collect data to diagnose a problem. .SH OPTIONS .TP .B \-a All data; collect detailed information (more files and output). .TP \fB\-d \fIdir Specify the directory where files and ouput will be collected (default: /tmp/ibmsupt). .TP .B \-h Print a help message. .TP \fB\-o \fIfile Specify the output path and filename (.tar required, .tar.gz optional) (default: snap.tar.gz). .TP \fB\-t Add hostname and timestamp to output filename. .TP .B \-v verbose output .SH FILES These are some of the files that are archived: .P /var/log/messages .br /var/log/scanoutlog.* .br /proc (select files) .br /dev/nvram .br /etc/yaboot.conf powerpc-utils-1.3.4/man/sys_ident.8000066400000000000000000000020041315235264300172010ustar00rootroot00000000000000.\" .\" Copyright (C) 2006 International Business Machines .\" Michael Strosaker .\" .TH SYS_IDENT 8 "Jan 2006" Linux "Linux on Power Service Tools" .SH NAME sys_ident \- generate unique identification numbers .SH SYNOPSIS .nf \fB/usr/sbin/sys_ident -s\fR \fB/usr/sbin/sys_ident -p\fR .fi .SH DESCRIPTION .P The \fIsys_ident\fR utility implements algorithms for generating identification numbers that are uniqe to each system. These numbers are generated with the same algorithm as the numbers generated by \fIuname -f\fR on AIX. .P When invoked with the \fB-s\fR option, a 64-bit identification number will be printed (as a 16-character hexadecimal number). The number will also be unique for each partition on a partitioned system. .P When invoked with the \fB-p\fR option, a 32-bit processor serial number will be printed (as an 8-character hexadecimal number). .SH OPTIONS .TP .B \-s Generate a unique system/partition identification 64-bit number .TP .B \-p Generate the processor serial number powerpc-utils-1.3.4/man/uesensor.8000066400000000000000000000045551315235264300170600ustar00rootroot00000000000000.\" .\" Copyright (C) 2004 International Business Machines .\" Michael Strosaker .\" .TH UESENSOR 8 "May 2004" Linux "Linux on Power Service Tools" .SH NAME uesensor \- view the state of system environmental sensors .SH SYNOPSIS .nf \fB/usr/sbin/uesensor -l \fR| \fB -a \fB/usr/sbin/uesensor -t \fItoken \fB-i \fIindex \fR[\fB-v\fR] .fi .SH DESCRIPTION .P The \fIuesensor\fR utility is used to view the state of environmental sensors on PowerPC-64 machines. .P There are 4 types of system sensors that can be retrieved with \fIuesensor\fR; each sensor has an identifying token: .TP .B 3 Thermal sensor .TP .B 9001 Fan speed sensor .TP .B 9002 Voltage sensor .TP .B 9004 Power supply sensor .P Each sensor is uniquely identified by a combination of token and index number; index numbers start at 0 and are contiguous. For example, the second fan on the system would be identified by token number 9001 and index 1. .P The state of each sensor consists of a status and a measured value. The status value is one of the following: .TP .B 9 Critical low .TP .B 10 Warning low .TP .B 11 Normal .TP .B 12 Warning high .TP .B 13 Critical high .P The measured value depends on the type of sensor. Thermal sensors are measured in degrees Celcius; fan speed is measured in revolutions per minute; voltage is measured in millivolts; power supply measurements are defined as follows: .TP .B 0 Not present .TP .B 1 Present and not operational .TP .B 2 Status unknown .TP .B 3 Present and operational .P Each sensor is also associated with a location code; this location code may not be unique (for example, there may be multiple voltage sensors on a planar). .SH OPTIONS .TP .B \-l List all the sensors in human-readable format. .TP .B \-a List all the sensors in a tabular, numerical format. One line will be printed for each sensor in the following format: .nf .I .fi .TP \fB\-t \fItoken Specify the token of a specific sensor to query. Also requires the \fB\-i\fR option to be specified. .TP \fB\-i \fIindex Specify the index of a specific sensor to query. Also requires the \fB\-t\fR option to be specified. .TP .B \-v Print the measured value rather than the sensor status, which is the default value printed. Requires both the \fB\-t\fR and \fB-i\fR options to be specified. .SH "SEE ALSO" .BR usysident (8), .BR usysattn (8) powerpc-utils-1.3.4/man/update_flash.8000066400000000000000000000144621315235264300176520ustar00rootroot00000000000000.\" .\" Copyright (C) 2002 - 2013 International Business Machines .\" Todd Inglett .\" Michael Strosaker .\" Vasant Hegde .\" .TH UPDATE_FLASH 8 "8 May 2013" Linux "PowerLinux Service Tools" .SH NAME update_flash \- manage system and service processor firmware .SH SYNOPSIS .nf \fB/usr/sbin/update_flash \fR[\fB-v|-n\fR] \fB-f \fIfirmware.img .B /usr/sbin/update_flash -h .B /usr/sbin/update_flash -c .B /usr/sbin/update_flash -r .B /usr/sbin/update_flash -s .fi .SH DESCRIPTION .P The .I update_flash script is used to validate, update and manage firmware on an IBM Power Systems servers. .TP .nf .B VALIDATION .fi When used with the .B -v option, the script will ONLY perform validation of the image file. Regardless of the outcome of the validation, no actual flash will occur. This option is only useful on machines that support validation of firmware images. .TP .nf .B UPDATE .fi When used with only the .B -f option and an image file name, the script will attempt to update the system firmware with the given image. If the machine has the ability to pre-validate the image, this will be done automatically before the flash. If the machine is not capable of pre-validation, or if validation passes, this script will upload the firmware image into the kernel and will perform a .B shutdown -r now which will reboot the system. The flash will occur at the end of the reboot process. .B WARNING: The system WILL be rebooted! Wait until the flash process has completed. This can be anywhere from 2 minutes to 20 minutes (or more) depending on the system. The control panel display will show that the system is flashing. Failure to wait may render a system inoperable. .B NOTE: If machine supports two firmware image areas, update is always applied to the temporary image area. The .B -c option is the normal means by which a temporary image is committed to the permanent side (see MANAGEMENT). However, if a platform is running from a temporary image when an update is to be applied, then the platform may automatically commit the current temporary image to the permanent side to allow the new image to be updated to the temporary image area. The .B -v option can be used to determine what would result from an attempt to update a flash image. The .B -n option will prevent the automatic overwrite of the permanent image area and abandon the update entirely. To apply an update to the temporary image area without overwriting the permanent image area, the system must first be running with the permanent image. The temporary image can then be rejected (see MANAGEMENT). Subsequently, the update can be applied. .TP .nf .B MANAGEMENT .fi When used with the .B -c option, the script will commit the temporary image to the permanent side. In order to use this, the machine must be running on the temporary image. This option is only useful on machines supporting two firmware image areas. When used with the .B -r option, the script will reject the temporary image. In order to use this, the machine must be running on the permanent image. To switch from the temporary image to the permanent image, you must reboot from the permanent image -- for example, using the ASMI or HMC. This option is only useful on machines supporting two firmware image areas. .SH OPTIONS .TP .B \-h Print the usage message and exit. .TP \fB\-f \fIfilename Supply the filename to flash (required). .TP .B \-v Validate ONLY with specified image file. .TP .B \-n Do not overwrite permanent side image automatically. .TP .B \-c Commit temporary image to permanent side. .TP .B \-r Reject temporary image. .TP .B \-s Determine if partition has access to perform flash image management. .SH EXAMPLES .P To determine if partition has authority to flash image: # update_flash -s .P For a typical firmware update (this may commit temporary to permanent): # update_flash -f 01AL740_100_042.img .P To update only if permanent side will not be overwritten: # update_flash -n -f 01AL740_100_042.img .P To validate an image: # update_flash -v -f 01AL740_100_042.img .P To commit temporary image to permanent (note that the system must be running on temporary image): # update_flash -c .P To reject temporary image, and copy to permanent to temporary (note that the system must be running on permanent image): # update_flash -r .SH EXIT STATUS .TP .nf All cases: 3 - Usage error 4 - Permission error 6 - Unexpected problem with /proc filesystem access 7 - Error loading module 8 - RTAS(pSeries)/OPAL(PowerNV) call failed 9 - User aborted operation .fi .TP .nf Determine if partition has authority to manage image (-s): 0 - Flash image management is supported 1 - Flash image management is not supported on this system .fi .TP .nf Validation (-v): 0 - Validation successful .fi .TP .nf Update ([-n] -f): 5 - Image file error 10 - Auto overwrite permanent side image 15 - Update Access Key Expired .fi .TP .nf Manage (-c|-r): 0 - Temporary image commit/reject successful .fi .SH FILES .TP .nf pSeries rtas_flash kernel module /proc/ppc64/rtas/firmware_flash (provided by kernel module) .fi .TP .nf PowerNV /sys/firmware/opal/image /sys/firmware/opal/{validate/manage/update}_flash .fi .SH NOTES Firmware may be downloaded from the IBM website. Instructions for downloading and installing the firmware image are also there, and information there will be more up-to-date than this page. .P Various conditions can lead to a firmware update failure. If you receive an authentication-related error, such as: .P .nf update_flash: RTAS: validate() Partition does not have authority -or- update_flash: System does not have authority to perform firmware update. .fi .P This can reflect either 1) That the permission is not set (correctable through the ASM interface, System -> Firmware Update Policy, or through an HMC if attached. .P -or- .P 2) Firmware still believes an HMC is attached. This can be corrected by following the steps outlined here: .P http://publib.boulder.ibm.com/infocenter/powersys/v3r1m5/index.jsp?topic=/p7hatl/iphblresetserverp6.htm .P For older "AIX format" images, the file will have a .BIN extension. This zip file happens to be an AIX binary, but it can be extracted with the unzip command (with password from the web page): unzip 70286C4F.BIN This should produce a file with a .img extension. This image file is what should be flashed. powerpc-utils-1.3.4/man/vscsisadmin.8000066400000000000000000000233051315235264300175320ustar00rootroot00000000000000.\" Copyright (c) 2005 International Business Machines. .\" Common Public License Version 1.0 (see COPYRIGHT) .\" .\" Author(s) .\" Ryan S. Arnold .\" Original version: January 14, 2005. .\" .Dd January 14, 2005 .Os LINUX .Dt VSCSISADMIN 8 .Sh NAME .Nm vscsisadmin .Nd virtual SCSI server administration utility .Sh SYNOPSIS .Nm Fl start .Op Fl adapter Ns = Ns Ar adapter .Op Fl adapter Ns = Ns Ar adapter Fl bus Ns = Ns Ar bus .Op Fl adapter Ns = Ns Ar adapter Fl bus Ns = Ns Ar bus Fl target Ns = Ns Ar target .Op Fl noisy .Op Fl noisy .Op Fl warn .Pp .Nm Fl status .Op Fl noisy .Op Fl noisy .Op Fl warn .Pp .Nm Fl stop .Op Fl path Ns = Ns Ar path .Op Fl adapter Ns = Ns Ar adapter .Op Fl adapter Ns = Ns Ar adapter Fl bus Ns = Ns Ar bus .Op Fl adapter Ns = Ns Ar adapter Fl bus Ns = Ns Ar bus Fl target Ns = Ns Ar target .Op Fl noisy .Op Fl noisy .Op Fl warn .Pp .Nm Fl help .Pp .Nm Fl version .Pp .Sh DESCRIPTION This is the IBM virtual SCSI server .Pq \fBibmvscsis\fR administration utility. This utility is responsible for configuring, starting, stopping, and gathering status on the virtual SCSI server. .Sh OPTIONS .Bl -tag -width -indent .It Fl help Output the \fBvscsisadmin\fR utility's help information, which gives a brief synopsis of this manual page. .It Fl noisy This directive is optional. Without a .Sq Fl noisy directive the vscsisadmin script is in \fBsilent\fR mode by default (except in the case of errors, warnings and output requests). The output verbosity of the script is managed by stacking .Sq Fl noisy directives. A single instance of .Sq Fl noisy indicates that the utility should output in \fBstatus\fR mode. A second instance of .Sq Fl noisy indicates that the utility should output in \fBverbose\fR mode. Verbose mode is generally used for script tracing and won't be used by a casual user unless problems arise. .It Fl start Configure and start the virtual SCSI server based upon the adapter:bus:target entries found in the configuration file (denoted in the \fBFILES\fR section of this manual). This directive will configure valid adapter:bus:target entries regardless of whether they are to be active or inactive at startup. If the vscsis target is already active this command will configure and start the remaining valid targets specified in the configuration file and leave the already active targets alone. For information on how to write a well formed configuration file .Xr ibmvscsis.conf 8 is provided as an accompanying man page. .It Fl start Fl adapter Ns = Ns Ar adapter This modified .Sq Fl start directive will read the config file and will only process those config file entries that are defined under the specified adapter. An example follows: .Pp .Bd -literal \fBvscsisadmin -start -adapter=30000005\fR .Ed .It Fl start Fl adapter Ns = Ns Ar adapter Fl bus Ns = Ns Ar bus This modified .Sq Fl start directive will read the config file and will only process those config file entries that are defined under the specified adapter and bus. An example follows: .Pp .Bd -literal \fBvscsisadmin -start -adapter=30000005 -bus=0\fR .Ed .It Fl start Fl adapter Ns = Ns Ar adapter Fl bus Ns = Ns Ar bus Fl target Ns = Ns Ar target This modified .Sq Fl start directive will read the config file and will only process those config file entries that are defined under the specified adapter, bus and target. An example follows: .Pp .Bd -literal \fBvscsisadmin -start -adapter=30000005 -bus=0 -target=2\fR .Ed .It Fl status Output a table of status on the virtual SCSI server. This table pertains to the activity found in the \fBibmvscsis\fR sysfs directory and not only to the adapter:bus:target entries in the ibmvscsis configuration file. Here is an example output: \fB .Pp .Bd -literal ibmvscsis:30000008 * bus0:target0:/dev/sdd6 * bus0:target1:/dev/sdd7 * bus1:target0:/dev/sdd8 ibmvscsis:30000009 bus0:target1:/dev/loop0-->/var/vscsis/vdisk1 ibmvscsis:3000000a ibmvscsis:3000000b * bus0:target1:/dev/loop1-->/var/vscsis/vdisk2 .Ed .Pp \fRIn the status output each vscsis adapter has a block of data. Within this block of data each target is preceded by the bus number it is on. Following the target information is the device path with which the target is associated. A loop file, if there is one, may follow the device path. Preceding every entry may be an asterisk. The presence of an asterisk indicates that the target is currently active. No asterisk indicates that the target is configured but not active. .Pp Existent bus:target combinations that lack any device_path data are left out of the status information because they aren't relevant. .Pp A single inclusion of the .Sq Fl noisy directive with the status directive will not change the output of this utility. A second .Sq Fl noisy inclusion will put the utility into verbose mode and may increase the amount of output. .It Fl stop The general behavior of the stop directive is that the \fBvscsisadmin\fR utility will walk the \fBibmvscsis\fR driver sysfs tree and silently deactivate all targets, detach all loop back devices, and remove all targets and buses from all adapters under the driver's care. .Pp There are extended options for a more selective stop operation. .It Fl stop Fl path Ns = Ns Ar path This is a robust stop operation which will determine whether to stop a single target, all targets on an entire bus, or all targets on an entire adapter. This is signalled through the selection of a path to one of the three (\fBvscsisadmin\fR doesn't care if the path contains a trailing '/'). Take the following three examples: .Pp .Bd -literal \fBvscsisadmin -stop \\ -path=/sys/bus/vio/drivers/ibmvscsis/30000005/bus0/target0 vscsisadmin -stop \\ -path=/sys/bus/vio/drivers/ibmvscsis/30000005/bus0/ vscsisadmin -stop \\ -path=/sys/bus/vio/drivers/ibmvscsis/30000005/\fR .Ed .Pp Example one will cause \fBvscsisadmin\fR to deactivate a single target. Example two will cause \fBvscsisadmin\fR to deactivate all targets on an entire bus and remove all of the targets from the bus. Example three will cause \fVvscsisadmin\fR to deactivate all targets on all buses under the adapter and it will remove all targets and all buses under the adapter. .It Fl stop Fl adapter Ns = Ns Ar adapter This operation takes an adapter number in hexadecimal. It will terminate all of the targets on all of the buses under the adapter. It will also remove all targets on all buses and remove all the buses under the adapter. An example follows: .Pp .Bd -literal \fBvscsisadmin -stop -adapter=30000005\fR .Ed .It Fl stop Fl adapter Ns = Ns Ar adapter Fl bus Ns = Ns Ar bus This operation takes an adapter number in hexadecimal and an integer bus number. It will deactivate all of the targets under the specified bus and will remove the targets from the bus. An example follows: .Pp .Bd -literal \fBvscsisadmin -stop -adapter=30000005 -bus=0\fR .Ed .It Fl stop Fl adapter Ns = Ns Ar adapter Fl bus Ns = Ns Ar bus Fl target Ns = Ns Ar target This operation takes an adapter number in hexadecimal, an integer bus number, and an integer target number. It will only deactivate the target specified. An example follows: .Pp .Bd -literal \fBvscsisadmin -stop -adapter=30000005 -bus=0 -target=0\fR .Ed .It Fl version Output the version number of the \fBvscsisadmin\fR utility. .It Fl warn Warning messages are suppressed even when \fBvscsisadmin\fR is in verbose output mode unless the application was run with the .Sq Fl warn flag. Warnings indicate that unexpected circumstances happened during \fBvscsisadmin\fR operations. Warning messages are not severe enough to terminate the running operation. .Pp There are two scenarios when warnings are generated. The first is when the \fBvscsisadmin\fR utility reads the config file and reads an entry for an expected adapter, bus, target, or target attributes that is not found in the \fBibmvscsis\fR driver's sysfs directory tree. This can be due to adapter being removed from firmware without the removal of the adapter configuration entry from the config file. The third scenario is when target config entries contain "none". Such entries are ignored. .El .Sh FILES .Bl -tag -width -indent .It \fI/etc/ibmvscsis.conf\fR This is the virtual SCSI server configuration file used by \fBvscsisadmin\fR to configure and manage \fBibmvscsis\fR. This configuration file has its own man page which describes how to properly write a virtual SCSI server config. .It \fI/etc/init.d/ibmvscsis.sh\fR This is the virtual SCSI server start and stop automation init script. This application invokes vscsisadmin internally and presents a standard init script interface. .El .Sh CAVEATS .Bl -tag -width -indent .It \fBstart caveats\fR It is \fBnot\fR advisable to manually create and activate targets without adding corresponding config file entries. .It \fBstop caveats\fR Currently the virtual SCSI server doesn't support an interface for determining if the partner vscsis adapter for each vscsis adapter is actually in use. Therefore it can be \fBVERY\fR dangerous to stop a running vscsi server before all partner partitions have been halted. In the future this script will, by default, not deactivate targets who are on actively connected adapters. At that time a .Sq Fl force directive can accompany a stop directive to force deactivate such targets. .El .Sh DEPENDENCIES The \fBvscsisadmin\fR utility requires that the \fBibmvscsis\fR driver module be installed on the system, or built-in when the application is invoked. .Pp This utility depends on the existence of the \fBsystool\fR application for querying the /sys file system and gathering data about the \fBibmvscsis\fR device driver. Execution of \fBvscsisadmin\fR will be stopped immediately if \fBsystool\fR is not present on the system. .Sh SEE ALSO .Xr ibmvscsis.sh 8 , .Xr ibmvscsis.conf 8 .Sh AUTHOR(S) .An Ryan S. Arnold Aq rsa@us.ibm.com powerpc-utils-1.3.4/powerpc-utils.spec.in000066400000000000000000000056301315235264300204420ustar00rootroot00000000000000%define name powerpc-utils %define version @PACKAGE_VERSION@ %define release 1 Summary: Utilities for PowerPC platforms Name: %{name} Version: %{version} Release: %{release} License: GNU General Public License (GPL) Group: System Environment Source: powerpc-utils-%{version}.tar.gz BuildRoot: /tmp/%{name}-buildroot/ Vendor: IBM Corp. Requires: /bin/bash, /bin/sh, /bin/sed, /usr/bin/perl, librtas >= 1.4.0, zlib Requires: bc Requires: coreutils Requires: findutils Requires: gawk Requires: grep Requires: /sbin/modprobe Requires: /sbin/shutdown Requires: udev Requires: util-linux Requires: which %description Utilities for maintaining and servicing PowerPC systems. %prep %setup -q %build %configure %{__make} %{?_smp_mflags} %install %{__rm} -rf $RPM_BUILD_ROOT %{__make} install DESTDIR=$RPM_BUILD_ROOT %files %defattr(-,root,root) /usr/share/doc/packages/powerpc-utils/README /usr/share/doc/packages/powerpc-utils/COPYING /usr/sbin/update_flash /usr/sbin/update_flash_nv /usr/sbin/activate_firmware /usr/sbin/set_poweron_time /usr/sbin/rtas_ibm_get_vpd /usr/sbin/serv_config /usr/sbin/uesensor /usr/sbin/hvcsadmin /usr/sbin/rtas_dump /usr/sbin/rtas_event_decode /usr/sbin/sys_ident /usr/sbin/drmgr /usr/sbin/lsslot /usr/sbin/lsprop /usr/sbin/nvram /usr/sbin/nvsetenv /usr/sbin/snap /usr/sbin/bootlist /usr/sbin/ofpathname /usr/sbin/ppc64_cpu /usr/sbin/lsdevinfo /usr/sbin/ls-veth /usr/sbin/ls-vdev /usr/sbin/ls-vscsi /usr/sbin/lparstat /usr/sbin/pseries_platform /usr/sbin/errinjct /usr/sbin/rtas_dbg /usr/bin/amsstat /usr/share/man/man8/update_flash.8.gz /usr/share/man/man8/activate_firmware.8.gz /usr/share/man/man8/set_poweron_time.8.gz /usr/share/man/man8/rtas_ibm_get_vpd.8.gz /usr/share/man/man8/serv_config.8.gz /usr/share/man/man8/uesensor.8.gz /usr/share/man/man8/hvcsadmin.8.gz /usr/share/man/man8/rtas_dump.8.gz /usr/share/man/man8/sys_ident.8.gz /usr/share/man/man8/nvram.8.gz /usr/share/man/man8/snap.8.gz /usr/share/man/man8/bootlist.8.gz /usr/share/man/man8/ofpathname.8.gz /usr/share/man/man5/lparcfg.5.gz /usr/share/man/man8/lparstat.8.gz /usr/share/man/man8/lsslot.8.gz /usr/share/man/man8/ppc64_cpu.8.gz /usr/share/man/man1/amsstat.1.gz /usr/share/man/man8/errinjct.8.gz /usr/share/man/man8/rtas_dbg.8.gz %post # Post-install script ----------------------------------------------- ln -sf /usr/sbin/serv_config usr/sbin/uspchrp ln -sf /usr/share/man/man8/serv_config.8 usr/share/man/man8/uspchrp.8 %postun # Post-uninstall script --------------------------------------------- if [ "$1" = "0" ]; then # last uninstall rm -f /usr/sbin/uspchrp rm -f /usr/share/man/man8/uspchrp.8.gz fi %changelog * Tue Dec 7 2011 Brian King - Added lsslot man page * Fri May 13 2011 Brian King - Fixed some ofpathname issues with various SAS and FC adapters * Fri Mar 11 2011 Brian King - Do not install vscsi server scripts, since they are deprecated powerpc-utils-1.3.4/scripts/000077500000000000000000000000001315235264300160275ustar00rootroot00000000000000powerpc-utils-1.3.4/scripts/Makefile.am000066400000000000000000000003161315235264300200630ustar00rootroot00000000000000dist_bin_SCRIPTS = amsstat dist_sbin_SCRIPTS = update_flash update_flash_nv hvcsadmin rtas_dump \ snap bootlist ofpathname lsdevinfo ls-veth ls-vscsi \ ls-vdev pseries_platform nvsetenv powerpc-utils-1.3.4/scripts/amsstat000077500000000000000000000146321315235264300174370ustar00rootroot00000000000000#!/bin/bash # IBM "amsstat": Active Memory Sharing statistics gathering tool # # Copyright (c) 2009 International Business Machines. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # Authors: # Andrew Theurer # Robert Jennings # # This script will gather AMS related information on supported Linux systems # usage: # amstat # # If you do not provide an interval, amsstat will display stats only once # # For further details on this tool and the fields it displays please # reference man page amsstat.1 sleep_interval=$1 indent=-4 devstat_data_spacing=-30 lparcfg_data_spacing=-30 lparcfg_file=/proc/ppc64/lparcfg # Hardcoding pseries_platform path as amstat will be placed in bin PSERIES_PLATFORM=/usr/sbin/pseries_platform function print_meminfo_stats { echo "System Memory Statistics:" OLD_IFS=${IFS} IFS=" " for stat in `cat /proc/meminfo`; do IFS=${OLD_IFS} if echo $stat | grep "^MemTotal\|^MemFree\|^Buffers\|^Cached\|^Inactive\|SwapTotal\|SwapFree" >/dev/null; then this_stat=`echo $stat | awk -F: '{print $1}'` this_value=`echo $stat | awk -F: '{print $2}'` printf "%${indent}s %${lparcfg_data_spacing}s %${lparcfg_data_spacing}s\n" " " "$this_stat:" "${this_value##\ }" fi done # Include Desired Memory value from /proc/ppc64/lparcfg stat=`grep "^DesMem" $lparcfg_file` if [ ! -z "${stat}" ]; then this_stat=`echo $stat | awk -F= '{print $1}'` this_value=`echo $stat | awk -F= '{print $2}'` printf "%${indent}s %${lparcfg_data_spacing}s %${lparcfg_data_spacing}s\n" " " "$this_stat:" "$this_value MB" fi } function print_entitlement_data { echo "Entitlement Information:" for stat in `cat $lparcfg_file`; do if echo $stat | grep "^entitled_memory\|^mapped_entitled_memory\|^entitled_memory_weight\|entitled_memory_pool_size\|^backing_memory\|^cmo_enabled\|^cmo_faults\|^cmo_fault_time_usec\|cmo_primary_psp\|^cmo_secondary_psp\|^coalesced_bytes\|^pool_coalesced_bytes" >/dev/null; then this_stat=`echo $stat | awk -F= '{print $1}'` this_value=`echo $stat | awk -F= '{print $2}'` printf "%${indent}s %${lparcfg_data_spacing}s %${lparcfg_data_spacing}s\n" " " "$this_stat:" "$this_value" fi done } function print_cmm_stats { # CMM kernel parameters echo "CMM Statistics:" local path=/sys/module/cmm/parameters pushd $path >/dev/null 2>&1 if [ $? -ne 0 ] ; then printf "%${indent}s Could not get CMM Statistics.\n" " " return fi for stat in `find . -mindepth 1 -maxdepth 1 -print`; do printf "%${indent}s %${devstat_data_spacing}s %${devstat_data_spacing}s\n" " " "${stat#\.\/}:" "`cat $stat`" done popd >/dev/null # CMM statistics local path=/sys/devices/system/cmm/cmm0 pushd $path >/dev/null 2>&1 if [ $? -ne 0 ] ; then return fi for stat in `find . -mindepth 1 -maxdepth 1 -print`; do printf "%${indent}s %${devstat_data_spacing}s %${devstat_data_spacing}s\n" " " "${stat#\.\/}:" "`cat $stat`" done popd >/dev/null } function print_vio_bus_stats { echo "VIO Bus Statistics:" local found=0 local path=/sys/bus/vio pushd $path >/dev/null 2>&1 if [ $? -ne 0 ] ; then printf "%${indent}s Could not get VIO Bus Statistics.\n" " " return fi for stat in `find . -mindepth 1 -maxdepth 1 -name "cmo*" -print`; do found=1 printf "%${indent}s %${devstat_data_spacing}s %${devstat_data_spacing}s\n" " " "${stat#\.\/}:" "`cat $stat`" done popd >/dev/null if [ "$found" -eq "0" ]; then printf "%${indent}s No AMS Busses found.\n" " " fi } function print_vio_dev_stats { echo "VIO Device Statistics:" local found=0 local path=/sys/bus/vio/devices pushd $path >/dev/null 2>&1 if [ $? -ne 0 ] ; then printf "%${indent}s Could not get VIO Device Statistics.\n" " " return fi for dir in `find . -mindepth 1 -print`; do pushd $dir >/dev/null 2>&1 if [ $? -ne 0 ] ; then break fi # Skip printing devices that are not using entitlement if [ ! -e "cmo_entitled" ]; then popd >/dev/null continue fi value=`cat cmo_entitled` if [ ${value} -eq "0" ]; then popd >/dev/null continue fi NAME=$(cat devspec) echo " ${NAME##/*/}:" for stat in `find . -mindepth 1 -maxdepth 1 -name "cmo*" -print`; do found=1 printf "%${indent}s %${devstat_data_spacing}s %${devstat_data_spacing}s\n" " " "${stat#\.\/}:" "`cat $stat`" done popd >/dev/null done popd >/dev/null if [ "$found" -eq "0" ]; then printf "%${indent}s No AMS devices found.\n" " " fi } if [ ! -f $PSERIES_PLATFORM ]; then echo "$PSERIES_PLATFORM does not exist" echo "amstat: is not supported on the Unknown platform" exit 1; fi . $PSERIES_PLATFORM if [[ $platform != $PLATFORM_PSERIES_LPAR ]]; then echo "amstat: is not supported on the $platform_name platform" exit 1 fi # Verify CMO is present and enabled enabled=`cat $lparcfg_file | grep "^cmo_enabled" | awk -F= '{print $2}'` if [ -z $enabled ]; then echo "This system is not capable of Active Memory Sharing." exit -1 elif [ "$enabled" -eq "0" ]; then echo "Active Memory Sharing is not enabled on this system." exit -1 fi if [ -z $sleep_interval ]; then date print_meminfo_stats print_entitlement_data print_cmm_stats print_vio_bus_stats print_vio_dev_stats else while [ 1 ]; do date print_meminfo_stats print_entitlement_data print_cmm_stats print_vio_bus_stats print_vio_dev_stats sleep $sleep_interval echo done fi powerpc-utils-1.3.4/scripts/bootlist000077500000000000000000000343441315235264300176240ustar00rootroot00000000000000#! /bin/bash # Copyright (c) 2004 International Business Machines # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # bootlist - command to display and/or update the bootlist in nvram. # # author Nathan Fontenot # OFPATHNAME=/usr/sbin/ofpathname NVRAM=/usr/sbin/nvram PSERIES_PLATFORM=$(dirname $0)/pseries_platform # # usage # usage() { echo "Usage: $0 -m {normal|service|both} -o | -r" echo " $0 -m {normal|service|both} [-o | -r] -f " echo " $0 -m {normal|service|both} [-o | -r] " echo "View and update the system boot lists" echo "" echo " -m {normal|service|both}" echo " Specify the boot mode for boolist manipulation" echo " -o Display bootlist entries as logical device names" echo " -r Display bootlist entries as Open Firmware device" echo " path names" echo " -f file Read the boolist device names from file" echo " -?, --help display this help information and exit" echo " a space-separated list of devices, specified as" echo " logical device names or OF device path names," echo " depending on whether the -o or -r option is specified" echo "" echo "Additional optional arguments for ethernet devices:" echo " bserver=" echo " gateway=" echo " client=" echo " speed=, default=auto" echo " duplex=, default=auto" echo "" } # # update_eth_dev # When specifying an ethernet device for the bootlist we need to also get # the additional parameters for ethernet devices (i.e gateway, speed, ...) # # Please NOTE: this routine does depend on global variables # update_eth_dev() { local speed=auto local duplex=auto local bserver=0.0.0.0 local gateway=0.0.0.0 local client=0.0.0.0 local eth_index=$[$ctr] local index=$[$ctr + 1] local found=1 while [[ $found -eq 1 ]]; do found=0 case ${LOGICAL_NAMES[$index]} in speed*) speed=${LOGICAL_NAMES[$index]##*=} found=1 ;; duplex*) duplex=${LOGICAL_NAMES[$index]##*=} found=1 ;; bserver*) bserver=${LOGICAL_NAMES[$index]##*=} found=1 ;; gateway*) gateway=${LOGICAL_NAMES[$index]##*=} found=1 ;; client*) client=${LOGICAL_NAMES[$index]##*=} found=1 ;; esac if [[ $found -eq 1 ]]; then index=$[$index + 1] ctr=$[$ctr + 1] fi done # update the ethernet device OF_DEVPATH[$eth_index]=${OF_DEVPATH[$eth_index]}:speed=$speed,duplex=$duplex,$bserver,,$client,$gateway } # # parse_eth_info # Ethernet read from nvram (possibly) have additional data appended to # them specifying the gateway, speed, ... # # $1 ethernet device name # $2 ethernet device data # parse_eth_info() { local eth_name=$1 local eth_info=${2##*:} echo $eth_name # first the speed local item=${eth_info%%,*} if [[ -n $item ]]; then echo " speed = ${item##*=}" fi # then the duplex eth_info=${eth_info#*,} item=${eth_info%%,*} if [[ -n $item ]]; then echo " duplex = ${item##*=}" fi # then the BOOTP server eth_info=${eth_info#*,} item=${eth_info%%,*} if [[ -n $item ]]; then echo " BOOTP Server: $item" fi # then the Mask eth_info=${eth_info#*,} item=${eth_info%%,*} if [[ -n $item ]]; then echo " Mask: $item" fi # then the client eth_info=${eth_info#*,} item=${eth_info%%,*} if [[ -n $item ]]; then echo " Client: $item" fi # then the Gateway eth_info=${eth_info#*,} item=${eth_info%%,*} if [[ -n $item ]]; then echo " Gateway: $item" fi } # # get_logical_device_name # Translate the provided boot device to its logical device name # # $1 device name to convert # get_logical_device_name() { local devname=$1 local logical_name logical_name=`$OFPATHNAME -l $devname 2>/dev/null` if [[ $? -ne 0 ]]; then echo "" else echo $logical_name fi } # # get_of_device_name # Translate the provided boot device to its OF device name # # $1 device name to convert # get_of_device_name() { local devname=$1 local of_name of_name=`$OFPATHNAME $devname 2>/dev/null` if [[ $? -ne 0 ]]; then echo "" else echo $of_name fi } # # show_bootlist # Retrieve a bootlist from nvram and print its contents # # $1 bootlist to print # show_bootlist() { local devlist=$1 local i for i in `$NVRAM --print-config=${devlist} | sed 's/ /\n/g'`; do if [[ $TRANSLATE_NAMES = "yes" ]]; then name=`get_logical_device_name $i` if [[ -z $name ]]; then echo "Could not translate $i to logical device name" else case $name in eth*) parse_eth_info $name $i ;; *) echo $name ;; esac fi else echo $i fi done } # # Main # . $PSERIES_PLATFORM if [[ $platform != $PLATFORM_PSERIES_LPAR ]]; then echo "bootlist: is not supported on the $platform_name platform" exit 1 fi # make sure we can parse names if [[ ! -a $OFPATHNAME ]]; then echo "no $OFPATHNAME!!!" fi # make sure we can update nvram if [[ ! -a $NVRAM ]]; then echo "no $NVRAM!!!" fi BOOTLIST_MODE=unknown dm_to_part() { local dmp=$1 local dmdev=$2 local sddev=$3 local dmmapper partname=$(cat "/sys/block/$dmp/dm/name" 2>/dev/null | sed 's/[0-9]*$//g') diskname=$(cat "/sys/block/$dmdev/dm/name" 2>/dev/null) delim=${partname##$diskname} dmpmajmin=$(cat "/sys/block/$dmp/dev" 2>/dev/null) dmdevmajmin=$(cat "/sys/block/$dmdev/dev" 2>/dev/null) for dmapper in /dev/mapper/* ; do dmajor=$(stat -L --format="%t" $dmapper 2>/dev/null) dminor=$(stat -L --format="%T" $dmapper 2>/dev/null) dmajmin=$(printf "%d:%d" 0x$dmajor 0x$dminor) if [[ "$dmajmin" = "$dmdevmajmin" ]]; then dmmapper=$dmapper; break; fi done kpartx -p $delim -l $dmmapper | while read kp ; do kpname=${kp%% *} tmajor=$(stat -L --format="%t" /dev/mapper/$kpname 2>/dev/null) tminor=$(stat -L --format="%T" /dev/mapper/$kpname 2>/dev/null) tmajmin=$(printf "%d:%d" 0x$tmajor 0x$tminor) if [[ "$tmajmin" = "$dmpmajmin" ]]; then partstart=${kp##* } for part in `ls -1d /sys/block/$sddev/$sddev*`; do pstart=$(cat $part/start 2>/dev/null) if [[ "$pstart" -eq "$partstart" ]] ; then echo "${part##*/}" return fi done fi done } add_logical() { local DEVNAME=$1 local major minor majmin devno local startctr=$ctr if [[ ! -e $DEVNAME ]]; then DEVNAME=/dev/$DEVNAME fi if [[ ! -e $DEVNAME ]]; then LOGICAL_NAMES[$ctr]=$1 ctr=$[$ctr + 1] return fi major=$(stat -L --format="%t" $DEVNAME 2>/dev/null) minor=$(stat -L --format="%T" $DEVNAME 2>/dev/null) majmin=$(printf "%d:%d" 0x$major 0x$minor) # Look for a matching multipath device for dm in /sys/block/dm*; do dmdev=${dm##*/} devno=$(cat $dm/dev 2>/dev/null) devmaj=${devno%:*} devmin=${devno#*:} if [[ ! -d $dm/slaves ]] ; then # Old kernel for which there is no good way to reliably map # a kpartx device with its parent break; fi if [[ ! -d $dm/dm ]] ; then # Old kernel for which there is no good way to reliably map # a kpartx device with its parent break; fi if [[ "$devno" = "$majmin" ]]; then for slave in $dm/slaves/*; do slavedev=${slave##*/} if [[ "$slavedev" == dm-* ]] ; then for slave2 in $slave/slaves/*; do slavedev2=${slave2##*/} if [[ "$slavedev2" == dm-* ]] ; then # dmdev is an LV on physical multipath partition for slave3 in $slave2/slaves/*; do slavedev3=${slave3##*/} partdev=$(dm_to_part $slavedev $slavedev2 $slavedev3) if [[ ! -z "$partdev" ]] ; then LOGICAL_NAMES[$ctr]=$partdev ctr=$[$ctr + 1] fi done else # /sys/block/dm-2/slave/dm-0/slaves/sdb kp=$(kpartx -l /dev/$slavedev) if [[ -z "$kp" ]] ; then # dmdev is an LV on physical multipath # disk LV->DMDEV->DEV LOGICAL_NAMES[$ctr]=$slavedev2 ctr=$[$ctr + 1] else # dmdev is multipath partition of slave # DMP->DMDEV->DEV partdev=$(dm_to_part $dmdev $slavedev $slavedev2) if [[ ! -z "$partdev" ]] ; then LOGICAL_NAMES[$ctr]=$partdev ctr=$[$ctr + 1] fi fi fi done else # DMDEV is a multipath device on a physical device or # a LV on a disk partition LOGICAL_NAMES[$ctr]=$slavedev ctr=$[$ctr + 1] fi done fi done if [[ "$startctr" = "$ctr" ]] ; then LOGICAL_NAMES[$ctr]=$1 ctr=$[$ctr + 1] fi } # # Parse the command line arguements and put them into two parallel # arrays, one to hold the logical device name and one to hold the # corresponding open firmware device path. # typeset -i ctr=0 while [[ -n $1 ]]; do if [[ $1 = "-o" ]]; then DISPLAY_BOOTLIST=yes TRANSLATE_NAMES=yes elif [[ $1 = "-r" ]]; then DISPLAY_BOOTLIST=yes elif [[ $1 = "-m" ]]; then shift if [[ ! -n $1 ]]; then echo "did not specify \"normal\" or \"service\" mode with -m" >&2 usage exit -1 fi if [[ $1 = "normal" ]]; then BOOTLIST_MODE=boot-device elif [[ $1 = "service" ]]; then BOOTLIST_MODE=diag-device elif [[ $1 = "both" ]]; then BOOTLIST_MODE=$1 else echo "invalid mode specified with -m; must be \"normal\", \"service\" or \"both\"" >&2 usage exit -1 fi elif [[ $1 = "-f" ]]; then # get bootlist names from specified file if [[ ! -a $2 ]]; then echo "file $2 does not exist" >&2 fi for i in `cat $2 2>/dev/null`; do add_logical $i done shift elif [[ $1 = -* ]]; then # catch any illegal flags here usage exit -1 else # add this element to the array add_logical $1 fi shift done if [[ ${BOOTLIST_MODE} = "unknown" ]]; then echo "The boot mode must be specified with the -m option" >&2 usage exit -1 fi # Now we need to convert all of the logical device names to # open firmware device paths. if [[ ${#LOGICAL_NAMES[*]} -ne 0 ]]; then ctr=0 while [[ $ctr -lt ${#LOGICAL_NAMES[*]} ]]; do OF_DEVPATH[$ctr]=`get_logical_device_name ${LOGICAL_NAMES[$ctr]}` if [[ -z ${OF_DEVPATH[$ctr]} ]]; then # See if this is an OF pathname OF_DEVPATH[$ctr]=`get_of_device_name ${LOGICAL_NAMES[$ctr]}` fi if [[ -z ${OF_DEVPATH[$ctr]} ]]; then echo "Device ${LOGICAL_NAMES[$ctr]} does not appear to be valid." >&2 else # See if this is an ethernet adapter. If so, the next entries # may be parameters for the bootlist entry. ethdev=`get_logical_device_name ${OF_DEVPATH[$ctr]}` ethdev=${ethdev%%[0-9]*} if [[ $ethdev = "eth" ]]; then update_eth_dev fi # bootlist entries cannot exceed more than 255 chars if [[ ${#OF_DEVPATH[$ctr]} -gt 255 ]]; then echo "Bootlist entries cannot exceed 255 characters" >&2 echo "${OF_DEVPATH[$ctr]}" >&2 exit -1 fi fi ctr=$[$ctr + 1] done # We cannot have a bootlist with more than five entries if [[ ${#OF_DEVPATH[*]} -gt 5 ]]; then echo "More than five entries cannot be specified in the bootlist" >&2 exit -1 fi # update the bootlist in nvram if [[ $BOOTLIST_MODE = "both" ]]; then $NVRAM --update-config "boot-device=${OF_DEVPATH[*]}" -pcommon if [[ $? -ne 0 ]]; then echo "Could not update service-mode bootlist" >&2 fi $NVRAM --update-config "diag-device=${OF_DEVPATH[*]}" -pcommon if [[ $? -ne 0 ]]; then echo "Could not update normal-mode bootlist" >&2 fi else $NVRAM --update-config "${BOOTLIST_MODE}=${OF_DEVPATH[*]}" -pcommon if [[ $? -ne 0 ]]; then echo "Could not update bootlist!" >&2 fi fi fi # Display the bootlist if desired if [[ $DISPLAY_BOOTLIST = "yes" ]]; then if [[ $BOOTLIST_MODE = "both" ]]; then show_bootlist "boot-device" show_bootlist "diag-device" else show_bootlist $BOOTLIST_MODE fi fi powerpc-utils-1.3.4/scripts/hvcsadmin000077500000000000000000000536461315235264300177470ustar00rootroot00000000000000#!/usr/bin/perl -w # IBM "hvcsadmin": HVCS driver 'helper' application # # Copyright (c) 2004, 2005 International Business Machines. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # Author(s): Ryan S. Arnold # # This application provides a simple command line interface for simplifying # the management of hvcs. # # For further details please reference man page hvcsadmin.8 use strict; use File::Basename; use vars '$app_name'; $app_name = "hvcsadmin"; use vars '$app_version'; $app_version = "1.0.0"; use vars '$driver'; $driver = "hvcs"; use vars '$global_node_name'; $global_node_name = "hvcs"; use vars '$noisy'; $noisy = 0; use Getopt::Long; sub verboseprint( $ ) { my $output = shift; if($noisy > 1) { print "$output"; } } sub statusprint( $ ) { my $output = shift; if($noisy > 0 ) { print "$output"; } } sub errorprint( $ ) { my $output = shift; print "$output"; } # Simply output the version information about this helper application. sub versioninfo { print "IBM ", $app_name, " version ",$app_version,"\n"; print "Copyright (C) 2004, IBM Corporation.\n"; print "Author(s) Ryan S. Arnold\n"; } # Help information text displayed to the user when they invoke the script with # the -h tag. sub helpinfo { print "Usage: ", $app_name, " [options]\n"; print "Options:\n"; print " -all"; print "\t\t\tClose all open vty-server adapter connections.\n"; print "\n"; print " -close "; print "\tClose the vty-server adapter connection for the\n"; print "\t\t\t$driver device node specified in the option.\n"; print "\n"; print " -console "; print "\tWhich /dev/$driver\* node provides the console for\n"; print "\t\t\tthe option specified partition?\n"; print "\n"; print " -help"; print "\t\t\tOutput this help text.\n"; print "\n"; print " -node "; print "\tWhich vty-server adapter is mapped to the option\n"; print "\t\t\tspecified /dev/$driver\* node?\n"; print "\n"; print " -noisy"; print "\t\t\tThis is a stackable directive denoting the verbosity\n"; print "\t\t\tof the $app_name script. The default noise level of\n"; print "\t\t\t'0' makes $app_name silent on success but verbose on\n"; print "\t\t\terror. A noise level of '1' will output additional\n"; print "\t\t\tsuccess information. A noisy level of '2' will\n"; print "\t\t\toutput $app_name script trace information.\n"; print "\n"; print "\t\t\tNOTE: options for which $app_name queries data are\n"; print "\t\t\tnot squelched with the default noise level.\n"; print "\n"; print " -rescan"; print "\t\tDirect the hvcs driver to rescan partner info\n"; print "\t\t\tfor all vty-server adapters.\n"; print "\n"; print " -status"; print "\t\tOutput a table with each row containing a vty-server,\n"; print "\t\t\tadapter, its /dev/$driver\* device node mapping, and\n"; print "\t\t\tits connection status. \"vterm_state:0\" means it is\n"; print "\t\t\tfree and \"vterm_state:1\" means the vty-server is\n"; print "\t\t\tconnected to its vty partner adapter.\n"; print "\n"; print " -version\t\tOutput the ", $app_name, " script's version number.\n"; print "\n"; } sub rescan { # Determine the sysfs path and driver name programatically because these can # change. my $val; my $local_driver; my $driver_path; verboseprint("$app_name: initiating rescan of all vty-server adapter partners.\n"); #use systool to find the vio devices which we want to close local *SYSTOOL; open SYSTOOL, "systool -b vio -D -p |" or die "systool: $!"; while (my $line = ) { ($val) = ($line =~ /^\s*Driver = "(.*)"\s*$/); if(defined $val) { $local_driver = $1; $driver_path = ""; next; } ($val) = ($line =~ /^\s*Driver path = "(.*)"\s*$/); if(defined $val) { $driver_path = $1; if ($local_driver eq $driver) { `echo 1 > $driver_path/rescan`; statusprint("$app_name: $driver driver rescan executed.\n"); close SYSTOOL; exit; } next; } } errorprint("$app_name: $driver sysfs entry or $driver rescan attribute not found.\n"); close SYSTOOL; } sub closeall { # Programatically locate all the vty-server adapters and close their # connections (or at least attempt to). One or more closures may fail if # there is an application using the device node that is mapped to the # vty-server adapter that is being closed. my $val; my $local_driver; my $local_device; my $vterm_state; my $device_path; local *SYSTOOL; #use systool to find the vio devices which we want to close open SYSTOOL, "systool -b vio -D -A vterm_state -p |" or die "systool: $!"; while (my $line = ) { ($val) = ($line =~ /^\s*Driver = "(.*)"\s*$/); if(defined $val) { $local_driver = $1; $local_device = ""; $device_path = ""; next; } ($val) = ($line =~ /^\s*Device path = "(.*)"\s*$/); if(defined $val) { $device_path = $1; next; } ($val) = ($line =~ /^\s*Device = "(.*)"\s*$/); if(defined $val) { $local_device = $1; next; } ($val) = ($line =~ /^\s*vterm_state\s*= "(.*)"\s*$/); if(defined $val) { $vterm_state = $1; if (($local_driver eq $driver) and ($vterm_state eq "1")) { `echo 0 > $device_path/vterm_state`; statusprint("$app_name: closed vty-server\@$local_device partner adapter connection.\n"); } next; } } close SYSTOOL; } # This is a input validation routine which checks a user entered device path # to determine if the device index is in the proper range. sub validindex( $ ) { my $dev_index = shift; verboseprint("$app_name: is $dev_index a valid device node number? ...\n"); # We didn't find an invalid number that starts with 0 and has more digits if ($dev_index =~ /(^0.+$)/) { errorprint("$app_name: \"$dev_index\" is an invalid device node number.\n"); return -1; } verboseprint("$app_name: $dev_index is a valid device node index.\n"); return 0; } # Checks to see if the user entered device node exists in the /dev directory. # If this unexpectedly indicates that there is no device it may be because # udev is managing the /dev directory and the hvcs driver has not yet been # inserted. sub finddeventry( $ $ ) { my $node_name = shift; my $dev_number = shift; my $device_path = "/dev/$node_name$dev_number"; verboseprint("$app_name: is $device_path in /dev? ...\n"); if(! -e "$device_path") { errorprint("$app_name: $device_path not found in /dev.\n"); return -1; } verboseprint("$app_name: found $device_path in /dev.\n"); return 0; } sub is_driver_installed() { my $val = ""; my $local_driver = ""; my $driver_path = ""; verboseprint("$app_name: is $driver loaded.\n"); local *SYSTOOL; open SYSTOOL, "systool -b vio -D -p|" or die "systool: $!"; while (my $line = ) { ($val) = ($line =~ /^\s*Driver = "(.*)"\s*$/); if(defined $val) { $local_driver = $1; $driver_path = ""; next; } ($val) = ($line =~ /^\s*Driver path = "(.*)"\s*$/); if(defined $val) { $driver_path = $1; # grab only the Driver,Driver path pair for $driver if ($local_driver eq $driver) { verboseprint("$app_name: verified that $driver is loaded at $driver_path\.\n"); close SYSTOOL; return $driver_path; } next; } } errorprint("$app_name: $driver is not loaded.\n"); close SYSTOOL; return ""; } # Verify that the systools package is installed. This package is required for # using this scripts because this script uses systools to make sysfs queries. # It then strips relevant data from the systool queries for use in additional # features. sub findsystools() { #--------------- Look for the systool application ----------------------- local *WHICH; open WHICH, "which systool|"; my @whicharray = ; my $whichline = join("\n", @whicharray); chomp($whichline); close WHICH; verboseprint("$app_name: looking for \"systool\" application.\n"); if ($whichline eq "") { errorprint("$app_name: systool is not installed or not in the path?\n"); errorprint("$app_name: systool is required by the $app_name script.\n"); return -1; } verboseprint("$app_name: found \"systool\" at $whichline\.\n"); return 0; } # This function is a helper function that is used to return a sysfs hvcs # device path based upon a partition number. This function always looks for # the zeroeth indexed partner adapter, meaning it will always return the path # to the console device for the selected target partition. sub get_device_path_by_partition ( $ ) { my $target_partition = shift; my $local_driver; my $found_partition; my $found_slot; my $device_path; my $val; verboseprint("$app_name: fetching device path for partition $target_partition\.\n"); local *SYSTOOL; open SYSTOOL, "systool -b vio -D -A current_vty -p|" or die "systool: $!"; while (my $line = ) { ($val) = ($line =~ /^\s*Driver = "(.*)"\s*$/); if(defined $val) { $local_driver = $1; $device_path = ""; $found_partition = ""; $found_slot = ""; next; } ($val) = ($line =~ /^\s*Device path = "(.*)"\s*$/); if(defined $val) { $device_path = $1; next; } # Grab the partition number out of clc, e.g. the numeric index # following the V, and grab the slot number, e.g. the numeric index # following the C: "U9406.520.100048A-V15-C0" ($val) = ($line =~ /^\s*current_vty\s*= "\w+\.\w+\.\w+-V(\d+)-C(\d+)"\s*$/); if(defined $val) { $found_partition = $1; $found_slot = $2; if (($local_driver eq $driver) and ($target_partition eq $found_partition) and ($found_slot eq "0")) { verboseprint("$app_name: found console device for partition $target_partition at $device_path\.\n"); return $device_path; } } } statusprint("$app_name: could not find device path for partition $target_partition\.\n"); return ""; } # This function is a helper function that is used to return a sysfs path based # upon an index number. The "index" is the number that is part of the hvcs # device path name. For instance, in "/dev/hvcs2", the number '2' is refered # to as the "index". Additionally, the sysfs entry keeps track of the index # number for the hvcs entries in sysfs so there is a correlation between the # data kept in the sysfs entry and the actual /dev/hvcs* entry. sub get_device_path_by_index ( $ ) { my $target_index = shift; my $device_path; my $index; my $local_driver; my $val; verboseprint("$app_name: fetching device path for index $target_index\.\n"); local *SYSTOOL; open SYSTOOL, "systool -b vio -D -A index -p|" or die "systool: $!"; while (my $line = ) { ($val) = ($line =~ /^\s*Driver = "(.*)"\s*$/); if(defined $val) { $local_driver = $1; $device_path = ""; $index = ""; next; } ($val) = ($line =~ /^\s*Device path = "(.*)"\s*$/); if(defined $val) { $device_path = $1; next; } ($val) = ($line =~ /^\s*index\s*= "(.*)"\s*$/); if(defined $val) { $index = $1; if (($local_driver eq $driver) and ($index eq $target_index)) { verboseprint("$app_name: found device path for device index $target_index at $device_path\.\n"); close SYSTOOL; return $device_path; } next; } } statusprint("$app_name: /dev/$global_node_name$target_index does not map to a vty-server adapter\.\n"); close SYSTOOL; return ""; } # This function takes a sysfs path to an hvcs adapter and displays it in a # formatted manner. This path is gathered using one of the previous path # retrieval functions. Generally devices are displayed in a sequence and a # table is created out of these details though they can be displayed # individually as well. sub displaybypath( $ ) { my $path = shift; verboseprint("$app_name: displaying status information for $path\.\n"); if ($path eq "") { errorprint("$app_name: displaybypath( \$ ) path parameter is empty.\n"); return -1; } if(! -e "$path/current_vty") { errorprint("$app_name: $path/current_vty attribute does not exist.\n"); exit; } verboseprint("$app_name: $path/current_vty attribute exists.\n"); if(! -e "$path/index") { errorprint("$app_name: $path/index attribute does not exist.\n"); exit; } verboseprint("$app_name: $path/index attribute exists.\n"); if(! -e "$path/vterm_state") { errorprint("$app_name: $path/vterm_state attribute does not exist.\n"); exit; } verboseprint("$app_name: verified that $path/vterm_state attribute exists.\n"); local *CURRENT_VTY; open CURRENT_VTY, "$path/current_vty"; chomp (my $current_vty = ); close CURRENT_VTY; # parse the CLC, nasty as it may be my ($machine, $partition, $slot) = $current_vty =~ /(\w+\.\w+\.\w+)-V(\d+)-C(\d+)$/; local *VTERM_STATE; open VTERM_STATE, "$path/vterm_state"; chomp (my $vterm_state = ); close VTERM_STATE; local *INDEX; open INDEX, "$path/index"; chomp (my $device_index = ); close INDEX; #/sys/devices/vio/30000005 my ($vty_server) = $path =~ /.+(3[[:xdigit:]]+)$/; print "vty-server\@$vty_server partition:$partition slot:$slot /dev/$driver$device_index vterm-state:$vterm_state\n"; } # This function simply takes a /dev/hvcs* entry and displays the relevant # sysfs entry data about that device node. sub querynode( $ ) { my $dev_node = shift; my $dev_index = getindex( $dev_node ); my $dev_name = getnodename( $dev_node ); verboseprint("$app_name: querying status information for node $dev_node\.\n"); if ($dev_name ne $global_node_name) { errorprint("$app_name: $dev_node is an invalid device node name.\n"); exit; } if (validindex($dev_index)) { exit; } if (finddeventry($dev_name, $dev_index)) { exit; } #check modinfo version of the hvcs module? my $path = get_device_path_by_index( $dev_index ); if ($path eq "") { return; } displaybypath( $path ); } # This function displays the sysfs information about a console to a specific # partition. This function should only display output if a device is found # that maps to a zero slotted vty-server adapter, since only slot 0 adapters # are console adapters. sub queryconsole( $ ) { my $partition = shift; my $path = get_device_path_by_partition( $partition ); if ($path eq "") { return; } displaybypath( $path ); } sub status { local *DIRHANDLE; opendir(DIRHANDLE, "/dev"); my @allentries = sort readdir DIRHANDLE; closedir DIRHANDLE; my $path = ""; my $count = 0; verboseprint("$app_name: gathering status for all vty-server adapters.\n"); verboseprint("$app_name: some device nodes won't be mapped to vty-server adapters.\n"); foreach my $entry (@allentries) { if( $entry =~ /$global_node_name(\d)$/) { $path = get_device_path_by_index( $1 ); if ($path ne "") { displaybypath( $path ); $count++; } } $path = ""; } if ($count eq 0) { print("$app_name: no hvcs adapters found\.\n"); } } sub getindex ( $ ) { $_ = shift; /$global_node_name([0-9]+$)/; if(defined $1) { return $1; } else { return -1; } } sub getnodename ( $ ) { $_ = shift; /($global_node_name)[0-9]+$/; if(defined $1) { return $1; } else { return ""; } } sub closedevice ( $ ){ my $parameter = shift; my $node_name = getnodename( $parameter ); my $node_index = getindex( $parameter ); #--------------- Is the specified device name valid? -------------------- if ($node_name ne "$global_node_name") { errorprint("$app_name: $parameter is an invalid device node name.\n"); exit; } #--------------- Is the specified device index reasonable? -------------- if (validindex($node_index)) { exit; } #--------------- Does the /dev/ entry exist ----------------------------- if (finddeventry($node_name, $node_index)) { exit; } #check modinfo version of the hvcs module #--------------- Gather sysfs info from systool ------------------------- my $device_path = get_device_path_by_index($node_index); if ($device_path eq "") { exit; } verboseprint("$app_name: vty-server adapter $device_path maps to /dev/$node_name$node_index\.\n"); if(! -e "$device_path/vterm_state"){ errorprint("$app_name: vterm_state attribute does not exist.\n"); exit; } verboseprint("$app_name: verified that $device_path/vterm_state attribute exists.\n"); local *CAT_VTERM_STATE; open CAT_VTERM_STATE, "cat $device_path/vterm_state|"; my $catval = ; close CAT_VTERM_STATE; if ($catval =~ /^0$/) { statusprint("$app_name: vty-server adapter $device_path is already disconnected.\n"); exit; } verboseprint("$app_name: preparing to terminate vty-server connection at $device_path\.\n"); system("echo 0 > $device_path/vterm_state"); local *CAT_STATE; open CAT_STATE, "cat $device_path/vterm_state|"; my $cat = ; close CAT_STATE; if ($cat !~ /^0$/) { errorprint("$app_name: vty-server adapter $device_path disconnection failed.\n"); errorprint("$app_name: please check dmesg for further information.\n"); exit; } my ($vty_server) = $device_path =~ /.+(3\d+)$/; statusprint("$app_name: /dev/node/$node_name$node_index is mapped to vty-server\@$vty_server\.\n"); statusprint("$app_name: closed vty-server\@$vty_server partner adapter connection.\n"); } my $PSERIES_PLATFORM = dirname(__FILE__) . "/pseries_platform"; my $perldumpenv='perl -MData::Dumper -e '."'". '\$Data::Dumper::Terse=1;print Dumper(\%ENV);'."'"; eval '%ENV=('.$1.')' if `bash -c " . $PSERIES_PLATFORM; $perldumpenv"` =~ /^\s*\{(.*)\}\s*$/mxs; if ($ENV{'platform'} != $ENV{'PLATFORM_PSERIES_LPAR'}) { print "$app_name: is not supported on the $ENV{'platform_name'} platform\n"; exit 1; } my $help = ''; my $version = ''; my $close_device = ''; my $all = ''; my $query_node = ''; my $query_console = ''; my $status = ''; my $rescan = ''; my $num_options = @ARGV; # -noisy is the only option that stacks GetOptions ( 'all' => \$all, 'help|?' => \$help, 'noisy+' => \$noisy,# noisy is incremental, # 0 : silent (except on error) [default] # 1 : status (successes) # 2 : verbose operation trace 'status' => \$status, 'rescan' => \$rescan, 'version' => \$version, 'node=s' => \$query_node, 'close=s' => \$close_device, 'console=s' => \$query_console, ); # An empty invocation of this script will result in the help text being # output. If help text has been specified then this script will terminate # after outputing the help text without completing further operations. if ($num_options == 0 || $help) { helpinfo(); exit; } if ($version) { versioninfo(); exit; } verboseprint("$app_name: executing in verbose mode.\n"); #--------------- Look for the systool application ----------------------- # The systool application is required for invoking most/many of these # operations so we'll express it as a standard requirement. if (findsystools()) { exit; } # DON'T rely on the module existence to determine whether $driver is # supported since it could have been built into the kernel. #--------------- Look for the $driver module in lsmod ------------------- if (!is_driver_installed()) { exit; } if ($status) { status(); exit; } if ($rescan) { rescan(); } if ($all) { closeall(); exit; } if ($close_device) { closedevice($close_device); exit; } if ($query_node) { querynode($query_node); exit; } if ($query_console) { queryconsole($query_console); exit; } exit; powerpc-utils-1.3.4/scripts/ibmvscsis.sh000077500000000000000000000065351315235264300204010ustar00rootroot00000000000000#! /bin/bash # IBM "ibmvscsis.sh": ibmvscsis init script # # Copyright (c) 2004, 2005 International Business Machines. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # Author: Ryan Arnold # # This file is tasked with testing for the existence of the ibmvscsis driver # and configuring the ibmvscsi server properly as indicated by the config file # located at /etc/ibmvscsis.conf # # For further details please reference man page ibmvscsis.sh.8 ### BEGIN INIT INFO # Provides: ibmvscsis # Required-Start: $syslog $remote_fs # Should-Start: iprinit iprupdate # Required-Stop: $syslog $remote_fs # Should-Stop: # Default-Start: 3 5 # Default-Stop: # Short-Description: configure this partition as virtual scsi server # Description: Based on /etc/ibmvscsis.conf, this partition # will export configured drives, partitions or loop mounted # files as SCSI drives to other partitions on this host. # Read the ibmvscsis.conf man page for further details. ### END INIT INFO DRIVER=ibmvscsis SYSFS=/sys/bus/vio/drivers/ibmvscsis CONFIG_FILE=/etc/ibmvscsis.conf APP=vscsisadmin # The existence of $SYSFS indicates that the module has been loaded or that # the driver is at least built into the kernel. if ! test -e $CONFIG_FILE ; then echo "$CONFIG_FILE file does not exist."; exit 6 fi # $APP is required to be in the path in order for this to work properly. It # is specified this way because the location may not be consistent across # distributions. app=`which $APP` if [ ! "$app" ]; then echo "$APP not found on \$PATH" exit 5 fi case "$1" in start) if ! test -e $SYSFS ; then echo "$DRIVER is not loaded, loading it for you." ret=`/sbin/modprobe $DRIVER 2>&1` if [ "$ret" == "FATAL: Module $DRIVER not found." ] ; then echo "$ret"; exit 5 fi fi $APP -start ;; stop) # If the module isn't loaded then exit if ! test -e $SYSFS ; then echo "$DRIVER module not loaded." exit 5 fi $APP -stop ;; status) # If the module isn't loaded then exit if ! test -e $SYSFS ; then echo "$DRIVER module not loaded." exit 5 fi $APP -status ;; restart) echo "Attempting to restart ibmvscsis configuration." # If the module isn't loaded then exit if ! test -e $SYSFS ; then echo "$DRIVER module not loaded." exit 5 fi $APP -stop $APP -start ;; *) echo "Usage: $0 {start|stop|status|restart}" exit 1 ;; esac powerpc-utils-1.3.4/scripts/ls-vdev000066400000000000000000000053161315235264300173370ustar00rootroot00000000000000#! /bin/bash # Copyright (c) 2010 International Business Machines # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # Author Brian King # # ls-vdev - This utility provides the HMC or IVM with name information for # virtual scsi adapters and devices # LSVDEV="ls-vdev" VERSION="0.1" LS="/bin/ls" GREP="/bin/grep" SED="/bin/sed" PSERIES_PLATFORM=$(dirname $0)/pseries_platform usage() { echo "Usage: $LSVDEV" echo "Provide information on Virtual SCSI adapters and devices" echo "" echo "Optional arguments." echo " -V Display version information and exit" echo " -h Display this help information and exit" echo "" } show_version() { echo "$LSVDEV: Version $VERSION" echo "Written by: Brian King " } . $PSERIES_PLATFORM if [[ $platform != $PLATFORM_PSERIES_LPAR ]]; then echo "$LSVDEV: is not supported on the $platform_name platform" exit 1 fi while getopts ":Vh" flag ; do case "$flag" in V) show_version exit 0 ;; h) usage exit 0 ;; \?) usage exit 1 ;; esac done # Look at every ibmvscsi (Virtual SCSI) device for dev in $($LS -d /proc/device-tree/vdevice/v-scsi* 2> /dev/null) ; do # find the slot so it can be used in sysfs slot=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/v-scsi@//") # there is only one host per device, assign it to the path's name for host in $($LS -d /sys/devices/vio/$slot/host* 2> /dev/null) ; do parent=$(echo $host | $SED -e "s/.*\///") host=$($LS -d /sys/devices/vio/$slot/host*/) # loop through the targets for this host. for t in $($LS -d $host/target* 2> /dev/null); do target=$(echo $($LS -d $t/$($LS $t | $GREP -v uevent | $GREP -v power | $GREP -v subsystem))) if [[ ! -d $target/block ]]; then name=$(echo $($LS -d $target/block*) | $SED -e "s/.*://") else name=$($LS $target/block) fi echo "$parent $name" done done done exit 0 # end powerpc-utils-1.3.4/scripts/ls-veth000077500000000000000000000043271315235264300173450ustar00rootroot00000000000000#! /bin/bash # Copyright (c) 2010 International Business Machines # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # Author Brian King # # ls-veth - This utility provides the HMC or IVM with name information for # virtual ethernet devices # LSVETH="ls-veth" VERSION="0.1" OFPATHNAME="/usr/sbin/ofpathname" CAT="/bin/cat" LS="/bin/ls" SED="/bin/sed" PSERIES_PLATFORM=$(dirname $0)/pseries_platform usage() { echo "Usage: $LSVETH " echo "Provide information on Virtual Ethernet devices" echo "" echo "Optional arguments." echo " -V Display version information and exit" echo " -h Display this help information and exit" echo "" } show_version() { echo "$LSVETH: Version $VERSION" echo "Written by: Brian King " } . $PSERIES_PLATFORM if [[ $platform != $PLATFORM_PSERIES_LPAR ]]; then echo "$LSVETH: is not supported on the $platform_name platform" exit 1 fi while getopts ":Vh" flag ; do case "$flag" in V) show_version exit 0 ;; h) usage exit 0 ;; \?) usage exit 1 ;; esac done # Look at every ibmveth (Virtual Ethernet) device for dev in $($LS -d /proc/device-tree/vdevice/l-lan* 2> /dev/null); do # use ofpathname to get the device name (i.e. eth0) name=$($OFPATHNAME -l $(echo $dev | $SED -e "s/\/proc\/device-tree//")) # get the physical location physloc=$(tr -d '\0' < $dev/ibm,loc-code) echo "$name $physloc" done exit 0 # end powerpc-utils-1.3.4/scripts/ls-vscsi000077500000000000000000000045111315235264300175210ustar00rootroot00000000000000#! /bin/bash # Copyright (c) 2010 International Business Machines # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # Author Brian King # # ls-vscsi - This utility provides the HMC or IVM with name information for # virtual scsi devices # LSVSCSI="ls-vscsi" VERSION="0.1" CAT="/bin/cat" LS="/bin/ls" SED="/bin/sed" PSERIES_PLATFORM=$(dirname $0)/pseries_platform usage() { echo "Usage: $LSVSCSI" echo "Provide information on Virtual devices" echo "" echo "Optional arguments." echo " -V Display version information and exit" echo " -h Display this help information and exit" echo "" } show_version() { echo "$LSVSCSI: Version $VERSION" echo "Written by: Brian King " } . $PSERIES_PLATFORM if [[ $platform != $PLATFORM_PSERIES_LPAR ]]; then echo "$LSVSCSI: is not supported on the $platform_name platform" exit 1 fi while getopts ":Vh" flag ; do case "$flag" in V) show_version exit 0 ;; h) usage exit 0 ;; \?) usage exit 1 ;; esac done # Look at every ibmvscsi (Virtual SCSI) device for dev in $($LS -d /proc/device-tree/vdevice/v-scsi* 2> /dev/null) ; do # pull the physical location physloc=$(tr -d '\0' < $dev/ibm,loc-code) # find the slot so it can be used in sysfs slot=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/v-scsi@//") # there is only one host per device, assign it to the path's name for host in $($LS -d /sys/devices/vio/$slot/host*) ; do name=$(echo $host | $SED -e "s/.*\///") echo "$name $physloc" done done exit 0 # end powerpc-utils-1.3.4/scripts/lsdevinfo000077500000000000000000000410301315235264300177440ustar00rootroot00000000000000#! /bin/bash # Copyright (c) 2004 International Business Machines # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.# # Author Santiago Leon # # lsdevinfo - This utility provides the HMC or IVM with name information for # virtual devices so they can be matched against the VIOS names. # # TODO: Show more device info # (currently only the essential information is displayed) # Show MPIO devices # LSDEVINFO="lsdevinfo" VERSION="0.1" OFPATHNAME="/usr/sbin/ofpathname" CAT="/bin/cat" LS="/bin/ls" GREP="/bin/grep" SED="/bin/sed" TR="/usr/bin/tr" OD="/usr/bin/od" CUT="/usr/bin/cut" PSERIES_PLATFORM=$(dirname $0)/pseries_platform # Usage statemnet usage() { echo "Usage: $LSDEVINFO [-q criteria] [-F format] [-R] [-c] [-h]" echo "Provide information on Virtual devices" echo "" echo "Optional arguments." echo " -q criteria Specifies a criteria to select which devices are" echo " to be displayed." echo " -F format Specifies the set of attributes to be displayed." echo " -R Recursively display children of selected devices" echo " -c Display output as a comma separated list for" echo " each device." echo " -V Display version information and exit" echo " -h Display this help information and exit" echo "" } show_version() { echo "$LSDEVINFO: Version $VERSION" echo "Written by: Santiago Leon " } # check_criteria # Modifies $show if the the attribute in the first parameter matches the # criteria from the command line. # The operands (=, !=, and LIKE) are defined the the lsdevinfo spec. # check_criteria() { attr=$1 attr_val=${!attr} if [[ $criteria =~ "!=" ]] ; then # Pull out the operands from the criteria (everything to the left of # the operand, and everything on the right of the operand) crit_opd1=$(echo $criteria | $SED -e "s/[ ]*!=.*//") crit_opd2=$(echo $criteria | $SED -e "s/.*!=[ ]*//") # Perfom the comparison of the attribute and its value if [[ $crit_opd1 == $attr && $crit_opd2 != $attr_val ]]; then show=1 fi elif [[ $criteria =~ "=" ]]; then crit_opd1=$(echo $criteria | $SED -e "s/[ ]*=.*//") crit_opd2=$(echo $criteria | $SED -e "s/.*=[ ]*//") if [[ $crit_opd1 == $attr && $crit_opd2 == $attr_val ]]; then show=1 fi elif [[ $criteria =~ " LIKE " ]]; then crit_opd1=$(echo $criteria | $SED -e "s/[ ]*LIKE.*//") crit_opd2=$(echo $criteria | $SED -e "s/.*LIKE[ ]*//") if [[ $crit_opd1 == $attr && $attr_val =~ $crit_opd2 ]]; then show=1 fi else echo "Criteria must have =, !=, or LIKE operand. Exiting." exit 1 fi } # print_attr # Prints the attribute in the first parameter if the name of the attribute is # in the argument of the -F command line parameter. # print_attr () { attr=$1 attr_val=${!attr} if [[ $format == "" || $format =~ $attr ]]; then echo -ne $separator$begin$attr=\"$attr_val\" fi } # # Main # # default: CR separated list comma_sep=0 # default: non recursive recursive=0 # default: display all devices criteria="" # default: display all attributes format="" . $PSERIES_PLATFORM if [[ $platform != $PLATFORM_PSERIES_LPAR ]]; then echo "$LSDEVINFO: is not supported on the $platform_name platform" exit 1 fi while getopts "cRq:F:Vh" flag ; do case "$flag" in c) comma_sep=1;; R) recursive=1;; q) criteria=$OPTARG;; F) format=$OPTARG;; V) show_version exit 0 ;; h) usage exit 0 ;; \?) usage exit 1 ;; :) echo "Option -$OPTARG requires an argument." exit 1 ;; esac done # Criteria can't have conjunctions (by the spec) if [[ $criteria =~ " AND " ]] ; then echo "AND conjunction not supported. Exiting" exit 1 fi # Fill variables for the two display formats (regular and comma-separated) so # we can print the output in a single place. if [[ $comma_sep -eq 0 ]]; then dev_begin="device:\n" separator="\n" begin="\t" dev_end="\n\n" path_begin="\n\npath:\n\tparent=" path_end="" else dev_begin="" separator="," dev_end="\n" path_begin=",path=(parent=" path_end=")" fi show_eth () { # if there is a criteria in the command line, check if this device matches if [[ $criteria != "" ]] ; then show=0 check_criteria "name" check_criteria "physloc" check_criteria "uniquetype" check_criteria "class" check_criteria "subclass" check_criteria "type" check_criteria "prefix" check_criteria "driver" check_criteria "status" fi # print the info only if the device matches the criteria if [[ $show -ne 0 ]]; then # the name attribute is always printed echo -ne $dev_begin$begin"name="\"$name\" print_attr "uniquetype" print_attr "class" print_attr "subclass" print_attr "type" print_attr "prefix" print_attr "driver" print_attr "status" # if there is no format in the command line or it contains "path", then # print the path. Doesn't use print_attr because all of the fields in # the path attribute should be printed. if [[ $format == "" || $format =~ "path" ]]; then echo -ne $path_begin\"$parent\" echo -ne $separator$begin"physloc="\"$physloc\" echo -ne $separator$begin"connection="\"$connection\" echo -ne $path_end fi # done with this device echo -ne $dev_end fi } # Look at every vNIC device for dev in $($LS -d /proc/device-tree/vdevice/vnic* 2> /dev/null); do # use ofpathname to get the device name (i.e. eth0) name=$($OFPATHNAME -l $(echo $dev | $SED -e "s/\/proc\/device-tree//")) connection=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/l-lan@//") parent="vio" # get the physical location physloc=$(tr -d '\0' < $dev/ibm,loc-code) uniquetype="adapter/vdevice/IBM,vnic" class="adapter" subclass="vdevice" type="IBM,vnic" prefix="eth" driver="ibmvnic" status=1 show=1 show_eth done # Look at every ibmveth (Virtual Ethernet) device for dev in $($LS -d /proc/device-tree/vdevice/l-lan* 2> /dev/null); do # use ofpathname to get the device name (i.e. eth0) name=$($OFPATHNAME -l $(echo $dev | $SED -e "s/\/proc\/device-tree//")) connection=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/l-lan@//") parent="vio" # get the physical location physloc=$(tr -d '\0' < $dev/ibm,loc-code) uniquetype="adapter/vdevice/IBM,l-lan" class="adapter" subclass="vdevice" type="IBM,l-lan" prefix="eth" driver="ibmveth" status=1 show=1 show_eth done # Look for PCI ethernet devices for pci_dev in $($LS -d /proc/device-tree/pci* 2> /dev/null); do for dev in $($LS -d $pci_dev/ethernet* 2> /dev/null); do # use ofpathname to get the device name (i.e. eth0) name=$($OFPATHNAME -l $(echo $dev | $SED -e "s/\/proc\/device-tree//")) connection=$(echo $pci_dev | $SED -e "s/\/proc\/device-tree\/pci@//") parent="pci" # get the physical location physloc=$($CAT $dev/ibm,loc-code) type="$($OD -t x2 $dev/vendor-id $dev/device-id | $CUT -f3,5 -d ' ' -s --output-delimiter='')" uniquetype="adapter/pci/$type" class="adapter" subclass="pci" prefix="eth" driver=$($LS -l /sys/class/net/$name/device/driver | $SED -e "s/^.*\///") status=1 show=1 show_eth done done # Look at every ibmvscsi (Virtual SCSI) device for dev in $($LS -d /proc/device-tree/vdevice/v-scsi* 2> /dev/null) ; do # pull the physical location physloc=$(tr -d '\0' < $dev/ibm,loc-code) hostphysloc=$physloc connection=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/v-scsi@//") # find the slot so it can be used in sysfs slot=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/v-scsi@//") # there is only one host per device, assign it to the path's name for host in $($LS -d /sys/devices/vio/$slot/host*) ; do parent=$(echo $host | $SED -e "s/.*\///") name=$parent uniquetype="adapter/vdevice/IBM,v-scsi" class="adapter" subclass="vdevice" type="IBM,v-scsi" prefix="host" driver="ibmvscsic" host=$($LS -d /sys/devices/vio/$slot/host*/) if [[ -d $host/scsi_host ]]; then scsihost=$($LS -d $host/scsi_host/host*/) else scsihost=$($LS -d $host/scsi_host*/) fi if [[ $(cat $scsihost/state) == "running" ]] ; then status=1 else status=0 fi show=1 # if there is a criteria in the command line, check if this # device matches if [[ $criteria != "" ]] ; then show=0 check_criteria "name" check_criteria "physloc" check_criteria "status" check_criteria "uniquetype" check_criteria "class" check_criteria "subclass" check_criteria "type" check_criteria "prefix" check_criteria "driver" fi if [[ $show -ne 0 ]]; then # the name attribute is always printed echo -ne $dev_begin$begin"name="\"$name\" print_attr "uniquetype" print_attr "class" print_attr "subclass" print_attr "type" print_attr "prefix" print_attr "driver" print_attr "status" # print the path, see note for ibmveth above if [[ $format == "" || $format =~ "path" ]]; then echo -ne $path_begin"\"vio\"" echo -ne $separator$begin"connection="\"$connection\" echo -ne $separator$begin"physloc="\"$physloc\" echo -ne $path_end fi # done with this target echo -ne $dev_end fi # loop through the targets for this host. for t in $($LS -d $host/target*); do target=$(echo $($LS -d $t/$($LS $t | $GREP -v uevent | $GREP -v power | $GREP -v subsystem))) if [[ ! -d $target/block ]]; then name=$(echo $($LS -d $target/block*) | $SED -e "s/.*://") else name=$($LS $target/block) fi conn=$($OFPATHNAME /dev/$name 2> /dev/null | $SED -e "s/.*disk@//") connection=${conn:0:12} uniquetype="disk/vscsi/vdisk" class="disk" subclass="vscsi" type="vdisk" physloc=$hostphysloc"-L"$conn if [[ $(cat $target/state) == "running" ]] ; then status=1 else status=0 fi # if there is a criteria in the command line, we are recursive and # the parent passed criteria, show the device if [[ $criteria != "" && $show -eq 1 && $recursive -eq 1 ]]; then show=1 elif [[ $criteria != "" ]] ; then # if there is a criteria in the command line, check if this # device matches show=0 check_criteria "name" check_criteria "status" check_criteria "physloc" check_criteria "parent" check_criteria "uniquetype" check_criteria "class" check_criteria "subclass" check_criteria "type" else show=1 fi # print the info only if the device matches the criteria if [[ $show -ne 0 ]]; then # the name attribute is always printed echo -ne $dev_begin$begin"name="\"$name\" print_attr "uniquetype" print_attr "class" print_attr "subclass" print_attr "type" print_attr "status" # print the path, see note for ibmveth above if [[ $format == "" || $format =~ "path" ]]; then echo -ne $path_begin\"$parent\" echo -ne $separator$begin"connection="\"$connection\" echo -ne $separator$begin"physloc="\"$physloc\" echo -ne $separator$begin"path_id="\""0"\" echo -ne $separator$begin"path_status="\"$status\" echo -ne $path_end fi # done with this target echo -ne $dev_end fi done done done # Look at every ibmvfc (Virtual FibreChannel) device for dev in $($LS -d /proc/device-tree/vdevice/vfc-client* 2> /dev/null) ; do # pull the physical location physloc=$(cat $dev/ibm,loc-code) connection=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/vfc-client@//") hostphysloc=$physloc # find the slot so it can be used in sysfs slot=$(echo $dev | $SED -e "s/\/proc\/device-tree\/vdevice\/vfc-client@//") # there is only one host per device, assign it to the path's name for host in $($LS -d /sys/devices/vio/$slot/host*) ; do parent=$(echo $host | $SED -e "s/.*\///") name=$parent uniquetype="adapter/vdevice/IBM,vfc-client" class="adapter" subclass="vdevice" type="IBM,vfc-client" prefix="host" driver="ibmvfc" host=$($LS -d /sys/devices/vio/$slot/host*/) if [[ -d $host/scsi_host ]]; then scsihost=$($LS -d $host/scsi_host/host*/) else scsihost=$($LS -d $host/scsi_host*/) fi if [[ $(cat $scsihost/state) == "running" ]] ; then status=1 else status=0 fi show=1 # if there is a criteria in the command line, check if this # device matches if [[ $criteria != "" ]] ; then show=0 check_criteria "name" check_criteria "physloc" check_criteria "status" check_criteria "uniquetype" check_criteria "class" check_criteria "subclass" check_criteria "type" check_criteria "prefix" check_criteria "driver" fi if [[ $show -ne 0 ]]; then # the name attribute is always printed echo -ne $dev_begin$begin"name="\"$name\" print_attr "uniquetype" print_attr "class" print_attr "subclass" print_attr "type" print_attr "prefix" print_attr "driver" print_attr "status" # print the path, see note for ibmveth above if [[ $format == "" || $format =~ "path" ]]; then echo -ne $path_begin"\"vio\"" echo -ne $separator$begin"connection="\"$connection\" echo -ne $separator$begin"physloc="\"$physloc\" echo -ne $path_end fi # done with this target echo -ne $dev_end fi # As opposed to ibmvscsi, there are multiple rports in each host for rport in $($LS -d $host/rport*); do # in ibmvfc there are two layers of directories before getting to # the targets for t in $($LS -d $rport/target*); do for target in $($LS $t | $GREP "[0-9]*:[0-9]*:[0-9]*:[0-9]*"); do if [[ ! -d $t/$target/block ]]; then name=$(echo $($LS -d $t/$target/block*) | $SED -e "s/.*://") else name=$($LS $t/$target/block) fi connection=$($OFPATHNAME /dev/$name 2> /dev/null | $SED -e "s/.*disk@//") physloc=$hostphysloc"-W"$(echo $connection | $TR "[:lower:]" "[:upper:]" | $SED -e "s/,/-L/") uniquetype="disk/fcp/disk" class="disk" subclass="fcp" type="disk" if [[ $(cat $t/$target/state) == "running" ]] ; then status=1 else status=0 fi # if there is a criteria in the command line, we are recursive and # the parent passed criteria, show the device if [[ $criteria != "" && $show -eq 1 && $recursive -eq 1 ]]; then show=1 elif [[ $criteria != "" ]] ; then # if there is a criteria in the command line, check if this # device matches show=0 check_criteria "name" check_criteria "physloc" check_criteria "status" check_criteria "parent" check_criteria "uniquetype" check_criteria "class" check_criteria "subclass" check_criteria "type" else show=1 fi # print the info only if the device matches the criteria if [[ $show -ne 0 ]]; then # the name attribute is always printed echo -ne $dev_begin$begin"name="\"$name\" print_attr "uniquetype" print_attr "class" print_attr "subclass" print_attr "type" print_attr "status" # print the path, see note for ibmveth above if [[ $format == "" || $format =~ "path" ]]; then echo -ne $path_begin\"$parent\" echo -ne $separator$begin"connection="\"$connection\" echo -ne $separator$begin"physloc="\"$physloc\" echo -ne $separator$begin"path_id="\""0"\" echo -ne $separator$begin"path_status="\"$status\" echo -ne $path_end fi # done with this device echo -ne $dev_end fi done done done done done exit 0 # end powerpc-utils-1.3.4/scripts/nvsetenv000066400000000000000000000004051315235264300176210ustar00rootroot00000000000000#!/bin/sh if [ "$1" = "--version" ]; then echo This version of nvsetenv is just a wrapper to invoke nvram exit 0 fi if [ -z "$1" ]; then nvram --print-config elif [ -z "$2" ]; then nvram --print-config="$1" else nvram --update-config "$1"="$2" fi exit $? powerpc-utils-1.3.4/scripts/ofpathname000077500000000000000000001163221315235264300201040ustar00rootroot00000000000000#! /bin/bash # Copyright (c) 2004 International Business Machines # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # Author Nathan Fontenot # # ofpathname - This utility provides a mechanism for converting a logical # device name to an open firmware device path, and vice versa. # # TODO: This script doesn't handle floppy drives and token ring devices, # perhaps they should be added in at some point. # OFPATHNAME="ofpathname" VERSION="0.5" FIND=/usr/bin/find CAT=/bin/cat PSERIES_PLATFORM=$(dirname $0)/pseries_platform # Find out what platfrom we are running on. Hopefully this # list will get expanded with time. PLATFORM=$(sed /proc/cpuinfo -ne "s/^machine\t*: \(.*\)/\1/p") case $PLATFORM in EFIKA5K2\ *) PLATFORM=efika ;; esac # Usage statemnet usage() { echo "Usage: $OFPATHNAME [OPTION] DEVICE" echo "Provide logical device names <==> Open Firmware Device Path Conversion" echo "" echo "Optional arguments." echo " -l Convert Open Firmware device pathname to" echo " logical device name." echo " -a Find matching Open Firmware device alias[es]." echo " -q, --quiet Do not report failures, exit quietly" echo " -V, --version Display version information and exit" echo " -h, --help Display this help information and exit" echo "" } show_version() { echo "$OFPATHNAME: Version $VERSION" echo "Written by: Nathan Fontenot " } # # err # Common routine to print error messages for ofpathname. Since most of the # error messages can be generated in multiple places, we put all the text # here to avoid errors in duplicating the messages. # # The first and only parameteris the error message number, all of which # are defined below as ERR_*. # ERR_NO_OFPATH=1 ERR_NO_SYSFS=2 ERR_NO_SYSFS_DEVINFO=3 ERR_NOT_CONFIG=4 ERR_NO_LOGDEV=5 err() { local emsg=$1 if [[ -n $be_quiet ]]; then exit 1 fi case $emsg in 1) echo "$OFPATHNAME: Could not retrieve Open Firmware device path" echo " for logical device \"$DEVNAME_ARG\"." ;; 2) echo "$OFPATHNAME: sysfs (/sys) is needed and does not appear" echo " to be mounted on this system." ;; 3) echo "$OFPATHNAME: Could not find sysfs information for logical" echo " device \"$DEVNAME_ARG\"." ;; 4) echo "$OFPATHANME: Logical device \"$DEVNAME_ARG\" does not appear" echo " to be configured." ;; 5) echo "$OFPATHNAME: Could not retrieve logical device name for" echo " Open Firmware path \"$DEVNAME_ARG\"." esac exit 1 } # is_hbtl # return true if the link is in HBTL (Host:Bus:Target ID:LUN) format is_hbtl() { local ln_name=$1; local tmp="${ln_name//[^:]}" if [[ ${#tmp} = 3 ]]; then echo 1 else echo 0 fi } # # get_link # return the directory path that a link points to. # The only parameter is the link name. # get_link() { local ln_name=$1; echo `ls -l $ln_name 2>/dev/null | awk -F"->" '{print $2}'` } # # get_hbtl # Given a path that ends in an HBTL (Host:Bus:Target ID:LUN), break it apart # into its constituent parts in the global vars HOST, BUS, TARGET and LUN # # #1 path ending in HBTL # get_hbtl() { local hbtl HBTL=${1##*/} hbtl=$HBTL HOST=${hbtl%%:*} hbtl=${hbtl#*:} BUS=${hbtl%%:*} BUS=`echo "ibase=10;obase=16; $BUS" | bc | tr "[:upper:]" "[:lower:]"` hbtl=${hbtl#*:} ID=${hbtl%%:*} ID=`echo "ibase=10;obase=16; $ID" | bc | tr "[:upper:]" "[:lower:]"` LUN=${hbtl#*:} LUN=`echo "ibase=10;obase=16; $LUN" | bc | tr "[:upper:]" "[:lower:]"` } # # get_scsi_disk_no # Given a path that ends in an HBTL, convert the HBTL values into a # virtual disk number (not sure what the real terminology is for it). # To do the conversion, the HBTL (A:B:C:D) is split apart and # calculated as; # no = (0x1000000 | C << 16 | D) # # $1 path ending in HBTL get_scsi_disk_no() { get_hbtl $1 local C D C=$((0x$ID << 16)) D=$((0x$LUN)) local vdiskno vdisk typeset -i vdiskno vdiskno=$((0x1000000 | $C | $D )) vdisk=${vdiskno##-} vdisk=`echo \`bc << END ibase=10 obase=16 $vdisk END\`` local extrazeroes="00000000" echo $vdisk$extrazeroes } # # get_vdisk_no # Given a path that ends in an HBTL, convert the HBTL values into a # virtual disk number (not sure what the real terminology is for it). # To do the conversion, the HBTL (A:B:C:D) is split apart and # calculated as; # no = (0x8000 | B << 8 | C << 5 | D) * 1000000000000 # # $1 path ending in HBTL # get_vdisk_no() { get_hbtl $1 local B C D typeset -i B C D B=$((0x$ID << 8)) C=$((0x$BUS << 5)) D=$((0x$LUN)) local vdiskno vdisk typeset -i vdiskno vdiskno=$((0x8000 | $B | $C | $D )) vdisk=${vdiskno##-} vdisk=`echo \`bc << END ibase=10 obase=16 $vdisk END\`` local extrazeroes="000000000000" echo $vdisk$extrazeroes } # # get_usb_vdisk_no # Given a path that ends in an HBTL, convert the HBTL values into a # virtual disk number (not sure what the real terminology is for it). # To do the conversion, the HBTL (A:B:C:D) is split apart and # calculated as; # no = (0x1000000 | (usb_port << 16) | D); # # $1 path ending in HBTL # get_usb_vdisk_no() { get_hbtl $1 local usb_port=$2 local B B=$((0x$usb_port << 16)) local vdiskno vdisk vdiskno=$((0x1000000 | $B | $LUN )) vdisk=${vdiskno##-} vdisk=$(bc << END ibase=10 obase=16 $vdisk END ) local extrazeroes="00000000" echo $vdisk$extrazeroes } # # get_usb_storage_no # Get usb device storage (port) number which is captured in # devpath file # # $1 starting directory to look for devpath file get_usb_storage_no() { for dir in `$FIND /sys -name $1`; do # Move up until we find one with a devpath link goto_dir $dir "devpath" 0 if [ $? -eq 0 ]; then break; fi done; if [ -f $PWD/devpath ]; then echo `$CAT $PWD/devpath` else err $ERR_NOT_CONFIG fi } # # goto_dir # This looks for a given file in a given directory or any parents of the # given directory. # # $1 starting directory # $2 file to search for # $3 on_exit behavior on error goto_dir() { local start_dir=$1 local fname=$2 local found=0 local on_exit=1 if [[ $# -eq 3 ]]; then on_exit=$3 fi cd $start_dir while [[ $PWD != "/" ]]; do ls $fname >/dev/null 2>&1 if [[ $? -eq 0 ]]; then found=1 break fi cd .. done if [[ $found -eq 0 ]]; then if [[ $on_exit -eq 1 ]]; then err $ERR_NO_SYSFS_DEVINFO else return 1 fi fi } # # find_dir # This looks for a given file in a given directory or any parents of the # given directory. This differs from goto_dir in that we don't actually try # to cd to the directories, we just return the directory name if found. # # $1 starting directory # $2 file to search for # $3 on_exit behavior on error find_dir() { local dir=$1 local fname=$2 while [[ -n $dir ]]; do /bin/ls $dir/$fname >/dev/null 2>&1 if [[ $? -eq 0 ]]; then echo $dir return fi dir=${dir%/*} done } # # is_pata_dev # Check to see if this is a PATA device # is_pata_dev() { local this_dir=$PWD local sysfs_dir local udev_path local udevinfo="/usr/bin/udevinfo" local udevadm="/sbin/udevadm" if [[ -a $udevadm ]]; then udev_path=`$udevadm info --query=path --name=$DEVNAME` elif [[ -a $udevinfo ]]; then udev_path=`$udevinfo -q path -n $DEVNAME` else echo "no" return fi if [[ -z $udev_path ]]; then echo "no" else sysfs_dir=`get_link -f /sys/$udev_path/device` if [[ ! -d $sysfs_dir ]]; then echo "no" else goto_dir $sysfs_dir devspec DEVTYPE=$(cat /proc/device-tree/$(cat $PWD/devspec)/device_type) if [[ $DEVTYPE = "ata" ]]; then echo "yes" else echo "no" fi fi fi cd $this_dir } # # print_aliases # Print the aliases from /proc/device-tree/aliases for the specified device # print_aliases() { dev=$1 local found=0 shopt -s nullglob for i in /proc/device-tree/aliases/*; do if sed -e "s/\x00$//g" $i | grep -qx "$dev" ; then echo ${i##*/} found=1 fi done if [[ $found = "0" ]]; then echo "No aliases found." exit 1 else exit 0 fi } get_slave() { cd /sys/class/*/$1 while [[ -n "`ls slaves 2> /dev/null`" ]]; do cd `echo slaves/* | head -n1 | cut -d " " -f1`; done $FIND /dev -name "`basename $PWD`" } # # is_net_interface # Check to see if this is a network interface # is_net_interface() { local res res=`$FIND /sys/class/net -name $1` if [[ ${#res} = 0 ]]; then echo "no" else echo "yes" fi } # # logical_to_ofpathname # Conversion for logical device name to an Open Firmware device path # logical_to_ofpathname() { local is_cdrom # follow any links to the real device name while [[ -L $DEVNAME ]]; do DEVNAME=`get_link $DEVNAME` done while [[ -L /dev/$DEVNAME ]]; do DEVNAME=`get_link /dev/$DEVNAME` done DEVICE=${DEVNAME##*/} DEVNODE=${DEVICE%%[0-9]*} # try to determine if this is a cdrom device if [[ ${DEVNAME_ARG##*/} = cdrom ]]; then is_cdrom=yes elif [[ `get_link /dev/cdrom` = /dev/$DEVICE ]]; then is_cdrom=yes else is_cdrom=no fi case $DEVICE in eth*) l2of_ethernet ;; hf*) l2of_hfi ;; sd* | sr*) # PATA devices appear as sd*, but should be converted # using the ide logic is_pata=$(is_pata_dev $DEVNAME) if [[ $is_pata = "yes" ]]; then l2of_ide else l2of_scsi fi ;; hd*) l2of_ide ;; vd*) l2of_vd ;; fd*) echo "no fd support yet" ;; mpath*) DEVNAME=$(printf "dm-%d" `stat -c "%T" /dev/mapper/$DEVICE`) logical_to_ofpathname ;; dm-*) DEVNAME=`get_slave $DEVICE` logical_to_ofpathname exit ;; nvme*) l2of_nvme ;; *) # check if the device is a network interface is_net=$(is_net_interface $DEVICE) if [[ $is_net = "yes" ]]; then l2of_ethernet fi ;; esac if [[ -z $OF_PATH ]]; then err $ERR_NO_OFPATH fi if [[ $is_cdrom = yes ]]; then OF_PATH=$OFPATH:1\\ppc\\bootinfo.txt fi if [[ $do_alias = "1" ]]; then print_aliases $OF_PATH else echo $OF_PATH fi } # # l2of_ide # Conversion routine for logical => OF path of ide devices # l2of_ide() { cd /sys/block/$DEVICE local link=`get_link "device"` if [[ -z $link ]]; then err $ERR_NO_SYSFS_DEVINFO fi cd $link # get the device number local devdir=${PWD##/*/} local channelno=${devdir%%\.*} local devno=${devdir##*\.} goto_dir $PWD "devspec" OF_PATH=`$CAT $PWD/devspec` if [[ -z $OF_PATH ]]; then err $ERR_NO_OFPATH fi # PCI ATA controller nodes (found on some Macs) have one child per IDE # channel. case `$CAT "/proc/device-tree/$OF_PATH/device_type"` in pci-ata | pci-ide) OF_PATH=$OF_PATH/@$channelno ;; esac # On Efika, obtained devno "0:0:0:0" doesn't match actual device. # Note: according to vendor, "0,0" means primary master. Secondary # channel is not present, and primary slave is rare enough that we # can reasonably ignore it. if [ "$PLATFORM" = "efika" ] ; then devno=0,0 fi OF_PATH=$OF_PATH/disk@$devno } # # l2of_vd # Conversion routine for logical => OF path of virtio block devices # l2of_vd() { local found=0 # There may be many instances of DEVICE under /sys for dir in `$FIND /sys -name $DEVICE`; do # Move up until we find one with a device link goto_dir $dir "device" 0 if [ $? -eq 0 ]; then found=1; break; fi done; if [ $found -eq 0 ]; then err $ERR_NOT_CONFIG fi local link=`get_link "device"` if [[ -z $link ]]; then err $ERR_NO_SYSFS_DEVINFO fi cd $link goto_dir $PWD "devspec" OF_PATH=`$CAT $PWD/devspec` if [[ -z $OF_PATH ]]; then err $ERR_NO_OFPATH fi } # # l2of_ethernet # Conversion routine for logical => OF path of ethernet devices # l2of_ethernet() { for syspath in `$FIND /sys -name $DEVICE 2> /dev/null`; do if [[ -e $syspath/device/devspec ]]; then OF_PATH=`$CAT $syspath/device/devspec` break fi done if [[ -z $OF_PATH ]]; then err $ERR_NO_OFPATH fi } # # l2of_hfi # Conversion routine for logical => OF path of HFI devices # l2of_hfi() { local hfnum=${DEVICE##hf} local hfpath if [[ $hfnum = "0" || $hfnum = "2" ]]; then hfpath=`$FIND /proc/device-tree -name hfi-ethernet* | sort | head -n 1` elif [[ $hfnum = "1" || $hfnum = "3" ]]; then hfpath=`$FIND /proc/device-tree -name hfi-ethernet* | sort | tail -n 1` else err $ERR_NO_OFPATH fi OF_PATH=${hfpath##/proc/device-tree} } # # l2of_nvme # Conversion routine for logical => OF path of nvme devices # l2of_nvme() { # OF path: /namespace@: # disk: nvmeX, nvmeXnY; not nvmeXnYpZ local devdisk="${DEVICE%p[0-9]*}" # namespace id: Y in nvmeXnY, nvmeXnYpZ local devnsid="${devdisk#nvme[0-9]*n}" if [[ $devnsid = $devdisk ]]; then devnsid='' # no namespace id fi # partition number: Z in nvmeXnYpZ local devpart="${DEVICE##*p}" if [[ $devpart = $DEVICE ]]; then devpart='' # no partition number fi # Get the device-tree device specification (devspec). local dir local found=0 for dir in `$FIND /sys/devices -name "$DEVICE"`; do cd $dir goto_dir $PWD "device/devspec" devspec=`$CAT $PWD/device/devspec` if [[ -n $devspec ]]; then found=1 break fi done if [[ $found -eq 0 ]]; then err $ERR_NO_SYSFS_DEVINFO fi if [[ -z $devspec ]]; then err $ERR_NO_OFPATH fi # OF path: /namespace@: OF_PATH="$devspec" # No namespace id (nY) specified. if [[ -z $devnsid ]]; then return fi # Device type is usually 'namespace'. # Get it from device-tree just in case. devtype=`$CAT /proc/device-tree${devspec}/namespace/name` if [[ -z $devtype ]]; then err $ERR_NO_OFPATH fi OF_PATH="$OF_PATH/$devtype@$devnsid" # No partition (pZ) specified. if [[ -z $devpart ]]; then return fi OF_PATH="${OF_PATH}:${devpart}" } # # int_to_scsilun # Conversion routine for SCSI HBTL LUN => SCSI LUN name # int_to_scsilun() { local lunint=$1 local A B C D A=$(( ($lunint >> 8) & 0xff )) B=$(($lunint & 0xff)) C=$(( ($lunint >> 24) & 0xff )) D=$(( ($lunint >> 16) & 0xff )) local lunstr=$(printf "%02x%02x%02x%02x00000000" $A $B $C $D) lunstr=`echo $lunstr | sed 's/^[0]*//'` echo "$lunstr" } # # scsilun_to_int # Conversion routine for SCSI LUN name => SCSI HBTL LUN # scsilun_to_int() { local lunstr=$1 local A B C D L L=${lunstr/00000000} L=`echo $L | tr "[a-z]" "[A-Z]"` L=`echo "ibase=16;obase=A; $L" | bc` A=$(( ($L >> 8) & 0xff )) B=$(($L & 0xff)) C=$(( ($L >> 24) & 0xff )) D=$(( ($L >> 16) & 0xff )) L=$(( (($A << 24) | ($B << 16) | ($C << 8) | $D) )) echo "$L" } get_fc_scsilun() { local lun=$1 local L L=`echo $lun | tr "[a-z]" "[A-Z]"` L=`echo "ibase=16;obase=A; $L" | bc` local fc_lun=`int_to_scsilun $L` echo "$fc_lun" } get_fc_wwpn() { local start_dir=$1 for f in `$FIND -H $start_dir -maxdepth 2 -name port_name`; do local wwpn=`$CAT $f` break done # strip the leading 0x wwpn=${wwpn:2} echo "$wwpn" } # # l2of_scsi # Converion routine for logical => OF path of scsi devices # l2of_scsi() { local found=0 local devtype # There may be many instances of DEVICE under /sys for dir in `$FIND /sys -name $DEVICE`; do # Move up until we find one with a device link goto_dir $dir "device" 0 if [ $? -eq 0 ]; then found=1; break; fi done; if [ $found -eq 0 ]; then err $ERR_NOT_CONFIG fi # follow the 'device' link local link=`get_link "device"` if [[ -z $link ]]; then # device may not be a link link=device fi get_hbtl $link cd $link # save the name of the current directory, we may need it later... local device_dir=${PWD##/*/} local device_path=$PWD # move up directories until we find one with devspec information goto_dir $PWD "devspec" OF_PATH=`$CAT $PWD/devspec` if [[ -z $OF_PATH ]]; then err $ERR_NO_OFPATH fi local vdev=${OF_PATH%/*} local fc=${OF_PATH%@*} fc=${fc##/*/} if [[ -e /proc/device-tree$OF_PATH/device_type ]]; then devtype=`tr -d '\0' < /proc/device-tree$OF_PATH/device_type`; if [[ $devtype = "fcp" || $devtype = "scsi-fcp" ]]; then fc="fibre-channel"; fi fi if [[ $fc = "usb" ]]; then local hub_no storage_no disk_no storage_no=`get_usb_storage_no $DEVICE` if [[ $storage_no = *.* ]]; then hub_no=${storage_no%%.*} storage_no=${storage_no##*.} fi disk_no=`get_usb_vdisk_no $device_dir $storage_no` if [[ -z $hub_no ]]; then OF_PATH=$OF_PATH/storage\@$storage_no/disk\@$disk_no else OF_PATH=$OF_PATH/hub\@$hub_no/storage\@$storage_no/disk\@$disk_no fi elif [[ $fc = "fibre-channel" ]]; then local wwpn=`get_fc_wwpn "$device_path/../../fc_remote_ports*"` if [[ ! -e /proc/device-tree$OF_PATH/disk ]]; then for dir in `$FIND /proc/device-tree$OF_PATH -type d`; do if [[ -e $dir/disk ]]; then OF_PATH=${dir##/proc/device-tree} break; fi done fi OF_PATH=$(printf "%s/disk@%s" $OF_PATH $wwpn) if [[ $LUN != "0" ]]; then local fc_lun=`get_fc_scsilun $LUN` OF_PATH=$(printf "%s,%s" $OF_PATH $fc_lun) fi elif [[ $vdev = "/vdevice" ]]; then # get the v-device data local tmp=${OF_PATH//\/vdevice/} local vdevtype=${tmp%@*} if [[ $vdevtype = "/vfc-client" ]]; then local vfc_lun=`get_fc_scsilun $LUN` local wwpn=`get_fc_wwpn "$device_path/../../fc_remote_ports*"` OF_PATH=$(printf "%s/disk@%s,%s" $OF_PATH $wwpn $vfc_lun) else local i vdiskno goto_dir $device_path $device_dir vdiskno=`get_vdisk_no $device_dir` OF_PATH=$OF_PATH/disk\@$vdiskno fi elif [[ -d /proc/device-tree$OF_PATH/sas ]]; then local vendor_id sas_id vendor_id=`od -tx /proc/device-tree/$OF_PATH/vendor-id` vendor_id=`echo $vendor_id | cut -d " " -f 2` if [[ $vendor_id = "00001000" ]]; then local dev_id goto_dir $device_path "sas_end_device*" dev_id=${PWD##*-} sas_id=`cat /sys/class/sas_device/end_device-$dev_id/sas_address` sas_id=${sas_id##0x} OF_PATH=$(printf "%s/sas/disk@%s" $OF_PATH $sas_id) if [[ $LUN != "0" ]]; then local LUNSTR=`int_to_scsilun $LUN` OF_PATH=$(printf "%s,%s" $OF_PATH $LUNSTR) fi else local B T L local fwtype="0" if [[ -e /sys/class/scsi_host/host$HOST/fw_type ]]; then fwtype=`$CAT /sys/class/scsi_host/host$HOST/fw_type` fi if [[ $fwtype = "1" ]]; then goto_dir $device_path "device_id" sas_id=`$CAT $PWD/device_id` sas_id=${sas_id##0x} OF_PATH=$(printf "%s/sas/disk@%s" $OF_PATH $sas_id) if [[ $LUN != "0" ]]; then local LUNSTR=`int_to_scsilun $LUN` OF_PATH=$(printf "%s,%s" $OF_PATH $LUNSTR) fi else B=`echo $BUS | tr "[a-z]" "[A-Z]"` B=`echo "ibase=16;obase=A; $B" | bc` T=`echo $ID | tr "[a-z]" "[A-Z]"` T=`echo "ibase=16;obase=A; $T" | bc` L=`echo $LUN | tr "[a-z]" "[A-Z]"` L=`echo "ibase=16;obase=A; $L" | bc` sas_id=$(( ($B << 16) | ($T << 8) | $L )) OF_PATH=$(printf "%s/sas/disk@%x" $OF_PATH $sas_id) if [[ $LUN != "0" ]]; then OF_PATH=$(printf "%s,%x" $OF_PATH $LUN) fi fi fi else # make sure the "scsi" information is on the end of the path local scsi_name=${OF_PATH##/*/} scsi_name=${scsi_name%%@*} if [[ $scsi_name != "scsi" ]]; then scsi_name="scsi@$BUS" OF_PATH=$OF_PATH/$scsi_name fi local modalias="" goto_dir $device_path "device" if [ $? -eq 0 ]; then modalias=`$CAT $PWD/modalias` fi if [[ $modalias =~ "virtio" ]]; then local diskno diskno=`get_scsi_disk_no $device_dir` OF_PATH=$OF_PATH/disk\@$diskno else OF_PATH=$OF_PATH/sd@$ID,$LUN fi fi } # # ofpathname_to_logical # Conversion for Open Firmware device paths to logical device names # ofpathname_to_logical() { DEVPATH=${DEVNAME%/*} DEVICE=${DEVNAME##/*/} DEVTYPE=${DEVICE%\@*} SAS=${DEVPATH##/*/} FC=${SAS%%\@*} if [[ $do_alias = "1" ]]; then print_aliases $OF_PATH fi if [[ $DEVTYPE = "disk" && $DEVICE != ${DEVICE%:*} ]]; then DEVTYPE=${DEVICE%:*} fi if [[ $DEVTYPE = "disk" && $FC = "v-scsi" ]]; then DEVTYPE="v-scsi" fi if [[ $DEVTYPE = "disk" && $FC = "scsi" ]]; then DEVTYPE="scsi" fi if [[ $DEVTYPE = "disk" && $SAS = "sas" ]]; then DEVTYPE="sas" fi if [[ $DEVTYPE = "disk" && $FC = "vfc-client" ]]; then DEVTYPE="vfc" fi if [[ $DEVTYPE = "disk" && $FC = "fibre-channel" ]]; then DEVTYPE="fc" fi if [[ $DEVTYPE = "disk" && $FC = "QLGC,qlc" ]]; then DEVTYPE="fc" fi if [[ $DEVTYPE = "disk" && $FC = "fp" ]]; then DEVTYPE="fc" fi if [[ $DEVTYPE = "disk" && $FC = "storage" ]]; then local devpath=$DEVPATH DEVPATH=${devpath%/*} DEVTYPE="usb" if [[ $DEVNAME = *hub* ]]; then devpath=$DEVPATH DEVPATH=${devpath%/*} fi fi if [[ $DEVTYPE = "namespace" ]]; then DEVTYPE="nvme" fi # Remove any possible cdrom data from DEVICE if [[ ${DEVICE##*,} = "\ppc\bootinfo.txt" || ${DEVICE##*,} = \ppc\bootinfo.txt ]]; then DEVICE=${DEVICE%,*} fi # Remove any possible yaboot suffix from DEVICE if [[ ${DEVICE##*,} = "yaboot" ]]; then DEVICE=${DEVICE%,*} fi case $DEVTYPE in sd* | scsi* ) of2l_scsi ;; sas ) of2l_sas ;; vfc ) of2l_vfc ;; fc ) of2l_fc ;; v-scsi | disk ) of2l_vscsi if [[ -z $LOGICAL_DEVNAME && $DEVTYPE = disk ]]; then of2l_ide fi ;; eth* | l-lan ) of2l_ethernet ;; vnic ) of2l_ethernet ;; hfi-ethernet* ) of2l_hfi ;; disk* ) of2l_ide ;; usb ) of2l_usb ;; nvme ) of2l_nvme ;; esac if [[ -z $LOGICAL_DEVNAME ]]; then err $ERR_NO_LOGDEV fi # See if this device is the cdrom if [[ `get_link "/dev/cdrom"` = $LOGICAL_DEVNAME ]]; then LOGICAL_DEVNAME="cdrom" fi echo $LOGICAL_DEVNAME } # # of2l_ide # Conversion routine for OF path => logical name for ide devices # of2l_ide() { local dir for dir in `$FIND /sys/block -name 'hd*'`; do # get devno local devno=${DEVICE##*@} devno=${devno%%:*} cd $dir local link=`get_link "device"` if [[ -n $link ]]; then cd $link # see if this is the correct device local this_devno=${PWD##*\.} if [[ $devno -eq $this_devno ]]; then goto_dir $PWD "devspec" local devspec=`$CAT ./devspec 2>/dev/null` if [[ $devspec = $DEVPATH ]]; then LOGICAL_DEVNAME="${dir##*/}" break fi fi fi done } # # of2l_ethernet # Conversion routine for OF path => logical names of ethernet devices # of2l_ethernet() { local dir # strip off ip info if present local devname=${DEVNAME%%:*} local netdir="/sys/class/net" for dir in `ls $netdir`; do local devdir=`find_dir $netdir/$dir device` if [[ -z $devdir ]]; then continue fi cd $devdir local link=`get_link "device"` if [[ -z $link ]]; then err $ERR_NO_SYSFS_DEVINFO fi cd $link local devspec=`$CAT ./devspec 2>/dev/null` if [[ $devspec = $devname ]]; then LOGICAL_DEVNAME="${dir##*/}" return fi done } # # of2l_hfi # Conversion routine for OF path => logical names of HFI devices # of2l_hfi() { # strip off ip info if present local devname=${DEVNAME%%:*} local hfpath hfpath=`$FIND /proc/device-tree -name hfi-ethernet* | sort | head -n 1` hfpath=${hfpath##/proc/device-tree} if [[ $hfpath = $devname ]] ; then LOGICAL_DEVNAME="hf0" else hfpath=`$FIND /proc/device-tree -name hfi-ethernet* | sort | tail -n 1` hfpath=${hfpath##/proc/device-tree} if [[ $hfpath = $devname ]] ; then LOGICAL_DEVNAME="hf1" else err $ERR_NO_LOGDEV fi fi } # # of2l_usb # Conversion routine for OF path => logical names of usb devices # of2l_usb() { DEV_HBTL_NO=${DEVICE##*\@} local dir for dir in `$FIND /sys/block -name 's[dr]*'`; do # go up to find directory with 'device' link local devdir=`find_dir $dir device` if [[ -z $devdir ]]; then continue fi cd $devdir local link=`get_link "device"` local vdisk_no if [[ -n $link ]]; then local port_no storage_no target target=${link##*/} port_no=`get_usb_storage_no $target` storage_no=${port_no##*.} vdisk_no=`get_usb_vdisk_no $target $storage_no` cd $link if [[ $vdisk_no = $DEV_HBTL_NO ]]; then goto_dir $PWD "devspec" local devspec=`$CAT ./devspec 2>/dev/null` if [[ $devspec = $DEVPATH ]]; then LOGICAL_DEVNAME=${dir##/*/} return fi fi fi done } # # of2l_vscsi # Conversion routine for OF path => logical names of virtual scsi devices # of2l_vscsi() { DEV_HBTL_NO=${DEVICE##*\@} local dir for dir in `$FIND /sys/block -name 's[dr]*'`; do # go up to find directory with 'device' link local devdir=`find_dir $dir device` if [[ -z $devdir ]]; then continue fi cd $devdir local link=`get_link "device"` if [[ -n $link ]]; then local vdiskno=`get_vdisk_no $link` cd $link if [[ $vdiskno = $DEV_HBTL_NO ]]; then goto_dir $PWD "devspec" local devspec=`$CAT ./devspec 2>/dev/null` if [[ $devspec = $DEVPATH ]]; then LOGICAL_DEVNAME=${dir##/*/} return fi fi fi done } # # of2l_scsi # Conversion routine for OF path => logical names of scsi devices # of2l_scsi() { DEV_HBTL_NO=${DEVICE##*\@} DEV_TARGET=${DEVICE##*\@} DEV_TARGET=${DEV_TARGET%%,*} DEV_LUN=${DEVICE##*,} # At this point DEV_LUN may be in the form X:Y, we're only interested # in the X component. DEV_LUN=${DEV_LUN%%:*} local dir for dir in `$FIND /sys/block -name '[sv][dr]*'`; do # go up to find directory with 'device' link local devdir=`find_dir $dir device` if [[ -z $devdir ]]; then continue fi cd $devdir local link=`get_link "device"` if [[ -z $link ]]; then err $ERR_NO_SYSFS_DEVINFO fi local hbtl=`is_hbtl $link` local diskno # Do not call get_hbtl for virtio block devices if [[ $hbtl = 1 ]]; then get_hbtl $link diskno=`get_scsi_disk_no $link` fi cd $link # save the name of the current directory, we may need it later... local device_dir=${PWD##/*/} if [[ $hbtl = 0 || $diskno = $DEV_HBTL_NO || ($ID = $DEV_TARGET && $LUN = $DEV_LUN) ]]; then goto_dir $PWD "devspec" local devspec=`$CAT ./devspec 2>/dev/null` # Handle virtio block devices if [[ $hbtl = 0 && $devspec = $DEVNAME ]]; then LOGICAL_DEVNAME="${dir##*/}" return fi if [[ $devspec = $DEVPATH ]]; then LOGICAL_DEVNAME="${dir##*/}" return fi local scsi_name=${devspec##/*/} scsi_name=${scsi_name%%@*} if [[ $scsi_name != "scsi" ]]; then scsi_name="scsi@$BUS" devspec=$devspec/$scsi_name if [[ $devspec = $DEVPATH ]]; then LOGICAL_DEVNAME="${dir##*/}" return fi fi fi done } # # of2l_sas # Conversion routine for OF path => logical names of sas devices # of2l_sas() { local matchtype dir DEV_NAME=${DEVICE##*\@} DEV_ID=${DEV_NAME%%,*} LUN=${DEV_NAME/$DEV_ID} LUN=${LUN/,/} if [[ ${#LUN} = 0 ]]; then LUN="0" fi lunint=`scsilun_to_int $LUN` PCI_ID=${DEVPATH%%/sas*} vendor_id=`od -tx /proc/device-tree/$PCI_ID/vendor-id` vendor_id=`echo $vendor_id | cut -d " " -f 2` if [[ $vendor_id = "00001000" ]]; then matchtype="libsas" else matchtype="ipr32" fi for dir in `$FIND /sys/class/scsi_host -maxdepth 1 -name 'host*'`; do cd $dir local link=`get_link "device"` cd $link cd .. local devspec=`$CAT ./devspec 2>/dev/null` if [[ $devspec = $PCI_ID ]]; then # check for ipr64 if [[ -e $dir/fw_type ]]; then local fwtype=`$CAT $dir/fw_type` if [[ $fwtype = "1" ]]; then matchtype="ipr64" break fi fi break fi done for dir in `$FIND /sys/block -name 's[dr]*'`; do # go up to find directory with 'device' link local devdir=`find_dir $dir device` if [[ -z $devdir ]]; then continue fi cd $devdir local link=`get_link "device"` if [[ -z $link ]]; then err $ERR_NO_SYSFS_DEVINFO fi get_hbtl $link cd $link # save the name of the current directory, we may need it later... local device_dir=$PWD local B T L B=`echo $BUS | tr "[a-z]" "[A-Z]"` B=`echo "ibase=16;obase=A; $B" | bc` T=`echo $ID | tr "[a-z]" "[A-Z]"` T=`echo "ibase=16;obase=A; $T" | bc` L=`echo $LUN | tr "[a-z]" "[A-Z]"` L=`echo "ibase=16;obase=A; $L" | bc` if [[ $matchtype = "ipr32" ]]; then local sas_id=$((($B << 16) | ($T << 8) | $L)) sas_id=`echo "ibase=A;obase=16; $sas_id" | bc` sas_id=`echo $sas_id | tr "[A-Z]" "[a-z]"` if [[ $sas_id = $DEV_ID ]]; then goto_dir $PWD "devspec" local devspec=`$CAT ./devspec 2>/dev/null` if [[ $devspec/sas = $DEVPATH ]]; then LOGICAL_DEVNAME="${dir##*/}" return fi fi elif [[ $matchtype = "ipr64" ]]; then if [[ -e $devdir/device/device_id ]]; then local deviceid=`$CAT $devdir/device/device_id` deviceid=${deviceid##0x} if [[ $deviceid != $DEV_ID ]]; then continue fi if [[ $L = $lunint ]]; then goto_dir $PWD "devspec" local devspec=`$CAT ./devspec 2>/dev/null` if [[ $devspec/sas = $DEVPATH ]]; then LOGICAL_DEVNAME="${dir##*/}" return fi fi fi elif [[ $matchtype = "libsas" ]]; then local dev_id goto_dir $device_dir "sas_end_device*" 0 dev_id=${PWD##*-} if [[ ! -e /sys/class/sas_device/end_device-$dev_id/sas_address ]]; then continue fi sas_id=`cat /sys/class/sas_device/end_device-$dev_id/sas_address` sas_id=${sas_id##0x} if [[ $sas_id != $DEV_ID ]]; then continue fi if [[ $L = $lunint ]]; then goto_dir $PWD "devspec" local devspec=`$CAT ./devspec 2>/dev/null` if [[ $devspec/sas = $DEVPATH ]]; then LOGICAL_DEVNAME="${dir##*/}" return fi fi else err $ERR_NO_LOGDEV fi done } # # of2l_vfc # Conversion routine for OF path => logical names of vFC devices # of2l_vfc() { DEV_ID=${DEVICE##*\@} OF_WWPN=${DEV_ID%%,*} OF_LUN=${DEV_ID##$OF_WWPN} OF_LUN=${OF_LUN#,} OF_LUN=`echo $OF_LUN | sed 's/^[0]*//'` local dir for dir in `$FIND /sys/block -name 's[dr]*'`; do # go up to find directory with 'device' link local devdir=`find_dir $dir device` if [[ -z $devdir ]]; then continue fi cd $devdir local link=`get_link "device"` if [[ -z $link ]]; then continue fi get_hbtl $link cd $link link=$PWD local device_dir=${PWD##/*/} goto_dir $PWD "devspec" OF_PATH=`$CAT $PWD/devspec` if [[ -z $OF_PATH ]]; then err $ERR_NO_LOGDEV fi local vdev=${OF_PATH%/*} local tmp=${OF_PATH//\/vdevice/} local vdevtype=${tmp%@*} if [[ $vdevtype != "/vfc-client" ]]; then continue fi local vfc_lun=`get_fc_scsilun $LUN` local wwpn=`get_fc_wwpn "$link/../../fc_remote_ports*"` if [[ $vfc_lun = $OF_LUN && $wwpn = $OF_WWPN ]]; then if [[ $OF_PATH = $DEVPATH ]]; then LOGICAL_DEVNAME="${dir##*/}" return fi fi done } # # of2l_fc # Conversion routine for OF path => logical names of FC devices # of2l_fc() { DEV_ID=${DEVICE##*\@} OF_WWPN=${DEV_ID%%,*} OF_LUN=${DEV_ID/$OF_WWPN} OF_LUN=${OF_LUN/,/} if [[ ${#OF_LUN} = 0 ]]; then OF_LUN="0" fi lunint=`scsilun_to_int $OF_LUN` local dir for dir in `$FIND /sys/block -name 's[dr]*'`; do # go up to find directory with 'device' link local devdir=`find_dir $dir device` if [[ -z $devdir ]]; then continue fi cd $devdir local link=`get_link "device"` if [[ -z $link ]]; then continue fi get_hbtl $link cd $link link=$PWD # find device_path, not all dirs will have a fc_remote_ports goto_dir $PWD "fc_remote_ports*" 0 if [[ $? -eq 1 ]]; then continue fi device_path=$PWD cd $link local device_dir=${PWD##/*/} goto_dir $PWD "devspec" OF_PATH=`$CAT devspec` if [[ -z $OF_PATH ]]; then err $ERR_NO_LOGDEV fi local wwpn=`get_fc_wwpn "$device_path/fc_remote_ports*"` if [[ $wwpn = $OF_WWPN ]]; then local L L=`echo $LUN | tr "[a-z]" "[A-Z]"` L=`echo "ibase=16;obase=A; $L" | bc` if [[ $L = $lunint ]]; then LOGICAL_DEVNAME="${dir##*/}" return fi fi done } # # of2l_nvme # Conversion routine for OF path => logical name for nvme devices # of2l_nvme() { # get namespace id and partition number local nsid_part=${DEVICE##*@} # [:partition-number] local nsid=${nsid_part%:*} # namespace id local part # partition number # set partition number only if ':' is present case "${nsid_part}" in *:*) part=${nsid_part#*:} ;; esac local dir local link for dir in `$FIND /sys/block -name "nvme*n$nsid"`; do cd $dir link=`get_link "device"` # points to nvme[0-9]+ (non-namespace) if [[ -n $link ]]; then cd $link else continue fi link=`get_link "device"` # points to pci address dir if [[ -n $link ]]; then cd $link else continue fi goto_dir $PWD "devspec" local devspec=`$CAT ./devspec 2>/dev/null` if [[ $devspec = $DEVPATH ]]; then LOGICAL_DEVNAME="${dir##*/}" break fi done if [[ -n $LOGICAL_DEVNAME ]] \ && [[ -n $part ]]; then if [[ -d "/sys/block/${LOGICAL_DEVNAME}/${LOGICAL_DEVNAME}p${part}" ]]; then LOGICAL_DEVNAME="${LOGICAL_DEVNAME}p${part}" else LOGICAL_DEVNAME='' fi fi } # # Main # . $PSERIES_PLATFORM if [[ $platform = $PLATFORM_POWERNV ]]; then echo "$OFPATHNAME: is not supported on the $platform_name platform" exit 1 fi if [[ "$#" -eq 0 ]]; then usage exit 0 fi # default: convert logical => OFpath do_of2l=0 # default: do not do alias lookups do_alias=0 getopt -o "l:Vqh" -l "help,version,quiet" $@ > /dev/null 2>&1 while [[ -n $1 ]]; do case "$1" in -a) do_alias=1 ;; -l) do_of2l=1 DEVNAME_ARG=$2 shift ;; -V | --version) show_version exit 0 ;; -q | --quiet) be_quiet=1 ;; -h | --help) usage exit 0 ;; *) DEVNAME_ARG=$1 ;; esac shift done DEVNAME=$DEVNAME_ARG # double check device name if [[ -z $DEVNAME ]]; then usage exit 1 fi # We need sysfs if [[ ! -d "/sys" ]]; then err $ERR_NO_SYSFS exit 1 fi if [[ $do_of2l = "0" ]]; then # logical devname => OF pathname logical_to_ofpathname else # OF pathnmae => logical devname ofpathname_to_logical fi exit 0 powerpc-utils-1.3.4/scripts/pseries_platform000066400000000000000000000026111315235264300213300ustar00rootroot00000000000000#!/bin/sh # Copyright (c) 2014 - IBM # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. SOURCE_FILE="pseries_platform" PLATFORM_FILE=/proc/cpuinfo export PLATFORM_UNKNOWN=0 export PLATFORM_POWERNV=1 export PLATFORM_POWERKVM_GUEST=2 export PLATFORM_PSERIES_LPAR=3 export platform_name="Unknown" export platform=$PLATFORM_UNKNOWN if grep -q "PowerNV" $PLATFORM_FILE; then platform_name="PowerNV Host" platform=$PLATFORM_POWERNV elif grep -q "IBM pSeries (emulated by qemu)" $PLATFORM_FILE; then platform_name="Power KVM pSeries Guest" platform=$PLATFORM_POWERKVM_GUEST elif grep -q "pSeries" $PLATFORM_FILE; then platform_name="PowerVM pSeries LPAR" platform=$PLATFORM_PSERIES_LPAR fi if [ $SOURCE_FILE = `basename $0` ]; then echo $platform_name fi powerpc-utils-1.3.4/scripts/rtas_dump000077500000000000000000000101421315235264300177510ustar00rootroot00000000000000#! /usr/bin/perl # # This updated version of the rtas_dump script will # do everything the original rtas_dump script does except # it does it cleaner and without as many cmdline options. # # Copyright (C) 2004 International Business Machines # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # Author: Nathan Fontenot # use vars qw/ %opt /; use Getopt::Long; use File::Basename; $re_decode = $ENV{RTAS_EVENT_DECODE} || "/usr/sbin/rtas_event_decode"; # # usage statement # sub usage() { print "Usage: rtas_dump [OPTIONS]\n"; print "Dump the contents of an RTAS event, by default RTAS events\n"; print "are read from stdin unless the -f flag is used.\n\n"; print " -d debug flag, passed through to rtas_event_decode\n"; print " -f dump the RTAS events from \n"; print " -h print this message and exit\n"; print " -n only dump RTAS event number \n"; print " -v dump the entire RTAS event, not just the header\n"; print " -w set the output character width\n"; exit 1; } # # Read in the contents of an RTAS event and invoke rtas_event_decode on it. # sub handle_rtas_event() { my ($event_no) = @_; $re_decode_args = "$re_decode_args -n $event_no"; # create the pipe to rtas_event_decode open EVENT_DECODE, "| $re_decode $re_decode_args"; while(<$fh>) { ($crud, $data) = split (/RTAS/); $rtas_str = $rtas_str . "RTAS" . $data; if (/RTAS event end/) { print EVENT_DECODE $rtas_str; $rtas_str = ""; last; } } close EVENT_DECODE; } # # Main # my $PSERIES_PLATFORM = dirname(__FILE__) . "/pseries_platform"; my $perldumpenv='perl -MData::Dumper -e '."'". '\$Data::Dumper::Terse=1;print Dumper(\%ENV);'."'"; eval '%ENV=('.$1.')' if `bash -c " . $PSERIES_PLATFORM; $perldumpenv"` =~ /^\s*\{(.*)\}\s*$/mxs; if ($ENV{'platform'} == $ENV{'PLATFORM_UNKNOWN'} || $ENV{'platform'} == $ENV{'PLATFORM_POWERNV'}) { print "rtas_dump: is not supported on the $ENV{'platform_name'} platform\n"; exit 1; } # process cmdline args Getopt::Long::Configure("bundling"); GetOptions("help|h" => \$help_flag, "dump_raw|d" => \$debug_flag, "file|f=s" => \$filename, "n=i" => \$event_no, "w=i" => \$width, "verbose|v+" => \$verbose) or usage(); usage() if $help_flag; # make sure the rtas_event_decode application is available -e $re_decode or die "File $re_decode does not exist and is needed by rtas_dump.\n"; -x $re_decode or die "File $re_decode is not executable.\n"; # get a reference to our input filehandle if ($filename) { if (-e $filename) { open INPUT_FILE, $filename; $fh = \*INPUT_FILE; $close_input_file = 1; } else { print "File $filename does not exist\n" ; return -1; } } else { $fh = \*STDIN; } # create the arg list to rtas_event_decode $re_decode_args = "$re_decode_args -d" if $debug_flag; $re_decode_args = "$re_decode_args -v" if $verbose; $re_decode_args = "$re_decode_args -w $width" if $width; while (<$fh>) { if (/RTAS event begin/) { # found the beginning of an RTAS event, process it. ($crud, $data) = split (/RTAS:/); ($this_event_no, $d) = split (' ', $data); if ($event_no) { if ($event_no == $this_event_no) { $rtas_str = $rtas_str . "RTAS:" . $data; &handle_rtas_event($this_event_no); } } else { $rtas_str = $rtas_str . "RTAS:" . $data; &handle_rtas_event($this_event_no); } next; } } if ($close_input_file) { close INPUT_FILE; } powerpc-utils-1.3.4/scripts/snap000077500000000000000000000302701315235264300167200ustar00rootroot00000000000000#!/usr/bin/perl -w # Copyright (c) 2003, 2004, 2012 International Business Machines # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # Author Todd Inglett # updates by Michael Strosaker # updates by Vasant Hegde # Snapshot system config # Command-line parameters: # a: all data; collect detailed information (more files and output) # d dir: specify the directory where files and output will be collected # (default: /tmp/ibmsupt) # h: print this help message # o file: specify the output file (.tar required, .tar.gz optional) # (default: snap.tar.gz) # v: verbose output # # Exit codes (view with "echo $?" immediately after running): # 0: snap data was successfully captured # 1: invalid command line # 2: other fatal error use strict; use Getopt::Std; use POSIX qw(strftime); use Sys::Hostname; use FileHandle; use File::Basename; my $PSERIES_PLATFORM = dirname(__FILE__) . "/pseries_platform"; my $outdir = "/tmp/ibmsupt"; # note NO trailing / my $outfile = "snap.tar.gz"; # in the working dir. my $cmddir = "snap_commands"; # cmd output dir. my $cmdoutdir = "$outdir/$cmddir"; # in outdir dir. my $rsxx_exists = 0; # Does an IBM Flash Adapter exist? sub check_distro_support { my $redhat_release_file = "/etc/redhat-release"; my $suse_release_file = "/etc/SuSE-release"; my $distro_file = "/etc/issue"; if (-e $redhat_release_file) { open(RELEASE, "< $redhat_release_file") or die "open: $!\n"; $_ = ; my $redhat_version = (split / /, $_)[6]; if ($redhat_version >= 7.0) { print "snap is not supported on the RHEL 7 onwards..!\n"; print "Please use sosreport to collect log data..!! \n"; close(RELEASE); exit 1; } close(RELEASE); } elsif (-e $suse_release_file) { open(RELEASE, "< $suse_release_file") or die "open: $!\n"; while() { if ($_ =~ /VERSION/) { my $suse_version = (split /=/, $_)[1]; if ($suse_version >= 12) { print "snap is deprecated from SLES 12 onwards..!\n"; print "Please use supportconfig to collect log data..!! \n"; close(RELEASE); exit 1; } } # if } # while close(RELEASE); } else { open(RELEASE, "< $distro_file") or die "open: $!\n"; if ( =~ /Ubuntu/) { print "snap: is not supported on the Ubuntu platform\n"; close(RELEASE); exit 1; } #if } #else } our($opt_a, $opt_d, $opt_h, $opt_o, $opt_t, $opt_v); # Files to include in all snaps my @snap_paths_general = ( "/var/log/messages", "/var/log/platform", "/var/log/scanoutlog.*", # "/proc/bus/pci", ?? binary file "/proc/cmdline", "/proc/cpuinfo", "/proc/devices", "/proc/dma", "/proc/filesystems", "/proc/fs", "/proc/ide", "/proc/interrupts", "/proc/iomem", "/proc/ioports", "/proc/loadavg", "/proc/locks", "/proc/mdstat", "/proc/meminfo", "/proc/misc", "/proc/modules", "/proc/mounts", "/proc/net", "/proc/partitions", "/proc/pci", "/proc/ppc64/lparcfg", "/proc/ppc64/eeh", "/proc/ppc64/pci", "/proc/ppc64/systemcfg", "/proc/scsi", "/proc/slabinfo", "/proc/stat", "/proc/swaps", "/proc/sys", "/proc/sysvipc", "/proc/uptime", "/proc/version", "/dev/nvram", "/etc/fstab", "/etc/raidtab", "/etc/yaboot.conf", ); # Files to include in all snaps on SuSE systems my @snap_paths_general_SuSE = ( "/etc/SuSE-release", "/var/log/boot.msg", ); # Files to include in all snaps on Red Hat systems my @snap_paths_general_RedHat = ( "/etc/redhat-release", "/var/log/dmesg", ); # Files to include only in detailed snaps (-a option) my @snap_paths_detailed = ( "/proc/tty", "/etc/inittab", "/proc/ppc64/", "/proc/device-tree/", ); # Command output to include in all snaps my @snap_commands_general = ( "lscfg -vp", "ifconfig -a", "lspci -vvv" ); # Command output to include only in detailed snaps (-a option) my @snap_commands_detailed = ( "rpm -qa", "servicelog --dump", "servicelog_notify --list", "usysattn", "usysident", "serv_config -l", "bootlist -m both -r", "lparstat -i", "lsmcode -A", "lsvpd --debug", "lsvio -des", "ppc64_cpu --smt --cores-present --cores-on --run-mode --frequency --dscr", ); # Command output to include for IBM Flash Adapter(s) my @snap_command_rsxx = ( "rs_cardreport -d 'all'", ); # Files, which are to be ignored as they are deprecated my @snap_deprecated_files = ( "retrans_time", "base_reachable_time", ); sub recurse_dir($); # function prototype sub error { my ($fatal, $message) = @_; if ($fatal) { print "$0: $message\n"; exit 2; } else { if ($opt_v) { print "$0: $message\n"; } } } sub print_usage { print "Usage: $0 [-athv] [-d dir] [-o file]\n\n"; print " Command-line parameters:\n"; print " a: all data; collect detailed information (more files and output)\n"; print " d dir: specify the directory where files and output will be collected\n"; print " (default: /tmp/ibmsupt)\n"; print " o file: specify the output file (.tar required, .tar.gz optional)\n"; print " (default: snap.tar.gz)\n"; print " t: add hostname and timestamp to output filename\n"; print " v: verbose output\n\n"; print " h: print this help message\n"; print " Exit codes (view with \"echo \$?\" immediately after running):\n"; print " 0: snap data was successfully captured\n"; print " 1: invalid command line\n"; print " 2: other fatal error\n\n"; } sub copy { my ($source, $destination) = @_; my ($dir, @path, $d, $blocksize, $buffer, $length, $offset, $written); #print "Copying $source..."; # Create directories, if necessary $dir = substr $destination, 0, rindex($destination, "/"); if (!(-d $dir)) { @path = split /\//, $dir; if (substr($dir, 0, 1) eq "/") { # remove leading / shift @path; } $dir = ""; foreach $d (@path) { $dir .= "/" . $d; if (!(-d $dir)) { if (!mkdir($dir, 0644)) { error(0, "Cannot create directory: $dir"); return; } } } } # Copy file if (!sysopen(SRC, "$source", O_NONBLOCK|O_RDONLY)) { error(0, "Cannot open file for reading: $source"); return; } binmode SRC; if (!open(DST, ">$destination")) { error(0, "Cannot open file for writing: $destination"); goto copy_out; } binmode DST; $blocksize = (stat SRC)[11] || 16384; while ($length = sysread SRC, $buffer, $blocksize) { if (!defined $length) { next if $! =~ /^Interrupted/; # ^Z and fg error(0, "System read error while reading $source: $!"); goto copy_out; } $offset = 0; while ($length) { if (!defined($written = syswrite DST, $buffer, $length, $offset)) { error(0, "System write error while writing $destination: $!"); goto copy_out; } $length -= $written; $offset += $written; } } copy_out: #print "done.\n"; close SRC; close DST; } sub recurse_dir ($) { my ($dir) = @_; my ($file) = ""; my (@contents) = (); if (!opendir(DIR, $dir)) { error(0, "Could not open directory $dir"); return; } @contents = readdir DIR; closedir DIR; foreach $file (@contents) { if ($file eq "." or $file eq ".." or (-l "$dir/$file")) { next; } if (-d "$dir/$file") { recurse_dir "$dir/$file"; } else { next if (grep { /$file/ } @snap_deprecated_files); copy "$dir/$file", $outdir."$dir/$file"; } } } sub snap_paths { my ($file, $dir, $search, @contents); foreach $file (@_) { # For now do not collect proc ppc64 files for guest. next if ($file =~ "/proc/ppc64/" && $ENV{'platform'} == $ENV{'PLATFORM_POWERKVM_GUEST'}); if (-d $file) { recurse_dir $file; } else { # Check for wildcard (* in last character only) if (substr($file, -1) eq "*") { $dir = substr $file, 0, rindex($file, "/"); $search = substr $file, rindex($file, "/")+1, -1; if (!opendir(DIR, $dir)) { error(0, "Could not open directory $dir"); return; } @contents = readdir DIR; closedir DIR; foreach $file (@contents) { if (substr($file, 0, length($search)) eq $search) { copy "$dir/$file", $outdir."$dir/$file"; } } } else { copy $file, $outdir.$file; } } } } sub snap_commands { my ($path, @junk, @path, $filename, $command, $exit_value); if (!(-d $cmdoutdir)) { if (!mkdir($cmdoutdir, 0644)) { error(0, "Cannot create directory: $cmdoutdir"); return; } } foreach $command (@_) { # Retrieve the name of the binary to run (for output file name) ($path, @junk) = split / /, $command; @path = reverse(split /\//, $path); $filename = shift @path; system("$command > $cmdoutdir/$filename.out 2>&1"); if ($exit_value = $? >> 8) { error(0, "\"$command\" returned $exit_value"); } } } $< == 0 or error(1, "Must be executed as root"); #check for the distro version check_distro_support(); my $perldumpenv='perl -MData::Dumper -e '."'". '\$Data::Dumper::Terse=1;print Dumper(\%ENV);'."'"; eval '%ENV=('.$1.')' if `bash -c " . $PSERIES_PLATFORM; $perldumpenv"` =~ /^\s*\{(.*)\}\s*$/mxs; if ($ENV{'platform'} == $ENV{'PLATFORM_UNKNOWN'} || $ENV{'platform'} == $ENV{'PLATFORM_POWERNV'}) { print "snap: is not supported on the $ENV{'platform_name'} platform\n"; exit 1; } if (!getopts('atd:ho:v')) { print_usage; exit 1; } if ($opt_h) { print_usage; exit 0; } if ($opt_d) { $outdir = $opt_d; $cmdoutdir = "$opt_d/$cmddir"; } if (-e $outdir) { print "$0: cannot run; $outdir already exists.\n"; exit 2; } if (substr($outdir, -1) eq "/") { $outdir = substr $outdir, 0, -1; } if ($opt_o) { if ($opt_o !~ /.tar/) { print "$0: The filename provided, $opt_o, does not contain .tar;"; print " Using default filename $outfile\n"; } else { $outfile = $opt_o; } } if ($opt_t) { my $host = `hostname`; chomp($host); my @halias = split(/\./, $host); my $time = strftime('%Y%m%d%H%M%S',localtime); my $temp = substr $outfile, 0, rindex($outfile, ".tar"); my $temp1 = substr $outfile, rindex($outfile, ".tar") + 1; $outfile = "$temp-$halias[0]-$time.$temp1"; } if (-e $outfile) { print "$0: cannot run; $outfile already exits.\n"; exit 2; } # Check to see if we need to gather information on IBM Flash Adapter(s). if (glob("/dev/rsxx*")) { $rsxx_exists = 1; } snap_paths(@snap_paths_general); # Check distro if (-e "/etc/SuSE-release") { snap_paths(@snap_paths_general_SuSE); } elsif (-e "/etc/redhat-release") { snap_paths(@snap_paths_general_RedHat); } # Run commands and capture output snap_commands(@snap_commands_general); # Gather detail files if requested (-a option) if ($opt_a) { snap_paths(@snap_paths_detailed); snap_commands(@snap_commands_detailed); } # Gather information regarding IBM Flash Adapter(s) if ($rsxx_exists) { # Verify the rsxx utils are installed. system("rpm -qa | grep rsxx-utils > /dev/null"); if ($? == 0) { snap_commands(@snap_command_rsxx); } else { print "Warning: The rsxx-utils RPM are not installed, ". "unable to gather IBM Flash Adapter information.\n". "\t Run 'yum install rsxx-utils' to install.\n"; } } my ($basefile, $extension) = split /\.tar/, $outfile; my $basedir = substr $outdir, 0, rindex($outdir, "/"); my $compressdir = substr $outdir, rindex($outdir, "/") + 1; system ("tar -cf $basefile.tar --directory=$basedir $compressdir 2>/dev/null"); if ($extension eq ".gz") { system ("gzip -f $basefile.tar"); } elsif ($extension eq "") { } else { $outfile = "$basefile.tar"; print "$0: Unrecognized extension $extension\n"; } # Delete temporary directory system("rm -rf $outdir"); print "output written to $outfile\n"; print "WARNING: archive may contain confidential data and/or cleartext passwords!\n"; exit 0; powerpc-utils-1.3.4/scripts/update_flash000077500000000000000000000354771315235264300204340ustar00rootroot00000000000000#!/bin/sh # Copyright (c) 2003, 2004, 2008 International Business Machines # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # Authors: John Rose # Mike Strosaker # Simple script to update flash. The kernel module rtas_flash does # the real work at reboot time. # This script has minimal dependencies so it can operate in a rescue # environment. This is probably overkill since it is easy enough to # flash without this script. #set -x # For now firmware can only handle 4k pages. At some point in the # future they will be able to handle large pages. When that (hopefully) # happens we will need to use getconf to retrieve the systems page size. PAGE_SIZE=4096 # Error Codes E_SUCCESS=0 # Success E_UNSUPPORTED=1 # Flash update is not supported on this system E_USAGE=3 # Usage error E_PERM=4 # Permission error E_IMAGE=5 # Image file error E_PROC_FS=6 # Proc file either doesn't exist, or behaves unexpectedly E_MODULE=7 # Error loading module E_RTAS=8 # RTAS call failed E_USER=9 # User aborted operation E_OVERWRITE=10 # Auto overwrite permanent side image E_WRNTY=15 # Update Access Key Expired E_KEXEC=16 # Kexec service stop error # Script Constants PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH PROCFLASH=/proc/ppc64/rtas/firmware_update PROCMANAGE=/proc/ppc64/rtas/manage_flash PROCVALIDATE=/proc/ppc64/rtas/validate_flash OLDPROCFLASH=/proc/ppc64/rtas/firmware_flash PSERIES_PLATFORM=$(dirname $0)/pseries_platform # firmware_update Status Values FLASH_AUTH=-9002 # RTAS Not Service Authority Partition FLASH_NO_OP=-1099 # No operation initiated by user FLASH_IMG_SHORT=-1005 # Flash image shorter than expected FLASH_IMG_BAD_LEN=-1004 # Bad length value in flash list block FLASH_IMG_NULL_DATA=-1003 # Bad data value in flash list block FLASH_IMG_READY=0 # Firmware img ready for flash on reboot # manage_flash Status Values MANAGE_AUTH=-9002 # RTAS Not Service Authority Partition MANAGE_ACTIVE_ERR=-9001 # RTAS Cannot Overwrite Active Img MANAGE_NO_OP=-1099 # No operation initiated by user MANAGE_PARAM_ERR=-3 # RTAS Parameter Error MANAGE_HW_ERR=-1 # RTAS Hardware Error MANAGE_SUCCESS=0 # Operation Successful # validate_flash Status Values VALIDATE_AUTH=-9002 # RTAS Not Service Authority Partition VALIDATE_INCOMPLETE=-1002 # User copied < VALIDATE_BUF_SIZE VALIDATE_READY=-1001 # Firmware image ready for validation VALIDATE_PARAM_ERR=-3 # RTAS Parameter Error VALIDATE_HW_ERR=-1 # RTAS Hardware Error VALIDATE_TMP_UPDATE=0 # RPA Section 7.3, Table 63 VALIDATE_FLASH_AUTH=1 # RPA Section 7.3, Table 63 VALIDATE_INVALID_IMG=2 # RPA Section 7.3, Table 63 VALIDATE_CUR_UNKNOWN=3 # RPA Section 7.3, Table 63 VALIDATE_TMP_COMMIT_DL=4 # RPA Section 7.3, Table 63 VALIDATE_TMP_COMMIT=5 # RPA Section 7.3, Table 63 VALIDATE_TMP_UPDATE_DL=6 # RPA Section 7.3, Table 63 VALIDATE_OUT_OF_WRNTY=7 # RPA Section 7.3, Table 63 error() { local exit_code=$1 if [ $# -lt 1 ]; then echo "error(): usage" >&2 return $E_USAGE fi shift; echo update_flash: $* >&2 exit $exit_code } usage() { local exit_code; if [ "$1" = $E_SUCCESS ]; then exit_code=$E_SUCCESS else exit_code=$E_USAGE fi echo "USAGE: update_flash {-h | -s | -r | -c | [-v|-n] -f }" >&2 echo " -h Print this message." >&2 echo " -s Determine if partition has access to" >&2 echo " perform flash image management." >&2 echo " -r Reject temporary image." >&2 echo " -c Commit temporary image." >&2 echo " -v Validate ONLY with given image file." >&2 echo " -n Do not overwrite Permanent side" >&2 echo " image automatically." >&2 echo " -f Update with given image file. If possible," >&2 echo " the image is automatically validated prior" >&2 echo " to update." >&2 echo "" >&2 exit $exit_code } # Check kexec service status check_kexec_service() { # check systemctl command which systemctl >/dev/null 2>&1 if [ $? -ne 0 ]; then return 1 fi # kexec service is running systemctl status kexec.service | grep -w "active" >/dev/null 2>&1 if [ $? -eq 0 ]; then return 0 fi return 1 } # Stop kexec service stop_kexec_service() { systemctl stop kexec.service >/dev/null 2>&1 if [ $? -ne 0 ]; then echo "update_flash: Failed to stop kexec service." error $E_KEXEC "Please stop kexec service and retry." fi echo echo "info: kexec service stopped." } query_support() { local exit_status=$E_UNSUPPORTED if [ ! -r "$PROCVALIDATE" ]; then modprobe rtas_flash || error $E_MODULE "could not load rtas_flash kernel module" fi if [ -e "/proc/device-tree/rtas/ibm,manage-flash-image" ]; then grep \\"$VALIDATE_AUTH" "$PROCVALIDATE" > /dev/null if [ $? -ne 0 ]; then # validate-flash did not return "not authorized" head --bytes=4k /dev/zero > $PROCVALIDATE 2>/dev/null grep 1 "$PROCVALIDATE" > /dev/null if [ $? -ne 0 ]; then # validate-flash did not return "not authorized" exit_status=0 fi fi else if [ -e "/proc/device-tree/rtas/ibm,update-flash-64-and-reboot" ] || [ -e "/proc/device-tree/rtas/udpate-flash-and-reboot" ]; then exit_status=0 fi fi if [ $exit_status -ne 0 ]; then echo update_flash: flash image cannot be managed from this partition else echo update_flash: flash image management is supported fi exit $exit_status; } echo_validate_rtas_buf() { local output="$1" local cur_t_name="$(echo "$output" | grep "^MI" | head -n 1 | awk ' { print $2 } ')" local cur_p_name="$(echo "$output" | grep "^MI" | head -n 1 | awk ' { print $3 } ')" local new_t_name="$(echo "$output" | grep "^MI" | tail -n 1 | awk ' { print $2 } ')" local new_p_name="$(echo "$output" | grep "^MI" | tail -n 1 | awk ' { print $3 } ')" echo "Projected Flash Update Results:" echo "Current T Image: $cur_t_name" echo "Current P Image: $cur_p_name" echo "New T Image: $new_t_name" echo "New P Image: $new_p_name" } echo_entitlement_expiry_date() { local build_date=`cat $PROCVALIDATE | grep "^MG" | tail -n 1 | cut -d " " -f2` local entl_date=`cat $PROCVALIDATE | grep "^ME" | cut -d " " -f2` echo "The selected firmware image cannot be applied." echo "" echo -n "The Build Date of the firmware image selected is " if [ "$build_date" != "" ]; then echo "$(date --date=$build_date +"%B %d, %Y")." else echo "UNKNOWN." fi echo -n "The System's Update Access Key Expiration Date is " if [ "$entl_date" != "" ]; then echo "$(date --date=$entl_date +"%B %d, %Y")." else echo "UNKNOWN." fi echo "" echo "Please go to http://www.ibm.com/servers/eserver/ess to obtain " echo "a replacement update access key." } echo_validate_return_status() { local output="$1" local rc=$(echo "$output" | head -n 1) local rtas_buf="$(echo "$output" | tail -n +2)" [ $# -eq 1 ] || error $E_USAGE "echo_validate_return_status(): usage" case "$rc" in $VALIDATE_PARAM_ERR) error $E_RTAS "RTAS: validate() Parameter Error";; $VALIDATE_HW_ERR) error $E_RTAS "RTAS: validate() Hardware Error";; $VALIDATE_FLASH_AUTH) error $E_RTAS "RTAS: validate() Partition does not have authority";; $VALIDATE_AUTH) error $E_RTAS "RTAS: validate() Partition does not have authority";; $VALIDATE_INVALID_IMG) error $E_RTAS "RTAS: validate() Invalid candidate image for this platform";; $VALIDATE_TMP_UPDATE) echo "info: Temporary side will be updated with a newer or" echo "identical image";; $VALIDATE_CUR_UNKNOWN) echo "info: Current fixpack level is unknown";; $VALIDATE_TMP_COMMIT_DL) echo "info: Current Temporary image will be committed to" echo "Permanent side before being replaced with new image, and" echo "the new image is downlevel from current image";; $VALIDATE_TMP_COMMIT) echo "info: Current Temporary side will be committed to" echo "Permanent side before being replaced with the new image";; $VALIDATE_TMP_UPDATE_DL) echo "info: Temporary side will be updated with a downlevel" echo "image";; $VALIDATE_OUT_OF_WRNTY) echo_entitlement_expiry_date error $E_WRNTY "Please contact your service support structure.";; *) error $E_RTAS "RTAS: Unknown validate-flash-image Return Status" esac echo echo_validate_rtas_buf "$rtas_buf" # Do not commit T side image to P side if [ $no_overwrite_opt -eq 1 ]; then if [ $rc -eq $VALIDATE_TMP_COMMIT_DL ] || [ $rc -eq $VALIDATE_TMP_COMMIT ]; then echo "" echo "update_flash: Run without -n option to flash new image" exit $E_OVERWRITE fi fi } validate_flash() { local img_file=$1 local output="" [ $# -eq 1 ] || error $E_USAGE "validate_flash(): usage" [ -r $PROCVALIDATE ] || return $E_PROC_FS grep \\"$VALIDATE_AUTH" "$PROCVALIDATE" > /dev/null if [ $? -eq 0 ]; then # validate-flash returned "not authorized" return $E_RTAS fi # Copy image file to proc file cp "$img_file" "$PROCVALIDATE" || error $E_PROC_FS "error copying flash image to rtas_flash validate module" # Display appropriate message, exiting if necessary output="$(cat $PROCVALIDATE)" echo_validate_return_status "$output" # Check kexec service status check_kexec_service if [ $? -eq 0 ]; then echo echo "info: kexec service is running. It will be stopped before flashing." fi return 0 } validate_flash_from_file() { local img_file=$1 [ $# -eq 1 ] || error $E_USAGE "validate_flash_from_file(): usage" if [ ! -r "$PROCVALIDATE" ]; then modprobe rtas_flash || error $E_MODULE "could not load rtas_flash kernel module" [ -r "$PROCVALIDATE" ] || error $E_PROC_FS "rtas_flash kernel module did not create $PROCVALIDATE" fi if validate_flash $img_file; then return 0; else case "$?" in $E_PROC_FS) error $E_PROC_FS "validate: $PROCVALIDATE does not exist";; $E_RTAS) error $E_RTAS "validate: firmware validation not supported on this system";; esac fi } echo_update_status() { local rc="$1" [ $# -eq 1 ] || error $E_USAGE "echo_update_status(): usage" case "$rc" in $FLASH_AUTH) error $E_RTAS "RTAS: Partition does not have authority";; $FLASH_IMG_SHORT) error $E_IMAGE "Flash image shorter than expected";; $FLASH_IMG_BAD_LEN) error $E_PROC_FS "Bad length value in flash list block";; $FLASH_IMG_NULL_DATA) error $E_PROC_FS "Bad data value in flash list block";; $FLASH_IMG_READY) echo "Flash image ready...rebooting the system...";; *) error $E_PROC_FS "RTAS: Unknown update flash status" esac } update_flash_from_file() { local img_file=$1 local output="" local oldkernel=0 [ $# -eq 1 ] || error $E_USAGE "update_flash_from_file(): usage" [ -r "$img_file" ] || error $E_IMAGE "cannot read $img_file" flashfile=$PROCFLASH if [ ! -r "$PROCFLASH" ]; then modprobe rtas_flash if [ ! -r "$PROCFLASH" ]; then if [ -r "$OLDPROCFLASH" ]; then oldkernel=1 else error $E_PROC_FS "rtas_flash kernel module did not create $PROCFLASH" fi fi fi if [ -r "$PROCVALIDATE" ]; then validate_flash "$img_file" fi if [ $oldkernel -eq 0 ]; then dd if="$img_file" of="$PROCFLASH" bs=$PAGE_SIZE 2>/dev/null || error $E_PROC_FS "error copying flash image to rtas_flash kernel module" output="$(cat $PROCFLASH)" echo_update_status "$output" else dd if="$img_file" of="$OLDPROCFLASH" bs=PAGE_SIZE 2>/dev/null || error $E_PROC_FS "error copying flash image to rtas_flash kernel module" cat "$OLDPROCFLASH" fi # Stop kexec service check_kexec_service if [ $? -eq 0 ]; then stop_kexec_service fi #XXX reboot return 0; } echo_manage_return_status() { local is_commit=$1 local output=$2 local rc=$(echo $output) [ $# -eq 2 ] || error $E_USAGE "echo_manage_return_status(): usage" case "$rc" in $MANAGE_AUTH) error $E_RTAS "RTAS: manage() Partition does not have authority";; $MANAGE_ACTIVE_ERR) error $E_RTAS "RTAS: manage() Cannot Overwrite the Active Firmware Image";; $MANAGE_PARAM_ERR) error $E_RTAS "RTAS: manage() Parameter Error";; $MANAGE_HW_ERR) error $E_RTAS "RTAS: manage() Hardware Error";; $MANAGE_SUCCESS) if [ $is_commit -eq 0 ]; then echo "success: Rejected temporary firmware image" else echo "success: Committed temporary firmware image" fi ;; *) error $E_RTAS "Unknown manage-flash-image Return Status" esac } manage_flash() { local is_commit=$1 local commit_str="1" local reject_str="0" local output="" [ $# -eq 1 ] || error $E_USAGE "manage_flash(): usage" if [ ! -r "$PROCMANAGE" ]; then modprobe rtas_flash || error $E_MODULE "could not load rtas_flash kernel module" [ -r "$PROCMANAGE" ] || error $E_PROC_FS "rtas_flash kernel module did not create $PROCMANAGE" fi if [ $is_commit -eq 1 ]; then echo $commit_str > $PROCMANAGE else echo $reject_str > $PROCMANAGE fi output=$(cat $PROCMANAGE) echo_manage_return_status $is_commit "$output" if echo $output | grep "^success" > /dev/null; then return 0 else return $E_RTAS fi } file="" check_opt=0 commit_opt=0 reject_opt=0 validate_opt=0 no_overwrite_opt=0 file_opt=0 [ -d /proc/device-tree ] || error $E_PROC_FS "iSeries or /proc not mounted" #XXX #[ "`whoami`" = "root" ] || error $E_PERM "must be root to execute this command" # Check for platform and if PowerNV call update_flash_nv # PowerNV update_flash tool UPDATE_FLASH_NV=$(dirname $0)/update_flash_nv . $PSERIES_PLATFORM case "$platform" in $PLATFORM_UNKNOWN | $PLATFORM_POWERKVM_GUEST) echo "update_flash: is not supported on the $platform_name platform" exit 1;; $PLATFORM_POWERNV) if [ ! -r "$UPDATE_FLASH_NV" ]; then error $E_PERM "Couldn't find $UPDATE_FLASH_NV file." fi /bin/sh $UPDATE_FLASH_NV $@ exit $? esac while [ -n "$1" ]; do arg="$1" shift case "$arg" in -q|-l|-D|-S) error $E_USAGE "the $arg option is not implemented";; -h) usage $E_SUCCESS;; -s) check_opt=1;; -c) commit_opt=1;; -r) reject_opt=1;; -v) validate_opt=1;; -n) no_overwrite_opt=1;; -f) file_opt=1; file="$1"; shift;; *) error $E_USAGE "unknown option $arg" esac done if [ -n "$file" ]; then if [ $commit_opt -eq 1 ] || [ $reject_opt -eq 1 ] || [ $check_opt -eq 1 ]; then usage elif [ $validate_opt -eq 1 ] && [ $no_overwrite_opt -eq 1 ]; then usage elif [ $validate_opt -eq 1 ]; then validate_flash_from_file $file else update_flash_from_file $file fi else [ $check_opt -eq 1 ] && query_support [ $commit_opt -eq 0 ] && [ $reject_opt -eq 0 ] && usage [ $commit_opt -eq 1 ] && [ $reject_opt -eq 1 ] && usage manage_flash $commit_opt fi powerpc-utils-1.3.4/scripts/update_flash_nv000077500000000000000000000431301315235264300211200ustar00rootroot00000000000000#!/bin/sh # Copyright (c) 2013 International Business Machines # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # Authors: Vasant Hegde # # Simple script for code update on "PowerNV (Non-Virtualized)" platform. # This is a simple wrapper script to pass the image. # - On FSP based system, the Linux kernel and FW does the real work # during system reboot. # - On OpenPower system, we use IPMI interface to pass image to service # processor and service processor will update the image. Then we make # reboot command to reboot the host. # # This script has minimal dependencies so it can operate in a # rescue environment. #set -x # Error codes E_SUCCESS=0 # Success E_UNSUPPORTED=1 # Firmware update is not supported E_USAGE=3 # Usage error E_PERM=4 # Permission error E_IMAGE=5 # Image file error E_SYS_FS=6 # Firmware update related sysfs file doesn't exist E_MODULE=7 # Error loading module E_OPAL=8 # OPAL call failed E_USER=9 # User aborted operation E_OVERWRITE=10 # Auto overwrite permanent side image E_WRNTY=15 # Update Access Key Expired E_KEXEC=16 # Kexec service stop error E_IPMI=17 # ipmitool is not installed # Firmware update related files on FSP based platform SYS_IMAGE_FILE=/sys/firmware/opal/image SYS_VALIDATE_FLASH=/sys/firmware/opal/validate_flash SYS_MANAGE_FLASH=/sys/firmware/opal/manage_flash SYS_UPDATE_FLASH=/sys/firmware/opal/update_flash # Device tree path DT_PATH=/proc/device-tree # Current firmware version files on FSP based platform DT_FW_MI_FILE=${DT_PATH}/ibm,opal/firmware/mi-version DT_FW_ML_FILE=${DT_PATH}/ibm,opal/firmware/ml-version # Code update status values FLASH_SUCCESS=0 # Success FLASH_PARAM_ERR=-1 # Parameter error FLASH_BUSY=-2 # OPAL busy FLASH_HW_ERR=-6 # Hardware error FLASH_INTERNAL_ERR=-11 # Internal error FLASH_NO_OP=-1099 # No operation initiated by user FLASH_NO_AUTH=-9002 # Inband firmware update is not allowed # Validate image status values FLASH_IMG_READY=-1001 # Image ready for validation FLASH_IMG_INCOMPLETE=-1002 # User copied < VALIDATE_BUF_SIZE # Manage image status values FLASH_ACTIVE_ERR=-9001 # Cannot overwrite active img # Flash image status values FLASH_IMG_READY=0 # Image ready for flash on reboot FLASH_INVALID_IMG=-1003 # Flash image shorter than expected FLASH_IMG_NULL_DATA=-1004 # Bad data FLASH_IMG_BAD_LEN=-1005 # Bad length # Validate image update result tokens # # T side will be updated VALIDATE_TMP_UPDATE=0 # # Partition does not have authority VALIDATE_FLASH_AUTH=1 # # Candidate image is not valid for this platform VALIDATE_INVALID_IMG=2 # # Current fixpack level is unknown VALIDATE_CUR_UNKNOWN=3 # # Current T side will be committed to P side before being replace # with new image, and the new image is downlevel from current image VALIDATE_TMP_COMMIT_DL=4 # # Current T side will be committed to P side before being replaced # with new image VALIDATE_TMP_COMMIT=5 # # T side will be updated with a downlevel image VALIDATE_TMP_UPDATE_DL=6 # # The candidate image's release date is later than the system's Update # Access Key Expiration date - service warranty period has expired VALIDATE_OUT_OF_WRNTY=7 error() { local exit_code=$1 if [ $# -lt 1 ]; then echo "error(): usage." >&2 return $E_USAGE fi shift; echo update_flash: $* >&2 exit $exit_code } usage() { local exit_code; if [ "$1" = $E_SUCCESS ]; then exit_code=$E_SUCCESS else exit_code=$E_USAGE fi echo "USAGE: update_flash {-h | -s | -r | -c | -d | [-v|-n] -f }" >&2 echo " -h Print this message." >&2 echo " -s Determine if partition has access to" >&2 echo " perform flash image management." >&2 echo " -r Reject temporary image." >&2 echo " -c Commit temporary image." >&2 echo " -d Display current firmware version." >&2 echo " -v Validate the given image file." >&2 echo " -n Do not overwrite Permanent side" >&2 echo " image automatically." >&2 echo " -f Update with given image file. If possible," >&2 echo " the image is automatically validated prior" >&2 echo " to update." >&2 echo "" >&2 exit $exit_code } # Validate sysfs interface fsp_validate_sysfs_file() { local file="$1" if [ -r "$file" ]; then return $E_SUCCESS fi error $E_SYS_FS "sysfs interface for firmware update does not exists." } # Check kexec service status check_kexec_service() { # check systemctl command which systemctl >/dev/null 2>&1 if [ $? -ne 0 ]; then return 1 fi # kexec service is running systemctl status kexec.service | grep -w "active" >/dev/null 2>&1 if [ $? -eq 0 ]; then return 0 fi return 1 } # Stop kexec service stop_kexec_service() { systemctl stop kexec.service >/dev/null 2>&1 if [ $? -ne 0 ]; then echo "update_flash: Failed to stop kexec service." error $E_KEXEC "Please stop kexec service and retry." fi echo echo "info: kexec service stopped." } # Copy image to sysfs file fsp_copy_candidate_image() { local img_file=$1 [ $# -eq 1 ] || error $E_USAGE "fsp_copy_candidate_image(): usage." [ -r "$img_file" ] || error $E_IMAGE "Cannot read ${img_file}." # Copy candidate image dd if=$img_file of=$SYS_IMAGE_FILE 2>/dev/null if [ $? -ne 0 ]; then echo "update_flash: Error copying firmware image." error $E_IMAGE "Please retry with valid firmware image." fi } fsp_echo_opal_return_status() { case "$1" in $FLASH_PARAM_ERR) error $E_OPAL "Parameter Error.";; $FLASH_BUSY) error $E_OPAL "OPAL Busy.";; $FLASH_HW_ERR) error $E_OPAL "Hardware error.";; $FLASH_INTERNAL_ERR) error $E_OPAL "OPAL internal error.";; $FLASH_NO_AUTH) error $E_PERM "System does not have authority to perform firmware update.";; $FLASH_IMG_INCOMPLETE) error $E_IMAGE "Invalid candidate image.";; $FLASH_ACTIVE_ERR) error $E_OVERWRITE "Cannot Overwrite the Active Firmware Image.";; $FLASH_INVALID_IMG) error $E_IMAGE "Invalid candidate image.";; $FLASH_IMG_NULL_DATA) error $E_IMAGE "Bad data value in flash list block.";; $FLASH_IMG_BAD_LEN) error $E_IMAGE "Bad length value in flash list block.";; *) error $E_OPAL "Unknown return status.";; esac } # Determine if partition has access to perform flash image management fsp_query_flash_support() { # Validate sysfs interface fsp_validate_sysfs_file $SYS_IMAGE_FILE # By default PowerNV host supports firmware management echo "update_flash: Firmware image management is supported." exit $E_SUCCESS } fsp_echo_validate_buf() { local output="$1" local cur_t="$(echo "$output" | grep "^MI" | head -n 1 | awk ' { print $2 } ')" local cur_p="$(echo "$output" | grep "^MI" | head -n 1 | awk ' { print $3 } ')" local new_t="$(echo "$output" | grep "^MI" | tail -n 1 | awk ' { print $2 } ')" local new_p="$(echo "$output" | grep "^MI" | tail -n 1 | awk ' { print $3 } ')" echo "Projected Flash Update Results:" echo "Current T Image: $cur_t" echo "Current P Image: $cur_p" echo "New T Image: $new_t" echo "New P Image: $new_p" } fsp_echo_validate_return_status() { local output="$1" local rc="$(echo "$output" | head -n 1)" local opal_buf="$(echo "$output" | tail -n +2)" [ $# -eq 1 ] || error $E_USAGE "fsp_echo_validate_return_status(): usage." if [ $rc -lt 0 ]; then fsp_echo_opal_return_status $rc fi # Validation result case "$rc" in $VALIDATE_TMP_UPDATE) echo -n "info: Temporary side will be updated with a newer or" echo " identical image.";; $VALIDATE_FLASH_AUTH) error $E_OPAL "System does not have authority.";; $VALIDATE_INVALID_IMG) error $E_OPAL "Invalid candidate image for this platform.";; $VALIDATE_CUR_UNKNOWN) echo "info: Current fixpack level is unknown.";; $VALIDATE_TMP_COMMIT_DL) echo "info: Current Temporary image will be committed to" echo "Permanent side before being replaced with new image," echo "and the new image is downlevel from current image.";; $VALIDATE_TMP_COMMIT) echo "info: Current Temporary side will be committed to" echo "Permanent side before being replaced with the new" echo "image.";; $VALIDATE_TMP_UPDATE_DL) echo "info: Temporary side will be updated with a downlevel image.";; *) error $E_OPAL "Unknown return status." esac echo fsp_echo_validate_buf "$opal_buf" # Do not commit T side image to P side if [ $no_overwrite_opt -eq 1 ]; then if [ $rc -eq $VALIDATE_TMP_COMMIT_DL ] || [ $rc -eq $VALIDATE_TMP_COMMIT ]; then echo "" echo "update_flash: Run without -n option to flash new image." exit $E_OVERWRITE fi fi } fsp_validate_flash() { local output="" # Validate candidate image echo 1 > $SYS_VALIDATE_FLASH 2>/dev/null # Display appropriate message, exiting if necessary output="$(cat $SYS_VALIDATE_FLASH)" fsp_echo_validate_return_status "$output" } fsp_validate_flash_from_file() { local img_file=$1 [ $# -eq 1 ] || error $E_USAGE "fsp_validate_flash_from_file(): usage." # Validate sysfs interface fsp_validate_sysfs_file $SYS_VALIDATE_FLASH # Copy candiadate image fsp_copy_candidate_image $img_file # Validate candidate image fsp_validate_flash # Check kexec service status check_kexec_service if [ $? -eq 0 ]; then echo echo "info: kexec service is running. It will be stopped before flashing." fi exit $E_SUCCESS } fsp_echo_update_return_status() { local rc="$1" [ $# -eq 1 ] || error $E_USAGE "fsp_echo_update_return_status(): usage." if [ $rc -lt 0 ]; then fsp_echo_opal_return_status $rc elif [ $rc -eq $FLASH_IMG_READY ]; then echo echo "FLASH: Image ready...rebooting the system..." echo "FLASH: This will take several minutes." echo "FLASH: Do not power off!" else error $E_SYS_FS "Unknown return status." fi } fsp_update_flash_from_file() { local img_file=$1 local output="" [ $# -eq 1 ] || error $E_USAGE "fsp_update_flash_from_file(): usage." # Validate sysfs interface fsp_validate_sysfs_file $SYS_UPDATE_FLASH # Copy candidate image fsp_copy_candidate_image $img_file # Validate candidate image fsp_validate_flash # Update image echo 1 > $SYS_UPDATE_FLASH 2>/dev/null output="$(cat $SYS_UPDATE_FLASH)" fsp_echo_update_return_status "$output" # Stop kexec service check_kexec_service if [ $? -eq 0 ]; then stop_kexec_service fi # Reboot system, so that we can flash new image reboot exit $E_SUCCESS } fsp_echo_manage_return_status() { local is_commit=$1 local output=$2 local rc=$(echo $output) [ $# -eq 2 ] || error $E_USAGE "fsp_echo_manage_return_status(): usage." if [ $rc -lt 0 ]; then fsp_echo_opal_return_status $rc elif [ $rc -eq $FLASH_SUCCESS ]; then if [ $is_commit -eq 0 ]; then echo "Success: Rejected temporary firmware image." else echo "Success: Committed temporary firmware image." fi else error $E_OPAL "Unknown return status." fi } fsp_manage_flash() { local is_commit=$1 local commit_str="1" local reject_str="0" local output="" [ $# -eq 1 ] || error $E_USAGE "fsp_manage_flash(): usage." # Validate sysfs interface fsp_validate_sysfs_file $SYS_MANAGE_FLASH # Commit operation if [ $is_commit -eq 1 ]; then echo $commit_str > $SYS_MANAGE_FLASH else echo $reject_str > $SYS_MANAGE_FLASH fi # Result output=$(cat $SYS_MANAGE_FLASH) fsp_echo_manage_return_status $is_commit "$output" exit $E_SUCCESS } fsp_display_current_fw_version() { if [ ! -r "$DT_FW_MI_FILE" ] || [ ! -r "$DT_FW_ML_FILE" ]; then error $E_SYS_FS "Firmware version information is not available" fi echo "Current firwmare version :" # P side local ml_ver=`cat $DT_FW_ML_FILE | head -n 1 | awk ' { print $3 }'` local mi_ver=`cat $DT_FW_MI_FILE | head -n 1 | awk ' { print $3 }'` echo " P side : $ml_ver ($mi_ver)" # T side local ml_ver=`cat $DT_FW_ML_FILE | head -n 1 | awk ' { print $2 }'` local mi_ver=`cat $DT_FW_MI_FILE | head -n 1 | awk ' { print $2 }'` echo " T side : $ml_ver ($mi_ver)" # Boot side local ml_ver=`cat $DT_FW_ML_FILE | head -n 1 | awk ' { print $4 }'` local mi_ver=`cat $DT_FW_MI_FILE | head -n 1 | awk ' { print $4 }'` echo " Boot side : $ml_ver ($mi_ver)" exit $E_SUCCESS } # Check for ipmitool command check_ipmitool() { which ipmitool >/dev/null 2>&1 if [ $? -ne 0 ]; then echo "update_flash: ipmitool command not found." error $E_IPMI "Please install ipmitool and retry." fi # Is BMC alive ? ipmitool -I usb mc info >/dev/null 2>&1 && break; if [ $? -ne 0 ]; then echo "update_flash: Failed to connect to BMC." error $E_IPMI "Please try again." fi } opp_query_flash_support() { check_ipmitool # By default PowerNV host supports firmware management echo "update_flash: Firmware image management is supported." exit $E_SUCCESS } opp_validate_flash_from_file() { local img_file=$1 [ $# -eq 1 ] || error $E_USAGE "opp_validate_flash_from_file(): usage." # Check ipmitool check_ipmitool # Check file exists [ -r "$img_file" ] || error $E_IMAGE "Cannot read ${img_file}." ipmitool -z 30000 -I usb hpm check ${img_file} >/dev/null 2>&1 if [ $? -ne 0 ]; then error $E_IPMI "Invalid candidate image for this platform." fi echo "info: Boot side firmware will be updated." echo ipmitool -z 30000 -I usb hpm check ${img_file} exit $E_SUCCESS } bmc_reset() { local timeout=120 # We need to discard the errors as the USB device is reseted # along with the BMC. ipmitool -I usb mc reset cold >/dev/null 2>&1 # The restart should take more or less 80 seconds for retry_count in 1 2; do echo "Waiting for BMC to cold reset. Sleeping $timeout seconds" sleep $timeout ipmitool -I usb mc info >/dev/null 2>&1 && break; retry_count=0 done if [ $retry_count -eq 0 ]; then echo "update_flash: Failed to reset BMC." error $E_IPMI "Please try again." fi } opp_update_flash_from_file() { local img_file=$1 [ $# -eq 1 ] || error $E_USAGE "opp_update_flash_from_file(): usage." # Check ipmitool check_ipmitool # -n option is not applicable for BMC based system if [ $no_overwrite_opt -eq 1 ]; then error $E_IMAGE "Option -n is not applicable on BMC based system." fi # Check file presence [ -r "$img_file" ] || error $E_IMAGE "Cannot read ${img_file}." # Start with a clean state: require a cold reset of the BMC. bmc_reset # Protect BMC memory content, avoid loosing network settings ipmitool -I usb raw 0x32 0xba 0x18 0x00 >/dev/null 2>&1 if [ $? -ne 0 ]; then echo "update_flash: Failed to protect BMC memory content." error $E_IPMI "Please try again." fi # Start firmware update # XXX We have -v option to validate the firmware image. Also BMC # validates image before upgrading. Hence I think we do not # need user confirmation again. Lets pass the confirmation # message here. echo "y" | ipmitool -z 30000 -I usb hpm upgrade $img_file all if [ $? -ne 0 ]; then echo "update_flash: Firmware update failed." # XXX Looks like BMC expects host reboot to # retry firmware update. error $E_IPMI "Please reboot and try again." fi # BMC should reset it self after the update of component 1. As # we need to be sure or reboot will fail, force a reset. bmc_reset # Reboot system echo echo "Firmware update complete." echo "Rebooting the system..." reboot exit $E_SUCCESS } opp_manage_flash() { echo "Commit/Reject operation is not supported on this platform." exit $E_SUCCESS } opp_display_current_fw_version() { check_ipmitool echo id=`ipmitool -I usb fru 2>/dev/null |grep "System Firmware" | cut -d " " -f8 | cut -d ")" -f1` if [ "x$id" = "x" ]; then error $E_IPMI "Failed to get firmware version." fi echo "Firmware version:" ipmitool -I usb fru print $id exit $E_SUCCESS } file="" check_opt=0 display_opt=0 commit_opt=0 reject_opt=0 validate_opt=0 no_overwrite_opt=0 file_opt=0 # Only root user can perform firmware update [ "`whoami`" = "root" ] || error $E_PERM "Must be root to execute this command." # Check for platform and call appropriate functions if [ -d ${DT_PATH}/fsps ]; then platform="fsp" elif [ -d ${DT_PATH}/bmc ]; then platform="opp" # OpenPower platform else echo "update_flash: Unknown platform" exit $E_UNSUPPORTED fi # Parse command line options while [ -n "$1" ]; do arg="$1" shift case "$arg" in -q|-l|-D|-S) error $E_USAGE "The $arg option is not implemented.";; -h) usage $E_SUCCESS;; -s) check_opt=1;; -d) display_opt=1;; -c) commit_opt=1;; -r) reject_opt=1;; -v) validate_opt=1;; -n) no_overwrite_opt=1;; -f) file_opt=1; file="$1"; shift;; *) error $E_USAGE "Unknown option ${arg}." esac done if [ -n "$file" ]; then if [ $commit_opt -eq 1 ] || [ $reject_opt -eq 1 ] || [ $display_opt -eq 1 ] || [ $check_opt -eq 1 ]; then usage elif [ $validate_opt -eq 1 ] && [ $no_overwrite_opt -eq 1 ]; then usage elif [ $validate_opt -eq 1 ]; then ${platform}_validate_flash_from_file $file else ${platform}_update_flash_from_file $file fi else if [ $check_opt -eq 1 ]; then if [ $commit_opt -eq 1 ] || [ $reject_opt -eq 1 ] || [ $display_opt -eq 1 ]; then usage else ${platform}_query_flash_support fi fi # Display current firmware version if [ $display_opt -eq 1 ]; then if [ $commit_opt -eq 1 ] || [ $reject_opt -eq 1 ]; then usage else ${platform}_display_current_fw_version fi fi [ $commit_opt -eq 0 ] && [ $reject_opt -eq 0 ] && usage [ $commit_opt -eq 1 ] && [ $reject_opt -eq 1 ] && usage ${platform}_manage_flash $commit_opt fi powerpc-utils-1.3.4/scripts/vscsisadmin000077500000000000000000001022021315235264300202750ustar00rootroot00000000000000#!/usr/bin/perl -w # IBM "vscsisadmin": IBMVSCSIS driver configuration application # # Copyright (c) 2004, 2005 International Business Machines. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # Author(s): Ryan S. Arnold # # This application provides a method to configure, start and stop a vscsi # server with minimum user interaction. # # For further details please reference man page vscsisadmin.8 use strict; use File::Basename; use vars '$app_name'; $app_name = "vscsiadmin"; use vars '$app_version'; $app_version = "1.0.0"; use vars '$driver'; $driver = "ibmvscsis"; use vars '$sysfs_node_name'; $sysfs_node_name = "ibmvscsis"; use vars '$noisy'; $noisy = 0; use vars '$warn'; $warn = 0; use vars '$stop_path'; $stop_path = ''; use vars '$param_adapter'; my $param_adapter = ''; use vars '$param_bus'; my $param_bus = ''; use vars '$param_target'; my $param_target = ''; use vars '$config_file'; $config_file = "ibmvscsis.conf"; use Getopt::Long; # Simply output the version information about this helper application. sub versioninfo { print "IBM ", $app_name, " version ",$app_version,"\n"; print "Copyright (C) 2004, IBM Corporation.\n"; print "Author(s) Ryan S. Arnold\n"; } sub verboseprint( $ ) { my $output = shift; if($noisy > 1) { print "$output"; } } sub warnprint( $ ) { my $output = shift; if($warn > 0 ) { print "$output"; } } sub statusprint( $ ) { my $output = shift; if($noisy > 0 ) { print "$output"; } } sub errorprint( $ ) { my $output = shift; print "$output"; } # Help information text displayed to the user when they invoke the script with # the -h tag. sub helpinfo { print "Usage: ", $app_name, " [options]\n"; print "Options:\n"; print " -start"; print "\t\t$app_name will read the $config_file config file and start\n"; print "\t\t$driver based upon the information contained therein.\n"; print "\n"; print "\t\tSupports the following extended commands for selective start:\n"; print "\n"; print "\t\t\t-adapter= -bus= -target=\n"; print "\t\t\t-adapter= -bus=\n"; print "\t\t\t-adapter=\n"; print "\n"; print " -stop"; print "\t\t$app_name will navigte the $driver sysfs directory and\n"; print "\t\tterminate the target and bus configurations found therein.\n"; print "\n"; print "\t\tSupports the following extended commands for selective stop:\n"; print "\n"; print "\t\t\t-adapter= -bus= -target=\n"; print "\t\t\t-adapter= -bus=\n"; print "\t\t\t-adapter=\n"; print "\t\t\t-path=\n"; print "\n"; print " -status"; print "\tOutput a table of ibmvscsis adapter information that highlights\n"; print "\t\tthe state of the running $driver and denotes the activity\n"; print "\t\tstate of each adapter:bus:target.\n"; print "\n"; print " -help"; print "\t\tOutput this help text.\n"; print "\n"; print "\t\tSee manual page vscsisadmin (8) for further information.\n"; print "\n"; print " -noisy"; print "\t\tA stackable directive that changes the script\n"; print "\t\tverbosity. The default noise level of '0' makes $app_name\n"; print "\t\tsilent on success but verbose on error. A noise level\n"; print "\t\tof '1' will output additional success information. A\n"; print "\t\tnoisy level of '2' will output $app_name script trace\n"; print "\t\tinformation.\n"; print "\n"; print " -version\tOutput the ", $app_name, " script's version number.\n"; } # Verify that the systools package is installed. This package is required for # using this scripts because this script uses systools to make sysfs queries. # It then strips relevant data from the systool queries for use in additional # features. sub findsystools() { #--------------- Look for the systool application ----------------------- local *WHICH; open WHICH, "which systool|"; my @whicharray = ; my $whichline = join("\n", @whicharray); if ($noisy > 1) { print "$app_name\: looking for \"systool\" application.\n"; } if ($whichline eq "") { print "$app_name\: systool is not installed or not in the path?\n"; print "$app_name\: systool is required by the $app_name script.\n"; return -1; } if ($noisy > 1) { print "$app_name\: found \"systool\" at ", $whichline; } return 0; } # If this function returns a non-empty string then the module is loaded and # the module's sysfs entry is located at the location given by the return # value. sub is_driver_installed() { my $val = ""; my $local_driver = ""; my $driver_path = ""; verboseprint("$app_name: is $driver loaded.\n"); local *SYSTOOL; open SYSTOOL, "systool -b vio -D -p|" or die "systool: $!"; while (my $line = ) { ($val) = ($line =~ /^\s*Driver = "(.*)"\s*$/); if(defined $val) { $local_driver = $1; $driver_path = ""; next; } ($val) = ($line =~ /^\s*Driver path = "(.*)"\s*$/); if(defined $val) { $driver_path = $1; # grab only the Driver,Driver path pair for $driver if ($local_driver eq $driver) { verboseprint("$app_name: verified that $driver is loaded at $driver_path\.\n"); return $driver_path; } next; } } errorprint("$app_name: $driver is not loaded.\n"); return ""; } sub status_target( $ $ $ ) { my $bus_path = shift; my $target = shift; my $bus = shift; my $target_path = "$bus_path/$target"; my $output = "$target:"; if (! -e "$target_path/active") { print "WARNING didn't find $target_path/active attribute.\n"; return; } if (! -e "$target_path/device") { print "WARNING didn't find $target_path/device attribute.\n"; return; } local *DEVICE; open DEVICE, "cat $target_path/device |"; my @data = ; close DEVICE; my $device = $data[0]; chomp($device); # If there was no device entry we can just bail. if ($device eq "") { return; } local *ACTIVE; open ACTIVE, "cat $target_path/active |"; my @activedata = ; close ACTIVE; my $active = $activedata[0]; chomp($active); if ($active) { $active = " *"; } else { $active = ""; } $output .= "$device"; local *LOSETUP; open LOSETUP, "losetup -a |"; my @entries = ; close LOSETUP; my $loop_back_device = ""; foreach my $entry (@entries) { chomp($entry); if ($entry =~ /^$device: \[\w+\]:\w+ \(([A-Za-z0-9\-\_\/]+)\)/) { $loop_back_device = $1; } } if ($loop_back_device ne "") { $output .= "-->$loop_back_device"; } else { $output .= ""; } print "$active\t$bus:$output\n"; } sub status_bus( $ $ ) { my $adapter_path = shift; my $bus = shift; my $bus_path = "$adapter_path/$bus"; local *ATTRIB_DIRHANDLE; opendir(ATTRIB_DIRHANDLE, "$bus_path"); my @target_list = sort readdir ATTRIB_DIRHANDLE; closedir ATTRIB_DIRHANDLE; my $targetnumber = ""; foreach my $targetentry (@target_list) { if ($targetentry =~ /^target(\w+)/) { $targetnumber = $1; status_target($bus_path, $targetentry, $bus); } } } sub status_adapter( $ $ ) { my $driver_path = shift; my $adapter = shift; my $adapter_path = "$driver_path/$adapter"; local *ATTRIB_DIRHANDLE; opendir(ATTRIB_DIRHANDLE, "$adapter_path"); my @bus_list = sort readdir ATTRIB_DIRHANDLE; closedir ATTRIB_DIRHANDLE; print "$driver:$adapter\n"; my $busnumber = ""; foreach my $busentry (@bus_list) { if ($busentry =~ /^bus(\w+)/) { $busnumber = $1; status_bus($adapter_path, $busentry); } } } sub status() { #cruise through sysfs looking for configurations with device entries #denote whether they are active or inactive my $driver_path = is_driver_installed(); if ($driver_path eq "") { print "$driver is not loaded.\n"; return -1; } local *ATTRIB_DIRHANDLE; opendir(ATTRIB_DIRHANDLE, "$driver_path"); my @adapter_list = sort readdir ATTRIB_DIRHANDLE; closedir ATTRIB_DIRHANDLE; foreach my $adapter (@adapter_list) { # Only operate on vscsi server adapters if (-e "$driver_path/$adapter/name") { # maybe we should check the value of name and make sure it is # v-scsi-host? status_adapter($driver_path, $adapter); } } } sub find_config_file() { local *DIRHANDLE; opendir(DIRHANDLE, "/etc"); my @allfiles = readdir DIRHANDLE; closedir DIRHANDLE; my $dirlist = join(":", @allfiles); if ($dirlist !~ /:$config_file/) { return 0; } return 1; } sub find_adapter( $ ) { my $adapter_number = shift; my $local_driver; my $local_device; my $local_device_path; my $val = ""; local *SYSTOOL; open SYSTOOL, "systool -b vio -D -p|" or die "systool: $!"; while (my $line = ) { ($val) = ($line =~ /^\s*Driver = "(.*)"\s*$/); if(defined $val) { $local_driver = $1; $local_device = ""; $local_device_path = ""; next; } ($val) = ($line =~ /^\s*Device = "(.*)"\s*$/); if(defined $val) { $local_device = $1; #reset with each Device or else we might pick up a stale one from #a previous device. $local_device_path = ""; next; } ($val) = ($line =~ /^\s*Device path = "(.*)"\s*$/); if(defined $val) { $local_device_path = $1; # Since this block is only true if the previous block was for the # right driver this can guarentee that all adapters that are # found are valid vscsis host adapters. if (($local_driver eq $driver) and ($local_device eq $adapter_number)) { close SYSTOOL; return $local_device_path; } next; } } close SYSTOOL; return ""; } # This function assumes a valid adapter path sub find_bus( $ $ ) { my $adapter_path = shift; my $bus = shift; my $middle = "| *"; # $adapter_path should ne "" if($adapter_path eq "") { errorprint("$app_name: find_bus invoked with empty adapter_path.\n"); return ""; } if(! -d "$adapter_path") { errorprint("$app_name: sysfs entry for adapter at: \"$adapter_path\" does not exists.\n"); return ""; } local *ATTRIB_DIRHANDLE; opendir(ATTRIB_DIRHANDLE, "$adapter_path"); my @attributes = readdir ATTRIB_DIRHANDLE; closedir ATTRIB_DIRHANDLE; my $attribute_list = ""; $attribute_list = join(":", @attributes); if ($attribute_list !~ /:bus$bus/) { # Bus doesn't exist return ""; } verboseprint("$middle $app_name: $adapter_path/bus$bus already exists.\n"); return "$adapter_path/bus$bus"; } sub find_target( $ $ ) { my $bus_path = shift; my $target = shift; my $middle = "| *"; # $bus_path should ne "" if($bus_path eq "") { errorprint("$app_name: find_target invoked with empty bus_path.\n"); return ""; } if(! -d "$bus_path") { errorprint("$app_name: sysfs entry for bus at: \"$bus_path\" does not exists.\n"); return ""; } local *ATTRIB_DIRHANDLE; opendir(ATTRIB_DIRHANDLE, "$bus_path"); my @attributes = readdir ATTRIB_DIRHANDLE; closedir ATTRIB_DIRHANDLE; my $attribute_list = ""; $attribute_list = join(":", @attributes); if ($attribute_list !~ /:target$target/) { # Target doesn't exist return ""; } verboseprint("$middle $app_name: $bus_path/target$target already exists.\n"); return "$bus_path/target$target"; } sub add_bus_and_target( $ $ $ ) { my $adapter_path = shift; my $bus = shift; my $target = shift; my $bus_path = ""; my $target_path = ""; my $begin = "|-.-"; my $end = "| `-- "; if ($adapter_path eq "") { errorprint("$app_name: add_bus_and_target invoked with empty \$adapter_path.\n"); return ""; } $bus_path = find_bus($adapter_path, $bus); if ($bus_path eq "") { #echo num busses++ to the adapter num_busses entry which will #automatically add the bus entry to the adapter entry. if( ! -e "$adapter_path/num_buses") { errorprint("$app_name: sysfs attribute \"$adapter_path/num_buses\" does not exists.\n"); return ""; } local *NUM_BUSES_FILE; open NUM_BUSES_FILE, "$adapter_path/num_buses"; my $num_buses = int(); # This should account for missordered bus entries in the config file. # If a config entry asks for bus3 to be created before bus2 has been # created then this app will create 4 bus targets to accomadate bus3 # and when bus2 is read from the config it won't need to be created. if (($bus + 1) > ($num_buses + 1)) { $num_buses = $bus + 1; # bus number + 1 (for indexing correction) } else { $num_buses = $num_buses + 1; } verboseprint("$begin Set $adapter_path/num_buses to $num_buses\.\n"); verboseprint("$end Added bus$bus to $adapter_path\.\n"); `echo $num_buses > $adapter_path/num_buses 2>/dev/null`; close NUM_BUSES_FILE; $bus_path = find_bus($adapter_path, $bus); if ($bus_path eq "") { errorprint("$app_name: bus$bus not found after supposed addition.\n"); return ""; } } $target_path = find_target($bus_path, $target); if ($target_path eq "") { if( ! -e "$bus_path/num_targets") { errorprint("$app_name: sysfs attribute \"$bus_path/num_targets\" does not exists.\n"); return ""; } local *NUM_TARGETS_FILE; open NUM_TARGETS_FILE, "$bus_path/num_targets"; my $num_targets = int(); # Same reasoning as with creating buses noted above. if (($target + 1) > ($num_targets + 1)) { $num_targets = $target + 1; # target num + 1 (for idx correction) } else { $num_targets = $num_targets + 1; } verboseprint("$begin Set $bus_path/num_targets to $num_targets\.\n"); verboseprint("$end Added target$target to bus$bus.\n"); `echo $num_targets > $bus_path/num_targets 2>/dev/null`; close NUM_TARGETS_FILE; $target_path = find_target($bus_path, $target); } # It is possible that $target_path might be empty if the config file was # not well formed. return $target_path; } sub get_start_pattern( $ $ $ ) { my $adapter = shift; my $bus = shift; my $target = shift; my $start_pattern = ""; #check for constraints if ($adapter ne "") { if ($bus ne "") { if ($target ne "") { $start_pattern = "($adapter):bus($bus):target($target)\\s*"; } else { $start_pattern = "($adapter):bus($bus):target(\\d+)\\s*"; } } else { $start_pattern = "($adapter):bus(\\d+):target(\\d+)\\s*"; } } else { $start_pattern = "(\\w+):bus(\\d+):target(\\d+)\\s*"; } return $start_pattern; } # The parameters may be used to constrain the start operation to a particular # target on a bus, on an adapter, or simply all the targets under a bus on an # adapter, or all targets on all buses under and adapter. sub start_all( $ $ $ ) { my $constrain_adapter = shift; my $constrain_bus = shift; my $constrain_target = shift; #tabled output prefixes. my $begin = "|-.-"; my $middle = "| |--"; my $end = "| `--"; #read the entire config file into one string and work from there. my $file_contents; { local *CONFIG_FILE; open CONFIG_FILE, "/etc/$config_file" or die "/etc/$config_file missing: $!"; local $/ = undef; $file_contents = ; close CONFIG_FILE; } my $start_pattern = get_start_pattern($constrain_adapter, $constrain_bus, $constrain_target); if ($start_pattern eq "") { errorprint("$app_name: start pattern is empty!\n"); return; } # Split into config entry blocks and process each block one at a time. # m means "Let ^ and $ match next to embedded \n # This strips the ibmvscsis: portion off the headers my @entries = split /^ibmvscsis:/m, $file_contents; statusprint(".- $app_name: Reading config file and starting vscsis server.\n"); foreach my $entry (@entries) { #header information my $adapter = ""; my $bus = ""; my $target = ""; #paths derived from header information my $adapter_path = ""; my $target_path = ""; #attributes in adapter/bus/target/ my $loop_file = ""; my $device_path = ""; my $valid = 0; my $type = ""; my $active = 1; #entries active by default #return value my $val = undef; #only match those config entries defined by $start_pattern ($val) = ($entry =~ /$start_pattern/i); if (defined $val) { ($adapter, $bus, $target) = ($1, $2, $3); $adapter_path = find_adapter($adapter); if ($adapter_path ne "") { $target_path = add_bus_and_target($adapter_path, $bus, $target); if ($target_path eq "") { errorprint("$app_name: creation of bus$bus:target$target under adapter:$adapter failed.\n"); next; #bail on this entry } else { # kind of missleading because the target may already exist, # but for output purposes this should be ok. statusprint("$begin vty-server\@$adapter/bus$bus/target$target created.\n"); } #precautionary, though it shouldn't be necessary if vscsis is working #properly if (! -e "$target_path/device") { errorprint("$app_name: target$target/device attribute doesn't exist.\n"); next; } elsif (! -e "$target_path/type") { errorprint("$app_name: target$target/type attribute doesn't exist.\n"); next; } elsif (! -e "$target_path/active") { errorprint("$app_name: target$target/active attribute doesn't exist.\n"); next; } } else { warnprint("$begin vty-server\@$adapter not present in sysfs.\n"); next; #bail on this entry } $val = undef; } else { #ignore empty entry blocks (may be a defect in the split) next; #bail on this entry } ($val) = ($entry =~ /\n\s*none\s*/i); if (defined $val) { statusprint("$end Found placeholder entry, ignoring.\n"); #no further configuration required for placeholder entries next; } # Must have a device_path element to be valid. ($val) = ($entry =~ /\n\s*device_path=\"(.*)\"\s*/i); if (defined $val) { $device_path = $1; $val = undef; } else { #This is an invalid entry and no device elements will be written #to sysfs. statusprint("$end Didn't find device path for bus$bus:target$target, ignoring entry.\n"); next; } ($val) = ($entry =~ /\n\s*loop_file=\"(.*)\"\s*/i); if (defined $val) { $loop_file = $1; if (! -e "$loop_file") { statusprint("$end loop_file \"$loop_file\" not found, ignoring entry.\n"); next; } $val = undef; } # defaults to block device if there is not a type element specified # in the future the type could be read from the /dev/ entry # pointed to by the "device" element, unless of course a flat file # .iso is set up as a loop device. ($val) = ($entry =~ /\n\s*type=\"(.*)\"\s*/i); if (defined $val) { $type = $1; $val = undef; } else { verboseprint("$middle didn't find 'type' element, defaulting to 'block'.\n"); $type = "b"; } # active by default ($val) = ($entry =~ /\n\s*inactive\s*/i); if (defined $val) { $active = 0; $val = undef; } #We checked to make sure all the attributes are present earlier. #Check if the target is active before writing any data to the target #entry. This is a good enough method for checking dupe config entries as #well. local *ACTIVE; open ACTIVE, "cat $target_path/active |"; my @activedata = ; close ACTIVE; chomp($activedata[0]); if ($activedata[0] eq "1") { statusprint("$end vty-server\@$adapter:bus$bus:target$target already active.\n"); next; } # Setup loop file to loop device if loop_file is present, we checked # for its existence earlier. if ($loop_file ne "") { `losetup $device_path $loop_file 2>/dev/null`; statusprint("$middle Mapping loop device $device_path\-->$loop_file\n"); } # By this point we know $target/device exists and so does $device_path so # just write it to the attribute. `echo $device_path > $target_path/device 2>/dev/null`; statusprint("$middle wrote \"$device_path\" to target$target/device.\n"); #write type to target/type in sysfs `echo $type > $target_path/type 2>/dev/null`; statusprint("$middle wrote \"$type\" to target$target/type.\n"); if ($active) { statusprint "$end Activating $adapter:bus$bus:target$target\.\n"; `echo 1 > $target_path/active 2>/dev/null`; } else { statusprint("$end $adapter:bus$bus:target$target left inactive by request.\n"); } } statusprint("`- $app_name Finished reading config file and starting targets.\n"); } sub start() { # If all of these eq "" then there are no start constraints and all # targets on all buses and adapters will be started. start_all( $param_adapter, $param_bus, $param_target ); } sub stop_target( $ $ ) { #Axiom 1: Target entries with missing attributes are malformed and are # not touched. #Axiom 2: The ibmvscsis driver prevents activation of a target if the # device attribute is empty (not set). Therefore if the device is # unset this function is considered complete for such targets. #Rule 1: Always detach the loop device even if the target isn't active. #Rule 2: Always deactivate an active connection. my $target_path = shift; my $target = shift; my $end = "| | `--"; my $middle = "| | |--"; if (! -e "$target_path/active") { statusprint("$end incomplete target entry, no \"active\" attribute.\n"); return; } if (! -e "$target_path/device") { statusprint("$end incomplete target entry, no \"device\" attribute.\n"); return; } local *ACTIVE; open ACTIVE, "cat $target_path/active |"; my @activedata = ; close ACTIVE; chomp($activedata[0]); my $active = $activedata[0]; local *DEVICE; open DEVICE, "cat $target_path/device |"; my @devicedata = ; close DEVICE; my $device = $devicedata[0]; chomp($device); if ($device eq "") { statusprint ("$end no device associated with $target\.\n"); return; } local *LOSETUP; open LOSETUP, "losetup -a |"; my @entries = ; close LOSETUP; my $loop_back_device = ""; foreach my $entry (@entries) { chomp($entry); if ($entry =~ /^$device: \[\w+\]:\w+ \(([A-Za-z0-9\-\_\/]+)\)/) { $loop_back_device = $1; } } if ($active eq "0" and $loop_back_device ne "") { # Not active and there is still a loop device, detach loop anyway. statusprint("$middle $target not active .\n"); statusprint("$end detaching loop device $device from $loop_back_device\n"); `losetup -d $device 2>/dev/null`; } elsif ($active eq "1" and $loop_back_device ne "") { #It is active and there is a loop device statusprint("$middle deactivating $target\.\n"); statusprint("$end detaching loop device $device from $loop_back_device\n"); `echo 0 > $target_path/active 2>/dev/null`; `losetup -d $device 2>/dev/null`; } elsif ($active eq "1") { statusprint("$end deactivating $target\n"); `echo 0 > $target_path/active 2>/dev/null`; } else { statusprint("$end $target not active.\n"); } } sub stop_bus( $ $ ) { my $bus_path = shift; my $bus = shift; my $middle = "| |--"; my $end = "| `--"; if(! -d "$bus_path") { errorprint("$app_name: $bus sysfs entry $bus_path does not exist.\n"); return; } opendir(ATTRIB_DIRHANDLE, "$bus_path"); my @tentry_list = sort readdir ATTRIB_DIRHANDLE; closedir ATTRIB_DIRHANDLE; my $target = ""; # work on targets in reverse order #foreach my $entry (reverse @entry_list) { foreach my $tentry (@tentry_list) { if ($tentry =~ /^target(\w+)/) { $target = $1; statusprint("$middle stopping $tentry\n"); stop_target("$bus_path/$tentry", $tentry); } } `echo 0 > $bus_path/num_targets 2>/dev/null`; statusprint("$end removed all targets from $bus\.\n"); } sub stop_adapter( $ $ ) { my $adapter_path = shift; my $adapter = shift; my $end = "`--"; my $middle = "|--"; if(! -d "$adapter_path") { errorprint("$app_name: adapter $adapter sysfs entry $adapter_path does not exist.\n"); return; } opendir(ATTRIB_DIRHANDLE, "$adapter_path"); my @bentry_list = sort readdir ATTRIB_DIRHANDLE; closedir ATTRIB_DIRHANDLE; my $bus = ""; # work on adapters in reverse order foreach my $bentry (@bentry_list) { if ($bentry =~ /^bus(\w+)/) { $bus = $1; statusprint("$middle stopping $bentry\n"); stop_bus("$adapter_path/$bentry", $bentry); } } `echo 0 > $adapter_path/num_buses 2>/dev/null`; statusprint("$end removed all buses from adapter $adapter\.\n"); } # The stop_all function is indescriminate. It'll clear out the bus & target # configuration for every single vscsis adapter, regardless of whether that # adapter has an entry in the config file. sub stop_all() { my $end = "`"; my $middle = "-"; my $driver_path = is_driver_installed(); if ($driver_path eq "") { print "$driver is not loaded.\n"; return -1; } opendir(ATTRIB_DIRHANDLE, "$driver_path"); my @adapter_list = sort readdir ATTRIB_DIRHANDLE; closedir ATTRIB_DIRHANDLE; statusprint("$app_name: stopping vscsi server.\n"); foreach my $adapter (@adapter_list) { # Only operate on vscsi server adapters if (-e "$driver_path/$adapter/name") { # maybe we should check the value of name and make sure it is # v-scsi-host? statusprint( ".- stopping vty-server\@$adapter\.\n"); stop_adapter("$driver_path/$adapter", $adapter); } } statusprint("$app_name: vscsi server stopped.\n"); } # This function simply parses a path that was a script arguement and breaks it # into adapter, bus, and target. sub stop_path() { my $val = undef; # if stop path is defined it cancels out trailing adapter, bus, and # target settings. if (! -d "$stop_path" ) { errorprint("$app_name: path $stop_path not found.\n"); return; } # the \/?$ catches a trailing '/' on the path, or not ($val) = ($stop_path =~ /\/ibmvscsis\/(.*)\/bus(\d*)\/target(\d*)\/?$/); if (defined $val) { $param_adapter = $1; $param_bus = $2; $param_target = $3; $val = undef; return; } ($val) = ($stop_path =~ /\/ibmvscsis\/(.*)\/bus(\d*)\/?$/); if (defined $val) { $param_adapter = $1; $param_bus = $2; $param_target = ""; $val = undef; return; } ($val) = ($stop_path =~ /\/ibmvscsis\/(\w+)\/?$/); if (defined $val) { $param_adapter = $1; $param_bus = ""; $param_target = ""; $val = undef; } } sub stop() { if ($stop_path ne "" ) { #divide the path into adapter, bus, and path. stop_path(); } #stop an entire adapter if there is no bus specified. if ($param_adapter ne "") { my $adapter_path = find_adapter($param_adapter); if ($adapter_path eq "") { errorprint("$app_name: no path for vty-server\@$param_adapter\.\n"); return; } if ($param_bus ne "") { my $bus_path = "$adapter_path/bus$param_bus"; if (! -d "$bus_path") { errorprint("$app_name: path $bus_path not found.\n"); return; } if ($param_target ne "") { statusprint(".--- Stopping vty-server\@$param_adapter/bus$param_bus/target$param_target\.\n"); #stop the target on the adapter/bus only stop_target("$bus_path/target$param_target","target$param_target"); statusprint("`--- Stopped.\n"); return } #stop the whole adapter/bus statusprint(".-- Stopping all targets on vty-server\@$param_adapter/bus$param_bus\.\n"); statusprint("|`.\n"); stop_bus("$adapter_path/bus$param_bus","bus$param_bus"); statusprint("`-- Stopped.\n"); return; } #stop the whole adapter statusprint( ".- stopping vty-server\@$param_adapter\.\n"); stop_adapter("$adapter_path", $param_adapter); return; } #default, with no args is to stop it all stop_all(); } my $PSERIES_PLATFORM = dirname(__FILE__) . "/pseries_platform"; my $perldumpenv='perl -MData::Dumper -e '."'". '\$Data::Dumper::Terse=1;print Dumper(\%ENV);'."'"; eval '%ENV=('.$1.')' if `bash -c " . $PSERIES_PLATFORM; $perldumpenv"` =~ /^\s*\{(.*)\}\s*$/mxs; if ($ENV{'platform'} != $ENV{'PLATFORM_PSERIES_LPAR'}) { print "$app_name: is not supported on the $ENV{'platform_name'} platform\n"; exit 1; } my $help = ''; my $version = ''; my $stop = ''; my $start = ''; my $status = ''; my $num_options = @ARGV; GetOptions ( 'help|?' => \$help, 'noisy+' => \$noisy,# noisy is incremental, # 0 : silent (except on error) [default] # 1 : status (successes) # 2 : verbose operation trace 'status' => \$status, 'stop' => \$stop, # and 'path=s' => \$stop_path, # or 'adapter=s' => \$param_adapter, 'bus=s' => \$param_bus, 'target=s' => \$param_target, 'start' => \$start, #also with adapter, bus, and target 'version' => \$version, 'warn+' => \$warn, ); # An empty invocation of this script will result in the help text being # output. If help text has been specified then this script will terminate # after outputing the help text without completing further operations. if ($num_options == 0 || $help) { helpinfo(); exit; } if ($version) { versioninfo(); exit; } if ($noisy > 1) { verboseprint("$app_name: executing in verbose mode.\n"); } if ($warn > 0) { verboseprint("$app_name: executing with warn enabled.\n"); } #--------------- Look for the systool application ----------------------- # The systool application is required for invoking most/many of these # operations so we'll express it as a standard requirement. if (findsystools()) { exit; } if ($status) { status(); exit; } if ($start) { start(); exit; } if ($stop) { stop(); exit; } exit; powerpc-utils-1.3.4/src/000077500000000000000000000000001315235264300151275ustar00rootroot00000000000000powerpc-utils-1.3.4/src/activate_fw.c000066400000000000000000000234261315235264300175760ustar00rootroot00000000000000/** * @file activate_fw.c * @brief Activate Firmware command */ /** * @mainpage activate_firmware documentation * @section Copyright * Copyright (c) 2004 International Business Machines * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * @section Overview * Simple command to call the "ibm,activate-firmware" rtas call via librtas.so * when called without any option. With -e option, the command either fetches * the current access key expiry date or sets the access key expiry date if * is provided. * * The return codes for this command are as follows:
* 0 - Success!!
* 1 - This platform doesn't support concurrent activation of firmware.
* 2 - There's no new firmware ready to activate (RTAS returned -9001).
* 3 - You must have root authority to run this command.
* 4 - Hardware failure (RTAS returned -1).
* 5 - Memory/resource allocation error.
* 6 - General error.
* 7 - Error in case of getting UAK expiry date or setting UAK.
* 8 - Parameter error when activating firmware.
* * For the specific mappings of librtas and rtas_call return codes (librtas * return codes are in all caps) to the return codes listed above see the * switch statement in the code. There are two values that can be returned * by the rtas call but are not explicitly handled below and are handled by * the default case statement. These are -2 (busy, try again) and 990x * (extended delay). The librtas module intercepts these return codes and * handles them itself, they should never be returned from librtas. * * In case of keyfile and general errors, the appropriate error description * (if available) is written to stderr. * * @author Nathan Fontenot * @author Chandni Verma */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "librtas_error.h" #include "pseries_platform.h" static int verbose; /* Size of array */ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /* Parameter tokens */ #define SYS_PARAM_UAK_EXPIRY_DATE 53 #define SYS_PARAM_UAK_KEY 54 /* Update Access Key expiry date buffer length */ #define UAK_EXPIRY_DATE_DATA_LENGTH 11 /* Actual Update Access Key length */ #define UAK_KEY_LENGTH 34 /* UAK key data buffer length */ #define UAK_KEY_DATA_LENGTH (UAK_KEY_LENGTH + 3) /* Size of buffer recording RTAS error description */ #define ERR_BUF_SIZE 40 #define UAK_ERROR 7 static int activate_firmware(void) { int rc; rc = rtas_activate_firmware(); /* Map 'rc' to valid return code listed above */ switch (rc) { /* 0 - Success!! */ case 0: if (verbose) printf("activate_firmware: rtas call succeeded\n"); break; /* 1 - activate-firmware not supported */ case RTAS_KERNEL_INT: /* No kernel interface to firmware */ case RTAS_KERNEL_IMP: /* No kernel implementation of function */ case RTAS_UNKNOWN_OP: /* No firmware implementation of function */ if (verbose) { printf("activate_fw: rtas call returned %d, " "converting to %d\n", rc, 1); } rc = 1; break; /* 2 - no new firmware to activate */ case -9001: if (verbose) { printf("activate_fw: rtas call returned %d, " "converting to %d\n", rc, 2); } rc = 2; break; /* 3 - no root authority */ case RTAS_PERM: if (verbose) { printf("activate_fw: rtas call returned %d, " "converting to %d\n", rc, 3); } rc = 3; break; /* 4 - hardware error */ case -1: if (verbose) { printf("activate_fw: rtas call returned %d, " "converting to %d\n", rc, 4); } rc = 4; break; /* 5 - Memory/resource allocation error */ case RTAS_NO_MEM: case RTAS_NO_LOWMEM: if (verbose) { printf("activate_fw: rtas call returned %d, " "converting to %d\n", rc, 5); } rc = 5; break; case -3: if (verbose) { printf("activate_fw: rtas call returned %d, " "converting to %d\n", rc, 8); } rc = 8; break; /* 6 - catch all other return codes here */ default: if (verbose) { printf("activate_fw: rtas call returned %d, " "converting to %d\n", rc, 6); } rc = 6; break; } return rc; } static int get_uak_expiry_date(void) { int rc; char date[UAK_EXPIRY_DATE_DATA_LENGTH] = {0}; char error_buf[ERR_BUF_SIZE]; rc = rtas_get_sysparm(SYS_PARAM_UAK_EXPIRY_DATE, ARRAY_SIZE(date), date); if (rc == 0) { /* +2 since first 2 bytes in date buffer filled by the RTAS call * are used for storing length of the buffer excluding the first * two bytes and including ending '\0' */ printf("Update Access Key expiry date (yyyymmdd) is: %s\n", date + 2); } else { switch (rc) { case -1: warnx("Hardware Error"); break; case -2: warnx("Busy, Try again later"); break; case -3: warnx("System parameter not supported"); break; case -9002: warnx("Not authorized"); break; case -9999: warnx("Parameter Error"); break; case 9900 ... 9905: warnx("Delay of %ld milliseconds is expected " "before calling ibm,get-system-parameter with " "the same parameter index", (long) pow(10, rc-9900)); break; default: if (is_librtas_error(rc)) { librtas_error(rc, error_buf, ERR_BUF_SIZE); warnx("%s", error_buf); } else { warnx("Unknown error"); } } rc = UAK_ERROR; } return rc; } static bool is_keyfile_valid(const char *keyfile, char *keydata) { int fd; int len; uint16_t size; fd = open(keyfile, O_RDONLY); if (fd == -1) { /* errno is set appropriately by the call to open() */ perror("Keyfile error"); return false; } /* First two bytes of data are used for storing the length. * +1 read for validation. */ len = read(fd, keydata + 2, UAK_KEY_LENGTH + 1); close(fd); if (len != UAK_KEY_LENGTH) { warnx("Keyfile of incorrect length"); return false; } /* Terminating '\0' is implied as buffer has been set to 0 * and exactly UAK_KEY_LENGTH bytes have been copied */ /* Fill first 2 bytes with the UAK length + 1 (+1 for ending '\0') */ size = htobe16(UAK_KEY_LENGTH + 1); memcpy(keydata, &size, sizeof(size)); return true; } static int apply_uak_key(const char *keyfile) { int rc = 0; char keyvalue[UAK_KEY_DATA_LENGTH + 1] = {0}; /* +1 for validation */ char error_buf[ERR_BUF_SIZE]; if (!is_keyfile_valid(keyfile, keyvalue)) return UAK_ERROR; rc = rtas_set_sysparm(SYS_PARAM_UAK_KEY, keyvalue); if (rc == 0) { printf("Update Access Key set successfully\n"); } else { switch (rc) { case -1: warnx("Hardware Error"); break; case -2: warnx("Busy, Try again later"); break; case -3: warnx("System parameter not supported"); break; case -9002: warnx("Setting not allowed/authorized"); break; case -9999: warnx("Parameter Error"); break; case 9900 ... 9905: warnx("Delay of %ld milliseconds is expected " "before calling ibm,set-system-parameter " "with the same parameter index", (long) pow(10, rc-9900)); break; default: if (is_librtas_error(rc)) { librtas_error(rc, error_buf, ERR_BUF_SIZE); warnx("%s", error_buf); } } rc = UAK_ERROR; } return rc; } static void print_usage(const char *cmd) { printf("Usage: %s [-e [keyfile]]\n", cmd); printf("Without any option, the activate_firmware utility will cause"); printf(" a firmware image\nthat has already been flashed to be"); printf(" activated concurrently.\n"); printf("\nOption summary:\n"); printf(" -e prints the current Update Access Key expiry"); printf(" date\n"); printf(" -e applies the provided Update Access key-file"); printf(" to extend\n"); printf(" the service expiry date\n"); printf(" -h, --help print this message.\n"); printf(" -V, --version print version information.\n"); printf(" -v, --verbose output extra debug information\n"); printf("\n"); } static struct option long_opts[] = { {"version", no_argument, NULL, 'V'}, {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'}, {0, 0, 0, 0}, }; int main(int argc, char *argv[]) { int opt, opt_index = 0; char *key = NULL; bool e_flag = false; int rc; if (get_platform() != PLATFORM_PSERIES_LPAR) errx(1, "activate_firmware is not supported on the %s platform", platform_name); while ((opt = getopt_long(argc, argv, "e::hVv", long_opts, &opt_index)) != -1) { switch (opt) { case 'e': e_flag = true; /* optarg isn't set to the option argument if it's * optional hence using optind */ if (argv[optind] && argv[optind][0] != '-') { key = argv[optind]; /* So that getopt doesn't try to parse * the keyfile option argument */ optind++; } break; case 'V': printf("activate_firmware - %s\n", VERSION); return 0; case 'v': verbose = 1; break; case 'h': case '?': print_usage(argv[0]); return (opt == 'h' ? 0 : -1); } } if (e_flag) { if (key) rc = apply_uak_key(key); else rc = get_uak_expiry_date(); } else { rc = activate_firmware(); } return rc; } powerpc-utils-1.3.4/src/common/000077500000000000000000000000001315235264300164175ustar00rootroot00000000000000powerpc-utils-1.3.4/src/common/librtas_error.c000066400000000000000000000050611315235264300214360ustar00rootroot00000000000000/** * @file librtas_error.c * @brief Common librtas_error routine for powerpc-utils-papr commands * * Copyright (c) 2004 International Business Machines * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * @author Nathan Fontenot */ #include #include /** * librtas_error * @brief check for librtas specific return codes * * This will check the erro value for a librtas specific return code * and fill in the buffer with the appropraite error message * * @param error return code from librtas * @param buf buffer to fill with error string * @param size size of "buffer" */ void librtas_error(int error, char *buf, size_t size) { switch (error) { case RTAS_KERNEL_INT: snprintf(buf, size, "No kernel interface to firmware"); break; case RTAS_KERNEL_IMP: snprintf(buf, size, "No kernel implementation of function"); break; case RTAS_PERM: snprintf(buf, size, "Non-root caller"); break; case RTAS_NO_MEM: snprintf(buf, size, "Out of heap memory"); break; case RTAS_NO_LOWMEM: snprintf(buf, size, "Kernel out of low memory"); break; case RTAS_FREE_ERR: snprintf(buf, size, "Attempt to free nonexistant RMO buffer"); break; case RTAS_TIMEOUT: snprintf(buf, size, "RTAS delay exceeded specified timeout"); break; case RTAS_IO_ASSERT: snprintf(buf, size, "Unexpected librtas I/O error"); break; case RTAS_UNKNOWN_OP: snprintf(buf, size, "No firmware implementation of function"); break; default: snprintf(buf, size, "Unknown librtas error %d", error); } return; } int is_librtas_error(int error) { int rc = 0; switch (error) { case RTAS_KERNEL_INT: case RTAS_KERNEL_IMP: case RTAS_PERM: case RTAS_NO_MEM: case RTAS_NO_LOWMEM: case RTAS_FREE_ERR: case RTAS_TIMEOUT: case RTAS_IO_ASSERT: case RTAS_UNKNOWN_OP: rc = 1; } return rc; } powerpc-utils-1.3.4/src/common/librtas_error.h000066400000000000000000000020531315235264300214410ustar00rootroot00000000000000/** * @file librtas_error.h * @brief Common librtas_error routine for powerpc-utils-papr commands * * Copyright (c) 2004 International Business Machines * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * @author Nathan Fontenot */ #ifndef _LIBRTAS_ERROR_H #define _LIBRTAS_ERROR_H void librtas_error(int, char *, size_t); int is_librtas_error(int); #endif powerpc-utils-1.3.4/src/common/pseries_platform.c000066400000000000000000000033011315235264300221360ustar00rootroot00000000000000/** * @file platform.c * * Copyright (C) 2014 IBM Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * @author Aruna Balakrishnaiah */ #include #include #include "pseries_platform.h" #define LENGTH 512 const char *power_platform_name[] = { "Unknown", "PowerNV", "Power KVM pSeries Guest", "PowerVM pSeries LPAR", /* Add new platforms name here */ }; const char *platform_name; int get_platform(void) { int rc = PLATFORM_UNKNOWN; FILE *fp; char line[LENGTH]; if((fp = fopen(PLATFORM_FILE, "r")) == NULL) return rc; while (fgets(line, LENGTH, fp)) { if (strstr(line, "PowerNV")) { rc = PLATFORM_POWERNV; break; } else if (strstr(line, "IBM pSeries (emulated by qemu)")) { rc = PLATFORM_POWERKVM_GUEST; break; } else if (strstr(line, "pSeries")) { rc = PLATFORM_PSERIES_LPAR; /* catch model for PowerNV guest */ continue; } } platform_name = power_platform_name[rc]; fclose(fp); return rc; } powerpc-utils-1.3.4/src/common/pseries_platform.h000066400000000000000000000021121315235264300221420ustar00rootroot00000000000000/** * file pseries_platform.h * * Copyright (C) 2014 IBM Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef PLATFORM_H #define PLARFORM_H #define PLATFORM_FILE "/proc/cpuinfo" enum { PLATFORM_UNKNOWN = 0, PLATFORM_POWERNV, PLATFORM_POWERKVM_GUEST, PLATFORM_PSERIES_LPAR, /* Add new platforms here */ PLATFORM_MAX, }; extern const char *platform_name; extern int get_platform(void); #endif powerpc-utils-1.3.4/src/drmgr/000077500000000000000000000000001315235264300162425ustar00rootroot00000000000000powerpc-utils-1.3.4/src/drmgr/common.c000066400000000000000000000765661315235264300177220ustar00rootroot00000000000000/** * @file common.c * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dr.h" #include "ofdt.h" char *add_slot_fname = ADD_SLOT_FNAME; char *remove_slot_fname = REMOVE_SLOT_FNAME; #define DR_LOG_PATH "/var/log/drmgr" #define DR_LOG_PATH0 "/var/log/drmgr.0" #define LPARCFG_PATH "/proc/ppc64/lparcfg" #define SYSFS_DLPAR_FILE "/sys/kernel/dlpar" static int dr_lock_fd = 0; static long dr_timeout; /** * set_output level * @brief Common routine to set the output level * * @param level level to set the output level to */ inline void set_output_level(int level) { output_level = level; if (output_level >= 14) { say(DEBUG, "Enabling RTAS debug\n"); rtas_set_debug(output_level); } } int say(enum say_level lvl, char *fmt, ...) { va_list ap; char buf[256]; int len; va_start(ap, fmt); memset(buf, 0, 256); len = vsnprintf(buf, 256, fmt, ap); va_end(ap); if (len >= 256) { strcpy(&buf[243], "\n"); len = 255; } if (log_fd) len = write(log_fd, buf, len); if (lvl <= output_level) fprintf(stderr, "%s", buf); return len; } void report_unknown_error(char *file, int line) { say(ERROR, "Unexpected error (%s:%d). Contact support and provide " "debug log from %s.\n", file, line, DR_LOG_PATH); } void * __zalloc(size_t size, const char *func, int line) { void *data; data = malloc(size); if (data) memset(data, 0, size); else say(ERROR, "Allocation failure (%lx) at %s:%d\n", size, func, line); return data; } static int check_kmods(void) { struct stat sbuf; int rc; /* We only need to do this for PHB/SLOT/PCI operations */ if (usr_drc_type != DRC_TYPE_PCI && usr_drc_type != DRC_TYPE_PHB && usr_drc_type != DRC_TYPE_SLOT) return 0; /* We don't use rpadlar_io/rpaphp for PCI operations run with the * -v / virtio flag, which relies on generic PCI rescan instead */ if (usr_drc_type == DRC_TYPE_PCI && pci_virtio) return 0; /* Before checking for dlpar capability, we need to ensure that * rpadlpar_io module is loaded or built into the kernel. This * does make the checking a bit redundant though. */ if ((stat(add_slot_fname, &sbuf)) && (stat(ADD_SLOT_FNAME2, &sbuf))) { rc = system("/sbin/modprobe rpadlpar_io"); if (WIFEXITED(rc) && WEXITSTATUS(rc)) { say(ERROR, "rpadlpar_io module was not loaded\n"); return WEXITSTATUS(rc); } } /* For unknown reasons the add_slot and remove_slot sysfs files * used for dlpar operations started appearing with quotes around * the filename. So, this little hack exists to ensure nothing * breaks on the kernels where this exists. * * The default value is without the quotes. This is what was and * what shall be again. */ rc = stat(add_slot_fname, &sbuf); if (rc) { add_slot_fname = ADD_SLOT_FNAME2; remove_slot_fname = REMOVE_SLOT_FNAME2; rc = stat(add_slot_fname, &sbuf); } return rc; } /** * dr_init * @brief Initialization routine for drmgr and lsslot * */ inline int dr_init(void) { int rc; rc = dr_lock(); if (rc) { say(ERROR, "Unable to obtain Dynamic Reconfiguration lock. " "Please try command again later.\n"); return -1; } log_fd = open(DR_LOG_PATH, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (log_fd == -1) { log_fd = 0; say(ERROR, "Could not open log file %s\n\t%s\n", DR_LOG_PATH, strerror(errno)); } else { time_t t; char tbuf[128]; /* Insert seperator at beginning of drmgr invocation */ time(&t); strftime(tbuf, 128, "%b %d %T %G", localtime(&t)); say(DEBUG, "\n########## %s ##########\n", tbuf); } /* Mask signals so we do not get interrupted */ if (sig_setup()) { say(ERROR, "Could not mask signals to avoid interrupts\n"); if (log_fd) close(log_fd); dr_unlock(); return -1; } rc = check_kmods(); if (rc) { if (log_fd) close(log_fd); dr_unlock(); } return rc; } /** * dr_fini * @brief Cleanup routine for drmgr and lsslot * */ inline void dr_fini(void) { struct stat sbuf; int max_dr_log_sz = 25000; int rc; time_t t; char tbuf[128]; free_drc_info(); if (! log_fd) return; /* Insert seperator at end of drmgr invocation */ time(&t); strftime(tbuf, 128, "%b %d %T %G", localtime(&t)); say(DEBUG, "########## %s ##########\n", tbuf); close(log_fd); /* Check for log rotation */ rc = stat(DR_LOG_PATH, &sbuf); if (rc) { fprintf(stderr, "Cannot determine log size to check for " "rotation:\n\t%s\n", strerror(errno)); return; } if (sbuf.st_size >= max_dr_log_sz) { fprintf(stderr, "Rotating logs...\n"); rc = unlink(DR_LOG_PATH0); if (rc && (errno != ENOENT)) { fprintf(stderr, "Could not remove %s\n\t%s\n", DR_LOG_PATH0, strerror(errno)); return; } rc = rename(DR_LOG_PATH, DR_LOG_PATH0); if (rc) { fprintf(stderr, "Could not rename %s to %s\n\t%s\n", DR_LOG_PATH, DR_LOG_PATH0, strerror(errno)); return; } } dr_unlock(); } /** * set_timeout * */ void set_timeout(int timeout) { if (!timeout) { dr_timeout = -1; return; } dr_timeout = time((time_t *)0); if (dr_timeout == -1) return; dr_timeout += timeout; } /** * */ int drmgr_timed_out(void) { if (dr_timeout == -1) return 0; /* No timeout specified */ if (dr_timeout > time((time_t *)0)) return 0; say(WARN, "Drmgr has exceeded its specified wait time and will not " "continue\n"); return 1; } /** * dr_lock * @brief Attempt to lock a token * * This will attempt to lock a token (either file or directory) and wait * a specified amount of time if the lock cannot be granted. * * @returns lock id if successful, -1 otherwise */ int dr_lock(void) { struct flock dr_lock_info; int rc; mode_t old_mode; old_mode = umask(0); dr_lock_fd = open(DR_LOCK_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IRGRP | S_IROTH); if (dr_lock_fd < 0) return -1; umask(old_mode); dr_lock_info.l_type = F_WRLCK; dr_lock_info.l_whence = SEEK_SET; dr_lock_info.l_start = 0; dr_lock_info.l_len = 0; do { rc = fcntl(dr_lock_fd, F_SETLK, &dr_lock_info); if (rc == 0) return 0; /* lock may be held by another process */ if (errno != EACCES && errno != EAGAIN) break; if (drmgr_timed_out()) break; sleep(1); } while (1); close(dr_lock_fd); dr_lock_fd = 0; perror(DR_LOCK_FILE); return -1; } /** * dr_unlock * @brief unlock a lock granted via dr_lock() * * @param lock_id * @returns 0 on success, -1 otherwise */ int dr_unlock(void) { struct flock dr_lock_info; dr_lock_info.l_whence = SEEK_SET; dr_lock_info.l_start = 0; dr_lock_info.l_len = 0; dr_lock_info.l_type = F_UNLCK; if (fcntl(dr_lock_fd, F_SETLK, &dr_lock_info) < 0) return -1; close(dr_lock_fd); dr_lock_fd = 0; return 0; } /** * add_node * @brief Add the specified node(s) to the device tree * * This will add the specified node(s) to the /proc Open Firmware * tree and the kernel Open Firmware tree. * * @param add_path * @param new_nodes * @returns 0 on success */ static int add_node(char *path, struct of_node *new_nodes) { int rc = 0; int nprops = 0; int fd; struct of_property *prop; char *buf, *pos; char *add_path; size_t bufsize = 0; struct stat sbuf; /* If the device node already exists, no work to be done. This is * usually the case for adding a dedicated cpu that shares a * l2-cache with another apu and that cache already exists in the * device tree. */ if (!stat(path, &sbuf)) { say(DEBUG, "Device-tree node %s already exists, skipping\n", path); return 0; } say(DEBUG, "Adding device-tree node %s\n", path); /* The path passed in is a full ofdt path, remove the preceeding * /proc/device-tree for the write to the kernel. */ add_path = path + strlen(OFDT_BASE); /* determine the total size of the buffer we need to allocate */ bufsize += strlen("add_node "); bufsize += strlen(add_path) + 1; for (prop = new_nodes->properties; prop; prop = prop->next) { char tmp[16] = { '\0' }; /* for length */ nprops++; bufsize += strlen(prop->name) + 1; /* name + space */ sprintf(tmp, "%d", prop->length); bufsize += strlen(tmp) + 1; /* length + space*/ bufsize += prop->length + 1; /* value + space */ } if (! nprops) { say(ERROR, "new_nodes have no properties\n"); return -1; } buf = zalloc(bufsize); if (buf == NULL) { say(ERROR, "Failed to allocate buffer to write to kernel\n"); return errno; } strcpy(buf, "add_node "); strcat(buf, add_path); pos = buf + strlen(buf); /* this is less than optimal, iterating over the entire buffer * for every strcat... */ for (prop = new_nodes->properties; prop; prop = prop->next) { char tmp[16] = { '\0' }; /* for length */ *pos++ = ' '; memcpy(pos, prop->name, strlen(prop->name)); pos += strlen(prop->name); *pos++ = ' '; sprintf(tmp, "%d", prop->length); memcpy(pos, tmp, strlen(tmp)); pos += strlen(tmp); *pos++ = ' '; memcpy(pos, prop->value, prop->length); pos += prop->length; } *pos = '\0'; /* dump the buffer for debugging */ say(DEBUG, "ofdt update: %s\n", buf); fd = open(OFDTPATH, O_WRONLY); if (fd == -1) { say(ERROR, "Failed to open %s: %s\n", OFDTPATH, strerror(errno)); free(buf); return -1; } rc = write(fd, buf, bufsize); if (rc <= 0) say(ERROR, "Write to %s failed: %s\n", OFDTPATH, strerror(errno)); else rc = 0; free(buf); close(fd); return rc; } /** * remove_node * @brief Remove the specified node to the device tree * * This will remove the specified node to the /proc Open Firmware * tree and the kernel Open Firmware tree. * * @param cmd * @returns 0 on success */ static int remove_node(char *path) { int rc = 0; int fd; int cmdlen; char buf[DR_PATH_MAX]; say(DEBUG, "Removing device-tree node %s\n", path); memset(buf, 0, DR_PATH_MAX); /* The path passed in is a full device path, remove the preceeding * /proc/device-tree part for the write to the kernel. */ sprintf(buf, "remove_node %s", path + strlen(OFDT_BASE)); cmdlen = strlen(buf); fd = open(OFDTPATH, O_WRONLY); if (fd == -1) { say(ERROR, "Failed to open %s: %s\n", OFDTPATH, strerror(errno)); return -1; } rc = write(fd, buf, cmdlen); if (rc != cmdlen) say(ERROR, "Write to %s failed: %s\n", OFDTPATH, strerror(errno)); else rc = 0; close(fd); return rc; } /** * add_device_tree_nodes * * Process new_nodes from configure_connector and call add_node to * add new nodes to /proc device-tree and the kernel's device tree. * * @param root_path * @param new_nodes * @returns 0 on success, !0 otherwise */ static int _add_device_tree_nodes(char *path, struct of_node *new_nodes) { struct of_node *node; char add_path[DR_PATH_MAX]; int rc = 0; for (node = new_nodes; node; node = node->sibling) { sprintf(add_path, "%s/%s", path, node->name); rc = add_node(add_path, node); if (rc) break; node->added = 1; if (node->child) { rc = _add_device_tree_nodes(add_path, node->child); if (rc) break; } } return rc; } int add_device_tree_nodes(char *path, struct of_node *new_nodes) { struct of_node *node; char rm_path[DR_PATH_MAX]; int rc; rc = _add_device_tree_nodes(path, new_nodes); if (rc) { for (node = new_nodes; node; node = node->sibling) { if (!node->added) continue; sprintf(rm_path, "%s/%s", path, node->name); remove_node(rm_path); } } return rc; } /** * remove_device_tree_nodes * * Remove all device nodes and children device nodes from Open Firmware * device tree * * @param root_path * @returns 0 on success, !0 otherwise */ int remove_device_tree_nodes(char *path) { DIR *d; struct dirent *de; struct stat sb; int found = 1; int rc; rc = lstat(path, &sb); if (rc || (!S_ISDIR(sb.st_mode)) || (S_ISLNK(sb.st_mode))) return rc; d = opendir(path); if (d == NULL) { say(ERROR, "Could not open %s: %s\n", path, strerror(errno)); return -1; } while (found) { char subdir_name[DR_PATH_MAX]; found = 0; /* Remove any subdirectories */ while ((de = readdir(d)) != NULL) { if (is_dot_dir(de->d_name)) continue; sprintf(subdir_name, "%s/%s", path, de->d_name); rc = lstat(subdir_name, &sb); if (!rc && (S_ISDIR(sb.st_mode)) && (!S_ISLNK(sb.st_mode))) { found = 1; break; } } if (found) { rc = remove_device_tree_nodes(subdir_name); rewinddir(d); } if (rc) break; } closedir(d); if (!rc) rc = remove_node(path); return rc; } /** * update_property * * */ int update_property(const char *buf, size_t len) { int fd, rc; say(DEBUG, "Updating OF property\n"); fd = open(OFDTPATH, O_WRONLY); if (fd == -1) { say(ERROR, "Failed to open %s: %s\n", OFDTPATH, strerror(errno)); return -1; } rc = write(fd, buf, len); if ((size_t)rc != len) say(ERROR, "Write to %s failed: %s\n", OFDTPATH, strerror(errno)); else rc = 0; close(fd); return rc; } /** * get_att_prop * @brief find the value for a given property/attribute. * * @param path path to the property/attribute to retrieve * @param name name of the property/attribute to retrieve * @param buf buffer to write property/attribute to * @param buf_sz size of the buffer * @returns 0 on success, -1 otherwise */ static int get_att_prop(const char *path, const char *name, char *buf, size_t buf_sz, const char *attr_type) { FILE *fp; int rc = 0; char dir[DR_PATH_MAX]; struct stat sbuf; if (buf == NULL) return -1; if (name != NULL) sprintf(dir, "%s/%s", path, name); else sprintf(dir, "%s", path); fp = fopen(dir, "r"); if (fp == NULL) return -1; memset(buf, 0, buf_sz); /* Yes, this is sort of a hack but we only read properties from * either /proc or sysfs so it works and is cheaper than a strcmp() */ switch (dir[1]) { case 'p': /* /proc */ rc = stat(dir, &sbuf); if (rc) break; if (sbuf.st_size > buf_sz) { rc = -1; break; } rc = fread(buf, sbuf.st_size, 1, fp); break; case 's': /* sysfs */ rc = fscanf(fp, attr_type, (int *)buf); break; } fclose(fp); /* * we're lucky, because if successed, both fread and fscanf will return * 1, so we can check whether rc is 1 for failures of reading files */ if (rc != 1) return -1; return 0; } /** * get_property * @brief retrieve a device-tree property from /proc * * @param path path to the property to retrieve * @param name name of the property to retrieve * @param buf buffer to write property to * @param buf_sz size of the buffer * @returns 0 on success, !0 otherwise */ int get_property(const char *path, const char *property, void *buf, size_t buf_sz) { return get_att_prop(path, property, buf, buf_sz, NULL); } /** * get_int_attribute * @brief retrieve an integer device attribute from sysfs * * @param path path to the attribute to retrieve * @param name name of the attribute to retrieve * @param buf buffer to write attribute to * @param buf_sz size of the buffer * @returns 0 on success, -1 otherwise */ int get_int_attribute(const char *path, const char *attribute, void *buf, size_t buf_sz) { return get_att_prop(path, attribute, buf, buf_sz, "%i"); } /** * get_str_attribute * @brief retrieve a string device attribute from sysfs * * @param path path to the attribute to retrieve * @param name name of the attribute to retrieve * @param buf buffer to write attribute to * @param buf_sz size of the buffer * @returns 0 on success, -1 otherwise */ int get_str_attribute(const char *path, const char *attribute, void *buf, size_t buf_sz) { return get_att_prop(path, attribute, buf, buf_sz, "%s"); } /** * get_ofdt_uint_property * @brief retrieve an unsigned integer property from the device tree and * byteswap if needed (device tree is big endian). * * @param path path to the property to retrieve * @param name name of the property to retrieve * @param data unsigned integer pointer to write property to * @returns 0 on success, -1 otherwise */ int get_ofdt_uint_property(const char *path, const char *attribute, uint *data) { uint tmp; int rc; rc = get_property(path, attribute, &tmp, sizeof(tmp)); if (!rc) *data = be32toh(tmp); return rc; } /** * get_property_size * @brief retrieve the size of a property * * @param path path to the property to retrieve * @param name name of the property to retrieve * @returns size of the property */ int get_property_size(const char *path, const char *property) { char dir[DR_PATH_MAX]; struct stat sb; if (property != NULL) sprintf(dir, "%s/%s", path, property); else sprintf(dir, "%s", path); stat(dir, &sb); return sb.st_size; } /** * sighandler * @brief Simple signal handler to print signal/stack info, cleanup and exit. * * @param signo signal number we caught. */ void sighandler(int signo) { say(ERROR, "Received signal %d, attempting to cleanup and exit\n", signo); if (log_fd) { void *callstack[128]; int sz; sz = backtrace(callstack, 128); backtrace_symbols_fd(callstack, sz, log_fd); } dr_fini(); exit(-1); } /** * sig_setup * @brief Mask signals so that dynamic reconfig operations won't be * interrupted and catch others. * * @returns 0 on success, !0 otherwise */ int sig_setup(void) { sigset_t sigset; struct sigaction sigact; void *callstack[128]; int rc; /* Now set up a mask with all signals masked */ sigfillset(&sigset); /* Clear mask bits for signals we don't want to mask */ sigdelset(&sigset, SIGBUS); sigdelset(&sigset, SIGXFSZ); sigdelset(&sigset, SIGSEGV); sigdelset(&sigset, SIGTRAP); sigdelset(&sigset, SIGILL); sigdelset(&sigset, SIGFPE); sigdelset(&sigset, SIGSYS); sigdelset(&sigset, SIGPIPE); sigdelset(&sigset, SIGVTALRM); sigdelset(&sigset, SIGALRM); sigdelset(&sigset, SIGQUIT); sigdelset(&sigset, SIGABRT); /* Now block all remaining signals */ rc = sigprocmask(SIG_BLOCK, &sigset, NULL); if (rc) return -1; /* Now set up a signal handler for the signals we want to catch */ memset(&sigact, 0, sizeof(sigact)); sigemptyset(&sigact.sa_mask); sigact.sa_handler = sighandler; if (sigaction(SIGQUIT, &sigact, NULL)) return -1; if (sigaction(SIGILL, &sigact, NULL)) return -1; if (sigaction(SIGABRT, &sigact, NULL)) return -1; if (sigaction(SIGFPE, &sigact, NULL)) return -1; if (sigaction(SIGSEGV, &sigact, NULL)) return -1; if (sigaction(SIGBUS, &sigact, NULL)) return -1; /* dummy call to backtrace to get symbol loaded */ backtrace(callstack, 128); return 0; } char *php_slot_type_msg[]={ "", "PCI 32 bit, 33MHz, 5 volt slot", "PCI 32 bit, 50MHz, 5 volt slot", "PCI 32 bit, 33MHz, 3.3 volt slot", "PCI 64 bit, 33MHz, 5 volt slot", "PCI 64 bit, 50MHz, 5 volt slot", /* 5 */ "PCI 64 bit, 33MHz, 3.3 volt slot", "PCI 32 bit, 66MHz, 3.3 volt slot", "PCI 64 bit, 66MHz, 3.3 volt slot", "", /* we don't have connector types for */ "", /* 9 or 10, so skip these indices. */ "PCI-X capable, 32 bit, 66MHz slot", "PCI-X capable, 32 bit, 100MHz slot", "PCI-X capable, 32 bit, 133MHz slot", "PCI-X capable, 64 bit, 66MHz slot", "PCI-X capable, 64 bit, 100MHz slot", /* 15 */ "PCI-X capable, 64 bit, 133MHz slot", "PCI-X capable, 64 bit, 266MHz slot", "PCI-X capable, 64 bit, 533MHz slot", "PCI-E capable, Rev 1, 1x lanes", "PCI-E capable, Rev 1, 2x lanes", /* 20 */ "PCI-E capable, Rev 1, 4x lanes", "PCI-E capable, Rev 1, 8x lanes", "PCI-E capable, Rev 1, 16x lanes", "PCI-E capable, Rev 1, 32x lanes", "PCI-E capable, Rev 2, 1x lanes", /* 25 */ "PCI-E capable, Rev 2, 2x lanes", "PCI-E capable, Rev 2, 4x lanes", "PCI-E capable, Rev 2, 8x lanes", "PCI-E capable, Rev 2, 16x lanes", "PCI-E capable, Rev 2, 32x lanes", /* 30 */ "PCI-E capable, Rev 3, 8x lanes with 1 lane connected", "PCI-E capable, Rev 3, 8x lanes with 4x lanes connected", "PCI-E capable, Rev 3, 8x lanes with 8x lanes connected", "PCI-E capable, Rev 3, 16x lanes with 1 lane connected", "PCI-E capable, Rev 3, 16x lanes with 8x lanes connected", /* 35 */ "PCI-E capable, Rev 3, 16x lanes with 16x lanes connected", "PCI-E capable, Rev 4, 8x lanes with 1 lane connected", "PCI-E capable, Rev 4, 8x lanes with 4x lanes connected", "PCI-E capable, Rev 4, 8x lanes with 8x lanes connected", "PCI-E capable, Rev 4, 16x lanes with 1 lane connected", /* 40 */ "PCI-E capable, Rev 4, 16x lanes with 8x lanes connected", "PCI-E capable, Rev 4, 16x lanes with 16x lanes connected", }; char * node_type(struct dr_node *node) { int desc_msg_num; char *desc = "Unknown"; desc_msg_num = atoi(node->drc_type); if ((desc_msg_num >= 1 && desc_msg_num <= 8) || (desc_msg_num >= 11 && desc_msg_num <= 42)) desc = php_slot_type_msg[desc_msg_num]; else { switch (node->dev_type) { case PCI_DLPAR_DEV: desc = "Logical I/O Slot"; break; case VIO_DEV: desc = "Virtual I/O Slot"; break; case HEA_DEV: desc = "HEA I/O Slot"; break; case HEA_PORT_DEV: desc = "HEA Port I/O Slot"; break; default: desc = "Unknown slot type"; break; } } return desc; } /** * valid_platform * @brief Validate that the platfomr we are on matches the one specified * * @param platform Name of platform to validate * @return 1 if valid, 0 otherwise */ int valid_platform(const char *platform) { char buf[128]; int rc; rc = get_property(OFDT_BASE, "device_type", buf, 128); if (rc) { say(ERROR, "Cannot validate platform %s\n", platform); return 0; } if (strcmp(buf, platform)) { say(ERROR, "This command is not supported for %s platforms.\n", platform); return 0; } return 1; } /** * get_sysparm * * @param parm * @returns 0 on success, !0 otherwise */ static int get_sysparm(const char *parm, unsigned long *value) { int rc = -1; char s[DR_BUF_SZ]; FILE *f; f = fopen(LPARCFG_PATH, "r"); if (f == NULL) { say(ERROR, "Could not open \"%s\"\n%s\n", LPARCFG_PATH, strerror(errno)); return -1; } while (fgets(s, sizeof(s), f)) { if (! strncmp(s, parm, strlen(parm))) { char *tmp = strchr(s, '='); if (tmp == NULL) break; tmp++; rc = 0; *value = strtoul(tmp, NULL, 0); break; } } fclose(f); if (rc) say(ERROR, "Error finding %s in %s\n", parm, LPARCFG_PATH); return rc; } /** * set_sysparm * * @param parm * @param val * @returns 0 on success, !0 otherwise */ static int set_sysparm(const char *parm, int val) { int rc = -1; FILE *f; f = fopen(LPARCFG_PATH, "w"); if (f == NULL) { say(ERROR, "Could not open \"%s\"\n%s\n", LPARCFG_PATH, strerror(errno)); return -1; } say(DEBUG, "Updating sysparm %s to %d...", parm, val); rc = fprintf(f, "%s=%d\n", parm, val); fclose(f); say(DEBUG, "%s.\n", (rc == -1) ? "fail" : "success"); return (rc == -1) ? -1 : 0; } struct sysparm_mapping { char *drmgr_name; char *linux_name; }; static struct sysparm_mapping cpu_sysparm_table[] = { { .drmgr_name = "variable_weight", .linux_name = "capacity_weight" }, { .drmgr_name = "ent_capacity", .linux_name = "partition_entitled_capacity" }, { .drmgr_name = NULL, .linux_name = NULL } }; static struct sysparm_mapping mem_sysparm_table[] = { { .drmgr_name = "variable_weight", .linux_name = "entitled_memory_weight" }, { .drmgr_name = "ent_capacity", .linux_name = "entitled_memory" }, { .drmgr_name = NULL, .linux_name = NULL } }; /** * update_sysparm * * Update the indicated system parameter by the amount specified. * This requires us to establish the current value of the parameter, * since the kernel interface accepts only absolute values. * * @param parm * @returns 0 on success, !0 otherwise */ int update_sysparm(void) { struct sysparm_mapping *sysparm_table; unsigned long curval; int i; char *linux_parm = NULL; /* Validate capability */ if (usr_drc_type == DRC_TYPE_CPU) { if (! cpu_entitlement_capable()) { say(ERROR, "CPU entitlement capability is not enabled " "on this platform.\n"); return -1; } sysparm_table = cpu_sysparm_table; } else if (usr_drc_type == DRC_TYPE_MEM) { if (! mem_entitlement_capable()) { say(ERROR, "Memory entitlement capability is not " "enabled on this platform.\n"); return -1; } sysparm_table = mem_sysparm_table; } else { say(ERROR, "Invalid entitlement update type \"%d\" " "specified.\n", usr_drc_type); return -1; } /* Convert the system parameter presented to drmgr into what is * expected by the kernel. */ i = 0; while (sysparm_table[i].drmgr_name) { if (!strcmp(sysparm_table[i].drmgr_name, usr_p_option)) { linux_parm = sysparm_table[i].linux_name; break; } i++; } if (linux_parm == NULL) { say(ERROR, "The entitlement parameter \"%s\" is not " "recognized\n", usr_p_option); return -1; } if ((get_sysparm(linux_parm, &curval)) < 0) { say(ERROR, "Could not get current system parameter value of " "%s (%s)\n", linux_parm, usr_p_option); return -1; } if (usr_action == REMOVE) { if (usr_drc_count > curval) { say(ERROR, "Cannot reduce system parameter value %s by " "more than is currently available.\nCurrent " "value: %lx, asking to remove: %x\n", usr_p_option, curval, usr_drc_count); return 1; } usr_drc_count = -usr_drc_count; } return set_sysparm(linux_parm, curval + usr_drc_count); } int cpu_dlpar_capable(void) { DIR *d; struct dirent *de; struct stat sbuf; char fname[DR_PATH_MAX]; char *cpu_dir = "/sys/devices/system/cpu"; int capable = 1; say(ERROR, "Validating CPU DLPAR capability..."); d = opendir(cpu_dir); if (d == NULL) { say(ERROR, "no.\n opendir(\"%s\"): %s\n", cpu_dir, strerror(errno)); return 0; } while ((de = readdir(d)) != NULL) { if (strncmp(de->d_name, "cpu", 3)) continue; /* Ensure this is a cpu directory, i.e. cpu0, and not a * non-cpu directory, i.e. cpufreq */ if (!isdigit(de->d_name[3])) continue; sprintf(fname, "%s/%s/online", cpu_dir, de->d_name); if (stat(fname, &sbuf)) { say(ERROR, "no.\n stat(\"%s\"): %s\n", fname, strerror(errno)); capable = 0; } say(ERROR, "yes.\n"); break; } closedir(d); return capable; } static inline int dlpar_capable(const char *type, const char *fname) { struct stat sbuf; int capable = 1; say(ERROR, "Validating %s capability...", type); if (stat(fname, &sbuf)) { say(ERROR, "no.\n stat(\"%s\"): %s\n", fname, strerror(errno)); capable = 0; } else { say(ERROR, "yes.\n"); } return capable; } int mem_dlpar_capable(void) { return dlpar_capable("Memory DLPAR", "/sys/devices/system/memory/block_size_bytes"); } int slot_dlpar_capable(void) { return dlpar_capable("I/O DLPAR", add_slot_fname); } int phb_dlpar_capable(void) { return dlpar_capable("PHB DLPAR", add_slot_fname); } int pmig_capable(void) { return dlpar_capable("partition migration", "/proc/device-tree/ibm,migratable-partition"); } int phib_capable(void) { return dlpar_capable("partition hibernation", "/sys/devices/system/power/hibernate"); } int slb_resize_capable(void) { unsigned long value; int rc; rc = get_sysparm("slb_size", &value); if (rc == -1) return 0; return 1; } int hea_dlpar_capable(void) { return dlpar_capable("HEA DLPAR", HEA_ADD_SLOT); } int cpu_entitlement_capable(void) { unsigned long value; int rc; rc = get_sysparm("partition_entitled_capacity", &value); if (rc == -1) return 0; return 1; } int mem_entitlement_capable(void) { unsigned long value; int rc; rc = get_sysparm("entitled_memory", &value); if (rc == -1) return 0; return 1; } void print_dlpar_capabilities(void) { int cpu_dlpar, mem_dlpar, slot_dlpar, phb_dlpar, hea_dlpar; int pmig, phib, slb_resize; int cpu_entitled, mem_entitled; cpu_dlpar = cpu_dlpar_capable(); mem_dlpar = mem_dlpar_capable(); slot_dlpar = slot_dlpar_capable(); phb_dlpar = phb_dlpar_capable(); hea_dlpar = hea_dlpar_capable(); pmig = pmig_capable(); phib = phib_capable(); slb_resize = slb_resize_capable(); cpu_entitled = cpu_entitlement_capable(); mem_entitled = mem_entitlement_capable(); printf("cpu_dlpar=%s,mem_dlpar=%s,slot_dlpar=%s,phb_dlpar=%s," "hea_dlpar=%s,pmig=%s,cpu_entitlement=%s,mem_entitlement=%s," "slb_resize=%s,phib=%s\n", (cpu_dlpar ? "yes" : "no"), (mem_dlpar ? "yes" : "no"), (slot_dlpar ? "yes" : "no"), (phb_dlpar ? "yes" : "no"), (hea_dlpar ? "yes" : "no"), (pmig ? "yes" : "no"), (cpu_entitled ? "yes" : "no"), (mem_entitled ? "yes" : "no"), (slb_resize ? "yes" : "no"), (phib ? "yes" : "no")); } /** * ams_balloon_active * @brief Determines if AMS and memory ballooning is enabled * * @returns 1 if ballooning is active, 0 if AMS or ballooning is inactive */ int ams_balloon_active(void) { /* CMM's loaned_kb file only appears when AMS is enabled */ char *ams_enabled = "/sys/devices/system/cmm/cmm0/loaned_kb"; char *cmm_param_path = "/sys/module/cmm/parameters"; struct stat sbuf; static int is_inactive = 1; static int ams_checked = 0; if (!ams_checked) { if (!stat(ams_enabled, &sbuf) && !stat(cmm_param_path, &sbuf)) get_int_attribute(cmm_param_path, "disable", &is_inactive, sizeof(is_inactive)); say(DEBUG, "AMS ballooning %s active\n", is_inactive?"is not":"is"); ams_checked = 1; } return !is_inactive; } int is_display_adapter(struct dr_node *node) { return !strncmp(node->drc_type, "display", 7); } /** * kernel_dlpar_exists * @brief determine if the sysfs file to do in-kernel dlpar exists * * @returns 1 if in-kernel dlpar exists, 0 otherwise. */ int kernel_dlpar_exists(void) { struct stat sbuf; if (!stat(SYSFS_DLPAR_FILE, &sbuf)) return 1; return 0; } /** * do_kernel_dlpar * @brief Use the in-kernel dlpar capabilities to perform the requested * dlpar operation. * * @param cmd command string to write to sysfs * @returns 0 on success, !0 otherwise */ int do_kernel_dlpar(const char *cmd, int cmdlen) { int fd, rc; int my_errno; say(DEBUG, "Initiating kernel DLPAR \"%s\"\n", cmd); /* write to file */ fd = open(SYSFS_DLPAR_FILE, O_WRONLY); if (fd <= 0) { say(ERROR, "Could not open %s to initiate DLPAR request\n", SYSFS_DLPAR_FILE); return -1; } rc = write(fd, cmd, cmdlen); my_errno = errno; close(fd); if (rc <= 0) { /* write does not set errno for rc == 0 */ say(ERROR, "Failed to write to %s: %s\n", SYSFS_DLPAR_FILE, (rc == 0) ? "wrote 0 bytes" : strerror(my_errno)); return -1; } say(INFO, "Success\n"); return 0; } enum drc_type to_drc_type(const char *arg) { if (!strncmp(arg, "pci", 3)) return DRC_TYPE_PCI; if (!strncmp(arg, "slot", 4)) return DRC_TYPE_SLOT; if (!strncmp(arg, "phb", 3)) return DRC_TYPE_PHB; if (!strncmp(arg, "cpu", 3)) return DRC_TYPE_CPU; if (!strncmp(arg, "mem", 3)) return DRC_TYPE_MEM; if (!strncmp(arg, "port", 4)) return DRC_TYPE_PORT; if (!strncmp(arg, "phib", 4)) return DRC_TYPE_HIBERNATE; if (!strncmp(arg, "pmig", 4)) return DRC_TYPE_MIGRATION; return DRC_TYPE_NONE; } powerpc-utils-1.3.4/src/drmgr/common_cpu.c000066400000000000000000000633741315235264300205620ustar00rootroot00000000000000/** * @file common_cpu.c * @brief Common routines for cpu data * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include "dr.h" #include "drcpu.h" #include "ofdt.h" /* format strings for easy access */ #define DR_THREAD_DIR_PATH "/sys/devices/system/cpu/cpu%d" #define DR_THREAD_ONLINE_PATH "/sys/devices/system/cpu/cpu%d/online" #define DR_THREAD_PHYSID_PATH "/sys/devices/system/cpu/cpu%d/physical_id" #define DR_CPU_INTSERVERS_PATH \ "/proc/device-tree/cpus/%s/ibm,ppc-interrupt-server#s" /** * free_thread_info * @brief free the thread list and any associated allocated memory * * @param thread_list list of threads to free */ static inline void free_thread_info(struct thread *thread_list) { struct thread *thread; while (thread_list) { thread = thread_list; thread_list = thread->next; free(thread); } } /** * get_cpu_threads * Associate a thread to the cpu it belongs to. * * @param all_cpus list of all cpus * @param thread thread to associate. */ static void get_cpu_threads(struct dr_node *cpu, struct thread *all_threads) { struct thread *thread; struct thread *last = NULL; int i; for (thread = all_threads; thread; thread = thread->next) { for (i = 0; i < cpu->cpu_nthreads; i++) { if (cpu->cpu_intserv_nums[i] != thread->phys_id) continue; /* Special case for older kernels where the default * physical id of a thread was 0, which is also a * valid physical id. */ if (thread->phys_id == 0) { char *cpuid = strrchr(thread->path, 'c'); if (cpuid[3] != '0') continue; } if (last) last->sibling = thread; else cpu->cpu_threads = thread; last = thread; thread->cpu = cpu; } } } /** * init_thread_info * @brief Initialize thread data * * Initialize global thread or "logical cpu" data. The physical cpu data * initialization must have been completed before this is called. * * @returns pointer to thread_info on success, NULL otherwise */ static int init_thread_info(struct dr_info *dr_info) { struct thread *thread = NULL; struct thread *thread_list = NULL; struct thread *last = NULL; int rc, i = 0; struct stat s; char path[DR_PATH_MAX]; int nr_threads, thread_cnt = 0; if (stat("/sys/devices/system/cpu", &s)) { say(ERROR, "Cannot gather CPU thread information,\n" "stat(\"/sys/devices/system/cpu\"): %s\n", strerror(errno)); return -1; } nr_threads = s.st_nlink - 2; sprintf(path, DR_THREAD_DIR_PATH, i); for (i = 0; 0 == stat(path, &s); i++) { thread = zalloc(sizeof(*thread)); thread->id = i; snprintf(thread->path, DR_PATH_MAX, "%s", path); rc = get_int_attribute(thread->path, "physical_id", &thread->phys_id, sizeof(thread->phys_id)); if (rc) { say(ERROR, "Could not get \"physical_id\" of thread " "%s\n", thread->path); free(thread); return -1; } if (thread_list) last->next = thread; else thread_list = thread; last = thread; sprintf(path, DR_THREAD_DIR_PATH, i + 1); thread_cnt++; } say(EXTRA_DEBUG, "Expecting %d threads...found %d.\n", nr_threads, thread_cnt); dr_info->all_threads = thread_list; return 0; } static int cpu_index_to_path(struct dr_node *cpu) { DIR *d; struct dirent *de; int found = 0; int rc = -1; char path[DR_PATH_MAX]; d = opendir(CPU_OFDT_BASE); if (d == NULL) { say(ERROR, "Could not open %s: %s\n", CPU_OFDT_BASE, strerror(errno)); return -1; } while ((de = readdir(d)) != NULL) { uint32_t my_drc_index; if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name)) continue; if (strncmp(de->d_name, "PowerPC", 7)) continue; sprintf(path, "%s/%s", CPU_OFDT_BASE, de->d_name); rc = get_my_drc_index(path, &my_drc_index); if (rc) { /* This is an error, but continue searching since * this may not be the drc index we are looking for */ say(DEBUG, "Could not retrieve drc_index for %s\n", path); continue; } if (my_drc_index == cpu->drc_index) { found = 1; break; } } closedir(d); if (found) { snprintf(cpu->ofdt_path, DR_PATH_MAX, "%s", path); rc = 0; } return rc; } static int update_cpu_node(struct dr_node *cpu, const char *path, struct dr_info *dr_info) { struct stat sb; char intserv_path[DR_PATH_MAX]; int rc, i; if (path) { snprintf(cpu->ofdt_path, DR_PATH_MAX, "%s", path); } else { rc = cpu_index_to_path(cpu); if (rc) { say(ERROR, "Could not find ofdt path for drc index " "%s\n", cpu->drc_index); return rc; } } /* Skip past CPU_OFDT_BASE plus the '/' */ cpu->name = cpu->ofdt_path + strlen(CPU_OFDT_BASE) + 1; memset(&cpu->cpu_intserv_nums, -1, sizeof(cpu->cpu_intserv_nums)); rc = get_property(cpu->ofdt_path, "ibm,ppc-interrupt-server#s", &cpu->cpu_intserv_nums, sizeof(cpu->cpu_intserv_nums)); /* Making sure the intserv_nums are in correct endian format */ for (i = 0; i < MAX_CPU_INTSERV_NUMS; i++) cpu->cpu_intserv_nums[i] = be32toh(cpu->cpu_intserv_nums[i]); if (rc) { say(ERROR, "Could not retrieve ibm,ppc-interrupt-server#s " "property for %s\n", cpu->name); return -1; } /* The number of threads is the number of 32-bit ints in the * cpu's ibm,ppc-interrupt-server#s property. */ sprintf(intserv_path, "/proc/device-tree/cpus/%s/ibm,ppc-interrupt-server#s", strstr(cpu->name, "PowerPC")); if (stat(intserv_path, &sb)) /* Assume no SMT */ cpu->cpu_nthreads = 1; else cpu->cpu_nthreads = sb.st_size / 4; rc = get_ofdt_uint_property(cpu->ofdt_path, "reg", &cpu->cpu_reg); if (rc) { say(ERROR, "Could not retrieve reg property for %s\n", cpu->name); return -1; } /* l2-cache may not exist */ cpu->cpu_l2cache = 0xffffffff; get_ofdt_uint_property(cpu->ofdt_path, "l2-cache", &cpu->cpu_l2cache); get_cpu_threads(cpu, dr_info->all_threads); cpu->is_owned = 1; return 0; } /** * init_cpu_info * @brief Initialize cpu information * * @returns pointer to cpu_info on success, NULL otherwise */ static int init_cpu_info(struct dr_info *dr_info) { struct dr_connector *drc_list, *drc; struct dr_node *cpu, *cpu_list = NULL; DIR *d; struct dirent *de; int rc = 0; drc_list = get_drc_info(CPU_OFDT_BASE); if (drc_list == NULL) { say(ERROR, "Could not get drc information for %s\n", CPU_OFDT_BASE); return -1; } /* For cpu dlpar, we need a list of all possible cpus on the system */ for (drc = drc_list; drc; drc = drc->next) { cpu = alloc_dr_node(drc, CPU_DEV, NULL); if (cpu == NULL) { say(ERROR, "Could not allocate CPU node structure\n"); free_node(cpu_list); return -1; } cpu->next = cpu_list; cpu_list = cpu; } d = opendir(CPU_OFDT_BASE); if (d == NULL) { say(ERROR, "Could not open %s: %s\n", CPU_OFDT_BASE, strerror(errno)); free_node(cpu_list); return -1; } while ((de = readdir(d)) != NULL) { char path[DR_PATH_MAX]; if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name)) continue; if (! strncmp(de->d_name, "PowerPC", 7)) { uint32_t my_drc_index; memset(path, 0, 1024); sprintf(path, "%s/%s", CPU_OFDT_BASE, de->d_name); rc = get_my_drc_index(path, &my_drc_index); if (rc) { say(ERROR, "Could not retrieve drc index for " "%s\n", path); break; } for (cpu = cpu_list; cpu; cpu = cpu->next) { if (cpu->drc_index == my_drc_index) break; } if (cpu == NULL) { say(ERROR, "Could not find cpu with drc index " "%x\n", my_drc_index); rc = -1; break; } rc = update_cpu_node(cpu, path, dr_info); if (rc) break; say(EXTRA_DEBUG, "Found cpu %s\n", cpu->name); } } closedir(d); if (rc) free_node(cpu_list); else dr_info->all_cpus = cpu_list; return rc; } /** * cpu_get_dependent_cache * @brief Return the cache whose ibm,phandle matches the given cpu's * l2-cache property. * * @param cpu * @returns pointer to cache_info on success, NULL otherwise */ struct cache_info * cpu_get_dependent_cache(struct dr_node *cpu, struct dr_info *dr_info) { struct cache_info * cache; for (cache = dr_info->all_caches; cache != NULL; cache = cache->next) { if (cache->removed) continue; if (cache->phandle == cpu->cpu_l2cache) { say(EXTRA_DEBUG, "found cache %s for cpu %s\n", cache->name, cpu->name); return cache; } } return NULL; } /** * cache_get_dependent_cache * @brief Return the cache whose ibm,phandle matches the given cache's * l2-cache property. * * @param cache * @returns pointer to cache_info on success, NULL otherwise */ struct cache_info * cache_get_dependent_cache(struct cache_info *cache, struct dr_info *dr_info) { struct cache_info *c; for (c = dr_info->all_caches; c != NULL; c = c->next) { if (cache->removed) continue; if (cache->phandle == cache->l2cache) { say(EXTRA_DEBUG, "found cache %s for cache %s\n", c->name, cache->name); return c; } } return NULL; } /** * cache_remove_devnode * @brief Remove the given cache device node from the kernel's device tree. * Also remove the cache from the global cache list. * * @param cache * @returns */ static int cache_remove_devnode(struct cache_info *cache) { int rc; rc = remove_device_tree_nodes(cache->path); if (!rc) cache->removed = 1; return rc; } /** * cache_get_use_count * @brief Calculate a cache's use count * * @param cache * @returns */ static int cache_get_use_count(struct cache_info *cache, struct dr_info *dr_info) { int count = 0; struct dr_node *cpu; struct cache_info *c; if (cache == NULL || cache->removed) return -1; /* Any cpu or cache node whose 'l2-cache' property matches * the ibm,phandle is using our cache */ for (cpu = dr_info->all_cpus; cpu != NULL; cpu = cpu->next) { if (!cpu->is_owned) continue; if (cache == cpu_get_dependent_cache(cpu, dr_info)) { say(EXTRA_DEBUG, "Cache %s is a dependent of cpu %s\n", cache->name, cpu->name); count++; } } for (c = dr_info->all_caches; c != NULL; c = c->next) { if (cache == cache_get_dependent_cache(c, dr_info)) { say(EXTRA_DEBUG, "Cache %s is a dependent of cache %s\n", cache->name, c->name); count++; } } say(EXTRA_DEBUG, "Cache %s dependency count: %d\n", cache->name, count); return count; } /** * free_cache_info * @brief free the cache list and any associated allocated memory * * @param cache_list list of cache structs to free */ void free_cache_info(struct cache_info *cache_list) { struct cache_info *tmp = cache_list; while (tmp != NULL) { cache_list = cache_list->next; free(tmp); tmp = cache_list; } } /** * init_cache_info * * @returns pointer to cache_info on success, NULL otherwise */ static int init_cache_info(struct dr_info *dr_info) { struct cache_info *cache_list = NULL; DIR *d; struct dirent *ent; int rc; d = opendir(CPU_OFDT_BASE); if (d == NULL) { say(ERROR, "Could not open %s: %s\n", CPU_OFDT_BASE, strerror(errno)); return -1; } while ((ent = readdir(d))) { char path[DR_PATH_MAX]; struct stat sb; /* skip everything but directories */ sprintf(path, "/proc/device-tree/cpus/%s", ent->d_name); if (lstat(path, &sb)) { say(ERROR, "Could not access %s,\nstat(): %s\n", path, strerror(errno)); break; } if (!S_ISDIR(sb.st_mode)) continue; if (strstr(ent->d_name, "-cache@")) { struct cache_info *cache; cache = zalloc(sizeof(*cache)); if (cache == NULL) { say(ERROR, "Could not allocate cache info." "\n%s\n", strerror(errno)); free_cache_info(cache_list); return -1; } snprintf(cache->name, DR_BUF_SZ, "%s", ent->d_name); snprintf(cache->path, DR_BUF_SZ, "%s", path); cache->removed = 0; cache->next = cache_list; cache_list = cache; rc = get_ofdt_uint_property(cache->path, "ibm,phandle", &cache->phandle); if (rc) { say(ERROR, "Could not retreive ibm,phandle " "property for %s\n", cache->path); free_cache_info(cache_list); return -1; } /* l3-caches do not have a l2-cache property */ cache->l2cache = 0xffffffff; get_ofdt_uint_property(cache->path, "l2-cache", &cache->l2cache); say(EXTRA_DEBUG, "Found cache %s\n", cache->name); } } closedir(d); dr_info->all_caches = cache_list; return 0; } /** * refresh_cache_info * * @returns 0 on success, !0 otherwise */ static int refresh_cache_info(struct dr_info *dr_info) { int rc; /* Some systems do not have cache device nodes. Assume * that if we did not find any cache nodes during initialization, * we won't find any during a refresh. */ if (dr_info->all_caches == NULL) return 0; free_cache_info(dr_info->all_caches); rc = init_cache_info(dr_info); if (rc) { say(ERROR, "failed to refresh cache information\n"); return rc; } return 0; } /** * acquire_cpu * * Acquire a new cpu for this partition from the hypervisor. * If drc_index is zero, look up an available index to use. * * @param drc_index * @returns pointer to cpu_info on success, NULL otherwise */ static int acquire_cpu(struct dr_node *cpu, struct dr_info *dr_info) { struct of_node *of_nodes; int rc; rc = acquire_drc(cpu->drc_index); if (rc) { say(DEBUG, "Could not acquire drc resources for %s\n", cpu->name); return rc; } of_nodes = configure_connector(cpu->drc_index); if (of_nodes == NULL) { say(ERROR, "Call to configure_connector failed for %s\n", cpu->name); release_drc(cpu->drc_index, CPU_DEV); return -1; } rc = add_device_tree_nodes(CPU_OFDT_BASE, of_nodes); free_of_node(of_nodes); if (rc) { say(ERROR, "Failure to add device tree nodes for %s\n", cpu->name); release_drc(cpu->drc_index, CPU_DEV); return rc; } update_cpu_node(cpu, NULL, dr_info); refresh_cache_info(dr_info); return 0; } #ifdef NOT_YET int do_cpu_kernel_dlpar(struct dr_node *cpu, int action) { char cmdbuf[256]; int offset; offset = sprintf(cmdbuf, "%s ", "cpu"); switch (action) { case ADD: offset += sprintf(cmdbuf + offset, "add "); break; case REMOVE: offset += sprintf(cmdbuf + offset, "remove "); break; default: say(ERROR, "Invalid DRC type specified\n"); return -EINVAL; } offset += sprintf(cmdbuf + offset, "index 0x%x", cpu->drc_index); return do_kernel_dlpar(cmdbuf, offset); } #endif int probe_cpu(struct dr_node *cpu, struct dr_info *dr_info) { char drc_index[DR_STR_MAX]; int probe_file; int write_len; int rc = 0; #ifdef NOT_YET if (kernel_dlpar_exists()) { rc = do_cpu_kernel_dlpar(cpu, ADD); } else { #endif probe_file = open(CPU_PROBE_FILE, O_WRONLY); if (probe_file <= 0) { /* Attempt to add cpu from user-space, this may be * an older kernel without the infrastructure to * handle dlpar. */ rc = acquire_cpu(cpu, dr_info); if (rc) return rc; rc = online_cpu(cpu, dr_info); if (rc) { /* Roll back the operation. Is this the * correct behavior? */ say(ERROR, "Unable to online %s\n", cpu->drc_name); offline_cpu(cpu); release_cpu(cpu, dr_info); cpu->unusable = 1; } } else { memset(drc_index, 0, DR_STR_MAX); write_len = sprintf(drc_index, "0x%x", cpu->drc_index); say(DEBUG, "Probing cpu 0x%x\n", cpu->drc_index); rc = write(probe_file, drc_index, write_len); if (rc != write_len) say(ERROR, "Probe failed! rc = %x\n", rc); else /* reset rc to success */ rc = 0; close(probe_file); } #ifdef NOT_YET } #endif if (!rc) { update_cpu_node(cpu, NULL, dr_info); refresh_cache_info(dr_info); } return rc; } /** * release_caches * Remove any unused cache info. Failure to remove the cache, while not * good, should not affect the removal of the cpu. Additionally, the only * way to add the cache info back to the device tree is via a * configure-connector call which could then put multiple copies of any * cache that wasn't fully removed into the device tree. For these reasons * we ignore cache removal failures and do not try to recover. * * @param cpu * @param dr_info */ static void release_caches(struct dr_node *cpu, struct dr_info *dr_info) { struct cache_info *L2_cache, *L3_cache; int usecount, rc; L2_cache = cpu_get_dependent_cache(cpu, dr_info); usecount = cache_get_use_count(L2_cache, dr_info); if (usecount == 0) { L3_cache = cache_get_dependent_cache(L2_cache, dr_info); rc = cache_remove_devnode(L2_cache); if (rc) return; usecount = cache_get_use_count(L3_cache, dr_info); if (usecount == 0) cache_remove_devnode(L3_cache); } return; } /** * release_cpu * * Release a cpu back to the hypervisor, using the cpu's drc-index. * The cpu must have already been offlined. We remove the cpu from the * device tree only when the isolate and set_indicator have succeeded. * The caller must not use the value given for the cpu parameter after * this function has returned. * * @param cpu * @returns 0 on success, !0 otherwise */ int release_cpu(struct dr_node *cpu, struct dr_info *dr_info) { int release_file; int rc; #ifdef NOT_YET if (kernel_dlpar_exists()) return do_cpu_kernel_dlpar(cpu, REMOVE); #endif release_file = open(CPU_RELEASE_FILE, O_WRONLY); if (release_file > 0) { /* DLPAR can be done in kernel */ char *path = cpu->ofdt_path + strlen(OFDT_BASE); int write_len = strlen(path); say(DEBUG, "Releasing cpu \"%s\"\n", path); rc = write(release_file, path, write_len); if (rc != write_len) say(ERROR, "Release failed! rc = %d\n", rc); else /* set rc to success */ rc = 0; close(release_file); } else { /* Must do DLPAR from user-space */ rc = offline_cpu(cpu); if (rc) { say(ERROR, "Could not offline cpu %s\n", cpu->drc_name); return rc; } rc = release_drc(cpu->drc_index, CPU_DEV); if (rc) { say(ERROR, "Could not release drc resources for %s\n", cpu->name); return rc; } rc = remove_device_tree_nodes(cpu->ofdt_path); if (rc) { struct of_node *of_nodes; say(ERROR, "Could not remove device tree nodes %s\n", cpu->name); of_nodes = configure_connector(cpu->drc_index); if (of_nodes == NULL) { say(ERROR, "Call to configure_connector failed " "for %s. The device tree\nmay contain " "invalid data for this cpu and a " "re-activation of the partition is " "needed to correct it.\n", cpu->name); } else { rc = add_device_tree_nodes(CPU_OFDT_BASE, of_nodes); free_of_node(of_nodes); } acquire_drc(cpu->drc_index); return rc; } release_caches(cpu, dr_info); } return rc; } /** * init_cpu_drc_info * * @returns pointer to drc_info on success, NULL otherwise */ int init_cpu_drc_info(struct dr_info *dr_info) { struct dr_node *cpu; struct thread *t; int rc; memset(dr_info, 0, sizeof(*dr_info)); rc = init_thread_info(dr_info); if (rc) { return -1; } rc = init_cpu_info(dr_info); if (rc) { free_cpu_drc_info(dr_info); return -1; } rc = init_cache_info(dr_info); if (rc) { free_cpu_drc_info(dr_info); return -1; } if (output_level >= EXTRA_DEBUG) { say(EXTRA_DEBUG, "Start CPU List.\n"); for (cpu = dr_info->all_cpus; cpu; cpu = cpu->next) { say(EXTRA_DEBUG, "%x : %s\n", cpu->drc_index, cpu->drc_name); for (t = cpu->cpu_threads; t; t = t->sibling) say(EXTRA_DEBUG, "\tthread: %d: %s\n", t->phys_id, t->path); } say(EXTRA_DEBUG, "Done.\n"); } return 0; } /** * free_cpu_drc_info * @brief free the allocated lists hanging off of the drc_info struct * * @param dr_info dr_info struct to free memory from */ void free_cpu_drc_info(struct dr_info *dr_info) { free_cache_info(dr_info->all_caches); free_thread_info(dr_info->all_threads); free_node(dr_info->all_cpus); memset(dr_info, 0, sizeof(*dr_info)); } /** * set thread_state * @brief Set the thread state * * Set the given thread to the desired state. This just writes "1" or "0" * to /sys/devices/system/cpu/cpu[id]/online. * * @param thread * @param state * @returns 0 on success, !0 otherwise */ int set_thread_state(struct thread *thread, int state) { char path[DR_PATH_MAX]; FILE *file; int rc = 0; say(DEBUG, "%slining thread id %d\n", ((state == ONLINE) ? "On" : "Off"), thread->id); sprintf(path, DR_THREAD_ONLINE_PATH, thread->id); file = fopen(path, "w"); if (file == NULL) { say(ERROR, "Could not open %s, unable to set thread state " "to %d\n", path); return -1; } fprintf(file, "%d", state); fclose(file); /* fprintf apparently does not return negative number * if the write() gets an -EBUSY, so explicitly check the * thread state. */ if (state != get_thread_state(thread)) { say(ERROR, "Failure setting thread state for %s\n", path); rc = -1; } return rc; } /** * get_thread_state * @brief Get the "online" status of the given thread. * * @param thread * @returns 0 = offline, 1 = online, -1 on error */ int get_thread_state(struct thread *thread) { char path[DR_PATH_MAX]; int rc, status = -1; sprintf(path, DR_THREAD_ONLINE_PATH, thread->id); rc = get_int_attribute(path, NULL, &status, sizeof(status)); return rc ? rc : status; } /** * cpu_enable_smt * * For the given physical cpu, online all of its threads. * Just call online_spu for now. * * @param cpu cpu to enable smt on * @returns 0 on success, !0 otherwise */ int cpu_enable_smt(struct dr_node *cpu, struct dr_info *dr_info) { return online_cpu(cpu, dr_info); } /** * cpu_diable_smt * @brief Disable all but one of a cpu's threads * * @param cpu cpu to disable smt on * @returns 0 on success, !0 otherwise */ int cpu_disable_smt(struct dr_node *cpu) { int rc = 0; struct thread *t; int survivor_found = 0; /* Ensure that the first thread of the processor is the thread that is left online * when disabling SMT. */ t = cpu->cpu_threads; if (get_thread_state(t) == OFFLINE) rc |= set_thread_state(t, ONLINE); for (t = cpu->cpu_threads; t != NULL; t = t->sibling) { if (ONLINE == get_thread_state(t)) { if (survivor_found) rc |= set_thread_state(t, OFFLINE); survivor_found = 1; } } return rc; } /** * online_first_dead_cpu * @brief Find the first cpu with attributes online and physical_id both * set to 0 and online it. * * @param nthreads * @returns 0 on success, !0 otherwise */ int online_first_dead_cpu(int nthreads, struct dr_info *dr_info) { struct thread *thread; int rc = 1; for (thread = dr_info->all_threads; thread; thread = thread->next) { if (OFFLINE == get_thread_state(thread) && ((thread->phys_id == 0xffffffff) || (thread->phys_id == 0))) { /* just assume that there will be nthreads to online. */ while (nthreads--) { set_thread_state(thread, ONLINE); thread = thread->next; } rc = 0; break; } } if (rc) say(ERROR, "Could not find any threads to online\n"); return rc; } /** * offline_cpu * @brief Mark the specified cpu as offline * * @param cpu * @param dr_info * @returns 0 on success, !0 otherwise */ int offline_cpu(struct dr_node *cpu) { int rc = 0; struct thread *thread; say(DEBUG, "Offlining cpu %s (%d threads)\n", cpu->name, cpu->cpu_nthreads); for (thread = cpu->cpu_threads; thread; thread = thread->sibling) { if (get_thread_state(thread) != OFFLINE) rc |= set_thread_state(thread, OFFLINE); } return rc; } /** * online cpu * * @param cpu * @param dr_info * @returns 0 on success, !0 otherwise */ int online_cpu(struct dr_node *cpu, struct dr_info *dr_info) { int rc = 0; struct thread *thread = NULL; int found = 0; say(DEBUG, "Onlining cpu %s (%d threads)\n", cpu->name, cpu->cpu_nthreads); /* Hack to work around kernel brain damage (LTC 7692) */ for (thread = dr_info->all_threads; thread; thread = thread->next) { if (thread->cpu == cpu) { found = 1; break; } } if (!found) { /* There are no threads which match this cpu because * the physical_id attribute is not updated until the * cpu is onlined -- this case is for cpus which are * not present at boot but are added afterwards. */ return online_first_dead_cpu(cpu->cpu_nthreads, dr_info); } for (thread = cpu->cpu_threads; thread; thread = thread->sibling) { if (get_thread_state(thread) != ONLINE) rc |= set_thread_state(thread, ONLINE); } return rc; } /** * smt_enabled * @brief Is smt enabled? * * @returns 1 if smt enabled, 0 if not */ int smt_enabled(struct dr_info *dr_info) { struct dr_node *cpu; /* Just return true if the number of threads in the * first owned cpu is more than one. */ for (cpu = dr_info->all_cpus; cpu; cpu = cpu->next) { if (cpu->is_owned) break; } if (cpu && (cpu->cpu_nthreads > 1)) return 1; return 0; } /** * system_enable_smt * @brief Activate all threads of each cpu * * @returns 0 on success, !0 otherwise */ int system_enable_smt(struct dr_info *dr_info) { struct dr_node *cpu; int rc = 0; for (cpu = dr_info->all_cpus; cpu != NULL; cpu = cpu->next) { if (cpu->is_owned) rc |= cpu_enable_smt(cpu, dr_info); } return rc; } /** * system_disable_smt * @brief Offline all but one thread of each cpu * * @returns 0 on success, !0 otherwise */ int system_disable_smt(struct dr_info *dr_info) { struct dr_node *cpu; int rc = 0; for (cpu = dr_info->all_cpus; cpu != NULL; cpu = cpu->next) { if (cpu->is_owned) rc |= cpu_disable_smt(cpu); } return rc; } powerpc-utils-1.3.4/src/drmgr/common_ofdt.c000066400000000000000000000237761315235264300207310ustar00rootroot00000000000000/** * @file common_ofdt.c * @brief Common routines for Open Firmware Device Tree access * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "dr.h" #include "ofdt.h" struct of_list_prop { char *_data; char *val; int n_entries; }; struct drc_prop_grp { struct of_list_prop drc_names; struct of_list_prop drc_types; struct of_list_prop drc_indexes; struct of_list_prop drc_domains; }; struct dr_connector *all_drc_lists = NULL; /** * get_of_list_prop * @breif retrieve the specified open firmware property list * * @param full_path * @param prop_name * @param prop * @returns 0 on success, !0 otherwise */ static int get_of_list_prop(char *full_path, char *prop_name, struct of_list_prop *prop) { int size, rc; size = get_property_size(full_path, prop_name); prop->_data = zalloc(size); if (prop->_data == NULL) return -1; rc = get_property(full_path, prop_name, prop->_data, size); if (rc) { free(prop->_data); return -1; } prop->n_entries = be32toh(*(uint *)prop->_data); if (prop->n_entries == 0) { say(ERROR, "No entries found in %s/%s\n", full_path, prop_name); return -1; } prop->val = prop->_data + sizeof(uint); return 0; } /** * get_drc_prop_grp * * @param full_path * @param group * @returns 0 on success, !0 otherwise */ static int get_drc_prop_grp(char *full_path, struct drc_prop_grp *group) { struct stat sbuf; char fname[DR_PATH_MAX]; int rc; memset(group, 0, sizeof(*group)); sprintf(fname, "%s/%s", full_path, "ibm,drc-names"); rc = stat(fname, &sbuf); if (rc) return rc; rc = get_of_list_prop(full_path, "ibm,drc-names", &group->drc_names); if (rc) return rc; rc = get_of_list_prop(full_path, "ibm,drc-types", &group->drc_types); if (rc) return rc; rc = get_of_list_prop(full_path, "ibm,drc-indexes", &group->drc_indexes); if (rc) return rc; rc = get_of_list_prop(full_path, "ibm,drc-power-domains", &group->drc_domains); if (rc) return rc; return 0; } /** * free_drc_props * @brief free the properties associated with a drc group * * @param group */ static void free_drc_props(struct drc_prop_grp *group) { if (group->drc_names._data) free(group->drc_names._data); if (group->drc_types._data) free(group->drc_types._data); if (group->drc_indexes._data) free(group->drc_indexes._data); if (group->drc_domains._data) free(group->drc_domains._data); } /** * build_connectors_group * * @param group * @param n_entries * @param list * @returns 0 on success, !0 otherwise */ static int build_connectors_list(struct drc_prop_grp *group, int n_entries, struct dr_connector *list) { struct dr_connector *entry; unsigned int *index_ptr; unsigned int *domain_ptr; char *name_ptr; char *type_ptr; int i; index_ptr = (unsigned int *) group->drc_indexes.val; domain_ptr = (unsigned int *) group->drc_domains.val; name_ptr = group->drc_names.val; type_ptr = group->drc_types.val; for (i = 0; i < n_entries; i++) { entry = &list[i]; entry->index = be32toh(*(index_ptr++)); entry->powerdomain = be32toh(*(domain_ptr++)); strncpy(entry->name, name_ptr, DRC_STR_MAX); name_ptr += strlen(name_ptr) + 1; strncpy(entry->type, type_ptr, DRC_STR_MAX); type_ptr += strlen(type_ptr) + 1; if (i == (n_entries - 1)) entry->next = NULL; else entry->next = &list[i+1]; } return 0; } /** * of_to_full_path * * NOTE: Callers of this function are expected to free full_path themselves * * @param of_path * @returns full path on success, NULL otherwise */ char * of_to_full_path(const char *of_path) { char *full_path = NULL; int full_path_len; if (!strncmp(of_path, OFDT_BASE, strlen(OFDT_BASE))) { full_path = strdup(of_path); if (full_path == NULL) return NULL; } else { full_path_len = strlen(OFDT_BASE) + strlen(of_path) + 2; full_path = zalloc(full_path_len); if (full_path == NULL) return NULL; if (*of_path == '/') sprintf(full_path, "%s%s", OFDT_BASE, of_path); else sprintf(full_path, "%s/%s", OFDT_BASE, of_path); } return full_path; } /** * get_dr_connectors * * NOTE:Callers of this function are expected to free drc_list themselves * * @param of_path * @param drc_list * @param n_drcs * @returns 0 on success, !0 otherwise */ struct dr_connector * get_drc_info(const char *of_path) { struct dr_connector *list = NULL; struct of_list_prop *drc_names; struct drc_prop_grp prop_grp; char *full_path = NULL; int rc, n_drcs; for (list = all_drc_lists; list; list = list->all_next) { if (! strcmp(list->ofdt_path, of_path)) return list; } full_path = of_to_full_path(of_path); if (full_path == NULL) return NULL; rc = get_drc_prop_grp(full_path, &prop_grp); if (rc) { say(DEBUG, "Could not find DRC property group in path: %s.\n", full_path); goto done; } drc_names = &prop_grp.drc_names; n_drcs = drc_names->n_entries; list = zalloc(n_drcs * sizeof(struct dr_connector)); if (list == NULL) goto done; /* XXX Unchecked rc */ rc = build_connectors_list(&prop_grp, n_drcs, list); snprintf(list->ofdt_path, DR_PATH_MAX, "%s", of_path); list->all_next = all_drc_lists; all_drc_lists = list; done: free_drc_props(&prop_grp); if (full_path) free(full_path); return list; } /** * free_drc_info * * @param drc_list */ void free_drc_info(void) { struct dr_connector *list; while (all_drc_lists) { list = all_drc_lists; all_drc_lists = list->all_next; free(list); } } /** * search_drc_list * * @param drc_list * @param n_entries * @param start * @param search_type * @param key * @param found_idx * @returns pointer to dr_connector on success, NULL otherwise */ struct dr_connector * search_drc_list(struct dr_connector *drc_list, struct dr_connector *start, int search_type, void *key) { struct dr_connector *drc; if (start) drc = start; else drc = drc_list; for ( ; drc != NULL; drc = drc->next) { switch (search_type) { case DRC_NAME: if (! strcmp(drc->name, (char *)key)) return drc; break; case DRC_TYPE: if (! strcmp(drc->type, (char *)key)) return drc; break; case DRC_INDEX: if (drc->index == *(uint32_t *)key) return drc; break; case DRC_POWERDOMAIN: if (drc->powerdomain == *(uint32_t *)key) return drc; }; } return NULL; } /** * get_my_drc_index * * @param of_path * @param index * @returns 0 on success, !0 otherwise */ int get_my_drc_index(char *of_path, uint32_t *index) { char *full_path = NULL; int rc; full_path = of_to_full_path(of_path); if (full_path == NULL) return -1; rc = get_ofdt_uint_property(full_path, "ibm,my-drc-index", index); free(full_path); return rc; } /** * drc_name_to_index * @brief Find the drc index for the given name * * @param name name to find * @returns drc index corresponding to name on success, 0 otherwise */ int drc_name_to_index(const char *name, struct dr_connector *drc_list) { struct dr_connector *drc; for (drc = drc_list; drc != NULL; drc = drc->next) { if (!strcmp(name, drc->name)) return drc->index; } return 0; /* hopefully 0 isn't a valid index... */ } /** * drc_index_to_name * @brief find the drc name for the specified drc index * * @param index * @returns drc name on success, NULL otherwise */ char * drc_index_to_name(uint32_t index, struct dr_connector *drc_list) { struct dr_connector *drc; for (drc = drc_list; drc != NULL; drc = drc->next) { if (index == drc->index) return drc->name; } return NULL; } /** * get_drc_by_name * @brief Retrieve a dr_connector with the specified drc_name * * This routine searches the drc lists for a dr_connector with the * specified name starting at the specified directory. If a dr_connector * is found the root_dir that the dr_connector was found in is also * filled out. * * @param drc_name name of the dr_connector to search for * @param drc pointer to a drc to point to the found dr_connector * @param root_dir pointer to buf to fill in with root directory * @param start_dir, directory to start searching * @returns 0 on success (drc and root_dir filled in), !0 on failure */ int get_drc_by_name(char *drc_name, struct dr_connector *drc, char *root_dir, char *start_dir) { struct dr_connector *drc_list = NULL; struct dr_connector *drc_entry; struct dirent *de; DIR *d; int rc = -1; memset(drc, 0, sizeof(*drc)); /* Try to get the drc in this directory */ drc_list = get_drc_info(start_dir); if (drc_list == NULL) return -1; drc_entry = search_drc_list(drc_list, NULL, DRC_NAME, drc_name); if (drc_entry != NULL) { memcpy(drc, drc_entry, sizeof(*drc)); sprintf(root_dir, "%s", start_dir); return 0; } /* If we didn't find it here, check the subdirs */ d = opendir(start_dir); if (d == NULL) return -1; while ((de = readdir(d)) != NULL) { char dir_path[DR_PATH_MAX]; if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name)) continue; sprintf(dir_path, "%s/%s", start_dir, de->d_name); rc = get_drc_by_name(drc_name, drc, root_dir, dir_path); if (rc == 0) break; } closedir(d); return rc; } struct dr_connector * get_drc_by_index(uint32_t drc_index, struct dr_connector *drc_list) { struct dr_connector *drc; for (drc = drc_list; drc; drc = drc->next) { if (drc->index == drc_index) return drc; } return NULL; } powerpc-utils-1.3.4/src/drmgr/common_pci.c000066400000000000000000001050431315235264300205340ustar00rootroot00000000000000/** * @file common_pci.c * @brief Common routines for pci data * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include "dr.h" #include "drpci.h" #include "ofdt.h" /* maximum seconds to wait for pci device removal */ #define PCI_REMOVE_TIMEOUT_MAX 60 /** * alloc_node * * XXX: This doesn't do any cleanup on error conditions. could be bad. * * @param drc * @param dev_type * @param of_path * @returns pointer to node on success, NULL otherwise */ struct dr_node * alloc_dr_node(struct dr_connector *drc, int dev_type, const char *of_path) { struct dr_node *node; node = zalloc(sizeof(*node)); if (node == NULL) return NULL; node->dev_type = dev_type; set_drc_info(node, drc); if (of_path) { get_property(of_path, "ibm,loc-code", node->loc_code, sizeof(node->loc_code)); snprintf(node->ofdt_path, DR_PATH_MAX, "%s", of_path); } return node; } /** * find_ofdt_dname * * Find "name" of the device_node that is a child * of given node and its "ibm,loc-code" is the same * as node->name. * * @param node * @param path * @param ofdt_dname */ static int find_ofdt_dname(struct dr_node *node, char *path) { DIR *d = NULL; struct dirent *de; struct stat sb; char new_path[DR_PATH_MAX]; char loc_code[DR_BUF_SZ]; char *q; int found = 0; int rc; rc = get_property(path, "ibm,loc-code", &loc_code, DR_BUF_SZ); if ((rc == 0) && (strstr(loc_code, node->drc_name))) { rc = get_property(path, "name", node->ofdt_dname, sizeof(node->ofdt_dname)); if (rc == 0) return 1; } /* First look for a ofdt node that has ibm,loc-code property * with a value that matches node->name. * * Set node->node->ofdt_dname to "name" of the ofdt node. */ d = opendir(path); if (d == NULL) { say(ERROR, "Could not open dir %s\n%s\n", path, strerror(errno)); return 0; } strcpy(new_path, path); q = new_path + strlen(new_path); *q++ = '/'; while(((de = readdir(d)) != NULL) && (! found)) { /* skip all dot files */ if (de->d_name[0] == '.') continue; strcpy(q, de->d_name); if (lstat(new_path, &sb) < 0) continue; if (S_ISLNK(sb.st_mode)) continue; if (S_ISDIR(sb.st_mode)) { rc = get_property(path, "ibm,loc-code", &loc_code, DR_BUF_SZ); if ((rc != 0) || (! strstr(loc_code, node->drc_name))) { found = find_ofdt_dname(node, new_path); continue; } rc = get_property(path, "name", node->ofdt_dname, sizeof(node->ofdt_dname)); if (rc == 0) { found = 1; break; } } } if (d != NULL) closedir(d); return found; } /** * add_child_node * * Create information about the Open Firmware node and * add that information to the appropriate per-node list of * Open Firmware nodes. Also create the corresponding information * for any PCI device. * * NOTES: * 1) does not need to be concerned about one or more Open * Firmware nodes having the used-by-rtas property present. * One of the RTAS services used during removing a PCI adapter * must take the appropriate action (most likely eliminate RTAS * usage) in this case. * 2) Open Firmware node RPA physical location code: * * [Un.m-]Pn[-Pm]-In[[/Zn]-An] * * where * Un.m is for the enclosure for multi-enclosue systems * Pn is for the planar * In is for the slot * /Zn is for the connector on the adapter card * An is for the device connected to the adapter * * note * There may be multiple levels of planars [Pm]. * * RECOVERY OPERATION: * 1) This function does not add the Open Firmware node if the user * mode process has exceeded all available malloc space. This * should not happen based on the rather small total amount of * memory allocation required. The node is marked as skip. * 2) This function does not add the device information if there * is a problem initializing device. The node is marked as skip. * * @param parent * @param child_path */ static void add_child_node(struct dr_node *parent, char *child_path) { struct dr_connector *drc_list, *drc; char loc_code[DR_BUF_SZ]; char *slash; struct dr_node *child; uint my_drc_index; int rc; assert(parent != NULL); assert(strlen(child_path) != 0); /* Make sure that the Open Firmware node is not added twice * in case the ibm,my-drc-index property is put in all nodes * for the adapter instead of just the ones at the connector. */ if (parent->children != NULL) { struct dr_node *tmp; for (tmp = parent->children; tmp; tmp = tmp->next) { if (! strcmp(tmp->ofdt_path, child_path)) return; } } /* Create the Open Firmware node's information and insert that * information into the node's list based on the node's RPA * physical location code. Ignore the OF node if the node * does not have an RPA physical location code because that is * a firmware error. */ rc = get_property(child_path, "ibm,loc-code", &loc_code, DR_BUF_SZ); if (rc) return; /* Skip the Open Firmware node if it is a device node. Determine that * the node is for a device by looking for a hyphen after the last * slash (...-In/Z1-An). */ slash = strrchr(loc_code, '/'); if (slash != NULL) { char *hyphen; hyphen = strchr(slash, '-'); if (hyphen != NULL) return; *slash = '\0'; } if (parent->dev_type == PCI_HP_DEV) { /* hotplug */ /* Squadrons don't have "/" in devices' (scsi, * ethernet, tokenring ...) loc-code strings. * * Skip the Open Firmware node if the node's RPA * physical location code does not match the node's * location code. Ignore the connector information, * i.e. information after last slash if no hyphen * follows. */ if ((strcmp(parent->drc_name, loc_code) != 0) && (slash != NULL)) { parent->skip = 1; return; } } /* Restore the slash because the full RPA location code * is saved for each OF node so that the connector * information can be used to sort the OF node list for * each node. */ if (slash != NULL) *slash = '/'; if (get_my_drc_index(child_path, &my_drc_index)) return; /* need the drc-info in the dir above */ slash = strrchr(child_path, '/'); *slash = '\0'; drc_list = get_drc_info(child_path); *slash = '/'; for (drc = drc_list; drc != NULL; drc = drc->next) { if (drc->index == my_drc_index) break; } /* Allocate space for the Open Firmware node information. */ child = alloc_dr_node(drc, parent->dev_type, child_path); if (child == NULL) { parent->skip = 1; return; } if ((! strcmp(parent->drc_type, "SLOT")) && (parent->dev_type == PCI_DLPAR_DEV)) snprintf(child->ofdt_dname, DR_STR_MAX, "%s", parent->ofdt_dname); else get_property(child_path, "name", child->ofdt_dname, sizeof(child->ofdt_dname)); switch (parent->dev_type) { case PCI_HP_DEV: case PCI_DLPAR_DEV: { get_ofdt_uint_property(child_path, "vendor-id", &child->pci_vendor_id); get_ofdt_uint_property(child_path, "device-id", &child->pci_device_id); get_ofdt_uint_property(child_path, "class_code", &child->pci_class_code); break; } case HEA_DEV: { child->dev_type = HEA_PORT_DEV; get_ofdt_uint_property(child_path, "ibm,hea-port-no", &child->hea_port_no); get_ofdt_uint_property(child_path, "ibm,hea-port-tenure", &child->hea_port_tenure); break; } } child->next = parent->children; parent->children = child; } /** * init_node * * @param node * @returns 0 on success, !0 otherwise */ static int init_node(struct dr_node *node) { DIR *d; struct dirent *de; char child_path[DR_PATH_MAX]; uint32_t my_drc_index; int rc; if (node->is_owned) find_ofdt_dname(node, node->ofdt_path); d = opendir(node->ofdt_path); if (!d) return -1; rc = 0; while ((de = readdir(d)) != NULL) { if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name)) continue; sprintf(child_path, "%s/%s", node->ofdt_path, de->d_name); if (get_my_drc_index(child_path, &my_drc_index)) continue; if (node->dev_type == PCI_HP_DEV) { if (node->drc_index == my_drc_index) { /* Add hotplug children */ add_child_node(node, child_path); } } else { if (!node->is_owned) { if (node->drc_index == my_drc_index) { /* Update node path */ snprintf(node->ofdt_path, DR_PATH_MAX, "%s", child_path); node->is_owned = 1; /* Populate w/ children */ rc = init_node(node); if (rc) break; } } else { /* Add all DR-capable children */ add_child_node(node, child_path); } } } closedir(d); return rc; } /** * create_vio_nodes * Creates a set of dr_nodes for any existing vio nodes in the supplied path. * This walks the device tree once. * * @param ofdt_path * @param drc_list * @param node_list - user responsible for freeing * @returns 0 on success, !0 otherwise */ static int create_vio_nodes(const char *ofdt_path, struct dr_connector *drc_list, struct dr_node **node_list) { DIR *d; struct dirent *de; char child_path[DR_PATH_MAX]; uint32_t my_drc_index; struct dr_node *node; struct dr_connector *drc; struct dr_connector *drc_search; int rc; d = opendir(ofdt_path); if (!d) return -1; rc = 0; while ((de = readdir(d)) != NULL) { if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name)) continue; snprintf(child_path, DR_PATH_MAX, "%s/%s", ofdt_path, de->d_name); if (get_my_drc_index(child_path, &my_drc_index)) continue; drc = NULL; for (drc_search = drc_list; drc_search; drc_search = drc_search->next) { if (drc_search->index == my_drc_index) { drc = drc_search; break; } } if (!drc) { say(ERROR, "Unable to find DRC index %d\n", my_drc_index); rc = -1; break; } node = alloc_dr_node(drc, VIO_DEV, child_path); if (!node) { say(ERROR, "Could not allocate pci/vio node\n"); rc = -1; break; } node->is_owned = 1; /* Populate w/ children */ rc = init_node(node); if (rc) { free(node); break; } node->next = *node_list; *node_list = node; } closedir(d); if (rc) free_node(*node_list); return rc; } static inline int is_hp_type(char *type) { return (strtoul(type, NULL, 10) > 0); } static inline int is_logical_type(char *type) { return (!strcmp(type, "SLOT")); } /** * free_node * @brief free a list of node struct and any allocated memory they reference * * @param node_list list of nodes to free */ void free_node(struct dr_node *node_list) { struct dr_node *node; if (node_list == NULL) return; while (node_list) { node = node_list; node_list = node->next; if (node->children) free_node(node->children); if (node->dev_type == MEM_DEV) { struct mem_scn *mem_scn; while (node->lmb_mem_scns != NULL) { mem_scn = node->lmb_mem_scns; node->lmb_mem_scns = mem_scn->next; free(mem_scn); } if (node->lmb_of_node) free(node->lmb_of_node); } free(node); } } /** * devspec_check_node * * @param node * @param sysfs_path * @param full_of_path * @param found * @returns 0 on success, !0 otherwise */ static int devspec_check_node(struct dr_node *node, char *sysfs_path, char *full_of_path, int *found) { struct dr_node *child; *found = 0; if (node->ofdt_path == NULL) return 0; if (! strcmp(full_of_path, node->ofdt_path)) { snprintf(node->sysfs_dev_path, DR_PATH_MAX, "%s", sysfs_path); *found = 1; return 0; } for (child = node->children; child; child = child->next) { if (! strcmp(full_of_path, child->ofdt_path)) { snprintf(child->sysfs_dev_path, DR_PATH_MAX, "%s", sysfs_path); *found = 1; return 0; } } return 0; } /** * correlate_devspec * * @param sysfs_path * @param ofdt_path */ static int correlate_devspec(char *sysfs_path, char *ofdt_path, struct dr_node *node_list) { struct dr_node *node; char *full_of_path; int found; int rc; full_of_path = of_to_full_path(ofdt_path); for (node = node_list; node != NULL; node = node->next) { rc = devspec_check_node(node, sysfs_path, full_of_path, &found); if (rc) return rc; if (found) break; } free(full_of_path); return 0; } /** * add_linux_devices * */ static void add_linux_devices(char *start_dir, struct dr_node *node_list) { struct dirent *de; DIR *d; char *dir; int rc; if (start_dir == NULL) dir = "/sys/devices"; else dir = start_dir; d = opendir(dir); if (d == NULL) { say(ERROR, "failed to open %s\n%s\n", dir, strerror(errno)); return; } while ((de = readdir(d)) != NULL) { char buf[1024]; if (is_dot_dir(de->d_name)) continue; if (de->d_type == DT_DIR) { sprintf(buf, "%s/%s", dir, de->d_name); add_linux_devices(buf, node_list); } else if (! strcmp(de->d_name, "devspec")) { char devspec[DR_PATH_MAX]; sprintf(buf, "%s/%s", dir, de->d_name); rc = get_str_attribute(buf, NULL, devspec, DR_PATH_MAX); if (rc == 0) rc = correlate_devspec(dir, devspec, node_list); } } closedir(d); } /** * add_hea_node * @brief Add a node for an HEA adapter * * @param path ofdt_path to this node * @param drc_list list of drc's at OFDT_BASE * @param pointer to the node list to add new nodes to * @return 0 on success, !0 otherwise */ static int add_hea_node(char *path, struct dr_connector *drc_list, struct dr_node **node_list) { struct dr_connector *drc; struct dr_node *hea_node; uint my_drc_index; int rc; if (drc_list == NULL) return -1; if (get_my_drc_index(path, &my_drc_index)) return -1; for (drc = drc_list; drc != NULL; drc = drc->next) { if (drc->index == my_drc_index) break; } if (drc == NULL) { say(ERROR, "Could not find drc index 0x%x to add to hea list\n", my_drc_index); return -1; } hea_node = alloc_dr_node(drc, HEA_DEV, path); if (hea_node == NULL) { say(ERROR, "Could not allocate hea node for drc index 0x%x\n", my_drc_index); return -1; } hea_node->is_owned = 1; rc = init_node(hea_node); if (rc) { free(hea_node); return -1; } hea_node->next = *node_list; *node_list = hea_node; return 0; } /** * add_pci_vio_node * @bried Add a PCI or virtual device node * * @param path ofdt path to this node * @param dev_type type of device * @param node_list pointer to list to add node to * @returns 0 on success, !0 otherwise */ static int add_pci_vio_node(const char *path, int dev_type, struct dr_node **node_list) { struct dr_connector *drc_list; struct dr_connector *drc; struct dr_node *node; struct dr_node *vio_node_list = NULL; struct dr_node *node_search; struct dr_node *node_search_prev; int child_dev_type = 0; int rc = -1; drc_list = get_drc_info(path); if (drc_list == NULL) return -1; // Create a list of existing VIO nodes so we can // walk the vio bus only once if (dev_type == VIO_DEV) { rc = create_vio_nodes(path, drc_list, &vio_node_list); if (rc) return rc; } for (drc = drc_list; drc != NULL; drc = drc->next) { node = NULL; switch (dev_type) { case PCI_HP_DEV: if (! is_hp_type(drc->type)) continue; child_dev_type = dev_type; break; case PCI_DLPAR_DEV: case VIO_DEV: if (! is_logical_type(drc->type)) continue; child_dev_type = dev_type; break; case PHB_DEV: if (is_logical_type(drc->type)) child_dev_type = PCI_DLPAR_DEV; else child_dev_type = PCI_HP_DEV; break; } // If this is VIO, look for the node in our existing list if (dev_type == VIO_DEV) { node_search = vio_node_list; node_search_prev = NULL; while (node_search) { if (drc->index == node_search->drc_index) { /* * Use this node - and remove it * from the list */ node = node_search; if (node_search_prev) node_search_prev->next = node->next; else vio_node_list = node->next; break; } node_search_prev = node_search; node_search = node_search->next; } } if (!node) { node = alloc_dr_node(drc, child_dev_type, path); if (!node) { say(ERROR, "Could not allocate pci/vio node\n"); free_node(vio_node_list); return -1; } if (child_dev_type == PCI_HP_DEV) node->is_owned = 1; if (dev_type != VIO_DEV) { rc = init_node(node); if (rc) { free(node); return rc; } } } node->next = *node_list; *node_list = node; } free_node(vio_node_list); return rc; } /** * add_phb_node * @brief Add a PHB node to the node list * * @param ofdt_poath, ofdt path to this node * @param drc_list list of drc's at OFDT_BASE * @param node_list list of nodes to add node to * @returns 0 on success, !0 otherwise */ static int add_phb_node(char *ofdt_path, struct dr_connector *drc_list, struct dr_node **node_list) { struct dr_node *phb_node; struct dr_connector *drc; uint my_drc_index; if (get_my_drc_index(ofdt_path, &my_drc_index)) return -1; for (drc = drc_list; drc; drc = drc->next) { if (drc->index == my_drc_index) break; } if (drc == NULL) { say(ERROR, "Could not find drc index 0x%x to add to phb list\n", my_drc_index); return -1; } phb_node = alloc_dr_node(drc, PHB_DEV, ofdt_path); if (phb_node == NULL) { say(ERROR, "Could not allocate PHB node for drc index 0x%x\n", my_drc_index); return -1; } phb_node->is_owned = 1; add_pci_vio_node(ofdt_path, PHB_DEV, &phb_node->children); phb_node->next = *node_list; *node_list = phb_node; return 0; } /** * update_phb_ic_info * @brief Add interrupt controller information to PHB nodes * * We need to have the interrupt-controller ofdt paths for all PHB * nodes to do DLPAR. This routine adds that information for PHB nodes * that we found. * * @param node_list list of PHB nodes * @returns 0 on success, !0 otherwise */ static int update_phb_ic_info(struct dr_node *node_list) { char *ic_dir = "interrupt-controller"; struct dr_node *node; struct dirent *de; DIR *d; int rc = 0; d = opendir(OFDT_BASE); if (d == NULL) { say(ERROR, "failed to open %s\n%s\n", OFDT_BASE, strerror(errno)); return -1; } while ((de = readdir(d)) != NULL) { uint my_drc_index; char ofdt_path[DR_PATH_MAX]; if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name)) continue; if (strncmp(de->d_name, ic_dir, strlen(ic_dir))) continue; sprintf(ofdt_path, "%s/%s", OFDT_BASE, de->d_name); rc = get_my_drc_index(ofdt_path, &my_drc_index); if (rc) /* This is expected to fail sometimes, as there can be * more ICs than PHBs on a system. In this case, some * ICs won't have my-drc-index. */ continue; for (node = node_list; node; node = node->next) { if ((node->dev_type == PHB_DEV) && (node->drc_index == my_drc_index)) { snprintf(node->phb_ic_ofdt_path, DR_PATH_MAX, "%s", ofdt_path); break; } } } closedir(d); return 0; } /** * get_dlpar_nodes * * @param list_type * @returns pointer to node list on success, NULL otherwise */ struct dr_node * get_dlpar_nodes(uint32_t node_types) { struct dr_connector *drc_list = NULL; struct dr_node *node_list = NULL; struct dirent *de; DIR *d; char path[1024]; say(DEBUG, "Getting node types 0x%08x\n", node_types); d = opendir(OFDT_BASE); if (d == NULL) { say(ERROR, "failed to open %s\n%s\n", OFDT_BASE, strerror(errno)); return NULL; } while ((de = readdir(d)) != NULL) { if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name)) continue; memset(path, 0, 1024); sprintf(path, "%s/%s", OFDT_BASE, de->d_name); if ((! strcmp(de->d_name, "vdevice")) && (node_types & VIO_NODES)) add_pci_vio_node(path, VIO_DEV, &node_list); else if (! strncmp(de->d_name, "pci@", 4)) { if (node_types & PCI_NODES) add_pci_vio_node(path, PCI_DLPAR_DEV, &node_list); else if (node_types & PHB_NODES) { if (drc_list == NULL) drc_list = get_drc_info(OFDT_BASE); add_phb_node(path, drc_list, &node_list); } } else if ((! strncmp(de->d_name, "lhea@", 5)) && (node_types & HEA_NODES)) { if (drc_list == NULL) drc_list = get_drc_info(OFDT_BASE); add_hea_node(path, drc_list, &node_list); } } closedir(d); if (node_list != NULL) { add_linux_devices(NULL, node_list); if (node_types & PHB_NODES) update_phb_ic_info(node_list); } return node_list; } /** * _get_hp_nodes * @brief The workhorse routine for finding hotplug nodes * * @param dir start directory for searching * @param pointer to list of nodes to return * @return 0 on success, !0 otherwise */ static int _get_hp_nodes(char *dir, struct dr_node **list) { struct dirent *de; DIR *d; char path[1024]; d = opendir(dir); if (d == NULL) { say(ERROR, "failed to open %s\n%s\n", dir, strerror(errno)); return -1; } while ((de = readdir(d)) != NULL) { if ((de->d_type != DT_DIR) || is_dot_dir(de->d_name)) continue; if (strncmp(de->d_name, "pci@", 4)) continue; memset(path, 0, 1024); sprintf(path, "%s/%s", dir, de->d_name); add_pci_vio_node(path, PCI_HP_DEV, list); _get_hp_nodes(path, list); } closedir(d); return 0; } /** * get_hp_nodes * @brief retrieve a list of hotplug nodes on the partition * * @return pointer to node list on success, NULL on failure */ struct dr_node * get_hp_nodes() { struct dr_node *node_list = NULL; say(DEBUG, "Retrieving hotplug nodes\n"); _get_hp_nodes(OFDT_BASE, &node_list); if (node_list != NULL) add_linux_devices(NULL, node_list); return node_list; } struct dr_node * get_node_by_name(const char *drc_name, uint32_t node_type) { struct dr_node *node, *all_nodes; struct dr_node *prev_node = NULL; int child_found = 0; all_nodes = get_dlpar_nodes(node_type); if (all_nodes == NULL) { say(ERROR, "There are no DR capable slots on this system\n"); return NULL; } print_node_list(all_nodes); for (node = all_nodes; node; node = node->next) { struct dr_node *child; uint32_t drc_index; if (strcmp(node->drc_name, drc_name) == 0) break; /* See if the drc index was specified */ drc_index = strtoul(drc_name, NULL, 0); if (node->drc_index == drc_index) continue; for (child = node->children; child; child = child->next) { if (strcmp(drc_name, child->drc_name) == 0) child_found = 1; if (child->drc_index == drc_index) child_found = 1; } if (child_found) break; prev_node = node; } if (node) { if (prev_node) prev_node->next = node->next; else /* First in list */ all_nodes = all_nodes->next; node->next = NULL; } free_node(all_nodes); return node; } /** * cmp_drcname * * Compare the drcname's opf two nodes * * @param name1 * @param name2 * @returns 1 if the drcnames match, 0 otherwise */ int cmp_drcname(char *name1, char *name2) { char *ptr; if (name2 == NULL) return 0; /* The string pointed to by name2 may in fact be a location code * for a device in a PCI node. Hence, its hardware location * code will not match exactly. However, if this is the case, * the substring in the device location code up to the first '/' * character should match the node's location exactly. * * If there's a '/' in name2, then shorten string to the * LAST '/' character. * Note: this affects name2 globally! */ ptr = strrchr(name2, '/'); if (ptr != NULL) /* End the string at the '/' * compiler doesn't like NULL --Linda */ *ptr = '\0'; /* Now compare */ return (! strcmp(name1, name2)); } /** * get_bus_id * * @param loc_code * @returns */ static char * get_bus_id(char *loc_code) { DIR *d; struct dirent *ent; char *dir = "/sys/bus/pci/slots"; int inlen; char *ptr; /* Strip any newline from the input location */ if ((ptr = strchr(loc_code, '\n')) != NULL) inlen = ptr - loc_code; else inlen = strlen(loc_code); d = opendir(dir); if (d == NULL) { say(ERROR, "failed to open %s: %s\n", dir, strerror(errno)); return NULL; } while ((ent = readdir(d))) { char path[DR_PATH_MAX], location[DR_BUF_SZ]; FILE *f; int rc; if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue; sprintf(path, "/sys/bus/pci/slots/%s/phy_location", ent->d_name); f = fopen(path, "r"); if (f == NULL) continue; rc = fread(location, sizeof(location), 1, f); fclose(f); if (rc != 1) { say(ERROR, "Could not %s, skipping\n", path); continue; } /* Strip any newline from the location to compare */ if ((ptr = strchr(location, '\n')) != NULL) *ptr = '\0'; if ((strlen(location) == inlen && !strncmp(loc_code, location, inlen))) { char *bus_id; bus_id = strdup(ent->d_name); if (bus_id) { closedir(d); return bus_id; } else { say(ERROR, "Failed to allocate bus id\n"); break; } } } closedir(d); return NULL; } /** * get_hp_adapter_status * @brief check adapter status * * @param drc_name * @returns 0 if slot is empty * @returns 1 if adapter is configured * @returns 2 if adapter is not configured * @returns <0 on error */ int get_hp_adapter_status(char *drc_name) { int value, rc = 0; char path[DR_PATH_MAX], *bus_id; bus_id = get_bus_id(drc_name); if (bus_id) sprintf(path, PHP_SYSFS_ADAPTER_PATH, bus_id); else sprintf(path, PHP_SYSFS_ADAPTER_PATH, drc_name); rc = get_int_attribute(path, NULL, &value, sizeof(value)); if (rc) return -1; say(DEBUG, "hp adapter status for %s is %d\n", drc_name, value); rc = value; if (rc != CONFIG && rc != NOT_CONFIG && rc != EMPTY) rc = -1; return rc; } /** * set_hp_adapter_status * * @param operation 1=> config 0=> unconfig * @param slot_name * @returns 0 on success, !0 otherwise */ int set_hp_adapter_status(uint operation, char *slot_name) { int rc = 0; FILE *file; char *bus_id; char path[DR_PATH_MAX]; bus_id = get_bus_id(slot_name); if (bus_id) sprintf(path, PHP_SYSFS_POWER_PATH, bus_id); else sprintf(path, PHP_SYSFS_POWER_PATH, slot_name); say(DEBUG, "setting hp adapter status to %s for %s\n", ((operation+1 - 1) ? "CONFIG adapter" : "UNCONFIG adapter"), slot_name); file = fopen(path, "w"); if (file == NULL) { say(ERROR, "failed to open %s: %s\n", path, strerror(errno)); return -ENODEV; } rc = fwrite((operation+1 - 1) ? "1" : "0", 1, 1, file); if (rc != 1) rc = -EACCES; else rc = 0; fclose(file); return rc; } /** * pci_rescan_bus * * @returns 0 on success, !0 otherwise */ int pci_rescan_bus() { int rc = 0; FILE *file; file = fopen(PCI_RESCAN_PATH, "w"); if (file == NULL) { say(ERROR, "failed ot open %s: %s\n", PCI_RESCAN_PATH, strerror(errno)); return -ENODEV; } rc = fwrite("1", 1, 1, file); if (rc != 1) rc = -EACCES; fclose(file); return rc; } /** * pci_remove_device * * @returns 0 on success, !0 otherwise */ int pci_remove_device(struct dr_node *node) { int rc = 0; FILE *file; char path[DR_PATH_MAX]; int wait_time = 0; sprintf(path, "%s/%s", node->sysfs_dev_path, "remove"); file = fopen(path, "w"); if (file == NULL) { say(ERROR, "failed to open %s: %s\n", path, strerror(errno)); return -ENODEV; } rc = fwrite("1", 1, 1, file); if (rc != 1) rc = -EACCES; fclose(file); if (rc == -EACCES) return rc; do { struct stat sb; rc = stat(node->sysfs_dev_path, &sb); if (rc) { rc = -errno; } else { say(DEBUG, "waiting for PCI device driver to quiesce device at %s\n", node->sysfs_dev_path); sleep(1); } } while (rc == 0 && (++wait_time < PCI_REMOVE_TIMEOUT_MAX && !drmgr_timed_out())); if (rc == 0) { say(ERROR, "timeout while quiescing device at %s\n", node->sysfs_dev_path); rc = -EBUSY; } else if (rc == -ENOENT) { /* sysfs entries cleaned up as part of device removal */ rc = 0; } return rc; } /** * dlpar_io_kernel_op * @brief access kernel interface files * * @param interface_file * @param drc_name * @returns 0 on success, !0 otherwise */ static int dlpar_io_kernel_op(const char *interface_file, const char *drc_name) { int rc = 0, len; FILE *file; int my_errno; len = strlen(drc_name); say(DEBUG, "performing kernel op for %s, file is %s\n", drc_name, interface_file); do { errno = 0; file = fopen(interface_file, "r+"); if (file == NULL) { say(ERROR, "failed to open %s: %s\n", interface_file, strerror(errno)); return -1; } rc = fwrite(drc_name, 1, len, file); my_errno = errno; fclose(file); /* Success, note we do fwrite with the values * size = 1 and nitems = len. */ if (rc == len) return 0; /* We should continue trying the kernel op if we get EBUSY, * this would indicate the add/remove operation has not * completed. */ if (my_errno != EBUSY) { say(ERROR, "kernel I/O op failed, %s\n", my_errno ? strerror(my_errno) : "incomplete write"); break; } sleep(1); if (drmgr_timed_out()) break; } while (1); return -1; } int dlpar_remove_slot(const char *drc_name) { return dlpar_io_kernel_op(remove_slot_fname, drc_name); } int dlpar_add_slot(const char *drc_name) { return dlpar_io_kernel_op(add_slot_fname, drc_name); } void print_node_list(struct dr_node *first_node) { struct dr_node *parent; struct dr_node *child; /* Short-circuit printing nodes if not requested. */ if (output_level < EXTRA_DEBUG) return; parent = first_node; say(EXTRA_DEBUG, "\nDR nodes list\n==============\n"); while (parent) { say(EXTRA_DEBUG, "%s: %s\n" "\tdrc index: 0x%x description: %s\n" "\tdrc name: %s\n\tloc code: %s\n", parent->ofdt_path, (parent->skip ? "(SKIP)" : ""), parent->drc_index, node_type(parent), parent->drc_name, parent->loc_code); child = parent->children; while (child) { say(EXTRA_DEBUG, "%s: %s\n" "\tdrc index: 0x%x description: %s\n" "\tdrc name: %s\n\tloc code: %s\n", child->ofdt_path, (child->skip ? "(SKIP)" : ""), child->drc_index, node_type(child), child->drc_name, child->loc_code); child = child->next; } parent = parent->next; } say(EXTRA_DEBUG, "\n"); } /** * acquire_hp_resource * * @param drc * @param of_path * @returns 0 on success, !0 otherwise */ static int acquire_hp_resource(struct dr_connector *drc, char *of_path) { struct of_node *new_nodes; int state; int rc; state = dr_entity_sense(drc->index); if (!pci_hotplug_only) { if (state == PRESENT || state == NEED_POWER || state == PWR_ONLY) { rc = set_power(drc->powerdomain, POWER_ON); if (rc) { say(ERROR, "set power failed for 0x%x\n", drc->powerdomain); return rc; } if (state == PWR_ONLY) state = dr_entity_sense(drc->index); } if (state == PRESENT || state == NEED_POWER) { rc = rtas_set_indicator(ISOLATION_STATE, drc->index, UNISOLATE); if (rc) { say(ERROR, "set ind failed for 0x%x\n", drc->index); return rc; } if (state == NEED_POWER) state = dr_entity_sense(drc->index); } } if (state < 0) { say(ERROR, "invalid state %d\n", state); return -1; } if (state == PRESENT) { new_nodes = configure_connector(drc->index); if (new_nodes == NULL) return -1; rc = add_device_tree_nodes(of_path, new_nodes); if (rc) { say(ERROR, "add nodes failed for 0x%x\n", drc->index); return rc; } } return 0; } /** * acquire_hp_children * * @param slot_of_path * @param n_acquired * @returns 0 on success, !0 otherwise */ int acquire_hp_children(char *slot_of_path, int *n_acquired) { struct dr_connector *drc_list, *drc; int rc; int failure = 0, count = 0; drc_list = get_drc_info(slot_of_path); if (drc_list == NULL) { /* No hotplug-capable children */ return 0; } for (drc = drc_list; drc != NULL; drc = drc->next) { if (is_hp_type(drc->type)) { rc = acquire_hp_resource(drc, slot_of_path); if (rc) { say(ERROR, "failed to acquire %s\n", drc->name); failure = 1; } count++; } } *n_acquired = count; return failure; } /** * release_hp_resource * * @param drc_index * @param power_domain * @returns 0 on success, !0 otherwise */ static int release_hp_resource(struct dr_node *node) { int rc; rc = remove_device_tree_nodes(node->ofdt_path); if (rc) { say(ERROR, "failed to remove kernel nodes for index 0x%x\n", node->drc_index); return -EIO; } if (pci_hotplug_only) return 0; rc = rtas_set_indicator(DR_INDICATOR, node->drc_index, LED_OFF); if (rc) { say(ERROR, "failed to set led off for index 0x%x\n", node->drc_index); return -EIO; } rc = rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); if (rc) { say(ERROR, "failed to isolate for index 0x%x\n", node->drc_index); return -EIO; } rc = set_power(node->drc_power, POWER_OFF); if (rc) { struct stat sb; say(ERROR, "failed to power off for index 0x%x\n", node->drc_index); if (!stat(IGNORE_HP_PO_PROP, &sb)) say(ERROR, "Ignoring hot-plug power off failure.\n"); else return -EIO; } return 0; } /** * release_hp_children_from_node * * @param parent_slot dr_node of slot to release children from * @returns 0 on success, !0 otherwise */ int release_hp_children_from_node(struct dr_node *slot) { struct dr_node *child; int rc; for (child = slot->children; child; child = child->next) { rc = release_hp_resource(child); if (rc) return rc; } return 0; } /** * release_hp_children * * @param parent_drc_name * @returns 0 on success, !0 otherwise */ int release_hp_children(char *parent_drc_name) { struct dr_node *hp_list, *slot; int rc; hp_list = get_hp_nodes(); for (slot = hp_list; slot; slot = slot->next) if (!strcmp(parent_drc_name, slot->drc_name)) break; if (slot == NULL) { rc = -EINVAL; goto out; } rc = release_hp_children_from_node(slot); out: free_node(hp_list); return (rc < 0) ? rc : 0; } /** * enable_hp_children * * @param drc_name * @returns 0 on success, !0 otherwise */ int enable_hp_children(char *drc_name) { if (get_hp_adapter_status(drc_name) == NOT_CONFIG) { set_hp_adapter_status(PHP_CONFIG_ADAPTER, drc_name); if (get_hp_adapter_status(drc_name) != CONFIG) return 1; } return 0; } /** * disable_hp_children * * @param drc_name * @returns 0 on success, !0 otherwise */ int disable_hp_children(char *drc_name) { if (get_hp_adapter_status(drc_name) != NOT_CONFIG) { int status; set_hp_adapter_status(PHP_UNCONFIG_ADAPTER, drc_name); status = get_hp_adapter_status(drc_name); if (status != NOT_CONFIG && status != EMPTY) return 1; } return 0; } powerpc-utils-1.3.4/src/drmgr/dr.h000066400000000000000000000112421315235264300170200ustar00rootroot00000000000000/** * @file dr.h * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _H_DR #define _H_DR #include #include #include #include #include #include "rtas_calls.h" #include "drpci.h" extern int output_level; extern int log_fd; /* Error Exit Codes */ #define RC_IN_USE 1 #define RC_NONEXISTENT 3 #define RC_DONT_OWN 4 #define RC_ALREADY_OWN 5 #define RC_LINUX_SLOT 6 /* Special case for ConcMaint */ /* Online/Offline */ #define OFFLINE 0 #define ONLINE 1 static inline int is_dot_dir(char * _p) { return (_p[0] == '.'); } void * __zalloc(size_t, const char *, int); #define zalloc(x) __zalloc((x), __func__, __LINE__); #define DR_LOCK_FILE "/var/lock/dr_config_lock" #define PLATFORMPATH "/proc/device-tree/device_type" #define OFDTPATH "/proc/ppc64/ofdt" #define DR_COMMAND "drslot_chrp_%s" #define DRMIG_COMMAND "drmig_chrp_%s" #define MAX(x,y) (((x) > (y)) ? (x) : (y)) /* Global User Specifications */ enum drmgr_action {NONE, ADD, REMOVE, QUERY, REPLACE, IDENTIFY, MIGRATE, HIBERNATE}; enum drc_type {DRC_TYPE_NONE, DRC_TYPE_PCI, DRC_TYPE_SLOT, DRC_TYPE_PHB, DRC_TYPE_CPU, DRC_TYPE_MEM, DRC_TYPE_PORT, DRC_TYPE_HIBERNATE, DRC_TYPE_MIGRATION}; extern enum drmgr_action usr_action; extern int usr_slot_identification; extern int usr_timeout; extern char *usr_drc_name; extern uint32_t usr_drc_index; extern int usr_prompt; extern int usr_drc_count; extern enum drc_type usr_drc_type; extern char *usr_p_option; extern int pci_virtio; /* qemu virtio device (legacy guest workaround) */ extern char *prrn_filename; extern int show_available_slots; extern int show_cpus_and_caches; extern int show_occupied_slots; extern int show_caches; extern char *usr_delimiter; extern int pci_hotplug_only; enum say_level { ERROR = 1, WARN, INFO, DEBUG, EXTRA_DEBUG}; /* The follwing are defined in common.c */ int say(enum say_level, char *, ...); void report_unknown_error(char *, int); int dr_init(void); void dr_fini(void); void set_timeout(int); int drmgr_timed_out(void); int dr_lock(void); int dr_unlock(void); int valid_platform(const char *); void free_of_node(struct of_node *); int add_device_tree_nodes(char *, struct of_node *); int remove_device_tree_nodes(char *); int update_property(const char *, size_t); int get_property(const char *, const char *, void *, size_t); int get_int_attribute(const char *, const char *, void *, size_t); int get_str_attribute(const char *, const char *, void *, size_t); int get_ofdt_uint_property(const char *, const char *, uint *); int get_property_size(const char *, const char *); int signal_handler(int, int, struct sigcontext *); int sig_setup(void); char *node_type(struct dr_node *); struct dr_node *alloc_dr_node(struct dr_connector *, int, const char *); int update_sysparm(void); int cpu_dlpar_capable(void); int mem_dlpar_capable(void); int slot_dlpar_capable(void); int phb_dlpar_capable(void); int pmig_capable(void); int phib_capable(void); int hea_dlpar_capable(void); int cpu_entitlement_capable(void); int mem_entitlement_capable(void); void print_dlpar_capabilities(void); void set_output_level(int); #define DR_BUF_SZ 256 int drslot_chrp_slot(void); int valid_slot_options(void); void slot_usage(char **); int drslot_chrp_cpu(void); int valid_cpu_options(void); void cpu_usage(char **); int drslot_chrp_pci(void); int valid_pci_options(void); void pci_usage(char **); int drslot_chrp_phb(void); int valid_phb_options(void); void phb_usage(char **); int drslot_chrp_mem(void); int valid_mem_options(void); void mem_usage(char **); int drslot_chrp_hea(void); int valid_hea_options(void); void hea_usage(char **); int drmig_chrp_pmig(void); int valid_pmig_options(void); void pmig_usage(char **); void phib_usage(char **); int ams_balloon_active(void); int is_display_adapter(struct dr_node *); enum drc_type to_drc_type(const char *); #define PRRN_TIMEOUT 30 int handle_prrn(void); int kernel_dlpar_exists(void); int do_kernel_dlpar(const char *, int); #endif powerpc-utils-1.3.4/src/drmgr/drcpu.h000066400000000000000000000041311315235264300175270ustar00rootroot00000000000000/** * @file drcpu.h * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _H_DRCPU #define _H_DRCPU #include "dr.h" #define CPU_PROBE_FILE "/sys/devices/system/cpu/probe" #define CPU_RELEASE_FILE "/sys/devices/system/cpu/release" struct cache_info { char name[DR_BUF_SZ]; /* node name */ char path[DR_BUF_SZ]; /* node path */ uint32_t phandle; uint32_t l2cache; uint32_t removed; struct cache_info *next; /* global list */ }; struct dr_info { struct dr_node *all_cpus; struct cache_info *all_caches; struct thread *all_threads; }; int init_cpu_drc_info(struct dr_info *); void free_cpu_drc_info(struct dr_info *); int get_thread_state(struct thread *); int set_thread_state(struct thread *, int); int get_cpu_state(struct dr_node *); int offline_cpu(struct dr_node *); int online_cpu(struct dr_node *, struct dr_info *); int cpu_enable_smt(struct dr_node *, struct dr_info *); int cpu_disable_smt(struct dr_node *); int smt_enabled(struct dr_info *); int system_enable_smt(struct dr_info *); int system_disable_smt(struct dr_info *); struct cache_info * cpu_get_dependent_cache(struct dr_node *, struct dr_info *); struct cache_info * cache_get_dependent_cache(struct cache_info *, struct dr_info *); int release_cpu(struct dr_node *, struct dr_info *); int probe_cpu(struct dr_node *, struct dr_info *); struct dr_node *get_available_cpu(struct dr_info *); #endif /* _H_DRCPU */ powerpc-utils-1.3.4/src/drmgr/drmem.h000066400000000000000000000030231315235264300175150ustar00rootroot00000000000000/* * @file drmem.h * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "drpci.h" struct lmb_list_head { struct dr_node *lmbs; struct dr_node *last; char *drconf_buf; int drconf_buf_sz; int lmbs_modified; int sort; int lmbs_found; }; struct drconf_mem { uint64_t address; uint32_t drc_index; uint32_t reserved; uint32_t assoc_index; uint32_t flags; }; #define DRMEM_ASSIGNED 0x00000008 #define DRMEM_DRC_INVALID 0x00000020 #define MEM_PROBE_FILE "/sys/devices/system/memory/probe" #define MEM_BLOCK_SIZE_BYTES "/sys/devices/system/memory/block_size_bytes" #define DYNAMIC_RECONFIG_MEM "/proc/device-tree/ibm,dynamic-reconfiguration-memory" #define LMB_NORMAL_SORT 0 #define LMB_REVERSE_SORT 1 #define LMB_RANDOM_SORT 2 struct lmb_list_head *get_lmbs(unsigned int); void free_lmbs(struct lmb_list_head *); powerpc-utils-1.3.4/src/drmgr/drmgr.c000066400000000000000000000212141315235264300175210ustar00rootroot00000000000000/** * @file drmgr.c * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #define _GNU_SOURCE #include #include "dr.h" #include "pseries_platform.h" #include "options.c" #define DRMGR_ARGS "ac:d:Iimnp:P:Qq:Rrs:w:t:hCVH" int output_level = 1; /* default to lowest output level */ int log_fd = 0; int action_cnt = 0; static int display_capabilities = 0; static int handle_prrn_event = 0; static int display_usage = 0; typedef int (cmd_func_t)(void); typedef int (cmd_args_t)(void); typedef void (cmd_usage_t)(char **); int drmgr(void); void drmgr_usage(char **); int valid_drmgr_options(void); struct command { cmd_func_t *func; cmd_args_t *validate_options; cmd_usage_t *usage; }; #define DRMGR 0 #define DRSLOT_CHRP_SLOT 1 #define DRSLOT_CHRP_PHB 2 #define DRSLOT_CHRP_PCI 3 #define DRSLOT_CHRP_MEM 4 #define DRSLOT_CHRP_HEA 5 #define DRSLOT_CHRP_CPU 6 #define DRMIG_CHRP_PMIG 7 #define DRSLOT_CHRP_PHIB 8 static struct command commands[] = { { .func = drmgr, .validate_options = valid_drmgr_options, .usage = drmgr_usage, }, { .func = drslot_chrp_slot, .validate_options = valid_slot_options, .usage = slot_usage, }, { .func = drslot_chrp_phb, .validate_options = valid_phb_options, .usage = phb_usage, }, { .func = drslot_chrp_pci, .validate_options = valid_pci_options, .usage = pci_usage, }, { .func = drslot_chrp_mem, .validate_options = valid_mem_options, .usage = mem_usage, }, { .func = drslot_chrp_hea, .validate_options = valid_hea_options, .usage = hea_usage, }, { .func = drslot_chrp_cpu, .validate_options = valid_cpu_options, .usage = cpu_usage, }, { .func = drmig_chrp_pmig, .validate_options = valid_pmig_options, .usage = pmig_usage, }, { .func = drmig_chrp_pmig, .validate_options = valid_pmig_options, .usage = phib_usage, }, }; static struct option long_options[] = { {"capabilities", no_argument, NULL, 'C'}, {"help", no_argument, NULL, 'h'}, {0,0,0,0} }; #define MAX_USAGE_LENGTH 512 void command_usage(struct command *command) { /* * Display the common usage options */ fprintf(stderr, "Usage: drmgr %s", "[-w minutes] [-d detail_level] [-C | --capabilities] [-h | --help]\n"); /* * Now retrieve the command specific usage text */ char *buffer = zalloc(MAX_USAGE_LENGTH); char *pusage=buffer; /* pusage may be over written */ command->usage(&pusage); fprintf(stderr, "%s\n", pusage); free(buffer); } static char *usagestr = "{-c {port | slot | phb | pci | mem | cpu} | -m}\n" "For more information on the specific options for the various\n" "connector types, run drmgr -c -h"; void drmgr_usage(char **pusage) { *pusage = usagestr; } int valid_drmgr_options(void) { if (usr_drc_type == DRC_TYPE_NONE) { say(ERROR, "A connector type (-c) must be specified\n"); return -1; } if (action_cnt == 0) { say(ERROR, "At least one action must be specified\n"); return -1; } if (action_cnt > 1) { say(ERROR, "Only one action may be specified\n"); return -1; } if ((usr_drc_count > 1) && usr_drc_name) { say(ERROR, "The -q and -s flags are mutually exclusive\n"); return -1; } if (usr_timeout < 0) { say(ERROR, "Invalid timeout specified: %s\n", usr_timeout); return -1; } return 0; } int parse_options(int argc, char *argv[]) { int c; int option_indx; int option_found = 0; /* disable getopt error messages */ opterr = 0; while ((c = getopt_long(argc, argv, DRMGR_ARGS, long_options, &option_indx)) != -1) { option_found = 1; switch (c) { case 'a': usr_action = ADD; action_cnt++; break; case 'c': usr_drc_type = to_drc_type(optarg); break; case 'C': display_capabilities = 1; break; case 'd': set_output_level(atoi(optarg)); break; case 'I': usr_slot_identification = 0; break; case 'i': usr_action = IDENTIFY; action_cnt++; break; case 'n': /* The -n option is also used to specify a number of * seconds to attempt a self-arp. Linux ignores this * for hibernation. */ usr_prompt = 0; break; case 'p': usr_p_option = optarg; break; case 'P': prrn_filename = optarg; handle_prrn_event = 1; break; case 'q': usr_drc_count = strtoul(optarg, NULL, 0); break; case 'R': usr_action = REPLACE; action_cnt++; break; case 'r': usr_action = REMOVE; action_cnt++; break; case 's': usr_drc_name = optarg; break; case 'Q': usr_action = QUERY; action_cnt++; break; case 'm': usr_action = MIGRATE; action_cnt++; break; case 'w': usr_timeout = strtol(optarg, NULL, 10) * 60; break; case 'h': display_usage = 1; return 0; break; case 'H': pci_hotplug_only = 1; break; case 't': /* target lpid (pmig, not used) */ break; case 'V': /* qemu virtio pci device (workaround) */ pci_virtio = 1; break; default: say(ERROR, "Invalid option specified '%c'\n", optopt); return -1; break; } } if (!option_found) display_usage = 1; return 0; } struct command *get_command(void) { /* Unfortunately, the connector type specified doesn't always result * in a 1-to-1 relationship with the resulting command to run so we * have to do some extra checking to build the correct command. */ if (usr_action == MIGRATE) return &commands[DRMIG_CHRP_PMIG]; if (usr_drc_name && !strncmp(usr_drc_name, "HEA", 3)) return &commands[DRSLOT_CHRP_HEA]; switch (usr_drc_type) { case DRC_TYPE_NONE: return &commands[DRMGR]; break; case DRC_TYPE_PORT: return &commands[DRSLOT_CHRP_HEA]; break; case DRC_TYPE_SLOT: return &commands[DRSLOT_CHRP_SLOT]; break; case DRC_TYPE_PHB: return &commands[DRSLOT_CHRP_PHB]; break; case DRC_TYPE_PCI: return &commands[DRSLOT_CHRP_PCI]; break; case DRC_TYPE_MEM: return &commands[DRSLOT_CHRP_MEM]; break; case DRC_TYPE_CPU: return &commands[DRSLOT_CHRP_CPU]; break; case DRC_TYPE_HIBERNATE: usr_action = HIBERNATE; return &commands[DRSLOT_CHRP_PHIB]; break; default: /* If we make it this far, the user specified an invalid * connector type. */ say(ERROR, "Dynamic reconfiguration is not supported for " "connector\ntype \"%s\" on this system\n", usr_drc_type); break; } return &commands[DRMGR]; } int drmgr(void) { say(ERROR, "Invalid command: %d\n", usr_action); return -1; } int main(int argc, char *argv[]) { char log_msg[DR_PATH_MAX]; struct command *command; int i, rc, offset; switch (get_platform()) { case PLATFORM_UNKNOWN: case PLATFORM_POWERNV: fprintf(stderr, "%s: is not supported on the %s platform\n", argv[0], platform_name); exit(1); } parse_options(argc, argv); rc = dr_init(); if (rc) { if (handle_prrn_event) { say(ERROR, "Failed to handle PRRN event\n"); unlink(prrn_filename); } return rc; } if (display_capabilities) { print_dlpar_capabilities(); dr_fini(); return 0; } if (handle_prrn_event) { rc = handle_prrn(); if (rc) say(ERROR, "Failed to handle PRRN event\n"); unlink(prrn_filename); dr_fini(); return rc; } command = get_command(); if (display_usage) { command_usage(command); dr_fini(); return 0; } /* Validate the options for the action we want to perform */ rc = command->validate_options(); if (rc) { dr_fini(); return -1; } /* Validate this platform */ if (!valid_platform("chrp")) { dr_fini(); return -1; } set_timeout(usr_timeout); /* Log this invocation to /var/log/messages and /var/log/drmgr */ offset = sprintf(log_msg, "drmgr: "); for (i = 1; i < argc; i++) offset += sprintf(log_msg + offset, "%s ", argv[i]); log_msg[offset] = '\0'; syslog(LOG_LOCAL0 | LOG_INFO, "%s", log_msg); say(DEBUG, "%s\n", log_msg); /* Now, using the actual command, call out to the proper handler */ rc = command->func(); dr_fini(); return rc; } powerpc-utils-1.3.4/src/drmgr/drmig_chrp_pmig.c000066400000000000000000000375241315235264300215530ustar00rootroot00000000000000/** * @file drmig_chrp_pmig.c * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "dr.h" #include "ofdt.h" #include "drpci.h" struct pmap_struct { struct pmap_struct *next; unsigned int phandle; int ibmphandle; char *name; }; #define SYSFS_HIBERNATION_FILE "/sys/devices/system/power/hibernate" #define SYSFS_MIGRATION_FILE "/sys/kernel/mobility/migration" #define SYSFS_MIGRATION_API_FILE "/sys/kernel/mobility/api_version" /* drmgr must call ibm,suspend-me and is responsible for postmobility fixups */ #define MIGRATION_API_V0 0 /* drmgr must write to sysfs migration store and allow kernel to do * postmobility fixups */ #define MIGRATION_API_V1 1 static struct pmap_struct *plist; static char *pmig_usagestr = "-m -p {check | pre} -s "; static char *phib_usagestr = "-m -p {check | pre} -s -n "; /** * pmig_usage * */ void pmig_usage(char **pusage) { *pusage = pmig_usagestr; } /** * phib_usage * */ void phib_usage(char **pusage) { *pusage = phib_usagestr; } /** * add_phandle * * @param name * @param phandle * @param ibmphandle */ static void add_phandle(char *name, unsigned int phandle, int ibmphandle) { struct pmap_struct *pm = zalloc(sizeof(struct pmap_struct)); if (strlen(name) == 0) name = "/"; pm->name = zalloc(strlen(name)+strlen(OFDT_BASE)+1); sprintf(pm->name, "%s%s", OFDT_BASE, name); pm->phandle = phandle; pm->ibmphandle = ibmphandle; pm->next = plist; plist = pm; } /** * find_phandle * * @param ph * @returns */ static char * find_phandle(unsigned int ph) { struct pmap_struct *pms = plist; while (pms && pms->phandle != ph) pms = pms->next; return pms ? pms->name : NULL; } /** * add_phandles * * @param parent * @param p * @returns */ static int add_phandles(char *parent, char *p) { DIR *d; struct dirent *de; char path[PATH_MAX]; unsigned int phandle; char *pend; FILE *fd; strcpy(path,parent); if (strlen(p)) { strcat(path,"/"); strcat(path,p); } pend = path + strlen(path); d = opendir(path); if (d == NULL) { perror(path); return 1; } while ((de = readdir(d))) { if ((de->d_type == DT_DIR) && (strcmp(de->d_name,".")) && (strcmp(de->d_name,".."))) add_phandles(path,de->d_name); } strcpy(pend,"/linux,phandle"); fd = fopen(path,"r"); if (fd != NULL) { if (fread(&phandle,sizeof(phandle),1,fd) != 1) { perror(path); say(DEBUG, "Error reading phandle data!\n"); fclose(fd); return 1; } *pend = '\0'; add_phandle(path + strlen("/proc/device-tree"),phandle, 0); fclose(fd); } strcpy(pend,"/ibm,phandle"); fd = fopen(path,"r"); if (fd != NULL) { if (fread(&phandle,sizeof(phandle),1,fd) != 1) { perror(path); say(DEBUG, "Error reading phandle data!\n"); fclose(fd); return 1; } *pend = '\0'; add_phandle(path + strlen("/proc/device-tree"), phandle, 1); fclose(fd); } closedir(d); return 0; } /** * do_update * * @param cmd * @param len * @returns 0 on success, !0 otherwise */ static int do_update(char *cmd, int len) { int rc; int i, fd; fd = open(OFDTPATH, O_WRONLY); if (fd == -1) { say(ERROR, "Failed to open %s: %s\n", OFDTPATH, strerror(errno)); return -1; } say(DEBUG, "len %d\n", len); if ((rc = write(fd, cmd, len)) != len) say(ERROR, "Error writing to ofdt file! rc %d errno %d\n", rc, errno); for (i = 0; i < len; i++) { if (! isprint(cmd[i])) cmd[i] = '.'; if (isspace(cmd[i])) cmd[i] = ' '; } cmd[len-1] = 0x00; say(DEBUG, "<%s>\n", cmd); close(fd); return rc; } /** * del_node * * @param phandle */ static void del_node(unsigned int phandle) { char *name = find_phandle(phandle); char delcmd[128] = "remove_node "; if (name == NULL) say(DEBUG, "Delete node error: Invalid phandle %8.8x", phandle); else { strcat(delcmd,name); do_update(delcmd, strlen(delcmd)); } } /** * update_properties * * @param phandle * @returns 0 on success, !0 otherwise */ static int update_properties(unsigned int phandle) { int rc; char cmd[DR_PATH_MAX]; char *longcmd = NULL; char *newcmd; int cmdlen = 0; int proplen = 0; unsigned int wa[1024]; unsigned int *op; unsigned int nprop; unsigned int vd; int lenpos = 0; char *pname; unsigned int i; int more = 0; char *name = find_phandle(phandle); int initial = 1; memset(wa, 0x00, 16); wa[0] = phandle; do { say(DEBUG, "about to call rtas_update_properties. work area:\n" "phandle %8.8x, node %s\n" " %8.8x %8.8x %8.8x %8.8x\n", phandle, name ? name : "NULL", wa[0], wa[1], wa[2], wa[3]); rc = rtas_update_properties((char *)wa, 1); if (rc && rc != 1) { say(DEBUG, "Error %d from rtas_update_properties()\n", rc); return 1; } say(DEBUG, "successful rtas_update_properties (more %d)\n", rc); op = wa+4; nprop = *op++; /* After the initial call to rtas_update_properties the first * property value descriptor in the buffer is the path of the * node being updated. Format is as follows: * * property name - 1 byte set to NULL 0x00 * value descriptor - 4 bytes containing length of value string * value string - fully qualified path name of updated node * */ if (initial) { say(DEBUG, "Null byte = %2.2x, ", *((char *)op)); op = (unsigned int *)(((char *)op) + 1); vd = *op++; say(DEBUG, "string length = %u, path = %s\n", vd, ((char *)op)); op = (unsigned int *)(((char *)op) + vd); initial = 0; /* The path we are skipping is inclusive in the * property count. */ nprop--; } for (i = 0; i < nprop; i++) { pname = (char *)op; op = (unsigned int *)(pname + strlen(pname) + 1); vd = *op++; switch (vd) { case 0x00000000: say(DEBUG, "%s - name only property %s\n", name, pname); break; case 0x80000000: say(DEBUG, "%s - delete property %s\n", name, pname); sprintf(cmd,"remove_property %u %s", phandle, pname); do_update(cmd, strlen(cmd) + 1); break; default: if (vd & 0x80000000) { say(DEBUG, "partial property!\n"); /* twos compliment of length */ vd = ~vd + 1; more = 1; } else { more = 0; } say(DEBUG, "%s - updating property %s length " "%d\n", name, pname, vd); /* See if we have a partially completed * command */ if (longcmd) { newcmd = zalloc(cmdlen + vd); memcpy(newcmd, longcmd, cmdlen); free(longcmd); longcmd = newcmd; } else { longcmd = zalloc(vd+128); /* Build the command with a length * of six zeros */ lenpos = sprintf(longcmd, "update_property %u " "%s ", phandle, pname); strcat(longcmd, "000000 "); cmdlen = strlen(longcmd); } memcpy(longcmd + cmdlen, op, vd); cmdlen += vd; proplen += vd; if (! more) { /* Now update the length to its actual * value and do a hideous fixup of * the new trailing null */ sprintf(longcmd+lenpos,"%06d",proplen); longcmd[lenpos+6] = ' '; do_update(longcmd, cmdlen); free(longcmd); longcmd = NULL; cmdlen = 0; proplen = 0; } op = (unsigned int *)(((char *)op) + vd); } } } while (rc == 1); return 0; } /** * add_new_node * * @param phandle * @param drcindex */ static void add_new_node(unsigned int phandle, unsigned int drcindex) { char *path; int rtas_rc; struct of_node *new_nodes;/* nodes returned from configure_connector */ new_nodes = configure_connector(drcindex); path = find_phandle(phandle); if (path == NULL) { say(DEBUG, "Cannot find pnahdle %x\n", phandle); return; } rtas_rc = add_device_tree_nodes(path, new_nodes); if (rtas_rc) say(DEBUG, "add_device_tree_nodes failed at %s\n", path); } /** * del_nodes * * @param op * @param n */ static void del_nodes(unsigned int *op, unsigned int n) { unsigned int i, phandle; for (i = 0; i < n; i++) { phandle = *op++; say(DEBUG, "Delete node with phandle %8.8x\n", phandle); del_node(phandle); } } /** * update_nodes * * @param op * @param n */ static void update_nodes(unsigned int *op, unsigned int n) { unsigned int i, phandle; for (i = 0; i < n; i++) { phandle = *op++; say(DEBUG, "Update node with phandle %8.8x\n", phandle); update_properties(phandle); } } /** * add_nodes * * @param op * @param n */ static void add_nodes(unsigned int *op, unsigned int n) { unsigned int i, pphandle, drcindex; for (i = 0; i < n; i++) { pphandle = *op++; drcindex = *op++; say(DEBUG, "Add node with parent phandle %8.8x and drc index " "%8.8x\n", pphandle, drcindex); add_new_node(pphandle, drcindex); } } /** * devtree_update * */ static void devtree_update(void) { int rc; unsigned int wa[1024]; unsigned int *op; say(DEBUG, "Updating device_tree\n"); if (add_phandles("/proc/device-tree","")) return; /* First 16 bytes of work area must be initialized to zero */ memset(wa, 0x00, 16); do { rc = rtas_update_nodes((char *)wa, 1); if (rc && rc != 1) { say(DEBUG, "Error %d from rtas_update_nodes()\n", rc); return; } say(DEBUG, "successful rtas_update_nodes (more %d)\n", rc); op = wa+4; while (*op & 0xFF000000) { unsigned int i; say(DEBUG, "op %p, *op %8.8x\n", op, *op); for (i = 0; i < (*op & 0x00FFFFFF); i++) say(DEBUG, " %8.8x\n",op[i+1]); switch (*op & 0xFF000000) { case 0x01000000: del_nodes(op+1, *op & 0x00FFFFFF); break; case 0x02000000: update_nodes(op+1, *op & 0x00FFFFFF); break; case 0x03000000: add_nodes(op+1, *op & 0x00FFFFFF); break; case 0x00000000: /* End */ break; default: say(DEBUG, "Unknown update_nodes op %8.8x\n", *op); } op += 1 + (*op & 0x00FFFFFF); } } while (rc == 1); say(DEBUG, "leaving\n"); } int valid_pmig_options(void) { if (!usr_p_option) { say(ERROR, "A command must be specified\n"); return -1; } /* Determine if this is a migration or a hibernation request */ if (usr_drc_type == DRC_TYPE_MIGRATION) { if (usr_action != MIGRATE) { /* The -m option must be specified with migrations */ say(ERROR, "The -m must be specified for migrations\n"); return -1; } if (!pmig_capable()) { say(ERROR, "Partition Mobility is not supported.\n"); return -1; } } else if (usr_drc_type == DRC_TYPE_HIBERNATE) { if (!phib_capable()) { say(ERROR, "Partition Hibernation is not supported.\n"); return -1; } usr_action = HIBERNATE; } else { say(ERROR, "The value \"%d\" for the -c option is not valid\n", usr_drc_type); return -1; } return 0; } int do_migration(uint64_t stream_val) { int rc, fd; int api_level = 0; char buf[64]; /* If the kernel can also do the device tree update we should let * the kernel do all the work. Check if sysfs migration api_version * is readable and use api level to determine how to perform * migration and post-mobility updates. */ rc = get_int_attribute(SYSFS_MIGRATION_API_FILE, NULL, &api_level, sizeof(&api_level)); if (rc) say(DEBUG, "get_int_attribute returned %d for path %s\n", rc, SYSFS_MIGRATION_API_FILE); if (api_level == MIGRATION_API_V0) { say(DEBUG, "about to issue ibm,suspend-me(%llx)\n", stream_val); rc = rtas_suspend_me(stream_val); say(DEBUG, "ibm,suspend-me() returned %d\n", rc); } else if (api_level == MIGRATION_API_V1) { sprintf(buf, "0x%" PRIx64 "\n", stream_val); fd = open(SYSFS_MIGRATION_FILE, O_WRONLY); if (fd == -1) { say(ERROR, "Could not open \"%s\" to initiate migration, " "%m\n", SYSFS_MIGRATION_FILE); return -1; } say(DEBUG, "Initiating migration via %s with %s\n", SYSFS_MIGRATION_FILE, buf); rc = write(fd, buf, strlen(buf)); if (rc < 0) { int my_errno = errno; say(DEBUG, "Write to migration file failed with rc: %d\n", rc); rc = my_errno; } else if (rc > 0) rc = 0; close(fd); say(DEBUG, "Kernel migration returned %d\n", rc); } else { say(ERROR, "Unknown kernel migration api version %d\n", api_level); rc = -1; } return rc; } int do_hibernation(uint64_t stream_val) { int rc, fd; char buf[64]; sprintf(buf, "0x%" PRIx64 "\n", stream_val); fd = open(SYSFS_HIBERNATION_FILE, O_WRONLY); if (fd == -1) { say(ERROR, "Could not open \"%s\" to initiate hibernation, " "%m\n", SYSFS_HIBERNATION_FILE); return -1; } say(DEBUG, "Initiating hibernation via %s with %s\n", SYSFS_HIBERNATION_FILE, buf); rc = write(fd, buf, strlen(buf)); if (rc < 0) { int my_errno = errno; say(DEBUG, "Write to hibernation file failed with rc: %d\n", rc); rc = my_errno; } else if (rc > 0) rc = 0; close(fd); say(DEBUG, "Kernel hibernation returned %d\n", rc); return rc; } void post_mobility_update(void) { int rc; int do_update = 0; char *path; if (usr_action == HIBERNATE) path = SYSFS_HIBERNATION_FILE; else path = SYSFS_MIGRATION_API_FILE; /* kernel will return 0 or sysfs attribute will be unreadable if drmgr needs to perform a device tree update */ rc = get_int_attribute(path, NULL, &do_update, sizeof(do_update)); if (rc) say(DEBUG, "get_int_attribute returned %d for path %s\n", rc, path); if (!do_update) { rc = rtas_activate_firmware(); if (rc) say(DEBUG, "rtas_activate_firmware() returned %d\n", rc); devtree_update(); } } int drmig_chrp_pmig(void) { int rc; char sys_src[20]; uint64_t stream_val; /* Ensure that this partition is migratable/mobile */ if (! pmig_capable()) { fprintf(stderr, "drmig_chrp_pmig: Partition Mobility is not " "supported on this kernel.\n"); return -1; } /* Today we do no pre-checks for migratability. The only check * we could do is whether the "ibm,suspend-me" RTAS call exists. * But if it doesn't, the firmware level doesn't support migration, * in which case why the heck are we being invoked anyways. */ if (strcmp(usr_p_option, "check") == 0) { say(DEBUG, "check: Nothing to do...\n"); return 0; } /* The only other command is pre, any other command is invalid */ if (strcmp(usr_p_option, "pre")) { say(DEBUG, "Invalid command \"%s\" specified\n", usr_p_option); return 1; } if (!usr_drc_name) { say(ERROR, "No streamid specified\n"); return -1; } errno = 0; stream_val = strtoull(usr_drc_name, NULL, 16); if (errno != 0) { say(ERROR, "Invalid streamid specified: %s\n", strerror(errno)); return -1; } /* Get the ID of the original system, for later logging */ get_str_attribute(OFDT_BASE, "system-id", sys_src, 20); sleep(5); /* Now do the actual migration */ do { if (usr_action == MIGRATE) rc = do_migration(stream_val); else if (usr_action == HIBERNATE) rc = do_hibernation(stream_val); else rc = -EINVAL; if (rc == NOT_SUSPENDABLE) sleep(1); } while (rc == NOT_SUSPENDABLE); syslog(LOG_LOCAL0 | LOG_INFO, "drmgr: %s rc %d\n", (usr_action == MIGRATE ? "migration" : "hibernation"), rc); if (rc) return rc; post_mobility_update(); say(DEBUG, "Refreshing RMC via refrsrc\n"); rc = system("/usr/sbin/rsct/bin/refrsrc IBM.ManagementServer"); return 0; } powerpc-utils-1.3.4/src/drmgr/drpci.h000066400000000000000000000056561315235264300175300ustar00rootroot00000000000000/** * @file drpci.h * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _DRPCI_H_ #define _DRPCI_H_ #include "rtas_calls.h" #include "ofdt.h" /* PCI Hot Plug defs */ #define PHP_SYSFS_ADAPTER_PATH "/sys/bus/pci/slots/%s/adapter" #define PHP_SYSFS_POWER_PATH "/sys/bus/pci/slots/%s/power" #define PHP_CONFIG_ADAPTER 1 #define PHP_UNCONFIG_ADAPTER 0 #define PCI_RESCAN_PATH "/sys/bus/pci/rescan" /* The following defines are used for adapter status */ #define EMPTY 0 #define CONFIG 1 #define NOT_CONFIG 2 /* Device type definitions */ #define PCI_HP_DEV 1 #define PCI_DLPAR_DEV 2 #define VIO_DEV 3 #define HEA_DEV 4 #define HEA_PORT_DEV 5 #define PHB_DEV 7 #define CPU_DEV 8 #define MEM_DEV 9 #define ADD_SLOT_FNAME "/sys/bus/pci/slots/control/add_slot" #define ADD_SLOT_FNAME2 "/sys/bus/pci/slots/control/\"add_slot\"" #define REMOVE_SLOT_FNAME "/sys/bus/pci/slots/control/remove_slot" #define REMOVE_SLOT_FNAME2 "/sys/bus/pci/slots/control/\"remove_slot\"" #define IGNORE_HP_PO_PROP "/proc/device-tree/ibm,ignore-hp-po-fails-for-dlpar" extern char *add_slot_fname; extern char *remove_slot_fname; #define HEA_ADD_SLOT "/sys/bus/ibmebus/probe" #define HEA_REMOVE_SLOT "/sys/bus/ibmebus/remove" /* %s is the loc-code of the HEA adapter for *_PORT defines */ #define HEA_ADD_PORT "/sys/bus/ibmebus/devices/%s/probe_port" #define HEA_REMOVE_PORT "/sys/bus/ibmebus/devices/%s/remove_port" #define PCI_NODES 0x00000001 #define VIO_NODES 0x00000002 #define HEA_NODES 0x00000004 #define PHB_NODES 0x00000010 struct dr_node *get_hp_nodes(void); struct dr_node *get_dlpar_nodes(uint32_t); struct dr_node *get_node_by_name(const char *, uint32_t); void free_node(struct dr_node *); /* Function prototypes for subroutines */ int get_hp_adapter_status(char *); int set_hp_adapter_status(uint, char *); int pci_rescan_bus(); int pci_remove_device(struct dr_node *); int release_hp_children_from_node(struct dr_node *); int release_hp_children(char *); int dlpar_remove_slot(const char *); int dlpar_add_slot(const char *); int cmp_drcname(char *, char *); int acquire_hp_children(char *, int *); int enable_hp_children(char *); int disable_hp_children(char *); void print_node_list(struct dr_node *); #endif /* _DRPCI_H_ */ powerpc-utils-1.3.4/src/drmgr/drslot_chrp_cpu.c000066400000000000000000000242041315235264300216020ustar00rootroot00000000000000/** * @file drslot_chrp_cpu.c * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include "dr.h" #include "drcpu.h" #include "drpci.h" #include "ofdt.h" struct cpu_operation; typedef int (cpu_op_func_t) (void); struct parm_to_func { char *parmname; cpu_op_func_t *func; }; static char *usagestr = "-c cpu {-a | -r} {-q -p {variable_weight | ent_capacity} [-s drc_name | drc_index]"; /** * cpu_usage * */ void cpu_usage(char **pusage) { *pusage = usagestr; } static struct dr_node * get_cpu_by_name(struct dr_info *drinfo, const char *name) { struct dr_node *cpu; for (cpu = drinfo->all_cpus; cpu; cpu = cpu->next) { if (strcmp(cpu->drc_name, name) == 0) { break; } } return cpu; } static struct dr_node * get_cpu_by_index(struct dr_info *drinfo, uint32_t index) { struct dr_node *cpu; for (cpu = drinfo->all_cpus; cpu; cpu = cpu->next) { if (cpu->drc_index == index) { break; } } return cpu; } /** * cpu_count * * Count the number of CPUs currently on the system * * @param dr_info cpu drc information * @return number of cpus */ static int cpu_count(struct dr_info *dr_info) { struct dr_node *cpu; int cpu_count = 0; for (cpu = dr_info->all_cpus; cpu; cpu = cpu->next) { if (cpu->is_owned) cpu_count++; } say(DEBUG, "Number of CPUs = %d\n", cpu_count); return cpu_count; } static struct dr_node *get_available_cpu_by_name(struct dr_info *dr_info) { struct dr_node *cpu; cpu = get_cpu_by_name(dr_info, usr_drc_name); if (!cpu) { say(ERROR, "Could not locate CPU \"%s\"\n", usr_drc_name); return NULL; } if (cpu->unusable) { say(ERROR, "Requested CPU \"%s\" is unusable\n", usr_drc_name); return NULL; } if (usr_action == ADD && cpu->is_owned) { say(ERROR, "Requested CPU \"%s\" is already present.\n", usr_drc_name); return NULL; } else if (usr_action == REMOVE && !cpu->is_owned) { say(ERROR, "Requested CPU \"%s\" is not present.\n", usr_drc_name); return NULL; } return cpu; } static struct dr_node *get_available_cpu_by_index(struct dr_info *dr_info) { struct dr_node *cpu; cpu = get_cpu_by_index(dr_info, usr_drc_index); if (!cpu) { say(ERROR, "Could not locate CPU with drc index %x\n", usr_drc_index); return NULL; } if (cpu->unusable) { say(ERROR, "Requested CPU with drc index %x is unusable\n", usr_drc_index); return NULL; } if (usr_action == ADD && cpu->is_owned) { say(ERROR, "Requested CPU with drc index %x is " "already present.\n", usr_drc_index); return NULL; } else if (usr_action == REMOVE && !cpu->is_owned) { say(ERROR, "Requested CPU with drc index %x is " "not present.\n", usr_drc_index); return NULL; } return cpu; } static struct dr_node *get_next_available_cpu(struct dr_info *dr_info) { struct dr_node *cpu = NULL; struct dr_node *survivor = NULL; struct thread *t; if (usr_action == ADD) { for (cpu = dr_info->all_cpus; cpu; cpu = cpu->next) { if (cpu->unusable) continue; if (!cpu->is_owned) survivor = cpu; } cpu = survivor; } else if (usr_action == REMOVE) { /* Find the first cpu with an online thread */ for (cpu = dr_info->all_cpus; cpu; cpu = cpu->next) { if (cpu->unusable) continue; for (t = cpu->cpu_threads; t; t = t->next) { if (get_thread_state(t) == ONLINE) return cpu; } } } if (!cpu) say(ERROR, "Could not find available cpu.\n"); return cpu; } /** * get_available_cpu * * Find an available cpu to that we can add or remove, depending * on the request. * * @param dr_info cpu drc information * @returns pointer to cpu on success, NULL on failure */ struct dr_node *get_available_cpu(struct dr_info *dr_info) { struct dr_node *cpu = NULL; if (usr_drc_name) cpu = get_available_cpu_by_name(dr_info); else if (usr_drc_index) cpu = get_available_cpu_by_index(dr_info); else cpu = get_next_available_cpu(dr_info); return cpu; } /** * add_cpus * * Attempt to acquire and online the given number of cpus. * This function calls itself recursively to simplify recovery * actions in case of an error. This is intended only for the case * where the user does not specify a drc-name. * * The final steps are to display the drc-names value to stdout and * return with 0. * * @param nr_cpus * @returns 0 on success, !0 otherwise */ static int add_cpus(struct dr_info *dr_info) { int rc = -1; uint count; struct dr_node *cpu = NULL; count = 0; while (count < usr_drc_count) { if (drmgr_timed_out()) break; cpu = get_available_cpu(dr_info); if (!cpu) break; rc = probe_cpu(cpu, dr_info); if (rc) { say(DEBUG, "Unable to acquire CPU with drc index %x\n", cpu->drc_index); cpu->unusable = 1; continue; } fprintf(stdout, "%s\n", cpu->drc_name); count++; } say(DEBUG, "Acquired %d of %d requested cpu(s).\n", count, usr_drc_count); return rc ? 1 : 0; } /** * remove_cpus * * Attempt to offline and release to the hypervisor the given number of * cpus. This functions calls itself recursively to simplify recovery * actions in the case of an error. This is intended only for the case * where the user does not specify a drc-name. * * From "Design Specification for AIX Configuration Support of * Dynamic Reconfiguration including the drmgr command and drslot for * memory, processors, and PCI slots" Version 1.2: * * Section V. Part B. Item 2. "drslot_chrp_cpu -r -c cpu" * "Once the resource has been released by the kernel, all the following * steps are taken. Errors are ignored. The code continues releasing the * resource by using RTAS services. ..." * "If successful, the code displays the drc-names value to stdout and * returns with 0, else displays an error message to stderr and returns with * non-zero." * * @param nr_cpus * @returns 0 on success, !0 otherwise */ static int remove_cpus(struct dr_info *dr_info) { int rc = 0; uint count = 0; struct dr_node *cpu; while (count < usr_drc_count) { if (drmgr_timed_out()) break; if (cpu_count(dr_info) == 1) { say(WARN, "Cannot remove the last CPU\n"); rc = -1; break; } cpu = get_available_cpu(dr_info); if (!cpu) break; /* cpu is invalid after release_cpu, so no recovery * steps seem feasible. We could copy the cpu name * and look it up again if the operation fails. */ rc = release_cpu(cpu, dr_info); if (rc) { online_cpu(cpu, dr_info); cpu->unusable = 1; continue; } fprintf(stdout, "%s\n", cpu->drc_name); count++; } say(DEBUG, "Removed %d of %d requested cpu(s)\n", count, usr_drc_count); return rc; } /** * smt_thread_func * @brief Act upon logical cpus/threads * * @returns 0 on success, !0 otherwise */ static int smt_threads_func(struct dr_info *dr_info) { int rc; struct dr_node *cpu; if (usr_drc_count != 1) { say(ERROR, "Quantity option '-q' may not be specified with " "the '-p smt_threads' option\n"); return -1; } if (! smt_enabled(dr_info)) { say(ERROR, "SMT functions not available on this system.\n"); return -1; } if (usr_drc_name) { cpu = get_cpu_by_name(dr_info, usr_drc_name); if (cpu == NULL) { say(ERROR, "Could not find cpu %s\n", usr_drc_name); return -1; } if (usr_action == ADD) rc = cpu_enable_smt(cpu, dr_info); else if (usr_action == REMOVE) rc = cpu_disable_smt(cpu); } else if (usr_drc_index) { cpu = get_cpu_by_index(dr_info, usr_drc_index); if (cpu == NULL) { say(ERROR, "Could not find cpu %x\n", usr_drc_index); return -1; } if (usr_action == ADD) rc = cpu_enable_smt(cpu, dr_info); else if (usr_action == REMOVE) rc = cpu_disable_smt(cpu); } else { /* no drc name given, action is system-wide */ if (usr_action == ADD) rc = system_enable_smt(dr_info); if (usr_action == REMOVE) rc = system_disable_smt(dr_info); } return rc; } int valid_cpu_options(void) { /* default to a quantity of 1 */ if (usr_drc_count == 0) usr_drc_count = 1; if ((usr_action != ADD) && (usr_action != REMOVE)) { say(ERROR, "The '-r' or '-a' option must be specified for " "CPU operations.\n"); return -1; } /* The -s option can specify a drc name or drc index */ if (usr_drc_name && !strncmp(usr_drc_name, "0x", 2)) { usr_drc_index = strtoul(usr_drc_name, NULL, 16); usr_drc_name = NULL; } return 0; } int drslot_chrp_cpu(void) { struct dr_info dr_info; int rc; if (! cpu_dlpar_capable()) { say(ERROR, "CPU DLPAR capability is not enabled on this " "platform.\n"); return -1; } if (usr_p_option && (!strcmp(usr_p_option, "ent_capacity") || !strcmp(usr_p_option, "variable_weight"))) { rc = update_sysparm(); if (rc) say(ERROR, "Could not update system parameter " "%s\n", usr_p_option); return rc; } if (init_cpu_drc_info(&dr_info)) { say(ERROR, "Could not initialize Dynamic Reconfiguration " "information.\n"); return -1; } /* If a user specifies a drc name, the quantity to add/remove is * one. Enforce that here so the loops in add/remove code behave * accordingly. */ if (usr_drc_name) usr_drc_count = 1; if (usr_p_option && !strcmp(usr_p_option, "smt_threads")) { rc = smt_threads_func(&dr_info); free_cpu_drc_info(&dr_info); return rc; } switch (usr_action) { case ADD: rc = add_cpus(&dr_info); break; case REMOVE: rc = remove_cpus(&dr_info); break; default: rc = -1; break; } free_cpu_drc_info(&dr_info); return rc; } powerpc-utils-1.3.4/src/drmgr/drslot_chrp_hea.c000066400000000000000000000203711315235264300215510ustar00rootroot00000000000000/** * @file drslot_chrp_hea.c * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include "dr.h" #include "drpci.h" #include "ofdt.h" static char *usagestr = "-c port {-a | -r | -Q} -s drc_name"; /** * hea_uasge */ void hea_usage(char **pusage) { *pusage = usagestr; } /** * sysfs_hea_op * @brief Write to the sysfs file to hotplug add/remove a HEA adapter or port * * @param fname sysfs file to write to * @param name information to write to the sysfs file * @returns 0 on success, !0 otherwise */ static int sysfs_write(char *fname, char *name) { int rc, len; FILE *file; int my_errno; file = fopen(fname, "w"); if (file == NULL) { say(ERROR, "Could not open %s:\n%s\n", fname, strerror(errno)); return -ENODEV; } len = strlen(name); rc = fwrite(name, 1, len, file); my_errno = errno; fclose(file); rc = (rc >= 0) ? 0 : rc; if (rc) say(ERROR, "Write to %s failed:\n%s\n", fname, strerror(my_errno)); return rc; } /** * hotplug_hea * @brief Hotplug add/remove a HEA adapter from the system. * * @param action add or remove the adapter * @param name name of the HEA adapter to add/remove * @returns 0 on success, !0 otherwise */ static int hotplug_hea(int action, char *name) { int rc; char *action_str = (action == ADD) ? "add" : "remove"; char *action_path = (action == ADD) ? HEA_ADD_SLOT : HEA_REMOVE_SLOT; say(DEBUG, "Attempting to hotplug %s %s\n", action_str, name); rc = sysfs_write(action_path, name); if (rc) say(ERROR, "Could not hotplug %s %s\n", action_str, name); return rc; } /** * hotplug_port * @brief Hotplug add/remove a HEA port to the system. * * @param action add/remove of the port * @parm hea HEA adpater of the port to be added * @param port port to be added/removed * @return 0 on success, !0 otherwise */ static int hotplug_port(int action, struct dr_node *hea, struct dr_node *port) { char fname[128]; char port_str[4]; char *action_str = (action == ADD) ? "add" : "remove"; uint port_no; int rc; say(DEBUG, "Attempting to hotplug %s Port.\n", action_str); if (! hea->sysfs_dev_path) { say(DEBUG, "Non-existant sysfs dev path for Port, hotplug " "failed.\n"); return -EINVAL; } rc = get_property(port->ofdt_path, "ibm,hea-port-no", &port_no, sizeof(port_no)); if (rc) return -EINVAL; sprintf(port_str, "%d", port_no); sprintf(fname, "%s/%s", hea->sysfs_dev_path, (action == ADD) ? "probe_port" : "remove_port"); rc = sysfs_write(fname, port_str); if (rc) say(ERROR, "Hotplug %s of Port %d failed\n", action_str, port_no); return rc; } /** * remove_port * @brief Remove the HEA adapater or port specified by the options * * @returns 0 on success, !0 otherwise */ static int remove_port(void) { struct dr_node *hea; struct dr_node *port, *tmp; int rc; int no_ports = 0; int hea_hp_removed = 0; hea = get_node_by_name(usr_drc_name, HEA_NODES); if (hea == NULL) return RC_NONEXISTENT; for (port = hea->children; port; port = port->next) { if (! strcmp(port->drc_name, usr_drc_name)) break; } if (!port) { say(ERROR, "Could not find HEA Port \"%s\" to remove\n", usr_drc_name); free_node(hea); return -1; } rc = hotplug_port(REMOVE, hea, port); if (rc) { free_node(hea); return -1; } /* if this is the last port to be removed, we need to remove the * hea adapter from the OS also. do not actually remove the * HEA adapter from the device tree or unallocate it, we will get * a request to do that later. */ for (tmp = hea->children; tmp; tmp = tmp->next) no_ports++; if (no_ports == 1) { rc = hotplug_hea(REMOVE, strstr(hea->ofdt_path, "/lhea")); if (rc) { hotplug_port(ADD, hea, port); free_node(hea); return -1; } hea_hp_removed = 1; } rc = release_drc(port->drc_index, port->dev_type); if (rc) { if (hea_hp_removed) hotplug_hea(ADD, strstr(hea->ofdt_path, "/lhea")); hotplug_port(ADD, hea, port); free_node(hea); return rc; } rc = remove_device_tree_nodes(port->ofdt_path); if (rc) { if (hea_hp_removed) hotplug_hea(ADD, strstr(hea->ofdt_path, "/lhea")); hotplug_port(ADD, hea, port); free_node(hea); return rc; } say(DEBUG, "device node(s) for %s removed\n", port->drc_name); free_node(hea); return 0; } /** * remove_hea * @brief Remove the HEA adapater or port specified by the options * * @returns 0 on success, !0 otherwise */ static int remove_hea(void) { struct dr_node *hea; int rc; hea = get_node_by_name(usr_drc_name, HEA_NODES); if (hea == NULL) return RC_NONEXISTENT; rc = release_drc(hea->drc_index, hea->dev_type); if (rc) { free_node(hea); return rc; } rc = remove_device_tree_nodes(hea->ofdt_path); if (rc) say(ERROR, "Error removing HEA adapter from the device tree\n"); free_node(hea); return rc; } /** * add_slot * @bried Add the HEA adapter or port specified by the options * * @returns 0 on success, !0 otherwise */ static int add_slot(void) { struct dr_connector drc; struct of_node *of_nodes; struct dr_node *hea; struct dr_node *port; char ofdt_path[DR_PATH_MAX]; char *slot_type = (usr_drc_name[0] == 'H') ? "HEA" : "Port"; int rc = 0; rc = get_drc_by_name(usr_drc_name, &drc, ofdt_path, OFDT_BASE); if (rc) return rc; rc = acquire_drc(drc.index); if (rc) return rc; of_nodes = configure_connector(drc.index); if (of_nodes == NULL) { release_drc(drc.index, HEA_DEV); return -1; } rc = add_device_tree_nodes(ofdt_path, of_nodes); free_of_node(of_nodes); if (rc) { say(ERROR, "Error adding % to the device tree\n", slot_type); release_drc(drc.index, HEA_DEV); return rc; } hea = get_node_by_name(usr_drc_name, HEA_NODES); if (hea == NULL) { say(ERROR, "Could not get find \"%s\" in the updated device " "tree,\nAddition of %s failed.\n", usr_drc_name, slot_type); remove_device_tree_nodes(ofdt_path); release_drc(drc.index, HEA_DEV); return -1; } switch (usr_drc_name[0]) { case 'H': rc = hotplug_hea(ADD, strstr(hea->ofdt_path, "/lhea")); break; case 'P': for (port = hea->children; port; port = port->next) { if (! strcmp(usr_drc_name, port->drc_name)) break; } rc = hotplug_port(ADD, hea, port); break; } if (rc) { remove_device_tree_nodes(ofdt_path); release_drc(drc.index, HEA_DEV); } free_node(hea); return rc; } int valid_hea_options(void) { if (!usr_drc_name) { say(ERROR, "A drc name must be specified\n"); return -1; } if ((usr_action != ADD) && (usr_action != REMOVE) && (usr_action != QUERY)) { say(ERROR, "The '-r', '-a', or '-Q' option must be specified " "for HEA operations.\n"); return -1; } return 0; } int drslot_chrp_hea(void) { int rc; if (! hea_dlpar_capable()) { say(ERROR, "DLPAR HEA operations are not supported on" "this kernel"); return -1; } switch (usr_action) { case ADD: rc = add_slot(); break; case REMOVE: if (usr_drc_type == DRC_TYPE_PORT) rc = remove_port(); else if (usr_drc_type == DRC_TYPE_SLOT) rc = remove_hea(); else { say(ERROR, "The connector type %d is not supported.\n", usr_drc_type); rc = -1; } break; case QUERY: { struct dr_node *node; node = get_node_by_name(usr_drc_name, HEA_NODES); if (node == NULL) { say(ERROR, "%s not owned by partition\n", usr_drc_name); rc = RC_DONT_OWN; } else { /* Special case for HMC */ rc = RC_LINUX_SLOT; } free_node(node); break; } default: rc = -1; } return rc; } powerpc-utils-1.3.4/src/drmgr/drslot_chrp_mem.c000066400000000000000000000773411315235264300216030ustar00rootroot00000000000000/** * @file drslot_chrp_mem * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include "dr.h" #include "ofdt.h" #include "drmem.h" static int block_sz_bytes = 0; static char *state_strs[] = {"offline", "online"}; static char *usagestr = "-c mem {-a | -r} {-q -p {variable_weight | ent_capacity} | {-q | -s [ | ]}}"; /** * mem_usage * @brief return usage string * * @param char ** pointer to usage string */ void mem_usage(char **pusage) { *pusage = usagestr; } /** * report_resource_count * @brief Report the number of LMBs that were added or removed. * * Note that the format of this message is what is expected by the HMC, * or other agent communicating through the RMC framework, and should not * be changed. * * @param count number of LMBs */ static void report_resource_count(int count) { printf("DR_TOTAL_RESOURCES=%d\n", count); } /** * get_phandle * * @param char * device tree node path * @param int * pointer to phandle */ int get_phandle(char *path, uint *phandle) { int rc1,rc2; /* get "linux,phandle" property */ rc1 = get_ofdt_uint_property(path, "linux,phandle", phandle); /* overwrite with "ibm,handle" if it exists */ rc2 = get_ofdt_uint_property(path, "ibm,phandle", phandle); /* return bad if both gets failed */ if (rc1 && rc2) return rc1; else return 0; } /** * free_lmbs * @brief Free any allocated memory referenced from the list head * * @param lmb_list list head to free */ void free_lmbs(struct lmb_list_head *lmb_list) { free_node(lmb_list->lmbs); if (lmb_list->drconf_buf) free(lmb_list->drconf_buf); free(lmb_list); } /** * get_mem_scns * @brief Find the memory sections associated with the specified lmb * * @param lmb lmb to find memory sections of * @return 0 on success, !0 otherwise */ static int get_mem_scns(struct dr_node *lmb) { uint32_t lmb_sz = lmb->lmb_size; uint64_t phys_addr = lmb->lmb_address; uint32_t mem_scn; int rc = 0; mem_scn = phys_addr / block_sz_bytes; /* Assume the lmb is removable. If we find a non-removable memory * section then we flip the lmb back to not removable. */ lmb->is_removable = 1; lmb_sz = lmb->lmb_size; while (lmb_sz > 0) { char *sysfs_path = "/sys/devices/system/memory/memory%d"; struct mem_scn *scn; struct stat sbuf; scn = zalloc(sizeof(*scn)); if (scn == NULL) return -1; sprintf(scn->sysfs_path, sysfs_path, mem_scn); scn->phys_addr = phys_addr; if (!stat(scn->sysfs_path, &sbuf)) { get_int_attribute(scn->sysfs_path, "removable", &scn->removable, sizeof(scn->removable)); if (!scn->removable) lmb->is_removable = 0; } scn->next = lmb->lmb_mem_scns; lmb->lmb_mem_scns = scn; lmb_sz -= block_sz_bytes; phys_addr += block_sz_bytes; mem_scn = phys_addr / block_sz_bytes; } /* If we do not find any associated memory sections, mark this * as not removable. */ if ((lmb->lmb_mem_scns == NULL) || lmb->unusable) lmb->is_removable = 0; return rc; } /** * get_lmb_size * @brief Retrieve the size of the lmb * * @param lmb lmb to get size for, or NULL for drconf lmb size * @param lmb_list list of lmbs, used to determine drconf usage * @returns size of lmb on succes, 0 on failure */ static int get_lmb_size(struct dr_node *lmb) { uint32_t regs[4]; int rc; rc = get_property(lmb->ofdt_path, "reg", ®s, sizeof(regs)); if (rc) { say(DEBUG, "Could not determine LMB size for %s\n", lmb->ofdt_path); return rc; } lmb->lmb_size = be32toh(regs[3]); return 0; } /** * lmb_list_add * @ brief add a dr_node to the specified lmb_list for the indicated drc_index * * @param drc_index drc index of the LMB to add * @param lmb_list lmb list head to add the lmb to * @return pointer to allocated lmb node on success, NULL on failure */ static struct dr_node *lmb_list_add(uint32_t drc_index, struct lmb_list_head *lmb_list) { struct dr_node *lmb; lmb = zalloc(sizeof(*lmb)); if (lmb == NULL) return NULL; lmb->drc_index = drc_index; lmb->dev_type = MEM_DEV; if (lmb_list->sort == LMB_REVERSE_SORT) { if (lmb_list->last) lmb->next = lmb_list->last; lmb_list->lmbs = lmb; } else { if (lmb_list->last) lmb_list->last->next = lmb; else lmb_list->lmbs = lmb; } lmb_list->last = lmb; return lmb; } /** * get_mem_node_lmbs * @brief Retrieve lmbs from the OF device tree represented as memory@XXX nodes * * @param lmb_list pointer to lmb list head to populate * @returns 0 on success, !0 on failure */ int get_mem_node_lmbs(struct lmb_list_head *lmb_list) { struct dr_node *lmb; struct dirent *de; DIR *d; int rc = 0; d = opendir(OFDT_BASE); if (d == NULL) { report_unknown_error(__FILE__, __LINE__); say(DEBUG, "Could not open %s\n", OFDT_BASE); return -1; } while ((de = readdir(d)) != NULL) { char path[1024]; uint32_t my_drc_index; char *tmp; if (de->d_type != DT_DIR) continue; if (strncmp(de->d_name, "memory@", 7)) continue; memset(path, 0, 1024); sprintf(path, "%s/%s", OFDT_BASE, de->d_name); if (get_my_drc_index(path, &my_drc_index)) continue; for (lmb = lmb_list->lmbs; lmb; lmb = lmb->next) { if (lmb->drc_index == my_drc_index) break; } if (lmb == NULL) { say(DEBUG, "Could not find LMB with drc-index of %x\n", my_drc_index); rc = -1; break; } snprintf(lmb->ofdt_path, DR_PATH_MAX, "%s", path); lmb->is_owned = 1; /* Find the lmb size for this lmb */ /* XXX Do nothing with size and break if it can't be found * but don't change rc to indicate failure? * Why not continue? If we break, set rc=-1? */ if (get_lmb_size(lmb)) break; /* Find the physical address for this lmb */ tmp = strrchr(lmb->ofdt_path, '@'); if (tmp == NULL) { say(DEBUG, "Could not determine physical address for " "%s\n", lmb->ofdt_path); /* XXX No rc change? */ break; } lmb->lmb_address = strtoull(tmp + 1, NULL, 16); /* find the associated sysfs memory blocks */ rc = get_mem_scns(lmb); if (rc) break; } closedir(d); return rc; } /** * get_dynamic_reconfig_lmbs * @brief Retrieve lmbs from OF device tree located in the ibm,dynamic-memory * property. * * @param lmb_list pointer to lmb list head to populate * @returns 0 on success, !0 on failure */ int get_dynamic_reconfig_lmbs(struct lmb_list_head *lmb_list) { struct drconf_mem *drmem; uint64_t lmb_sz; int i, num_entries; int rc = 0; rc = get_property(DYNAMIC_RECONFIG_MEM, "ibm,lmb-size", &lmb_sz, sizeof(lmb_sz)); /* convert for LE systems */ lmb_sz = be64toh(lmb_sz); if (rc) { say(DEBUG, "Could not retrieve drconf LMB size\n"); return rc; } lmb_list->drconf_buf_sz = get_property_size(DYNAMIC_RECONFIG_MEM, "ibm,dynamic-memory"); lmb_list->drconf_buf = zalloc(lmb_list->drconf_buf_sz); if (lmb_list->drconf_buf == NULL) { say(DEBUG, "Could not allocate buffer to get dynamic " "reconfigurable memory\n"); return -1; } rc = get_property(DYNAMIC_RECONFIG_MEM, "ibm,dynamic-memory", lmb_list->drconf_buf, lmb_list->drconf_buf_sz); if (rc) { say(DEBUG, "Could not retrieve dynamic reconfigurable memory " "property\n"); return -1; } /* The first integer of the buffer is the number of entries */ num_entries = *(int *)lmb_list->drconf_buf; /* convert for LE systems */ num_entries = be32toh(num_entries); /* Followed by the actual entries */ drmem = (struct drconf_mem *) (lmb_list->drconf_buf + sizeof(num_entries)); for (i = 0; i < num_entries; i++) { struct dr_node *lmb; lmb = lmb_list_add(be32toh(drmem->drc_index), lmb_list); if (lmb == NULL) { say(DEBUG, "Could not find LMB with drc-index of %x\n", drmem->drc_index); rc = -1; break; } sprintf(lmb->ofdt_path, DYNAMIC_RECONFIG_MEM); lmb->lmb_size = lmb_sz; lmb->lmb_address = be64toh(drmem->address); lmb->lmb_aa_index = be32toh(drmem->assoc_index); if (be32toh(drmem->flags) & DRMEM_ASSIGNED) { lmb->is_owned = 1; /* find the associated sysfs memory blocks */ rc = get_mem_scns(lmb); if (rc) break; } lmb_list->lmbs_found++; drmem++; /* trust your compiler */ } say(INFO, "Found %d LMBs currently allocated\n", lmb_list->lmbs_found); return rc; } /** * shuffle_lmbs * @brief Randomly shuffle list of lmbs * * @param list pointer to lmb list to be randomly shuffled * @param length number of lmbs in the list */ static void shuffle_lmbs(struct lmb_list_head *lmb_list) { struct dr_node **shuffled_lmbs, *lmb; int total_lmbs = lmb_list->lmbs_found; int i, j; srand(time(NULL)); shuffled_lmbs = zalloc(sizeof(*shuffled_lmbs) * total_lmbs); for (i = 0, lmb = lmb_list->lmbs; lmb; i++, lmb = lmb->next) { j = rand() % (i + 1); if (j == i) { shuffled_lmbs[i] = lmb; } else { shuffled_lmbs[i] = shuffled_lmbs[j]; shuffled_lmbs[j] = lmb; } } for (i = 0; i < (total_lmbs - 1); i++) shuffled_lmbs[i]->next = shuffled_lmbs[i + 1]; shuffled_lmbs[total_lmbs - 1]->next = NULL; lmb_list->lmbs = shuffled_lmbs[0]; free(shuffled_lmbs); } /** * get_lmbs * @brief Build a list of all possible lmbs for the system * * @param sort LMB_NORMAL_SORT or LMB_REVERSE_SORT to control sort order * * @return list of lmbs, NULL on failure */ struct lmb_list_head * get_lmbs(unsigned int sort) { struct lmb_list_head *lmb_list = NULL; struct dr_node *lmb = NULL; struct stat sbuf; char buf[DR_STR_MAX]; int rc = 0; lmb_list = zalloc(sizeof(*lmb_list)); if (lmb_list == NULL) { say(DEBUG, "Could not allocate LMB list head\n"); return NULL; } lmb_list->sort = sort; rc = get_str_attribute("/sys/devices/system/memory", "/block_size_bytes", &buf, DR_STR_MAX); if (rc) { say(DEBUG, "Could not determine block size bytes for memory.\n"); free_lmbs(lmb_list); return NULL; } block_sz_bytes = strtoul(buf, NULL, 16); /* We also need to know which lmbs are already allocated to * the system and their corresponding memory sections as defined * by sysfs. Walk the device tree and update the appropriate * lmb entries (and their memory sections) as we find their device * tree entries. */ if (stat(DYNAMIC_RECONFIG_MEM, &sbuf)) { struct dr_connector *drc_list, *drc; drc_list = get_drc_info(OFDT_BASE); if (drc_list == NULL) { report_unknown_error(__FILE__, __LINE__); rc = -1; } else { /* For memory dlpar, we need a list of all * posiible memory nodes for the system, initalize * those here. */ for (drc = drc_list; drc; drc = drc->next) { if (strncmp(drc->name, "LMB", 3)) continue; lmb = lmb_list_add(drc->index, lmb_list); if (!lmb) { say(ERROR, "Failed to add LMB (%x)\n", drc->index); rc = -1; break; } lmb_list->lmbs_found++; } } say(INFO, "Maximum of %d LMBs\n", lmb_list->lmbs_found); rc = get_mem_node_lmbs(lmb_list); } else { /* A small hack to here to allow memory add to work in * certain kernels. Due to a bug in the kernel (see comment * in acquire_lmb()) we need to get lmb info from both places. * For a good kernel, the get_mem_node_lmbs routine will not * update the lmb_list. */ rc = get_dynamic_reconfig_lmbs(lmb_list); if (! rc) rc = get_mem_node_lmbs(lmb_list); } if (rc) { free_lmbs(lmb_list); lmb_list = NULL; } else if (sort == LMB_RANDOM_SORT) { shuffle_lmbs(lmb_list); } return lmb_list; } /** * get_available_lmb * * Find the first lmb which does not correspond to a lmb * already owned by the partition and is available, or the lmb * matching the one specified by the user. * * @param start_lmb first lmbs to be searched for an available lmb * @returns pointer to avaiable lmb on success, NULL otherwise */ static struct dr_node *get_available_lmb(struct dr_node *start_lmb) { uint32_t drc_index; struct dr_node *lmb; struct dr_node *usable_lmb = NULL; int balloon_active = ams_balloon_active(); for (lmb = start_lmb; lmb; lmb = lmb->next) { int rc; if (usr_drc_name) { drc_index = strtoul(usr_drc_name, NULL, 0); if ((strcmp(lmb->drc_name, usr_drc_name)) && (lmb->drc_index != drc_index)) continue; } else if (usr_drc_index) { if (lmb->drc_index != usr_drc_index) continue; } if (lmb->unusable) continue; if (usr_action == ADD) { if (lmb->is_owned) continue; rc = dr_entity_sense(lmb->drc_index); if (rc != STATE_UNUSABLE) continue; usable_lmb = lmb; } else if (usr_action == REMOVE) { /* removable is ignored if AMS ballooning is active. */ if ((!balloon_active && !lmb->is_removable) || (!lmb->is_owned)) continue; usable_lmb = lmb; break; } /* Found an available lmb */ break; } if (usable_lmb) say(DEBUG, "Found available LMB, %s, drc index 0x%x\n", usable_lmb->drc_name, usable_lmb->drc_index); return usable_lmb; } static void update_drconf_affinity(struct dr_node *lmb, struct drconf_mem *drmem) { struct of_node *node; struct of_property *prop; uint32_t assoc_prop_sz; uint32_t *assoc_prop; uint32_t assoc_entries; uint32_t assoc_entry_sz; uint32_t *prop_val; int i; /* find the ibm,associativity property */ node = lmb->lmb_of_node; for (prop = node->properties; prop; prop = prop->next) { if (!strcmp(prop->name, "ibm,associativity")) break; } if (!prop) return; /* find the associtivity index atrrays */ assoc_prop_sz = get_property_size(DYNAMIC_RECONFIG_MEM, "ibm,associativity-lookup-arrays"); assoc_prop = zalloc(assoc_prop_sz); if (!assoc_prop) return; get_property(DYNAMIC_RECONFIG_MEM, "ibm,associativity-lookup-arrays", assoc_prop, assoc_prop_sz); assoc_entries = be32toh(assoc_prop[0]); assoc_entry_sz = be32toh(assoc_prop[1]); prop_val = (uint32_t *)prop->value; for (i = 0; i < assoc_entries; i++) { if (memcmp(&assoc_prop[(i * assoc_entry_sz) + 2], &prop_val[1], assoc_entry_sz * sizeof(uint32_t))) continue; /* found it */ drmem->assoc_index = htobe32(i); break; } free(assoc_prop); return; } /** * update_drconf_node * @brief update the ibm,dynamic-memory property for added/removed memory * * @param lmb pointer to updated lmb * @param lmb_list pointer to all lmbs * @param action ADD or REMOVE * @returns 0 on success, !0 on failure */ static int update_drconf_node(struct dr_node *lmb, struct lmb_list_head *lmb_list, int action) { char *prop_buf; size_t prop_buf_sz; char *tmp; struct drconf_mem *drmem; uint phandle; int i, entries; int rc; /* The first int of the buffer is the number of entries */ entries = *(int *)lmb_list->drconf_buf; /* convert for LE systems */ entries = be32toh(entries); drmem = (struct drconf_mem *)(lmb_list->drconf_buf + sizeof(entries)); for (i = 0; i < entries; i++) { if (be32toh(drmem->drc_index) != lmb->drc_index) { drmem++; continue; } if (action == ADD) { drmem->flags |= be32toh(DRMEM_ASSIGNED); update_drconf_affinity(lmb, drmem); } else { drmem->flags &= be32toh(~DRMEM_ASSIGNED); } break; } /* Now create the buffer we pass to the kernel to have this * property updated. This buffer has the format * "update_property ibm,dynamic-memory \ * [strlen("remove") | strlen("add")] " * * The simple collapsing of all strings, spaces, and ints makes this * a length of 61 + the size of the drconf property, round the * calculation to 128 + to ensure the buffer is * always big enough. */ prop_buf_sz = 128 + lmb_list->drconf_buf_sz; prop_buf = zalloc(prop_buf_sz); if (prop_buf == NULL) return -1; rc = get_phandle(lmb->ofdt_path, &phandle); if (rc) { say(DEBUG, "Failed to get phandle for %s under %s. (rc=%d)\n", lmb->drc_name, lmb->ofdt_path, rc); return rc; } memset(prop_buf, 0, prop_buf_sz); tmp = prop_buf; tmp += sprintf(tmp, "update_property 0x%x ibm,dynamic-memory %d ", phandle, lmb_list->drconf_buf_sz); memcpy(tmp, lmb_list->drconf_buf, lmb_list->drconf_buf_sz); tmp += lmb_list->drconf_buf_sz; tmp += sprintf(tmp, " %s %" PRId64 " ", (action == ADD ? "add" : "remove"), sizeof(lmb->lmb_address)); memcpy(tmp, &lmb->lmb_address, sizeof(lmb->lmb_address)); tmp += sizeof(lmb->lmb_address); rc = update_property(prop_buf, (tmp - prop_buf)); free(prop_buf); return rc; } /** * remove_device_tree_lmb * @brief Update the device tree for the lmb being removed. * * @param lmb memory block to be removed from the device tree * @param lmb_list list of all lmbs * @returns 0 on success, !o otherwise */ static int remove_device_tree_lmb(struct dr_node *lmb, struct lmb_list_head *lmb_list) { if (lmb_list->drconf_buf) return update_drconf_node(lmb, lmb_list, REMOVE); return remove_device_tree_nodes(lmb->ofdt_path); } /** * add_device_tree_lmb * @brief Update the device tree for the lmb being added.. * * @param lmb lmb to acquire * @param lmb_list list of all lmbs * @returns 0 on success, !0 otherwise */ static int add_device_tree_lmb(struct dr_node *lmb, struct lmb_list_head *lmb_list) { int rc; lmb->lmb_of_node = configure_connector(lmb->drc_index); if (lmb->lmb_of_node == NULL) { release_drc(lmb->drc_index, MEM_DEV); return -1; } if (lmb_list->drconf_buf) { errno = 0; rc = update_drconf_node(lmb, lmb_list, ADD); if (errno == ENODEV) { /* Due to bug in pre 2.6.27 kernels, updating the * property in the device tree fails when the phandle * is processed as a signed int instead of unsigned * In this case we provide this little hack to allow * memory add to work on these kernels. */ say(DEBUG, "Assuming older kernel, trying to add " "node\n"); sprintf(lmb->ofdt_path, "%s/%s", OFDT_BASE, lmb->lmb_of_node->name); rc = add_device_tree_nodes(OFDT_BASE, lmb->lmb_of_node); } else { sprintf(lmb->ofdt_path, "%s/%s", OFDT_BASE, "/ibm,dynamic-reconfiguration-memory"); } } else { /* Add the new nodes to the device tree */ sprintf(lmb->ofdt_path, "%s/%s", OFDT_BASE, lmb->lmb_of_node->name); rc = add_device_tree_nodes(OFDT_BASE, lmb->lmb_of_node); } if (rc) return rc; if (! lmb_list->drconf_buf) { /* Find the physical address for this lmb. This is only * needed for non-drconf memory. The address for drconf * lmbs is correctly initialized when building the lmb list */ char *tmp = strrchr(lmb->ofdt_path, '@'); if (tmp == NULL) { say(DEBUG, "Could not determine physical address for " "%s\n", lmb->ofdt_path); remove_device_tree_nodes(lmb->ofdt_path); return -1; } lmb->lmb_address = strtoull(tmp + 1, NULL, 16); rc = get_lmb_size(lmb); if (rc) { remove_device_tree_nodes(lmb->ofdt_path); return rc; } } rc = get_mem_scns(lmb); if (rc) remove_device_tree_lmb(lmb, lmb_list); return rc; } /** * get_mem_scn_state * @brief Find the state of the specified memory section * * @param mem_scn memory section to validate * @return OFFLINE, ONLINE, or -1 for failures */ static int get_mem_scn_state(struct mem_scn *mem_scn) { char path[DR_PATH_MAX]; char state[8]; int file; int rc; memset(path, 0, DR_PATH_MAX); sprintf(path, "%s/state", mem_scn->sysfs_path); file = open(path, O_RDONLY); if (file <= 0) { say(DEBUG, "Could not open %s to validate its state.\n%s\n", path, strerror(errno)); return -1; } memset(state, 0, 8); rc = read(file, state, 8); close(file); if (!strncmp(state, "online", 6)) return ONLINE; if (! strncmp(state, "offline", 7)) return OFFLINE; return rc; } /** * set_mem_scn_state * @brief Marks a memory section as online or offline * * @param mem_scn memory section to update * @param state state to mark memory section * @return 0 on success, !0 otherwise */ static int set_mem_scn_state(struct mem_scn *mem_scn, int state) { int file; char path[DR_PATH_MAX]; int rc = 0; time_t t; char tbuf[128]; int my_errno; time(&t); strftime(tbuf, 128, "%T", localtime(&t)); memset(path, 0, DR_PATH_MAX); sprintf(path, "%s/state", mem_scn->sysfs_path); say(DEBUG, "%s Marking %s %s\n", tbuf, mem_scn->sysfs_path, state_strs[state]); file = open(path, O_WRONLY); if (file <= 0) { say(DEBUG, "Could not open %s to %s memory.\n\t%s\n", path, state_strs[state], strerror(errno)); close(file); return -1; } rc = write(file, state_strs[state], strlen(state_strs[state])); my_errno = errno; close(file); if (rc < 0) { say(ERROR, "Could not write to %s to %s memory\n\t%s\n", path, state_strs[state], strerror(my_errno)); return rc; } if (get_mem_scn_state(mem_scn) != state) { time(&t); strftime(tbuf, 128, "%T", localtime(&t)); say(DEBUG, "%s Could not %s %s.\n", tbuf, state_strs[state], mem_scn->sysfs_path); rc = EAGAIN; } else { time(&t); strftime(tbuf, 128, "%T", localtime(&t)); say(DEBUG, "%s Completed marking %s %s.\n", tbuf, mem_scn->sysfs_path, state_strs[state]); rc = 0; } return rc; } /** * probe_lmb * @brief Probe all of the memory sections of the lmb * * @param lmb pointer to lmb to probe * @returns 0 on success,!0 otherwise */ static int probe_lmb(struct dr_node *lmb) { struct mem_scn *scn; int probe_file; int rc = 0; probe_file = open(MEM_PROBE_FILE, O_WRONLY); if (probe_file == -1) { int my_errno = errno; say(DEBUG, "Could not open %s to probe memory\n", MEM_PROBE_FILE); return my_errno; } for (scn = lmb->lmb_mem_scns; scn; scn = scn->next) { char addr[DR_STR_MAX]; memset(addr, 0, DR_STR_MAX); sprintf(addr, "0x%"PRIx64, scn->phys_addr); say(DEBUG, "Probing memory address 0x%llx\n", scn->phys_addr); rc = write(probe_file, addr, strlen(addr)); if (rc == -1) { say(DEBUG, "Probe failed:\n%s\n", strerror(errno)); return rc; } } close(probe_file); return 0; } /** * set_lmb_state * * @param lmb lmb to set the state for * @param state 1 = online, 0 = offline * @returns 0 on success, !0 otherwise */ static int set_lmb_state(struct dr_node *lmb, int state) { struct mem_scn *scn; int rc = 0; struct stat sbuf; say(INFO, "Attempting to %s %s.\n", state_strs[state], lmb->drc_name); if (state == ONLINE) { rc = probe_lmb(lmb); if (rc) return rc; } for (scn = lmb->lmb_mem_scns; scn; scn = scn->next) { if (stat(scn->sysfs_path, &sbuf)) continue; rc = set_mem_scn_state(scn, state); if (rc) break; } if (rc) { /* Revert state of any memory sections of this lmb to their * original state */ int new_state = (state == OFFLINE) ? ONLINE : OFFLINE; for (scn = lmb->lmb_mem_scns; scn; scn = scn->next) { if (stat(scn->sysfs_path, &sbuf)) continue; if (get_mem_scn_state(scn) == state) set_mem_scn_state(scn, new_state); } } if (rc) { if (rc == EAGAIN) say(INFO, "Could not %s %s at this time.\n", state_strs[state], lmb->drc_name); else report_unknown_error(__FILE__, __LINE__); } else say(INFO, "%s is %s.\n", lmb->drc_name, state_strs[state]); return rc; } /** * add_lmbs * * Attempt to acquire and online the given number of LMBs. * This function calls itself recursively to simplify recovery * actions in case of an error. This is intended only for the case * where the user does not specify a drc-name. * * @param nr_lmbs number of lmbs to add * @param lmb_list list of lmbs on the partition * @returns 0 on success, !0 otherwise */ static int add_lmbs(struct lmb_list_head *lmb_list) { int rc = 0; struct dr_node *lmb_head = lmb_list->lmbs; struct dr_node *lmb; lmb_list->lmbs_modified = 0; while (lmb_list->lmbs_modified < usr_drc_count) { if (drmgr_timed_out()) break; lmb = get_available_lmb(lmb_head); if (lmb == NULL) return -1; /* Iterate only over the remaining LMBs */ lmb_head = lmb->next; rc = acquire_drc(lmb->drc_index); if (rc) { report_unknown_error(__FILE__, __LINE__); lmb->unusable = 1; continue; } rc = add_device_tree_lmb(lmb, lmb_list); if (rc) { report_unknown_error(__FILE__, __LINE__); release_drc(lmb->drc_index, MEM_DEV); lmb->unusable = 1; continue; } rc = set_lmb_state(lmb, ONLINE); if (rc) { report_unknown_error(__FILE__, __LINE__); remove_device_tree_lmb(lmb, lmb_list); release_drc(lmb->drc_index, MEM_DEV); lmb->unusable = 1; continue; } lmb_list->lmbs_modified++; } return rc; } /** * mem_add * @brief Add memory to the partition * * @returns 0 on success, !0 otherwise */ static int mem_add(void) { struct lmb_list_head *lmb_list; int rc; lmb_list = get_lmbs(LMB_NORMAL_SORT); if (lmb_list == NULL) { say(ERROR, "Could not gather LMB (logical memory block " "information.\n"); return -1; } say(DEBUG, "Attempting to add %d LMBs\n", usr_drc_count); rc = add_lmbs(lmb_list); say(DEBUG, "Added %d of %d requested LMB(s)\n", lmb_list->lmbs_modified, usr_drc_count); report_resource_count(lmb_list->lmbs_modified); free_lmbs(lmb_list); return rc; } /** * remove_lmbs * * @param nr_lmbs * @param lmb_list * @return 0 on success, !0 otherwise */ static int remove_lmbs(struct lmb_list_head *lmb_list) { struct dr_node *lmb_head = lmb_list->lmbs; struct dr_node *lmb; int rc; while (lmb_list->lmbs_modified < usr_drc_count) { if (drmgr_timed_out()) break; lmb = get_available_lmb(lmb_head); if (!lmb) return -1; /* Iterate only over the remaining LMBs */ lmb_head = lmb->next; rc = set_lmb_state(lmb, OFFLINE); if (rc) { lmb->unusable = 1; continue; } rc = remove_device_tree_lmb(lmb, lmb_list); if (rc) { report_unknown_error(__FILE__, __LINE__); set_lmb_state(lmb, ONLINE); lmb->unusable = 1; continue; } while (lmb->lmb_mem_scns) { struct mem_scn *scn = lmb->lmb_mem_scns; lmb->lmb_mem_scns = scn->next; free(scn); } rc = release_drc(lmb->drc_index, 0); if (rc) { report_unknown_error(__FILE__, __LINE__); add_device_tree_lmb(lmb, lmb_list); set_lmb_state(lmb, ONLINE); lmb->unusable = 1; continue; } lmb->is_removable = 0; lmb_list->lmbs_modified++; } return 0; } /** * mem_remove * * @return 0 on success, !0 otherwise */ static int mem_remove(void) { struct lmb_list_head *lmb_list; struct dr_node *lmb; unsigned int removable = 0; int rc = 0; lmb_list = get_lmbs(LMB_RANDOM_SORT); if (lmb_list == NULL) { say(ERROR, "Could not gather LMB (logical memory block " "information.\n"); return -1; } /* Can not know which lmbs are removable by the is_removable field * if AMS ballooning is active. */ if (!ams_balloon_active()) { /* Make sure we have enough removable memory to fulfill * this request */ for (lmb = lmb_list->lmbs; lmb; lmb = lmb->next) { if (lmb->is_removable) removable++; } if (removable == 0) { say(ERROR, "There is not enough removable memory " "available to fulfill the request.\n"); rc = -1; } if (removable < usr_drc_count) { say(INFO, "Only %u LMBs are currently candidates " "for removal.\n", removable); usr_drc_count = removable; } } if (!rc) { say(DEBUG, "Attempting removal of %d LMBs\n", usr_drc_count); rc = remove_lmbs(lmb_list); } say(ERROR, "Removed %d of %d requested LMB(s)\n", lmb_list->lmbs_modified, usr_drc_count); if (lmb_list->lmbs_modified < usr_drc_count) say(ERROR, "Unable to hotplug remove the remaining %d LMB(s)\n", usr_drc_count - lmb_list->lmbs_modified); report_resource_count(lmb_list->lmbs_modified); free_lmbs(lmb_list); return rc; } /* These two defines are taken from drivers/net/ehea/ehea.h in the kernel. * Unfortunately they do not appear in any header we can include so we * have to define the values here so we can check ehea capabilities. */ #define MEM_ADD_ATTR 0x0000000000000002 #define MEM_RM_ATTR 0x0000000000000004 /** * ehea_compatable * @brief Determine if ehea is loaded and if it can handle memory dlpar * * In order to properly support memory DLPAR on systems with HEAdevices, * we have to ensure that the ehea module is either not loaded or we are * using a version that can handle memory dlpar operations. Otherwise bad * stuff happens. * * This uses system() to run lsmod and grep to check for the presence * of the ehea module. If it is present we check its capabilities file * to determine if it can handle memory dlpar. * * @return 1 if we are ehea compatable, 0 otherwise */ static int ehea_compatable(void) { FILE *fp; uint64_t flags = 0; int rc; rc = system("/sbin/lsmod | grep ehea >/dev/null 2>&1"); if (WEXITSTATUS(rc) != 0) { /* The ehea module is not loaded, everything is good */ return 1; } /* The module is loaded, now we need to see if it * can handle memory dlpar operations. */ fp = fopen("/sys/bus/ibmebus/drivers/ehea/capabilities", "r"); if (fp == NULL) { /* File doesn't exist, memory dlpar operations are not * supported by this version of the ehea driver. */ say(INFO, "The eHEA module for this system does not support " "memory DLPAR operations.\n"); return 0; } rc = fscanf(fp, "%"PRIu64, &flags); fclose(fp); /* Assume memory dlpar is not supported */ rc = 0; if ((usr_action == ADD) && (flags & MEM_ADD_ATTR)) rc = 1; if ((usr_action == REMOVE) && (flags & MEM_RM_ATTR)) rc = 1; if (!rc) say(INFO, "The eHEA modules loaded on this system does not " "support memory DLPAR %s operations.\n", (usr_action == ADD) ? "add" : "remove"); return rc; } int valid_mem_options(void) { /* default to a quantity of 1 */ if (usr_drc_count == 0) usr_drc_count = 1; if ((usr_action != ADD) && (usr_action != REMOVE)) { say(ERROR, "The '-r' or '-a' option must be specified for " "memory operations\n"); return -1; } /* The -s option can specify a drc name or drc index */ if (usr_drc_name && !strncmp(usr_drc_name, "0x", 2)) { usr_drc_index = strtoul(usr_drc_name, NULL, 16); usr_drc_name = NULL; } return 0; } int do_mem_kernel_dlpar(void) { char cmdbuf[128]; int rc, offset; offset = sprintf(cmdbuf, "%s ", "memory"); switch (usr_action) { case ADD: offset += sprintf(cmdbuf + offset, "add "); break; case REMOVE: offset += sprintf(cmdbuf + offset, "remove "); break; default: say(ERROR, "Invalid DRC type specified\n"); return -EINVAL; } if (usr_drc_index) offset += sprintf(cmdbuf + offset, "index 0x%x", usr_drc_index); else offset += sprintf(cmdbuf + offset, "count %d", usr_drc_count); rc = do_kernel_dlpar(cmdbuf, offset); /* Memory DLPAR in the kernel is handled as an all-or-nothing * request, we either add all the requested LMBs or add none * of them. */ if (rc) report_resource_count(0); else report_resource_count(usr_drc_count); return rc; } int drslot_chrp_mem(void) { int rc = -1; if (usr_p_option) { /* This is a entitlement or weight change */ return update_sysparm(); } if (! mem_dlpar_capable() || ! ehea_compatable()) { say(ERROR, "DLPAR memory operations are not supported on" "this kernel."); return -1; } /* The recursive nature of the routines that add/remove lmbs * require that the quantity be non-zero. */ if (usr_drc_name) usr_drc_count = 1; if (kernel_dlpar_exists()) { rc = do_mem_kernel_dlpar(); } else { if (usr_action == ADD) rc = mem_add(); else if (usr_action == REMOVE) rc = mem_remove(); } return rc; } powerpc-utils-1.3.4/src/drmgr/drslot_chrp_pci.c000066400000000000000000000575631315235264300216040ustar00rootroot00000000000000/** * @file drslot_chrp_pci.c * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include "rtas_calls.h" #include "dr.h" #include "drpci.h" static char *sw_error = "Internal software error. Contact your service " "representative.\n"; static char *speed_error = "Add operation failed. The 33MHz PCI card may\n" "not be added to the PCI bus with another adapter\n" "running at 66 MHz.\n"; #define HW_ERROR -1 /* RTAS hardware error */ /* Error status from set-power */ #define SPEED_ERROR -9000 /* 33MHz card on bus running at 66MHz */ #define USER_QUIT 0 /* user wants to bail out of operation */ #define USER_CONT 1 /* user wants to continue with operation */ static char *usagestr = "-c pci -s {-i | -a [-I] | -r [-I] | -R [-I]}"; /** * pci_usage * */ void pci_usage(char **pusage) { *pusage = usagestr; } /** * process_led * * sets the given slot's led to the specified state. If the * return from set_led is bad, call the error_exit function to clean up * and exit the command. * * @param lslot pointer to slot we're setting * @param led setting for led */ static int process_led(struct dr_node *node, int led) { int rtas_rc; rtas_rc = rtas_set_indicator(DR_INDICATOR, node->drc_index, led); if (rtas_rc) { if (rtas_rc == HW_ERROR) say(ERROR, "%s", hw_error); else say(ERROR, "%s", sw_error); return -1; } return 0; } /** * identify_slot * * Given a slot structure, set the led of the slot to the identify * state and print a message to the user. Read the user input and return it. * * @param islot pointer to slot to be set * @returns USER_CONT if user pushes enter key, USER_QUIT otherwise */ static int identify_slot(struct dr_node *node) { if (process_led(node, LED_ID)) return USER_QUIT; printf("The visual indicator for the specified PCI slot has\n" "been set to the identify state. Press Enter to continue\n" "or enter x to exit.\n"); if (getchar() == '\n') return (USER_CONT); else return (USER_QUIT); } static char * find_drc_name(uint32_t drc_index, struct dr_node *all_nodes) { struct dr_node *node; node = all_nodes; while (node != NULL) { say(DEBUG, "%#x =? %#x\n", drc_index, node->drc_index); if (node->drc_index == drc_index) { say(DEBUG, "Found drc_name %s\n", node->drc_name); return node->drc_name; } else node = node->next; } if ((node == NULL)) say(ERROR, "Could not find drc_name for index %#x\n", drc_index); return NULL; } /** * find_slot * * Searches through all slots and returns a pointer to the slot * whose location code matches the user input. If no slot is found, * an error message is displayed and the entire command is exited. * * This routine uses a common function "cmp_drcname" so that all routines * validating a slot name will compare on the same basis. A slot could be * found, but if the "skip" field of the slot structure is set, we * shouldn't use it. * * @returns pointer to slot on success, NULL otherwise */ static struct dr_node * find_slot(char *drc_name, struct dr_node *all_nodes) { struct dr_node *node; /* working pointer */ /* Search through all_nodes to see if the * user-specified location exists. */ node = all_nodes; while (node != NULL) { if (cmp_drcname(node->drc_name, drc_name)) break; else node = node->next; } if ((node == NULL) || (node->skip)) say(ERROR, "The specified PCI slot is either invalid\n" "or does not support hot plug operations.\n"); return node; } static int check_card_presence(struct dr_node *node) { int state = EMPTY; int i, keep_working; say(DEBUG, "Waiting for the card to appear...\n"); do { keep_working = 0; for (i = 0; i < 30; i++) { state = dr_entity_sense(node->drc_index); if (state != EMPTY) return state; sleep(1); } if (usr_prompt) { printf("The card still does not appear to be present" "\npress Enter to continue to wait or enter " "'x' to exit.\n"); if ((getchar() == '\n')) keep_working = 1; } } while (keep_working); return state; } /** * card_present * @brief Determines if there is a card present in the specified slot * * Attempt to check if a card is present. If we get a definite answer, * return that and indicate that we did not turn the power on. Depending * on the adapter, we may have to power on and we may have to unisolate * to determine if a card is present. If that's the case, power on * maybe isolate and try sensing again. If we hit fatal errors, call * error_exit to clean up and exit the command. * * @param slot pointer to slot we're checking * @param power_state state of power when we leave this routine * @param isolate_state state of isolation when we leave this routine * @returns EMPTY or PRESENT */ static int card_present(struct dr_node *node, int *power_state, int *isolate_state) { int state, rc; *power_state = POWER_OFF; /* initialize */ *isolate_state = ISOLATE; state = check_card_presence(node); if ((state == EMPTY) || (state == PRESENT)) return state; else if (state == HW_ERROR) { say(ERROR, "%s", hw_error); return -1; } else if ((state == NEED_POWER) || (state == PWR_ONLY)) { /* set power on, and if needed, unisolate too */ rc = set_power(node->drc_power, POWER_ON); if (rc) { if (rc == HW_ERROR) { say(ERROR, "%s", hw_error); return -1; } else if (rc == SPEED_ERROR) { say(ERROR, "%s", speed_error); set_power(node->drc_power, POWER_OFF); return -1; } /* Catch any other errors. */ else { say(ERROR, "%s", sw_error); set_power(node->drc_power, POWER_OFF); return -1; } } *power_state = POWER_ON; if (state == NEED_POWER) { /* If we get here, we have power on now * but we still need to unisolate */ rc = rtas_set_indicator(ISOLATION_STATE, node->drc_index, UNISOLATE); if (rc) { if (rc == HW_ERROR) say(ERROR, "%s", hw_error); else say(ERROR, "%s", sw_error); rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); set_power(node->drc_power, POWER_OFF); return -1; } *isolate_state = UNISOLATE; } /* Now we have power on, and the unisolate is done * if it was needed. check for card again. */ state = check_card_presence(node); if ((state == EMPTY) || (state == PRESENT)) return state; if (state) { if (rc == HW_ERROR) say(ERROR, "%s", hw_error); else say(ERROR, "%s", sw_error); rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); set_power(node->drc_power, POWER_OFF); return -1; } } else { /* catch any other errors from first dr_entity_sense */ say(ERROR, "%s", sw_error); } return state; } /** * do_identify * @brief Main processor for the drslot_chrp_pci -i command * * Validate the user input, a slot name. Call the routine which actually * does the call to set the LED. When we're done identifying, reset the * LED based on whether or not there's an OF node representing an adapter * connected to the slot. If an adapter node exists, turn the LED on, * else turn if off. */ static int do_identify(struct dr_node *all_nodes) { struct dr_node *node; int usr_key; int led_state; node = find_slot(usr_drc_name, all_nodes); if (node == NULL) return -1; if (is_display_adapter(node)) { say(ERROR, "Display adapters are not supported by drmgr.\n"); return -1; } usr_key = identify_slot(node); /* when we're done with identify, put the LED back * where we think it ought to be. ON if an adapter is * connected, OFF if not */ if (node->children == NULL) led_state = LED_OFF; else led_state = LED_ON; if (process_led(node, led_state)) return -1; if (usr_key == USER_QUIT) return -1; return 0; /* don't return anything on identify */ } /** * add_work * * Prepares a PCI hot plug slot for adding an adapter, then * configures the adapter and any PCI adapters below into the * kernel's and /proc's Open Firmware device tree. * * If there are any errors from the RTAS routines, * the slot is powered off, isolated, and the LED is turned off. No * configuration is completed. * If the OF tree cannot be updated, the slot is powered * off, isolated, and the LED is turned off. * * @param slot * @returns 0 on success, !0 on failure */ static int add_work(struct dr_node *node) { int pow_state; /* Tells us if power was turned on when */ int iso_state; /* Tells us isolation state after */ int rc; struct of_node *new_nodes;/* nodes returned from configure_connector */ /* if we're continuing, set LED_ON and see if a card is really there. */ if (process_led(node, LED_ON)) return -1; say(DEBUG, "is calling card_present\n"); rc = card_present(node, &pow_state, &iso_state); if (!rc) { say(ERROR, "No PCI card was detected in the specified " "PCI slot.\n"); rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); set_power(node->drc_power, POWER_OFF); return -1; } if (!pow_state) { say(DEBUG, "is calling set_power(POWER_ON index 0x%x, " "power_domain 0x%x\n", node->drc_index, node->drc_power); rc = set_power(node->drc_power, POWER_ON); if (rc) { if (rc == HW_ERROR) say(ERROR, "%s", hw_error); else if (rc == SPEED_ERROR) say(ERROR, "%s", speed_error); else say(ERROR, "%s", sw_error); rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); set_power(node->drc_power, POWER_OFF); return -1; } } if (!iso_state) { say(DEBUG, "calling rtas_set_indicator(UNISOLATE index 0x%x)\n", node->drc_index); rc = rtas_set_indicator(ISOLATION_STATE, node->drc_index, UNISOLATE); if (rc) { if (rc == HW_ERROR) say(ERROR, "%s", hw_error); else say(ERROR, "%s", sw_error); rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); set_power(node->drc_power, POWER_OFF); return -1; } } /* Now go get all the new nodes for this adapter. If * the return status requires a message, print it out * and exit, otherwise, add the nodes to the OF tree. */ new_nodes = configure_connector(node->drc_index); if (new_nodes == NULL) { rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); set_power(node->drc_power, POWER_OFF); return -1; } say(DEBUG, "Adding %s to %s\n", new_nodes->name, node->ofdt_path); rc = add_device_tree_nodes(node->ofdt_path, new_nodes); if (rc) { say(DEBUG, "add_device_tree_nodes failed at %s\n", node->ofdt_path); say(ERROR, "%s", sw_error); rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); set_power(node->drc_power, POWER_OFF); return -1; } return 0; } /** * do_insert_card_work * * Performs the steps required to set the isolation state and turn the * power to a slot off. The prompts the user to insert the new card * into the slot. */ static int do_insert_card_work(struct dr_node *node) { int rc; /* Now it's time to isolate, power off, set the action LED, and * prompt the user to put the card in. */ say(DEBUG, "is calling rtas_set_indicator(ISOLATE index 0x%x)\n", node->drc_index); rc = rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); if (rc) { if (rc == HW_ERROR) say(ERROR, "%s", hw_error); else say(ERROR, "%s", sw_error); set_power(node->drc_power, POWER_OFF); return -1; } say(DEBUG, "is calling set_power(POWER_OFF index 0x%x, " "power_domain 0x%x)\n", node->drc_index, node->drc_power); rc = set_power(node->drc_power, POWER_OFF); if (rc) { if (rc == HW_ERROR) say(ERROR, "%s", hw_error); else say(ERROR, "%s", sw_error); return -1; } if (usr_prompt) { /* Prompt user to put in card and to press * Enter to continue or other key to exit. */ if (process_led(node, LED_ACTION)) return -1; printf("The visual indicator for the specified PCI slot has\n" "been set to the action state. Insert the PCI card\n" "into the identified slot, connect any devices to be\n" "configured and press Enter to continue. Enter x to " "exit.\n"); if (!(getchar() == '\n')) { process_led(node, LED_OFF); return 0; } } return 0; } /** * do_add * * Prepares a PCI hot plug slot for adding an adapter, then * configures the adapter and any PCI adapters below into * the Open Firmware device tree. * * Verifies that a given hot plug PCI slot does not have an adapter * already connected, identifies the slot to the user unless requested not * to with the -i flag, prompts the user to connect the adapter, powers * the slot on, and calls configure connector. When configure connector * completes and returns the new node(s) for the new PCI adapter and any * attached devices then the Open Firmware device tree is * updated to reflect the new devices. */ static int do_add(struct dr_node *all_nodes) { struct dr_node *node; int usr_key = USER_CONT; int rc; node = find_slot(usr_drc_name, all_nodes); if (node == NULL) return -1; if (is_display_adapter(node)) { say(ERROR, "DLPAR of display adapters is not supported.\n"); return -1; } /* Prompt user only if in interactive mode. */ if (usr_prompt) { if (usr_slot_identification) usr_key = identify_slot(node); if (usr_key == USER_QUIT) { if (node->children == NULL) process_led(node, LED_OFF); else process_led(node, LED_ON); return 0; } } if (node->children != NULL) { /* If there's already something here, turn the * LED on and exit with user error. */ process_led(node, LED_ON); say(ERROR, "The specified PCI slot is already occupied.\n"); return -1; } if (!pci_hotplug_only) { rc = do_insert_card_work(node); if (rc) return rc; } /* Call the routine which determines * what the user wants and does it. */ rc = add_work(node); if (rc) return rc; say(DEBUG, "is calling enable_slot to config adapter\n"); /* Try to config the adapter. The rpaphp module doesn't play well with * qemu pci slots so we let the generic kernel pci code probe the device * by rescanning the bus in the qemu virtio case. */ if (!pci_virtio) set_hp_adapter_status(PHP_CONFIG_ADAPTER, node->drc_name); else pci_rescan_bus(); return 0; } /** * remove_work * * Removes nodes associated a PCI slot from the * Open Firmware device tree and isolates and powers off the PCI slot. * * A remove may be specified by the location code of the PCI slot. * Unless the user specifies the -I flag, the slot is identified to * the user. * Nodes representing the device(s) are removed from the * Open Firmware device tree. The slot is isolated and powered off, * and the LED is turned off. * * @returns pointer slot on success, NULL on failure */ static struct dr_node *remove_work(struct dr_node *all_nodes) { struct dr_node *node; struct dr_node *child; int rc; int usr_key = USER_CONT; node = find_slot(usr_drc_name, all_nodes); if (node == NULL) return NULL; say(DEBUG, "found node: drc name=%s, index=0x%x, path=%s\n", node->drc_name, node->drc_index, node->ofdt_path); if (is_display_adapter(node)) { say(ERROR, "DLPAR of display adapters is not supported.\n"); return NULL; } if (usr_prompt) { if (usr_slot_identification) usr_key = identify_slot(node); if (usr_key == USER_QUIT) { if (node->children == NULL) process_led(node, LED_OFF); else process_led(node, LED_ON); return NULL; } } /* Turn on the LED while we go do some work. */ if (process_led(node, LED_ON)) return NULL; /* Make sure there's something there to remove. */ if (node->children == NULL) { process_led(node, LED_OFF); say(ERROR, "There is no configured card to remove from the " "specified PCI slot.\n"); return NULL; } if (!pci_virtio) { /* Make sure all the devices are * not configured before proceeding */ if (get_hp_adapter_status(node->drc_name) == CONFIG) { say(DEBUG, "unconfiguring adapter in slot[%s]\n", node->drc_name); set_hp_adapter_status(PHP_UNCONFIG_ADAPTER, node->drc_name); int rc = get_hp_adapter_status(node->drc_name); if (rc != NOT_CONFIG) { say(ERROR, "Unconfig adapter failed.\n"); return NULL; } } else { /* In certain cases such as a complete failure of the * adapter there may not have been the possibility to clean * up everything. Mark these adapaters for additional * processing later. */ node->post_replace_processing = 1; } } else { /* The rpaphp module fails to work with qemu pci slots so * so we rely on the devices remove attribute in sysfs to * inform the generic kernel pci code to remove the qemu virtio * device */ for (child = node->children; child; child = child->next) pci_remove_device(child); /* The kernel adds the pci device removal to a work queue which * makes the previous pci_remove_device call asynchronous. Need * to let kernel finish cleanup before informing qemu to isolate * and power down virtio pci device. */ sleep(3); } /* Call subroutine to remove node(s) from * the device tree. */ for (child = node->children; child; child = child->next) { rc = remove_device_tree_nodes(child->ofdt_path); if (rc) { say(ERROR, "%s", sw_error); rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); set_power(node->drc_power, POWER_OFF); return NULL; } } if (pci_hotplug_only) return node; /* We have to isolate and power off before * allowing the user to physically remove * the card. */ say(DEBUG, "is calling rtas_set_indicator(ISOLATE index 0x%x)\n", node->drc_index); rc = rtas_set_indicator(ISOLATION_STATE, node->drc_index, ISOLATE); if (rc) { if (rc == HW_ERROR) say(ERROR, "%s", hw_error); else say(ERROR, "%s", sw_error); set_power(node->drc_power, POWER_OFF); return NULL; } say(DEBUG, "is calling set_power(POWER_OFF index 0x%x, power_domain " "0x%x)\n", node->drc_index, node->drc_power); rc = set_power(node->drc_power, POWER_OFF); if (rc) { if (rc == HW_ERROR) say(ERROR, "%s", hw_error); else say(ERROR, "%s", sw_error); set_power(node->drc_power, POWER_OFF); return NULL; } return node; } /** * do_remove * * Removes nodes associated a PCI slot from the Open Firmware * device tree and isolates and powers off the PCI slot. * * A remove may be specified by the location code of the PCI slot. * Unless the user specifies the -I flag, the slot is identified * the user. Nodes representing the device(s) are removed from the * Open Firmware device tree. The slot is isolated and powered off, * and the LED is turned off. * * If there are any errors from the RTAS routines, * the slot is powered off, isolated, and the LED is turned off. No * unconfiguration is completed. * If the OF tree cannot be updated, the slot is powered * off, isolated, and the LED is turned off. */ static int do_remove(struct dr_node *all_nodes) { struct dr_node *node; /* Remove the specified slot and update the device-tree */ node = remove_work(all_nodes); if (node == NULL) return -1; /* Prompt user to remove card and to press * Enter to continue. Can't exit out of here. */ if (usr_prompt) { if (process_led(node, LED_ACTION)) return -1; printf("The visual indicator for the specified PCI slot " "has\nbeen set to the action state. Remove the PCI " "card\nfrom the identified slot and press Enter to " "continue.\n"); getchar(); if (process_led(node, LED_OFF)) return -1; } return 0; } /** * do_replace * @brief Allows the replacement of an adapter connected to a * PCI hot plug slot * * A replace may be specified by the location code of the PCI slot. * Unless the user specifies the -I flag, the slot is identified to * the user. * Nodes representing the old device(s) are removed from the * Open Firmware device tree. The slot is isolated and powered off, * and the LED is set to the ACTION state. The user is prompted to replace * the adpater. The slot is powered on and unisolated and configure * connector is executed. * * If there are any errors from the RTAS routines, * the slot is powered off, isolated, and the LED is turned off. If the * original adapter has been removed, it is left in that state. * If the OF tree cannot be updated, the slot is powered * off, isolated, and the LED is turned off. */ static int do_replace(struct dr_node *all_nodes) { struct dr_node *repl_node; int rc; /* Call the routine which does the work of getting the node info, * then removing it from the OF device tree. */ repl_node = remove_work(all_nodes); if (repl_node == NULL) return -1; if (!repl_node->children) { say(ERROR, "Bad node struct.\n"); return -1; } say(DEBUG, "repl_node:path=%s node:path=%s\n", repl_node->ofdt_path, repl_node->children->ofdt_path); /* Prompt user to replace card and to press * Enter to continue or x to exit. Exiting here * means the original card has been removed. */ if (usr_prompt) { if (process_led(repl_node, LED_ACTION)) return -1; printf("The visual indicator for the specified PCI slot " "has\nbeen set to the action state. Replace the PCI " "card\nin the identified slot and press Enter to " "continue.\nEnter x to exit. Exiting now leaves the " "PCI slot\nin the removed state.\n"); if (!(getchar() == '\n')) { process_led(repl_node, LED_OFF); return 0; } } rc = add_work(repl_node); if (rc) return rc; say(DEBUG, "CONFIGURING the card in node[name=%s, path=%s]\n", repl_node->drc_name, repl_node->ofdt_path); set_hp_adapter_status(PHP_CONFIG_ADAPTER, repl_node->drc_name); if (repl_node->post_replace_processing) { int prompt_save = usr_prompt; say(DEBUG, "Doing post replacement processing...\n"); /* disable prompting for post-processing */ usr_prompt = 0;; repl_node = remove_work(repl_node); rc = add_work(repl_node); if (!rc) set_hp_adapter_status(PHP_CONFIG_ADAPTER, repl_node->drc_name); usr_prompt = prompt_save; } return rc; } int valid_pci_options(void) { if ((usr_action == IDENTIFY) && (!usr_slot_identification)) { say(ERROR, "Cannot specify the -i and -I option together\n"); return -1; } /* The -s option can specify a drc name or drc index */ if (usr_drc_name && !strncmp(usr_drc_name, "0x", 2)) { usr_drc_index = strtoul(usr_drc_name, NULL, 16); usr_drc_name = NULL; } if (!usr_drc_name && !usr_drc_index) { say(ERROR, "A drc name or index must be specified\n"); return -1; } if ((usr_action != ADD) && (usr_action != REMOVE) && (usr_action != IDENTIFY) && (usr_action != REPLACE)) { say(ERROR, "The '-r', '-a', '-R' or '-i' option must be spcified " "for PCI operations\n"); return -1; } return 0; } int drslot_chrp_pci(void) { int rc; struct dr_node *all_nodes; all_nodes = get_hp_nodes(); if (all_nodes == NULL) { say(ERROR, "There are no PCI hot plug slots on this system.\n"); return -1; } #ifdef DBG_HOT_PLUG print_slots_list(all_nodes); #endif if (!usr_drc_name) usr_drc_name = find_drc_name(usr_drc_index, all_nodes); switch (usr_action) { case ADD: rc = do_add(all_nodes); break; case REMOVE: rc = do_remove(all_nodes); break; case REPLACE: rc = do_replace(all_nodes); break; case IDENTIFY: rc = do_identify(all_nodes); break; default: say(ERROR, "Invalid operation specified!\n"); rc = -1; break; } free_node(all_nodes); return rc; } powerpc-utils-1.3.4/src/drmgr/drslot_chrp_phb.c000066400000000000000000000264761315235264300216010ustar00rootroot00000000000000/** * @file drslot_chrp_phb.c * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "dr.h" #include "drpci.h" #include "ofdt.h" static char *usagestr = "-c phb [-Q | -r | -a] -s "; static int release_phb(struct dr_node *); static int acquire_phb(char *, struct dr_node **); /** * phb_usage * @brief return the usage message * * @returns 1, always */ void phb_usage(char **pusage) { *pusage = usagestr; } static int phb_has_dlpar_children(struct dr_node *phb) { struct dr_node *child; /* If this PHB still owns children that are not hotplug, fail. */ for (child = phb->children; child; child = child->next) { if ((child->is_owned) && (child->dev_type != PCI_HP_DEV)) return 1; } return 0; } static int phb_has_display_adapter(struct dr_node *phb) { struct dr_node *child; for (child = phb->children; child; child = child->next) { if (is_display_adapter(child)) return 1; } return 0; } /** * query_phb * * @returns 0 if a remove would succeed, or if it's alreday been removed * @returns 1 if a remove would not succeed */ static int query_phb(void) { struct dr_node *phb; int rc; phb = get_node_by_name(usr_drc_name, PHB_NODES); if (phb == NULL) rc = RC_NONEXISTENT; else if (phb_has_display_adapter(phb)) rc = RC_IN_USE; else if (phb_has_dlpar_children(phb)) rc = RC_IN_USE; else rc = RC_LINUX_SLOT; if (phb) free_node(phb); return rc; } /** * release_phb * */ static int release_phb(struct dr_node *phb) { int rc; rc = remove_device_tree_nodes(phb->ofdt_path); if (rc) return rc; if (phb->phb_ic_ofdt_path[0] != '\0') { rc = remove_device_tree_nodes(phb->phb_ic_ofdt_path); if (rc) return rc; } rc = release_drc(phb->drc_index, PHB_DEV); return rc; } struct hpdev { struct hpdev *next; char path[256]; char devspec[256]; }; #define SYSFS_PCI_DEV_PATH "/sys/bus/pci/devices" static void free_hpdev_list(struct hpdev *hpdev_list) { struct hpdev *hpdev; while (hpdev_list) { hpdev = hpdev_list; hpdev_list = hpdev_list->next; free(hpdev); } } static int get_os_hp_devices(struct hpdev **hpdev_list) { struct hpdev *hp_list = NULL; struct hpdev *hpdev; DIR *d; struct dirent *de; int rc = 0; d = opendir(SYSFS_PCI_DEV_PATH); if (!d) { say(ERROR, "Failed to open %s\n", SYSFS_PCI_DEV_PATH); return -1; } while ((de = readdir(d)) != NULL) { if (is_dot_dir(de->d_name)) continue; hpdev = zalloc(sizeof(*hpdev)); if (!hpdev) { rc = -1; break; } hpdev->next = hp_list; hp_list = hpdev; rc = sprintf(hpdev->path, "%s/%s", SYSFS_PCI_DEV_PATH, de->d_name); if (rc < 0) break; rc = get_str_attribute(hpdev->path, "devspec", hpdev->devspec, 256); if (rc) break; say(EXTRA_DEBUG, "HPDEV: %s\n %s\n", hpdev->path, hpdev->devspec); } closedir(d); if (rc) { free_hpdev_list(hp_list); hp_list = NULL; } *hpdev_list = hp_list; return rc; } static int hp_remove_os_device(struct hpdev *hpdev) { FILE *file; char path[256]; int rc; sprintf(path, "%s/%s", hpdev->path, "remove"); file = fopen(path, "w"); if (!file) return -1; say(DEBUG, "Removing %s\n", hpdev->path); rc = fwrite("1", 1, 1, file); if (rc == 1) rc = 0; fclose(file); sleep(5); return rc; } static int disable_os_hp_children_recurse(struct dr_node *phb, struct hpdev *hpdev_list, char *ofpath) { struct hpdev *hpdev; DIR *d; struct dirent *de; int rc = 0; d = opendir(ofpath); if (!d) return -1; while ((de = readdir(d)) != NULL) { char devspec[256]; if (is_dot_dir(de->d_name)) continue; if (de->d_type == DT_DIR) { char lpath[4096]; sprintf(lpath, "%s/%s", ofpath, de->d_name); rc = disable_os_hp_children_recurse(phb, hpdev_list, lpath); } memset(devspec, 0, 256); sprintf(devspec, "%s/%s", ofpath + strlen(OFDT_BASE), de->d_name); for (hpdev = hpdev_list; hpdev; hpdev = hpdev->next) { if (!strcmp(hpdev->devspec, devspec)) { rc = hp_remove_os_device(hpdev); break; } } if (rc) { say(ERROR, "Failed to hotplug remove %s\n", hpdev->path); break; } } closedir(d); return rc; } static int disable_os_hp_children(struct dr_node *phb) { struct hpdev *hpdev_list; int rc = 0; rc = get_os_hp_devices(&hpdev_list); if (rc) return -1; rc = disable_os_hp_children_recurse(phb, hpdev_list, phb->ofdt_path); free_hpdev_list(hpdev_list); return rc; } /** * remove_phb * * @returns 0 on success, !0 otherwise */ static int remove_phb(void) { struct dr_node *phb; struct dr_node *child; struct dr_node *hp_list = NULL; int rc = 0; phb = get_node_by_name(usr_drc_name, PHB_NODES); if (phb == NULL) { say(ERROR, "Could not find PHB %s\n", usr_drc_name); return RC_NONEXISTENT; } if (phb_has_display_adapter(phb)) { say(ERROR, "This PHB contains a display adapter, DLPAR " "remove of display adapters is not supported.\n"); goto phb_remove_error; } if (phb_has_dlpar_children(phb)) { rc = -1; goto phb_remove_error; } /* Now, disable any hotplug children */ hp_list = get_hp_nodes(); for (child = phb->children; child; child = child->next) { struct dr_node *slot; if (child->dev_type == PCI_HP_DEV) { rc = disable_hp_children(child->drc_name); if (rc) say(ERROR, "failed to disable hotplug children\n"); /* find dr_node corresponding to child slot's drc_name */ for (slot = hp_list; slot; slot = slot->next) if (!strcmp(child->drc_name, slot->drc_name)) break; /* release any hp children from the slot */ rc = release_hp_children_from_node(slot); if (rc && rc != -EINVAL) { say(ERROR, "failed to release hotplug children\n"); goto phb_remove_error; } } } /* If there are any directories under the phb left at this point, * they are OS hotplug devies. Note: this is different from DR * hotplug devices. This really occurs on systems that do not * support DR hotplug devices. The device tree does not get populated * with drc information for these devices and such they do not appear * on the list generated by the calls to get_node_* * * For these devices we simply hotplug remove them from the OS. */ rc = disable_os_hp_children(phb); if (rc) goto phb_remove_error; rc = dlpar_remove_slot(phb->drc_name); if (rc) { say(ERROR, "kernel remove failed for %s, rc = %d\n", phb->drc_name, rc); goto phb_remove_error; } rc = release_phb(phb); phb_remove_error: if (phb) free_node(phb); if (hp_list) free_node(hp_list); return rc; } /** * acquire_phb * */ static int acquire_phb(char *drc_name, struct dr_node **phb) { struct dr_connector drc; struct of_node *of_nodes; char path[DR_PATH_MAX]; int rc; rc = get_drc_by_name(drc_name, &drc, path, OFDT_BASE); if (rc) { say(ERROR, "Could not find drc index for %s, unable to add the" "PHB.\n", drc_name); return rc; } rc = acquire_drc(drc.index); if (rc) return rc; of_nodes = configure_connector(drc.index); if (of_nodes == NULL) { release_drc(drc.index, PHB_DEV); return -1; } rc = add_device_tree_nodes(path, of_nodes); free_of_node(of_nodes); if (rc) { say(ERROR, "add_device_tree_nodes failed at %s\n", path); release_drc(drc.index, PHB_DEV); return -1; } /* Now that the node has been added to the device-tree, retrieve it. * This also acts as a sanity check that everything up to this * point has succeeded. */ *phb = get_node_by_name(drc_name, PHB_NODES); if (*phb == NULL) { say(ERROR, "Could not get find \"%s\"\n", drc_name); /* or should we call release_drc? but need device type */ release_drc(drc.index, PHB_DEV); return -1; } return 0; } /** * add_phb * * @returns 0 on success, !0 otherwise */ static int add_phb(void) { struct dr_node *phb = NULL; int rc, n_children = 0; phb = get_node_by_name(usr_drc_name, PHB_NODES); if (phb) { say(ERROR, "PHB is already owned by this partition\n"); rc = RC_ALREADY_OWN; goto phb_add_error; } rc = acquire_phb(usr_drc_name, &phb); if (rc) return rc; rc = acquire_hp_children(phb->ofdt_path, &n_children); if (rc) { if (release_phb(phb)) { say(ERROR, "Unknown failure. Data may be out of sync " "and\nthe system may require a reboot.\n"); } goto phb_add_error; } rc = dlpar_add_slot(phb->drc_name); if (rc) { if (n_children) { if (release_hp_children(phb->drc_name)) { say(ERROR, "Unknown failure. Data may be out " "of sync and\nthe system may require " "a reboot.\n"); } } if (release_phb(phb)) { say(ERROR, "Unknown failure. Data may be out of sync " "and\nthe system may require a reboot.\n"); } goto phb_add_error; } if (n_children) { rc = enable_hp_children(phb->drc_name); if (rc) { say(ERROR, "Adapter configuration failed.\n"); if (release_hp_children(phb->drc_name)) { say(ERROR, "Unknown failure. Data may be out " "of sync and \nthe system may require " "a reboot.\n"); } if (dlpar_remove_slot(phb->drc_name)) { say(DEBUG, "remove %s from hotplug subsystem " "failed\n", phb->drc_name); say(ERROR, "Unknown failure. Data may be out " "of sync and \nthe system may require " "a reboot.\n"); } if (release_phb(phb)) { say(ERROR, "Unknown failure. Data may be out " "of sync and \nthe system may require " "a reboot.\n"); } } } phb_add_error: if (phb) free_node(phb); return rc; } int valid_phb_options(void) { /* The -s option can specify a drc name or drc index */ if (usr_drc_name && !strncmp(usr_drc_name, "0x", 2)) { usr_drc_index = strtoul(usr_drc_name, NULL, 16); usr_drc_name = NULL; } if (!usr_drc_name && !usr_drc_index) { say(ERROR, "A drc name or index must be specified\n"); return -1; } if ((usr_action != ADD) && (usr_action != REMOVE) && (usr_action != QUERY)) { say(ERROR, "The '-r', '-a', or '-Q' option must be specified " "for PHB operations.\n"); return -1; } return 0; } int drslot_chrp_phb(void) { int rc = -1; if (! phb_dlpar_capable()) { say(ERROR, "DLPAR PHB operations are not supported on" "this kernel."); return rc; } if (!usr_drc_name) { struct dr_connector *drc_list = get_drc_info(OFDT_BASE); usr_drc_name = drc_index_to_name(usr_drc_index, drc_list); if (!usr_drc_name) { say(ERROR, "Could not locate DRC name for DRC index: 0x%x", usr_drc_index); return -1; } } switch(usr_action) { case ADD: rc = add_phb(); break; case REMOVE: rc = remove_phb(); break; case QUERY: rc = query_phb(); break; default: rc = -1; } return rc; } powerpc-utils-1.3.4/src/drmgr/drslot_chrp_slot.c000066400000000000000000000173561315235264300220060ustar00rootroot00000000000000/** * @file drslot_chrp_slot.c * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include "dr.h" #include "drpci.h" #include "ofdt.h" static char *usagestr = "-c slot {-a | -r | -Q} -s "; void slot_usage(char **pusage) { *pusage = usagestr; } static int query_slot(struct dr_node *node) { if (node == NULL) return RC_NONEXISTENT; if (! node->is_owned) { say(ERROR, "%s not owned by partition\n", usr_drc_name); return RC_DONT_OWN; } if (is_display_adapter(node)) { say(ERROR, "Display adapters adre not supported by drmgr.\n"); return RC_IN_USE; } /* Special case for HMC */ return RC_LINUX_SLOT; } /** * release_slot * */ static int release_slot(struct dr_node *slot) { int rc; rc = release_drc(slot->drc_index, slot->dev_type); if (rc) return rc; rc = remove_device_tree_nodes(slot->ofdt_path); if (rc) { acquire_drc(slot->drc_index); return rc; } return rc; } /** * remove_slot * */ static int remove_slot(struct dr_node *node) { int rc,rc2; if (is_display_adapter(node)) { say(ERROR, "DLPAR of display adapters is not supported.\n"); return -1; } rc = disable_hp_children(node->drc_name); if (rc) say(ERROR, "failed to disable hotplug children\n"); rc = release_hp_children(node->drc_name); if (rc && rc != -EINVAL) { say(ERROR, "failed to release hotplug children\n"); return rc; } say(DEBUG, "The sensor-state of drc_index 0x%x is %d\n", node->drc_index, dr_entity_sense(node->drc_index)); /* need to remove slot from sysfs which will * "Hot unplug" the slot from pci world. unmap_bus_range will be * done here also. */ rc = dlpar_remove_slot(node->drc_name); if (rc) { say(DEBUG, "remove %s from hotplug subsystem failed\n", node->drc_name); say(ERROR, "Unknown failure. Data may be out of sync and \n" "the system may require a reboot.\n"); return rc; } rc = release_slot(node); if (rc) { int num_acquired = 0; // try to restore to previous state rc2 = acquire_hp_children(node->ofdt_path, &num_acquired); if (rc2 && rc2 != -EINVAL) { say(ERROR, "Unknown failure %d. Data may be out of " "sync and\nthe system may require a reboot.\n", rc2); return rc; } rc2 = dlpar_add_slot(node->drc_name); if (rc2) { say(ERROR, "Unknown failure %d. Data may be out of " "sync and\nthe system may require a reboot.\n", rc2); return rc; } if (num_acquired) { rc2 = enable_hp_children(node->drc_name); if (rc2) { say(ERROR, "failed to re-enable hotplug " "children. %d\n", rc2); return rc; } } } return rc; } /** * acquire_slot * */ static int acquire_slot(char *drc_name, struct dr_node **slot) { struct dr_connector drc; struct of_node *of_nodes; char path[DR_PATH_MAX]; int rc; rc = get_drc_by_name(drc_name, &drc, path, OFDT_BASE); if (rc) { say(ERROR, "Could not find drc index for %s, unable to add the" "slot.\n", drc_name); return rc; } if (!strncmp(drc.type, "display", 7)) { say(ERROR, "DLPAR of display adapters is not supported.\n"); return -1; } rc = acquire_drc(drc.index); if (rc) return rc; of_nodes = configure_connector(drc.index); if (of_nodes == NULL) { release_drc(drc.index, PCI_DLPAR_DEV); return -1; } rc = add_device_tree_nodes(path, of_nodes); free_of_node(of_nodes); if (rc) { say(ERROR, "add_device_tree_nodes failed at %s\n", path); release_drc(drc.index, PCI_DLPAR_DEV); return -1; } /* Now that the node has been added to the device-tree, retrieve it. * This also acts as a sanity check that everything up to this * point has succeeded. */ *slot = get_node_by_name(drc_name, PCI_NODES | VIO_NODES); if (*slot == NULL) { say(ERROR, "Could not get find \"%s\"\n", drc_name); /* or should we call release_drc? but need device type */ release_drc(drc.index, PHB_DEV); return -1; } return 0; } /** * add_slot * */ static int add_slot() { struct dr_node *node = NULL; int rc, n_children = 0; rc = acquire_slot(usr_drc_name, &node); if (rc) return rc; /* For PCI nodes */ if (node->dev_type == PCI_DLPAR_DEV) { rc = acquire_hp_children(node->ofdt_path, &n_children); if (rc) { if (release_slot(node)) { say(ERROR, "Unknown failure. Data may be out " "of sync and\nthe system may require " "a reboot.\n"); } goto slot_add_exit; } } /* Need to add node into sysfs which will "Hot plug" the node into * pci world. */ rc = dlpar_add_slot(node->drc_name); if (rc) { if (n_children) { if (release_hp_children(node->drc_name)) { say(ERROR, "Unknown failure. Data may be out " "of sync and\nthe system may require " "a reboot.\n"); } } if (release_slot(node)) { say(ERROR, "Unknown failure. Data may be out of sync " "and\nthe system may require a reboot.\n"); } } if (n_children) { rc = enable_hp_children(node->drc_name); if (rc) { say(ERROR, "Configure adapter failed.\n"); if (release_hp_children(node->drc_name)) { say(ERROR, "Unknown failure. Data may be out " "of sync and\nthe system may require " "a reboot.\n"); } if (dlpar_remove_slot(node->drc_name)) { say(DEBUG, "remove %s from hotplug subsystem " "failed\n", node->drc_name); say(ERROR, "Unknown failure. Data may be out " "of sync and\nthe system may require " "a reboot.\n"); } if (release_slot(node)) { say(ERROR, "Unknown failure. Data may be out " "of sync and\nthe system may require " "a reboot.\n"); } goto slot_add_exit; } say(DEBUG, "adapter in node[%s] has been configured.\n", node->drc_name); } slot_add_exit: if (node) free_node(node); return rc; } int valid_slot_options(void) { if (!usr_drc_name) { say(ERROR, "A drc name must be specified\n"); return -1; } if ((usr_action != ADD) && (usr_action != REMOVE) && (usr_action != QUERY)) { say(ERROR, "The '-r', '-a', or '-Q' option must be specified " "for slot operations.\n"); return -1; } return 0; } int drslot_chrp_slot(void) { struct dr_node *node; int rc; if (! slot_dlpar_capable()) { say(ERROR, "DLPAR slot operations are not supported on" "this kernel."); return -1; } node = get_node_by_name(usr_drc_name, PCI_NODES | VIO_NODES); switch (usr_action) { case ADD: if (node && node->is_owned) { say(ERROR, "partition already owns %s\n", usr_drc_name); rc = RC_ALREADY_OWN; } else { free_node(node); node = NULL; rc = add_slot(); } break; case REMOVE: if (node == NULL) { say(ERROR, "%s does not exist\n", usr_drc_name); rc = RC_NONEXISTENT; } else { if (! node->is_owned) { say(ERROR, "%s not owned by partition\n", usr_drc_name); rc = RC_DONT_OWN; } else rc = remove_slot(node); } break; case QUERY: rc = query_slot(node); break; default: rc = -1; } free_node(node); return rc; } powerpc-utils-1.3.4/src/drmgr/lsslot.c000066400000000000000000000570731315235264300177420ustar00rootroot00000000000000/** * @file lsslot.c * * Copyright (C) IBM Corporation 2005 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "rtas_calls.h" #include "drpci.h" #include "dr.h" #include "drmem.h" #include "pseries_platform.h" #include "options.c" int output_level = 0; int log_fd = 0; extern int lsslot_chrp_cpu(void); /** * struct print_node * @ brief struct to track list of nodes to be printed. */ struct print_node { struct dr_node *node; /**< node information */ char *desc; /**< message description from catalog*/ struct print_node *next; }; struct print_node *print_list = NULL; /* These are used to determine column widths for output */ uint32_t max_sname = 0; /* Max size of node location codes */ uint32_t max_desc = 0; /* Max size of node descriptions */ #define LNAME_SIZE 12 /* xxxx:xx:xx.x */ /** * usage * @brief Print the usage message and exit */ static void usage(void) { fprintf(stderr, "Usage: lsslot [-c | -a | -b | -p | -o | -s ]" "[-F | -d | -w]\n"); fprintf(stderr, " -c \n"); fprintf(stderr, " Display the slots of the specified " "connector type. The valid\n"); fprintf(stderr, " connector types are \"pci\" for " "hotplug PCI slots, \"slot\" for\n"); fprintf(stderr, " logical slots, \"phb\" for PHB's, " "\"port\" for LHEA ports, \"mem\"\n"); fprintf(stderr, " for memory, and \"cpu\" " "for cpu's. The default\n"); fprintf(stderr, " is \"slot\" if no -c option is " "specified.\n"); fprintf(stderr, " -a Display available slots, valid for " "\"pci\" slots only.\n"); fprintf(stderr, " -b Display cpu's and caches, valid for " "\"cpu\" only.\n"); fprintf(stderr, " -o Display occupied slots, valid for " "\"pci\" slots only.\n"); fprintf(stderr, " -p Display caches, valid for \"cpu\" " "slots only.\n"); fprintf(stderr, " -s [ | ]\n"); fprintf(stderr, " Display characteristics of the " "specified slot or the LMB\n"); fprintf(stderr, " associated with drc index.\n"); fprintf(stderr, " -F \n"); fprintf(stderr, " Specified a single character to " "delimit the output. The \n"); fprintf(stderr, " heading is not displayed and the " "columns are delimited by the\n"); fprintf(stderr, " specified character.\n"); fprintf(stderr, " -d \n"); fprintf(stderr, " Enable debugging output. When " "displaying LMB information\n"); fprintf(stderr, " this will enable printing of LMBs " "not owned by the system.\n"); fprintf(stderr, " -w \n"); fprintf(stderr, " Specify a timeout when attempting to " "acquire locks.\n"); exit (1); } /** * free_print_nodes * @brief Free all of the items on the print_list * * NOTE: We do not free the node pointed to by the print_node, these * nodes exist on other lists and should be free when those lists are * cleaned up. */ static void free_print_list(void) { struct print_node *pnode; while (print_list != NULL) { pnode = print_list; print_list = print_list->next; free(pnode); } } /** * loc_code_cmp * * loc_code_cmp is used to sort a list of nodes based on their location code. * location codes take the form of * * pn[.n][- or /]pn[.n][- or /] ... * * where p is an alpha location type prefix and n is an instance * number (see RS/6000 Processor Architecture, Location Code Format). * The location code has to be parsed by hyphens, if any. * * @param node1 * @param node2 * @returns 0 if (node1 = node2), -1 if (node1 < node2), 1 if (node1 > node2) */ static int loc_code_cmp(char *node1, char *node2) { char save_n1[64],save_n2[64]; /* for holding node1 and node2 */ char *n1, *n2; ulong nbr1,nbr2; /* hex numbers representing location */ size_t dash_cnt; n1 = save_n1; n2 = save_n2; while (strlen(node1) && strlen(node2)) { dash_cnt = strcspn(node1, "-"); strncpy(n1, node1, dash_cnt); *(n1 + dash_cnt) = '\0'; node1 += dash_cnt; dash_cnt = strcspn(node2, "-"); strncpy(n2, node2, dash_cnt); *(n2 + dash_cnt) = '\0'; node2 += dash_cnt; /* First look at the location type */ if (*n1 < *n2) return -1; else if (*n1 > *n2) return 1; n1++; n2++; /* get the hex value of the instance number */ nbr1 = strtoul(n1, &n1, 16); nbr2 = strtoul(n2, &n2, 16); if (nbr1 < nbr2) return -1; else if (nbr1 > nbr2) return 1; if (strlen(n1) && strlen(n2)) { /* If both strings have more characters, first * determine if they are the same. */ if (*n1 == *n2) { /* If they're the same, compare whatever * follows the delimiter. The slash will have * an alpha and hex following it, while the dot * will have just a hex following it. */ if (*n1 == '/') { n1++; n2++; /* First look at the location type, * which is a single character. */ if (*n1 < *n2) return -1; else if (*n1 > *n2) return 1; } n1++; n2++; /* get the hex value of the instance number */ nbr1 = strtoul(n1, &n1, 16); nbr2 = strtoul(n2, &n2, 16); if (nbr1 < nbr2) return -1; else if (nbr1 > nbr2) return 1; } /* The delimiters are not the same, so check * what they are and return results based on * order of precedence : slash, then dot. */ else if (*n1 == '/') return -1; else if (*n2 == '/') return 1; } /* If we've reached here, either the strings are * the same or one of the strings has run out. * If only one has run out, we can return. */ if (strlen(n1) < strlen(n2)) return -1; else if (strlen(n1) > strlen(n2)) return 1; /* If we get here, we've determined everything * in the n1 and n2 strings are the same. Now * increment past the dash, if any, in the * original strings. */ if (*node1 == '-') node1++; if (*node2 == '-') node2++; } if (strlen(node1)) return 1; else if (strlen(node2)) return -1; return 0; } /** * insert_print_node * * Insert the node into the list of nodes. The list is * sorted by location codes. * * @param node dlpar node to add */ void insert_print_node(struct dr_node *node) { struct print_node *pnode; pnode = zalloc(sizeof(*pnode)); if (pnode == NULL) { fprintf(stderr, "Could not allocate print node for drc %x\n", node->drc_index); return; } pnode->node = node; pnode->desc = node_type(node); pnode->next = NULL; max_sname = MAX(max_sname, strlen(node->drc_name)); max_desc = MAX(max_desc, strlen(pnode->desc)); /* Insert the new print_node into the sorted list of print nodes */ if (print_list == NULL) { print_list = pnode; return; } if (loc_code_cmp(print_list->node->drc_name, pnode->node->drc_name) > 0) { /* The location code for the new node is less than that * of the first node so insert the new node at the front. */ pnode->next = print_list; print_list = pnode; } else { /* Find the first node in the list where the new node's * location code is less than the existing node's location * code and insert the new node before that node. */ struct print_node *last; last = print_list; while (last->next != NULL) { if (loc_code_cmp(last->next->node->drc_name, pnode->node->drc_name) > 0) { pnode->next = last->next; last->next = pnode; break; } last = last->next; } /* Put the new node at the end of the list if itslocation * code is not less than any other node's location code. */ if (last->next == NULL) last->next = pnode; } } /** * print_drslot_line * @brief print a SLOT entry * * @param pnode print_node to print * @param fmt output format string */ static void print_drslot_line(struct print_node *pnode, char *fmt) { struct dr_node *node = pnode->node; char *linux_dname; /* Print node name, description, and linux name */ if (node->sysfs_dev_path[0]) linux_dname = strrchr(node->sysfs_dev_path, '/') + 1; else linux_dname = "?"; printf(fmt, node->drc_name, pnode->desc, linux_dname); /* If no node info, then it is an empty node */ if (node->dev_type == HEA_DEV) { struct dr_node *port = node->children; if (!port) { printf("Empty\n"); } else { int first = 1; for (port = node->children; port; port = port->next) { printf("%s%s ", first ? "" : ",", port->drc_name); first = 0; } printf("\n"); } } else { if (node->ofdt_dname[0] == '\0') printf("Empty\n"); else printf("%s\n", node->ofdt_dname); } } /** * print_phpslot_line * @brief print a hotplug slot entry * * @param pnode print_node to print * @param fmt output format string */ static void print_phpslot_line(struct print_node *pnode, char *fmt) { struct dr_node *child; struct dr_node *node = pnode->node; /* Print node name and description */ printf(fmt, node->drc_name, pnode->desc); /* If no node info, then it is an empty node */ if (! node->children) printf("Empty\n"); else { /* Else we want to print the device names */ for (child = node->children; child; child = child->next) { if (child != node->children) printf(fmt, "", ""); if (child->sysfs_dev_path[0]) printf("%s\n", strrchr(child->sysfs_dev_path, '/') + 1); else if (child->ofdt_dname[0]) printf("%s\n", child->ofdt_dname); else printf("?\n"); } } } /** * parse_options * @brief parse the command line options and fillin the options struct * * @param argc * @param argv */ static void parse_options(int argc, char *argv[]) { int c; while ((c = getopt(argc, argv, "abc:d:F:ops:w:")) != EOF) { switch (c) { case 'a': show_available_slots = 1; break; case 'b': show_cpus_and_caches = 1; break; case 'c': usr_drc_type = to_drc_type(optarg); if (usr_drc_type == DRC_TYPE_NONE) { printf("\nThe specified connector type " "is invalid.\n\n"); usage(); } break; case 'd': set_output_level(atoi(optarg)); break; case 'F': usr_delimiter = optarg; /* make sure the arg specified is only one character * long and is not the '%' character which would * confuse the formatting. */ if ((usr_delimiter[1] != '\0') || (usr_delimiter[0] == '%')) { say(ERROR, "You may specify only one character " "for the -F option,\nand it must not " "be the %% character.\n"); exit(1); } break; case 'o': show_occupied_slots = 1; break; case 'p': show_caches = 1; break; case 's': usr_drc_name = optarg; break; case 'w': usr_timeout = strtoul(optarg, NULL, 10) * 60; if (usr_timeout < 0) usage(); break; default: usage(); break; } } /* Validate the options */ switch (usr_drc_type) { case DRC_TYPE_SLOT: case DRC_TYPE_PORT: /* The a,b,o,p flags are not valid for slot */ if (show_available_slots || show_cpus_and_caches || show_occupied_slots || show_caches) usage(); /* Now, to make the code work right (which is wrong) we * need to set the a and o flags if the s flag wasn't * specified. */ if (!usr_drc_name) { show_available_slots = 1; show_occupied_slots = 1; } break; case DRC_TYPE_PHB: /* The a,b,F,o,p options are not valid for phb */ if (show_available_slots || show_cpus_and_caches || usr_delimiter || show_occupied_slots || show_caches) usage(); break; case DRC_TYPE_PCI: /* The b,p flags are valid for pci */ if (show_cpus_and_caches || show_caches) usage(); /* If no flags specified, then set show_available_slots and * show_occupied_slots so that all slots will be formatted * in the output */ if ((!show_available_slots) && (!show_occupied_slots) && !usr_drc_name) { show_available_slots = 1; show_occupied_slots = 1; } break; case DRC_TYPE_CPU: /* The a,F,o,s options are not valid for cpu */ if (show_available_slots || usr_delimiter || show_occupied_slots || usr_drc_name) usage(); if (show_cpus_and_caches && show_caches) { say(ERROR, "You cannot specify both the -b and -p " "options.\n"); usage(); } break; default: break; } } /** * lsslot_chrp_pci * @brief main entry point for lsslot command * * @returns 0 on success, !0 otherwise */ int lsslot_chrp_pci(void) { struct dr_node *all_nodes; /* Pointer to list of all node info */ struct dr_node *node; /* Used to traverse list of node info */ char fmt[128]; struct print_node *p; char *sheading = "# Slot"; /* Used in printing headers */ char *dheading = "Description"; /* Used in printing headers */ char *lheading = "Device(s)"; /* Used in printing headers */ char *lname_header = "Linux Name"; int rc = 0; /* Set initial column sizes */ max_sname = MAX(max_sname, strlen(sheading)); max_desc = MAX(max_desc, strlen(dheading)); /* Get all of node(logical DR or PCI) node information */ if (usr_drc_type == DRC_TYPE_PCI) all_nodes = get_hp_nodes(); else all_nodes = get_dlpar_nodes(PCI_NODES | VIO_NODES | HEA_NODES); /* If nothing returned, then no hot plug node */ if (all_nodes == NULL) { if (usr_drc_type == DRC_TYPE_PCI) say(ERROR, "There are no PCI hot plug slots on " "this system.\n"); else say(ERROR, "There are no DR slots on this system.\n"); return 0; } print_node_list(all_nodes); /* Otherwise, run through the node list looking for the nodes * we want to print */ for (node = all_nodes; node; node = node->next) { if (! node->is_owned || node->skip) continue; if (usr_drc_name) { if (cmp_drcname(node->drc_name, usr_drc_name)) insert_print_node(node); } /* If aflag and slot is empty, then format the slot */ else if (show_available_slots && (node->children == NULL)) insert_print_node(node); /* If oflag and slot occupied, then format the slot */ else if (show_occupied_slots && (node->children != NULL)) insert_print_node(node); } if (print_list == NULL) { /* If nothing to print, display message based on if * user specified a slot or a device name. */ if (!usr_drc_name) { say(ERROR, "The specified PCI slot is either invalid\n" "or does not support hot plug operations.\n"); rc = 1; } goto lsslot_pci_exit; } /* This creates a format string so that slot name and description * prints out in the required field width. When the -F flag is * specified, the format string contains the delimiting character * which the user specified at the command line. */ if (usr_drc_type == DRC_TYPE_SLOT) { if (usr_delimiter) sprintf(fmt, "%s%s%s%s%s%s", "%s", usr_delimiter, "%s", usr_delimiter, "%s", usr_delimiter); else { sprintf(fmt, "%%-%ds%%-%ds%%-%ds", max_sname + 2, max_desc + 2, LNAME_SIZE + 2); /* Print out the header. */ printf(fmt, sheading, dheading, lname_header); printf("%s\n", lheading); } } else { if (usr_delimiter) sprintf(fmt, "%s%s%s%s", "%s", usr_delimiter, "%s", usr_delimiter); else { sprintf(fmt, "%%-%ds%%-%ds", max_sname + 2, max_desc + 2); /* Print out the header. */ printf(fmt, sheading, dheading); printf("%s\n", lheading); } } /* Now run through the list of slots we actually want to print */ for (p = print_list; p != NULL; p = p->next) { if (! p->node->is_owned) { /* skip it, because the partition doesn't own it */ continue; } if (usr_drc_type == DRC_TYPE_SLOT) print_drslot_line(p, fmt); else print_phpslot_line(p, fmt); } lsslot_pci_exit: free_print_list(); free_node(all_nodes); return rc; } /** * lsslot_chrp_phb * @brief Main entry point for handling lsslot_chrp_phb command * * @returns 0 on success, !0 otherwise */ int lsslot_chrp_phb(void) { struct dr_node *phb_list; struct dr_node *phb; phb_list = get_dlpar_nodes(PHB_NODES); if (phb_list == NULL) return -1; /* display header */ printf("%-10s%-20s %s\n", "PHB name", "OFDT Name", "Slot(s) Connected"); for (phb = phb_list; phb; phb = phb->next) { struct dr_node *child; char *name; int printed_count = 0; if (usr_drc_name && strcmp(usr_drc_name, phb->drc_name)) continue; name = strstr(phb->ofdt_path, "/pci"); printf("%-10s%-20s ", phb->drc_name, name); for (child = phb->children; child; child = child->next) { if (! child->is_owned) continue; if (printed_count == 0) printf("%s\n", child->drc_name); else printf("%-30s %s\n", "", child->drc_name); printed_count++; } if (printed_count) printf("\n"); else printf("\n\n"); } free_node(phb_list); return 0; } int print_drconf_mem(struct lmb_list_head *lmb_list) { struct dr_node *lmb; struct mem_scn *scn; int scn_offset = strlen("/sys/devices/system/memory/memory"); char *aa_buf; __be32 *aa; int aa_size, aa_list_sz; int i, rc; uint32_t drc_index = 0; aa_size = get_property_size(DYNAMIC_RECONFIG_MEM, "ibm,associativity-lookup-arrays"); aa_buf = zalloc(aa_size); rc = get_property(DYNAMIC_RECONFIG_MEM, "ibm,associativity-lookup-arrays", aa_buf, aa_size); if (rc) { say(ERROR, "Could not get associativity information.\n"); return -1; } aa = (__be32 *)aa_buf; /* skip past the number of associativity lists */ aa++; aa_list_sz = be32toh(*aa++); if (usr_drc_name) drc_index = strtol(usr_drc_name, NULL, 0); printf("Dynamic Reconfiguration Memory (LMB size 0x%x)\n", lmb_list->lmbs->lmb_size); for (lmb = lmb_list->lmbs; lmb; lmb = lmb->next) { int first = 1; int aa_start, aa_end; if (drc_index && drc_index != lmb->drc_index) continue; else if ((output_level < DEBUG) && !lmb->is_owned) continue; printf("%s: %s\n", lmb->drc_name, lmb->is_owned ? "" : "Not Owned"); printf(" DRC Index: %x Address: %lx\n", lmb->drc_index, lmb->lmb_address); printf(" Removable: %s Associativity: ", lmb->is_removable ? "Yes" : "No "); if (lmb->lmb_aa_index == 0xffffffff) { printf("Not Set\n"); } else { printf("(index: %d) ", lmb->lmb_aa_index); aa_start = lmb->lmb_aa_index * aa_list_sz; aa_end = aa_start + aa_list_sz; for (i = aa_start; i < aa_end; i++) printf("%d ", be32toh(aa[i])); printf("\n"); } if (lmb->is_owned) { printf(" Section(s):"); for (scn = lmb->lmb_mem_scns; scn; scn = scn->next) { if (first) { printf(" %s", &scn->sysfs_path[scn_offset]); first = 0; } else printf(", %s", &scn->sysfs_path[scn_offset]); } printf("\n"); } } free(aa_buf); return 0; } int lsslot_chrp_mem(void) { struct lmb_list_head *lmb_list; struct dr_node *lmb; struct mem_scn *scn; int scn_offset = strlen("/sys/devices/system/memory/memory"); int lmb_offset = strlen(OFDT_BASE); lmb_list = get_lmbs(LMB_NORMAL_SORT); if (lmb_list == NULL || lmb_list->lmbs == NULL) { free_lmbs(lmb_list); return -1; } if (lmb_list->drconf_buf) { print_drconf_mem(lmb_list); } else { printf("lmb size: 0x%x\n", lmb_list->lmbs->lmb_size); printf("%-20s %-5s %c %s\n", "Memory Node", "Name", 'R', "Sections"); printf("%-20s %-5s %c %s\n", "-----------", "----", '-', "--------"); for (lmb = lmb_list->lmbs; lmb; lmb = lmb->next) { int first = 1; if (!lmb->is_owned) continue; if (!lmb_list->drconf_buf) printf("%-20s ", &lmb->ofdt_path[lmb_offset]); printf("%-5s %c ", lmb->drc_name, lmb->is_removable ? 'Y' : 'N'); for (scn = lmb->lmb_mem_scns; scn; scn = scn->next) { if (first) { printf(" %s", &scn->sysfs_path[scn_offset]); first = 0; } else printf(", %s", &scn->sysfs_path[scn_offset]); } printf("\n"); } } free_lmbs(lmb_list); return 0; } /** * lsslot_chrp_port * @brief Print LHEA ports based on command line options * * @returns 0 on success, !0 otherwise */ int lsslot_chrp_port(void) { struct dr_node *all_nodes; /* Pointer to list of all node info */ struct dr_node *node; /* Used to traverse list of node info */ struct dr_node *child; /* Used to traverse list of children */ char fmt[128]; struct print_node *p; char *sheading = "LHEA port name"; /* Used in printing headers */ char *dheading = "Description"; /* Used in printing headers */ int rc = 0; /* Set initial column sizes */ max_sname = MAX(max_sname, strlen(sheading)); max_desc = MAX(max_desc, strlen(dheading)); all_nodes = get_dlpar_nodes(HEA_NODES); /* If nothing returned, then no hot plug node */ if (all_nodes == NULL) { say(ERROR, "There are no LHEA ports on this system.\n"); return 1; } print_node_list(all_nodes); /* Otherwise, run through the node list looking for the nodes * we want to print */ for (node = all_nodes; node; node = node->next) { if (node->skip) continue; for (child = node->children; child; child = child->next) { if (child->skip) continue; /* If there is a search parameter, add matching ports. * If there is no search, add all the ports. */ if (usr_drc_name) { if (cmp_drcname(child->drc_name, usr_drc_name)) insert_print_node(child); } else insert_print_node(child); } } if (print_list == NULL) { /* If nothing to print, display message based on if * user specified a slot or a device name. */ if (usr_drc_name) { say(ERROR, "The specified port was not found.\n"); rc = 1; } goto lsslot_port_exit; } /* This creates a format string so that port name and description * prints out in the required field width. When the -F flag is * specified, the format string contains the delimiting character * which the user specified at the command line. */ if (usr_delimiter) sprintf(fmt, "%s%s%s\n", "%s", usr_delimiter, "%s"); else { sprintf(fmt, "%%-%ds%%-%ds\n", max_sname + 2, max_desc + 2); /* Print out the header. */ printf(fmt, sheading, dheading); } /* Now run through the list of ports we actually want to print */ for (p = print_list; p != NULL; p = p->next) { printf(fmt, p->node->drc_name, p->desc); } lsslot_port_exit: free_print_list(); free_node(all_nodes); return rc; } int main(int argc, char *argv[]) { int rc; switch (get_platform()) { case PLATFORM_UNKNOWN: case PLATFORM_POWERNV: fprintf(stderr, "%s: is not supported on the %s platform\n", argv[0], platform_name); exit(1); } /* make sure that we're running on the proper platform. */ if (! valid_platform("chrp")) exit(1); /* default to DRSLOT type */ usr_drc_type = DRC_TYPE_SLOT; parse_options(argc, argv); rc = dr_lock(); if (rc) { say(ERROR, "Unable to obtain Dynamic Reconfiguration lock. " "Please try command again later.\n"); exit(1); } switch (usr_drc_type) { case DRC_TYPE_SLOT: case DRC_TYPE_PCI: rc = lsslot_chrp_pci(); break; case DRC_TYPE_PHB: rc = lsslot_chrp_phb(); break; case DRC_TYPE_CPU: rc = lsslot_chrp_cpu(); break; case DRC_TYPE_MEM: rc = lsslot_chrp_mem(); break; case DRC_TYPE_PORT: rc = lsslot_chrp_port(); break; default: break; } free_drc_info(); dr_unlock(); exit(rc); } powerpc-utils-1.3.4/src/drmgr/lsslot_chrp_cpu.c000066400000000000000000000074531315235264300216220ustar00rootroot00000000000000/** * @file lsslot_chrp_cpu.c * @brief routines for lsslot_chrp_cpu command * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "dr.h" #include "drcpu.h" /** * list_cpus * @brief list all cpus * */ void list_cpus(struct dr_info *dr_info) { struct dr_node *cpu; struct thread *t; char *fmt_s = "%-11s%-20s%-13s%-13s\n"; char *fmt = "%-11s%-20s%-12x"; printf(fmt_s, "drc-name", "OFDT-node", "drc_index", "thread id(s)"); for (cpu = dr_info->all_cpus; cpu != NULL; cpu = cpu->next) { if (cpu->is_owned || output_level >= DEBUG) { printf(fmt, cpu->drc_name, cpu->name ? cpu->name : "--", cpu->drc_index); for (t = cpu->cpu_threads; t; t = t->sibling) printf(" %x", t->id); printf("\n"); } } return; } /** * list_caches * @brief list all caches * */ void list_caches(struct dr_info *dr_info) { struct cache_info *cache = NULL; printf("cache-name phandle\n"); for (cache = dr_info->all_caches; cache != NULL; cache = cache->next) printf("%-21s%-8x\n", cache->name, cache->phandle); return; } /** * list_all_cpus_and_caches * @bried list all of the cpus and caches * */ void list_cpus_and_caches(struct dr_info *dr_info) { struct dr_node *cpu = NULL; struct thread *t; int thread_id_field_sz = 17; char *fmt_s = "%-10s%-18s%-11s%-17s%-15s%-15s\n"; char *fmt = "%-10s%-18s%-11x%"; char *fmt_caches = "%-15s%-15s\n"; printf(fmt_s, "drc-name", "OFDT-node", "drc_index", "thread id(s)", "l2-cache", "l3-cache"); for (cpu = dr_info->all_cpus; cpu != NULL; cpu = cpu->next) { int i, count = 0; struct cache_info *l2_cache = NULL; struct cache_info *l3_cache = NULL; printf(fmt, cpu->drc_name, cpu->name ? cpu->name : "--", cpu->drc_index); for (t = cpu->cpu_threads; t; t = t->sibling) { printf("%x ", t->id); count += 2; } /* pad out the thread ids field */ for (i = count; i < thread_id_field_sz; i++) printf(" "); l2_cache = cpu_get_dependent_cache(cpu, dr_info); if (l2_cache) l3_cache = cache_get_dependent_cache(l2_cache, dr_info); printf(fmt_caches, (l2_cache ? l2_cache->name : "N/A"), (l3_cache ? l3_cache->name : "N/A")); } return; } /** * lsslot_chrp_cpu * @brief main entry point for lsslot_chrp_cpu command * * @returns 0 on success, !0 otherwise */ int lsslot_chrp_cpu(void) { struct stat sb; struct dr_info dr_info; /* Mask signals so the command doesn't get interrupted */ if (sig_setup()) { fprintf(stderr, "\nUnknown failure. Rerun the command.\n\n"); return 1; } /* Check if this is an LPAR System. */ if (stat("/proc/device-tree/ibm,lpar-capable", &sb)) { fprintf(stderr, "\nThe system is not LPAR.\n\n"); return 1; } if (init_cpu_drc_info(&dr_info)) { fprintf(stderr, "\nThere are no dynamically reconfigurable " "CPUs on this system.\n\n"); return 1; } if (show_cpus_and_caches) list_cpus_and_caches(&dr_info); else if (show_caches) list_caches(&dr_info); else list_cpus(&dr_info); free_cpu_drc_info(&dr_info); return 0; } powerpc-utils-1.3.4/src/drmgr/ofdt.h000066400000000000000000000110111315235264300173410ustar00rootroot00000000000000/** * @file ofdt.h * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _OFDT_H_ #define _OFDT_H_ #define DRC_STR_MAX 48 #define OFDT_BASE "/proc/device-tree" #define CPU_OFDT_BASE "/proc/device-tree/cpus" #define DR_PATH_MAX 1024 #define DR_STR_MAX 128 #define MAX_CPU_INTSERV_NUMS 8 struct dr_connector { char name[DRC_STR_MAX]; char type[DRC_STR_MAX]; char ofdt_path[DR_PATH_MAX]; unsigned int index; unsigned int powerdomain; struct dr_connector *next; struct dr_connector *all_next; }; struct mem_scn { struct mem_scn *next; int removable; uint64_t phys_addr; char sysfs_path[DR_PATH_MAX]; }; struct thread { int id; /* linux "logical" cpu id */ uint32_t phys_id; char path[DR_PATH_MAX]; /* node path */ struct thread *next; struct thread *sibling; struct dr_node *cpu; }; /* This structure represents a DR-capable node. Data from * the Open Firmware tree is gathered here. There is a pointer * to a linked list of the OF nodes representing the device(s) * connected to this slot (if they exist) */ struct dr_node { struct dr_node *next; struct dr_node *children; uint32_t drc_index; char drc_type[DR_STR_MAX]; char drc_name[DR_STR_MAX]; uint32_t drc_power; char loc_code[DR_STR_MAX]; char ofdt_path[DR_PATH_MAX]; char *name; /* This will just point to the name part of * the ofdt_path buffer, no need to free */ char ofdt_dname[DR_STR_MAX]; char sysfs_dev_path[DR_PATH_MAX]; uint32_t dev_type; uint32_t is_owned:1; uint32_t skip:1; uint32_t unusable:1; uint32_t is_removable:1; uint32_t post_replace_processing:1; uint32_t reserved:27; union { struct mem_info { uint64_t _address; uint32_t _lmb_size; uint32_t _lmb_aa_index; struct mem_scn *_mem_scns; struct of_node *_of_node; } _smem; #define lmb_address _node_u._smem._address #define lmb_size _node_u._smem._lmb_size #define lmb_aa_index _node_u._smem._lmb_aa_index #define lmb_mem_scns _node_u._smem._mem_scns #define lmb_of_node _node_u._smem._of_node struct hea_info { uint _port_no; uint _port_tenure; }_shea; #define hea_port_no _node_u._shea._port_no #define hea_port_tenure _node_u._shea._port_tenure struct pci_info { uint _vendor_id; /* vendor ID */ uint _device_id; /* device ID */ uint _class_code; /* class code */ }_spci; #define pci_vendor_id _node_u._spci._vendor_id #define pci_device_id _node_u._spci._device_id #define pci_class_code _node_u._spci._class_code struct phb_info { char _ic_ofdt_path[DR_PATH_MAX]; }_sphb; #define phb_ic_ofdt_path _node_u._sphb._ic_ofdt_path struct cpu_info { uint32_t _intserv_nums[MAX_CPU_INTSERV_NUMS]; int _nthreads; uint32_t _reg; uint32_t _l2cache; struct thread *_threads; }_scpu; #define cpu_intserv_nums _node_u._scpu._intserv_nums #define cpu_nthreads _node_u._scpu._nthreads #define cpu_reg _node_u._scpu._reg #define cpu_l2cache _node_u._scpu._l2cache #define cpu_threads _node_u._scpu._threads } _node_u; }; static inline void set_drc_info(struct dr_node *node, struct dr_connector *drc) { node->drc_index = drc->index; node->drc_power = drc->powerdomain; snprintf(node->drc_name, DR_STR_MAX, "%s", drc->name); snprintf(node->drc_type, DR_STR_MAX, "%s", drc->type); } struct dr_connector *get_drc_info(const char *); void free_drc_info(void); char *of_to_full_path(const char *); /* Search types for search_drc_list() */ #define DRC_NAME 0 #define DRC_TYPE 1 #define DRC_INDEX 2 #define DRC_POWERDOMAIN 3 struct dr_connector *search_drc_list(struct dr_connector *, struct dr_connector *, int, void *); int get_my_drc_index(char *, uint32_t *); int drc_name_to_index(const char *, struct dr_connector *); char * drc_index_to_name(uint32_t, struct dr_connector *); int get_drc_by_name(char *, struct dr_connector *, char *, char *); #endif /* _OFDT_H_ */ powerpc-utils-1.3.4/src/drmgr/options.c000066400000000000000000000036361315235264300201110ustar00rootroot00000000000000/** * @file options.c * * Copyright (C) IBM Corporation 2016 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Global User Specifications */ enum drmgr_action usr_action = NONE; /* default is to do slot identification, unless the drmgr -I * option is specified. */ int usr_slot_identification = 1; /* timeout specified with the -w option */ int usr_timeout = 0; /* user specified drc name */ char *usr_drc_name = NULL; /* user specified drc index */ uint32_t usr_drc_index = 0; /* default to prompting the user for pci hotplug operations * unless the drmgr -n option is specified. */ int usr_prompt = 1; /* user specified number of devices to add/remove */ int usr_drc_count = 0; /* user specified drc type to use */ enum drc_type usr_drc_type = DRC_TYPE_NONE; /* user specified -p option, meaning varies depending on usr_drc_type */ char *usr_p_option = NULL; /* user specified workaround for qemu pci dlpar */ int pci_virtio = 0; /* user specified file for handling prrn events */ char *prrn_filename = NULL; /* perform hotplug only operation */ int pci_hotplug_only = 0; /* lsslot specific options */ int show_available_slots = 0; int show_cpus_and_caches = 0; int show_occupied_slots = 0; int show_caches = 0; char *usr_delimiter = NULL; powerpc-utils-1.3.4/src/drmgr/prrn.c000066400000000000000000000033121315235264300173660ustar00rootroot00000000000000/** * Copyright (c) 2016 International Business Machines * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "dr.h" #include "drmem.h" #include "drcpu.h" int handle_prrn(void) { char fmt_drc[11]; char type[4]; char drc[9]; int rc = 0; FILE *fd; fd = fopen(prrn_filename, "r"); if (!fd) { say(ERROR, "Failed to open the file %s\n", prrn_filename); return -1; } set_output_level(4); while (fscanf(fd, "%3s %8s\n", type, drc) == 2) { usr_drc_type = to_drc_type(type); sprintf(fmt_drc, "0x%s", drc); usr_drc_name = fmt_drc; set_timeout(PRRN_TIMEOUT); if (!strcmp(type, "mem")) { usr_action = REMOVE; rc = drslot_chrp_mem(); if (rc) continue; usr_action = ADD; drslot_chrp_mem(); } else if (!strcmp(type, "cpu")) { usr_action = REMOVE; rc = drslot_chrp_cpu(); if (rc) continue; usr_action = ADD; drslot_chrp_cpu(); } else { say(ERROR, "Device type \"%s\" not recognized.\n", type); continue; } } return 0; } powerpc-utils-1.3.4/src/drmgr/rtas_calls.c000066400000000000000000000333541315235264300205450ustar00rootroot00000000000000/** * @file rtas_calls.c * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "rtas_calls.h" #include "dr.h" #include "ofdt.h" char *hw_error = "Hardware error. You must correct this error before\n" "attempting any further dynamic reconfiguration " "operations.\nCheck the system error log for more " "information.\n"; /** * get_node * @brief Allocates and initializes a node structure. * * @param workarea work area returned by "ibm,configure-connector" RTAS call. * @returns pointer to allocated node on success, NULL otherwise */ static struct of_node * get_node(char *workarea) { struct of_node *node; /* Pointer to new node structure */ int *work_int; /* Pointer to workarea */ char *node_name; /* Pointer to memory for node name */ /* Allocate new node structure */ node = zalloc(sizeof(*node)); if (node == NULL) return NULL; work_int = (int *)workarea; node_name = workarea + be32toh(work_int[2]); node->name = (char *)zalloc(strlen(node_name)+1); if (node->name == NULL) { /* Malloc error */ free(node); return NULL; } strcpy(node->name, node_name); return node; } /** * free_of_node * @brief Free all memory allocated by the configure_connector() * * @param node node returnd by configure_connector() * @returns 0 on success, !0 otherwise */ void free_of_node(struct of_node *node) { struct of_property *prop; /* Used in freeing property memory */ struct of_property *next_prop; /* Used in freeing property memory */ /* If node has a child, make recursive call to free child memory */ if (node->child) free_of_node(node->child); /* If node has a sibling, make recursive call to free its memory */ if (node->sibling) free_of_node(node->sibling); /* Now loop through and free all property related memory */ prop = node->properties; while (prop) { next_prop = prop->next; free(prop->name); free(prop->value); free(prop); prop = next_prop; } /* Finally free the memory for the name and the node itself */ if (node->name) free(node->name); free(node); } /** * get_rtas_property * @brief Allocates and initializes a property structure. * * @param Pointer to work area returned by "ibm,configure-connector" RTAS call. * @returns pointer to of_property_t on success, NULL otherwise */ static struct of_property * get_rtas_property(char *workarea) { struct of_property *prop; /* Pointer to new property strucutre */ int *work_int; /* Pointer to workarea */ char *name; /* Pointer to memory for property name */ char *value; /* Pointer to memory for property value */ /* Allocate a new property structure */ prop = zalloc(sizeof(*prop)); if (prop != NULL) { /* Initialize the new property structure */ work_int = (int *)workarea; prop->next = NULL; name = workarea + be32toh(work_int[2]); prop->name = (char *)zalloc(strlen(name)+1); if (prop->name == NULL) { /* Malloc error */ free(prop); return NULL; } strcpy(prop->name, name); prop->length = be32toh(work_int[3]); value = workarea + be32toh(work_int[4]); prop->value = (char *)zalloc(prop->length); if (prop->value == NULL) { /* Malloc error */ free(prop->name); free(prop); return NULL; } memcpy(prop->value, value, prop->length); } return prop; } /** * dr_entity_sense * @brief Determine if a PCI card is present in a hot plug slot. * * @param index slot index to check * @returns EMPTY if no card detected in slotor not a valid state for logical * resources * @returns PRESENT if a card was detected in the slot or logical connector * is owned by the partition. * @returns EXCHANGE Logical resource is unlicensed and is available for * sparing operations. * @returns NEED_POWER Must power on slot before checking for card presence. * @returns PWR_ONLY Power on slot, but leave isolated. * @returns STATE_UNUSABLE No DR operation will succeed * @returns HW_ERROR Hardware error * @returns SW_ERROR Other errors. */ int dr_entity_sense(int index) { int state; int rc; rc = rtas_get_sensor(DR_ENTITY_SENSE, index, &state); say(DEBUG, "get-sensor for %x: %d, %d\n", index, rc, state); return (rc >= 0) ? state : rc; } /* * entity_sense_error * @brief provide a detailed error message for dr_entity_sense() errors * * @param error error returned from dr_entity_sense() * @return pointer to message string, empty string if error is invalid */ char * entity_sense_error(int error) { char *empty = "Unable to allocate the resource to the partition."; char *present = "Resource is already assigned to the partition."; char *unusable = "Resource is not available to the partition."; char *exchange = "Resource is available for exchange."; char *recovery = "Resource is available for recovery by partition."; char *rc = ""; switch (error) { case EMPTY: rc = empty; break; case PRESENT: rc = present; break; case STATE_UNUSABLE: rc = unusable; break; case EXCHANGE: rc = exchange; break; case RECOVERY: rc = recovery; break; } return rc; } /* * set_indicator_error * @brief provide a detailed error message for rtas_set_indicator() errors * * @param error error returned from rtas_set_indicator() * @return pointer to message string, empty string if error is invalid */ char * set_indicator_error(int error) { char *hw_error = "Hardware error."; char *hw_busy = "Hardware busy, try again later."; char *no_ind = "No such indicator implemented."; char *iso_error = "Multi-level isolation error."; char *vot = "Valid outstanding translations exist."; char *rc = ""; switch (error) { case HARDWARE_ERROR: rc = hw_error; break; case HARDWARE_BUSY: rc = hw_busy; break; case NO_INDICATOR: rc = no_ind; break; case MULTI_LEVEL_ISO_ERROR: rc = iso_error; break; case VALID_TRANSLATION: rc = vot; break; } return rc; } #define WORK_SIZE 4096 /* RTAS work area is 4K page size */ /** * configure_connector * * Obtain all of the Open Firmware properties for nodes associated * with the hot plug entitiy. * * @param index slot index from "ibm,drc-indexes" property * @returns pointer to node on success, NULL on failure. */ struct of_node * configure_connector(int index) { char *workarea; struct of_node *node; struct of_node *first_node = NULL; struct of_node *last_node = NULL; /* Last node processed */ struct of_property *property; struct of_property *last_property = NULL; /* Last property processed */ int *work_int; int rc; say(DEBUG, "Configuring connector for drc index %x\n", index); workarea = zalloc(WORK_SIZE); if (!workarea) return NULL; /* initialize work area and args structure */ work_int = (int *)workarea; work_int[0] = htobe32(index); work_int[1] = 0; while (1) { rc = rtas_cfg_connector(workarea); if (rc == 0) break; /* Success */ if (rc == NEXT_SIB) { if (last_node == NULL) { say(ERROR, "unexpected sibling returned from " "configure_connector\n"); break; } /* Allocate and initialize the node */ node = get_node(workarea); if (node == NULL) { say(ERROR, "failed to allocate sibling node " "for drc index %x\n", index); break; } /* Set parent node to same as that of last node */ node->parent = last_node->parent; /* Chain to last node */ last_node->sibling = node; /* This node becomes the last node */ last_node = node; } else if (rc == NEXT_CHILD) { /* Allocate and initialize the node */ node = get_node(workarea); if (node == NULL) { say(ERROR, "Failed to allocate child node for " "drc index %x\n", index); break; } if (first_node == NULL) { first_node = node; } else { node->parent = last_node; if (last_node) last_node->child = node; } /* This node becomes the last node */ last_node = node; } else if (rc == NEXT_PROPERTY){ if (last_node == NULL) { say(ERROR, "Configure_connector returned a " "property before returning a node\n"); break; } /* Allocate and initialize the property structure */ property = get_rtas_property(workarea); if (property == NULL) break; if (last_node->properties == NULL) last_node->properties = property; else last_property->next = property; /* This property becomes last property for node */ last_property = property; } else if (rc == PREV_PARENT) { /* Need to back up to parent device */ last_node = last_node->parent; } else if (rc == MORE_MEMORY) { say(ERROR, "Configure_connector called with " "insufficient memory.\n"); break; } else if (rc == NOT_THIS_SYSTEM) { /* this card is not supported in this system */ say(ERROR, "This adapter cannot be attached to this " "system at this\ntime. You may have to remove " "other adapters before this\nadapter can be " "successfully attached. Consult the hardware" "\ndocumentation for your system to find an " "explanation of\nthe supported combinations " "of adapters that may be attached\nat one " "time.\n"); break; } else if (rc == NOT_THIS_SLOT) { /* this card is not supported in this slot */ say(ERROR, "This adapter is not supported in the " "specified slot,\nbut there may be other " "slots where it is supported. Consult\nthe " "hardware documentation for your system to " "find the\nappropriate slots for this " "adapter.\n"); break; } else if (rc == ERR_CFG_USE) { /* This entity is not usable */ say(ERROR, "This adapter is currently unusable, available " "for exchange or available for recovery\n"); break; } else if (rc == HARDWARE_ERROR) { say(ERROR, "%s\n", hw_error); break; } else { say(ERROR, "Unexpected error (%d) returned from " "configure_connector\n", rc); break; } } /* end while */ if (rc) { say(ERROR, "Configure_connector failed for drc index %x\n" "Data may be out of sync and the system may require " "a reboot.\n", index); if (first_node) { free_of_node(first_node); first_node = NULL; /* Indicates error condition */ } } free(workarea); return first_node; } /** * set_power * @brief Sets the power level for the specified slot. * * @param domain power domain for the slot from "ibm,drc-power-domains" * @param level POWER_ON or POWER_OFF * @returns 0 Successful completion * @returns SPEED_ERROR Inserted a PCI 33 MHz IOA into a PCIbus which is * operating at 66 MHz. * @returns HW_ERROR Hardware error. * @returns SW_ERROR Other errors. */ int set_power(int domain, int level) { int ret_level; return rtas_set_power_level(domain, level, &ret_level); } /** * acquire_drc * */ int acquire_drc(uint32_t drc_index) { int rc; say(DEBUG, "Acquiring drc index 0x%x\n", drc_index); rc = dr_entity_sense(drc_index); if (rc != STATE_UNUSABLE) { say(ERROR, "Entity sense failed for drc %x with %d\n%s\n", drc_index, rc, entity_sense_error(rc)); return -1; } say(DEBUG, "Setting allocation state to 'alloc usable'\n"); rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE); if (rc) { say(ERROR, "Allocation failed for drc %x with %d\n%s\n", drc_index, rc, set_indicator_error(rc)); return -1; } say(DEBUG, "Setting indicator state to 'unisolate'\n"); rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); if (rc) { int ret; rc = -1; say(ERROR, "Unisolate failed for drc %x with %d\n%s\n", drc_index, rc, set_indicator_error(rc)); ret = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE); if (ret) { say(ERROR, "Failed recovery to unusable state after " "unisolate failure for drc %x with %d\n%s\n", drc_index, ret, set_indicator_error(ret)); } } return rc; } int release_drc(int drc_index, uint32_t dev_type) { int rc; say(DEBUG, "Releasing drc index 0x%x\n", drc_index); rc = dr_entity_sense(drc_index); if (rc != PRESENT) say(DEBUG, "drc_index %x sensor-state: %d\n%s\n", drc_index, rc, entity_sense_error(rc)); say(DEBUG, "Setting isolation state to 'isolate'\n"); rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE); if (rc) { if (dev_type == PHB_DEV) { /* Workaround for CMVC 508114, where success returns * too quickly */ int i = 0; while ((rc != 0) && (i < 20)) { rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE); sleep(1); i++; } } if (rc) { say(ERROR, "Isolation failed for %x with %d\n%s\n", drc_index, rc, set_indicator_error(rc)); return -1; } } say(DEBUG, "Setting allocation state to 'alloc unusable'\n"); rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE); if (rc) { say(ERROR, "Unable to un-allocate drc %x from the partition " "(%d)\n%s\n", drc_index, rc, set_indicator_error(rc)); rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); say(DEBUG, "UNISOLATE for drc %x, rc = %d\n", drc_index, rc); return -1; } rc = dr_entity_sense(drc_index); say(DEBUG, "drc_index %x sensor-state: %d\n%s\n", drc_index, rc, entity_sense_error(rc)); return 0; } powerpc-utils-1.3.4/src/drmgr/rtas_calls.h000066400000000000000000000075341315235264300205530ustar00rootroot00000000000000/** * @file rtas_calls.h * * Copyright (C) IBM Corporation 2006 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _RTAS_CALLS_H_ #define _RTAS_CALLS_H_ #include #include "drpci.h" /* The following definitions are used in the interfaces to various * subroutines. */ /* Indicators for rtas_set_indicator */ #define ISOLATION_STATE 9001 /* value for isolation-state */ #define DR_INDICATOR 9002 /* value for dr-indicator */ #define ALLOCATION_STATE 9003 /* value for allocation-state */ /* Error status from rtas_set_indicator */ #define HARDWARE_ERROR -1 #define HARDWARE_BUSY -2 #define NO_INDICATOR -3 #define MULTI_LEVEL_ISO_ERROR -9000 #define VALID_TRANSLATION -9001 /* Error status from dr-entity-sense(get-sensor-state) */ #define NEED_POWER -9000 /* Need to turn on power to slot */ #define PWR_ONLY -9001 /* Power on slot, leave isolated */ /* Sensor values from dr-entity-sense(get-sensor-state) */ #define EMPTY 0 /* No card in slot */ #define PRESENT 1 /* Card in slot */ #define STATE_UNUSABLE 2 /* No DR operation will succeed */ #define EXCHANGE 3 /* resource unlicensed, for sparing only */ #define RECOVERY 4 /* can be recovered by platform */ /* Return status from configure-connector */ #define NOT_THIS_SYSTEM -9001 /* DR entity not supported on this system */ #define NOT_THIS_SLOT -9002 /* DR entity not supported in this slot */ #define DR_UNUSABLE -9003 /* Logical DR connector unusable */ /* Return status from ibm,suspend_me */ #define NOT_SUSPENDABLE -9004 #define MULTIPLE_THREADS -9005 /* State values for set-indicator dr-indicator */ #define LED_OFF 0 #define LED_ON 1 #define LED_ID 2 #define LED_ACTION 3 /* State values for isolation-state */ #define ISOLATE 0 #define UNISOLATE 1 /* Level values for set-power-level */ #define POWER_OFF 0 #define POWER_ON 100 /* State values for allocation-state */ #define ALLOC_UNUSABLE 0 /* Release Unusable Resource to FW */ #define ALLOC_USABLE 1 /* Assign Usable Resource from FW */ /* Tokens for RTAS calls */ #define DR_ENTITY_SENSE 9003 /* token value for dr-entity-sense */ /* Return status from configure-connector */ #define NEXT_SIB 1 /* Next sibling */ #define NEXT_CHILD 2 /* Next child */ #define NEXT_PROPERTY 3 /* Next property */ #define PREV_PARENT 4 /* Previous parent */ #define MORE_MEMORY 5 /* Need more memory */ #define ERR_CFG_USE -9003 /* DR connector unusable */ struct of_property { struct of_property *next; /* Ptr to next property for node */ char *name; /* OF property name */ int length; /* Length of property value in bytes */ char *value; /* Pointer to property value */ }; struct of_node { char *name; /* Node name including unit address */ struct of_property *properties; /* Pointer to OF properties */ struct of_node *parent; /* Pointer to parent node */ struct of_node *sibling; /* Pointer to next sibling node */ struct of_node *child; /* Pointer to first child node */ int added; }; extern char *hw_error; int dr_entity_sense(int index); struct of_node *configure_connector(int index); int set_power(int domain, int level); int acquire_drc(uint32_t); int release_drc(int, uint32_t); struct of_node *configure_connector(int); #endif /* _RTAS_CALLS_H_ */ powerpc-utils-1.3.4/src/errinjct/000077500000000000000000000000001315235264300167475ustar00rootroot00000000000000powerpc-utils-1.3.4/src/errinjct/dcache.c000066400000000000000000000062771315235264300203360ustar00rootroot00000000000000/** * @file dcache.c * @author Nathan Fontenot * @author Linas Vepstas * * @brief Inject corrupted-dcache-start and corrupted-dcache-end errors * * Copyright (c) 2004 IBM Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "errinjct.h" /** * @var action * @brief action code for the corrupted D-cache error injection */ static int action = -1; /** * @var action_codes * @brief descriptions of the corrupted D-cache action codes */ static char *action_codes[] = { "parity error", "D-ERAT parity error", "tag parity error" }; #define MAX_DCACHE_ACTION_CODE 2 /** * corrupted_dcache_usage * @brief print the "corrupted D-cache" error injection usage statement * * @param ei_func errinjct functionality */ static void corrupted_dcache_usage(ei_function *ei_func) { int i; printf("Usage: %s %s [OPTIONS]\n", progname, ei_func->name); printf(" %s %s [OPTIONS]\n", progname, ei_func->alt_name); printf("%s\n\n", ei_func->desc); printf("Mandatory arguments:\n"); printf(HELP_FMT, "-a action", "type of D-cache error to inject"); for (i = 0; i <= MAX_DCACHE_ACTION_CODE; i++) printf("%22d: %s\n", i, action_codes[i]); print_cpu_arg(); print_token_arg(); print_optional_args(); } /** * corrupted_dcache_arg * @brief check for "corrupted D-cache arg" cmdline args * * @param arg cmdline arg * @param optarg optional cmdline argument to 'arg' * @return 0 - indicates this is a corrupted dcache arg * @return 1 - indicates this is _not_ a corrupted dcache arg */ int corrupted_dcache_arg(char arg, char *optarg) { if (arg == 'a') { action = atoi(optarg); return 0; } return 1; } /** * corrupted_dcache * @brief "corrupted D-cache" error injection handler * * This will inject a corrupted D-cache error onto the system * * @param ei_func errinjct functionality * @return 0 on success, !0 otherwise */ int corrupted_dcache(ei_function *ei_func) { int rc; if (ext_help || check_cpu_arg() || check_token_arg()) { corrupted_dcache_usage(ei_func); return 1; } if ((action < 0) || (action > MAX_DCACHE_ACTION_CODE)) { perr(0, "Invalid action code (%d)", action); corrupted_dcache_usage(ei_func); return 1; } if (!be_quiet) { printf("Injecting a %s error\n", ei_func->name); printf("Action: %d - %s\n", action, action_codes[action]); } if (dryrun) return 0; err_buf[0] = action; rc = do_rtas_errinjct(ei_func); return rc; } powerpc-utils-1.3.4/src/errinjct/errinjct.c000066400000000000000000000446451315235264300207500ustar00rootroot00000000000000/** * @file errinjct.c * @brief Hardware Error Injection Tool main * @author Nathan Fontenot * @author Linas Vepstas * * This program can be used to simulate hardware error events. * It uses librtas to inject artificial errors into the system. * * Copyright (c) 2004 IBM Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "errinjct.h" #include "pseries_platform.h" #define EI_TOKEN_PROCFILE "/proc/device-tree/rtas/ibm,errinjct-tokens" #define EI_IBM_ERRINJCT "/proc/device-tree/rtas/ibm,errinjct" int verbose; int dryrun; int ei_token = -1; int logical_cpu = -1; int ext_help; int be_quiet; int debug; /** * @var progname * @brief name this app was invoked as (argv[0]) */ char *progname; uint err_buf[EI_BUFSZ / sizeof(uint)]; /** * @var ei_funcs * @brief array of known RTAS error injection functionality */ static ei_function ei_funcs[] = { { .name = "open", .alt_name = NULL, .desc = "open the RTAS error injection facility", .rtas_token = -1, .arg = ei_open_arg, .func = ei_open }, { .name = "close", .alt_name = NULL, .desc = "close the RTAS error injection facility", .rtas_token = -1, .arg = ei_close_arg, .func = ei_close }, { .name = "corrupted-dcache-start", .alt_name = "dcache-start", .desc = "Start causing a LI data cache error", .rtas_token = -1, .arg = corrupted_dcache_arg, .func = corrupted_dcache }, { .name = "corrupted-dcache-end", .alt_name = "dcache-end", .desc = "Stop causing a LI data cache error", .rtas_token = -1, .arg = corrupted_dcache_arg, .func = corrupted_dcache }, { .name = "corrupted-icache-start", .alt_name = "icache-start", .desc = "Start causing an instruction cache error", .rtas_token = -1, .arg = corrupted_icache_arg, .func = corrupted_icache }, { .name = "corrupted-icache-end", .alt_name = "icache-end", .desc = "Stop causing an instruction cache error", .rtas_token = -1, .arg = corrupted_icache_arg, .func = corrupted_icache }, { .name = "corrupted-page", .alt_name = NULL, .desc = "Corrupt the specified location (and potentially surrounding locations up to the containing page)", .rtas_token = -1, .arg = NULL, .func = NULL }, { .name = "corrupted-slb", .alt_name = "slb", .desc = "Corrupt the SLB entry associated with a specific effective address", .rtas_token = -1, .arg = corrupted_slb_arg, .func = corrupted_slb }, { .name = "corrupted-tlb-start", .alt_name = "tlb-start", .desc = "Start corrupting TLB", .rtas_token = -1, .arg = corrupted_tlb_arg, .func = corrupted_tlb }, { .name = "corrupted-tlb-end", .alt_name = "tlb-end", .desc = "Stop corrupting TLB", .rtas_token = -1, .arg = corrupted_tlb_arg, .func = corrupted_tlb }, { .name = "fatal", .alt_name = NULL, .desc = "Simulate a platform fatal error", .rtas_token = -1, .arg = NULL, .func = NULL }, { .name = "ioa-bus-error", .alt_name = "eeh", .desc = "Simulate an error on an IOA bus", .rtas_token = -1, .arg = ioa_bus_error_arg, .func = ioa_bus_error32 }, { .name = "ioa-bus-error-64", .alt_name = "eeh-64", .desc = "Simulate an error on a 64-bit IOA bus", .rtas_token = -1, .arg = ioa_bus_error_arg, .func = ioa_bus_error64 }, { .name = "platform-specific", .alt_name = "platform", .desc = "Request the firmware perform a platform specific error injection", .rtas_token = -1, .arg = platform_specific_arg, .func = platform_specific }, { .name = "recovered-random-event", .alt_name = "random-event", .desc = "Simulate a recovered random event", .rtas_token = -1, .arg = NULL, .func = NULL }, { .name = "recovered-special-event", .alt_name = "special-event", .desc = "Simulate a recoverd special (statistically significant) event", .rtas_token = -1, .arg = NULL, .func = NULL }, { .name = "translator-failure", .alt_name = NULL, .desc = "Simulate a translator failure", .rtas_token = -1, .arg = NULL, .func = NULL }, { .name = "upstream-IO-error", .alt_name = NULL, .desc = "Inject I/O error above the IOA", .rtas_token = -1, .arg = NULL, .func = NULL } }; /** * perr * @brief Creates a formatted error message and prints it to stderr * @param fmt format of the message to be printed * @param ... variable args */ void perr(int error, const char *fmt, ...) { char buf[EI_BUFSZ]; va_list ap; int len; memset(buf, 0, EI_BUFSZ); len = sprintf(buf, "%s: ", progname); va_start(ap, fmt); len += vsprintf(buf + len, fmt, ap); va_end(ap); if (error) len += sprintf(buf + len, ", %s\n", strerror(error)); else len += sprintf(buf + len, "\n"); buf[len] = '\0'; fprintf(stderr, "%s\n", buf); fflush(stderr); } /** * ei_ext_usage * @brief Print the extended usage message for errinjct * * This will print the name and description for all currently supported * error injection functions. */ static void ei_ext_usage(void) { int i; printf("Currently supported functions:\n"); for (i = 0; i < NUM_ERRINJCT_FUNCS; i++) { if (ei_funcs[i].func != NULL) printf(" %-25s%s\n", ei_funcs[i].name, ei_funcs[i].desc); } printf("\n"); printf("Try \"%s function -H\" for more information\n", progname); } /** * print_optional_args * @brief Print the optional arguments to errijnjct * * There are several options to the errinjct tool that are not specific * to any of the error injection functions (i.e. global). This routine * is provided for all of the error injection functions to use to print * these optional args. */ void print_optional_args(void) { printf("Optional arguments:\n"); printf(HELP_FMT, "--dry-run", "don't perform the action,"); printf(HELP_FMT, "", "just print what would have been done"); printf(HELP_FMT, "-H --help", "print usage information for a particular function"); printf(HELP_FMT, "-v --verbose", "be more verbose with messages"); printf(HELP_FMT, "-vv", "turn on librtas tracing"); printf(HELP_FMT, "-vvv", "turn on RTAS call argument tracing"); printf(HELP_FMT, "-q --quiet", "shhhh.... only report errors"); } /** * print_cpu_arg * @brief Print the usage for the "-C cpu" option * * Print the "-C cpu" part of a usage statement. This argument may or * may not be mandatory (depending on the function) so we provide a * common print routine to centrlize messages. */ void print_cpu_arg(void) { printf(HELP_FMT, "-C cpu", "cpu to inject errors on"); } /** * check_cpu_arg * @brief Common routine to check if the "-C cpu" flag was used. * * This routine is provided to check if the "-C cpu" option was * specified and generate a common erro message. */ int check_cpu_arg(void) { if (logical_cpu == -1) { perr(0, "Please specify a logical cpu with the -C option"); return 1; } return 0; } /** * print_token_arg * @brief Print the "-k token" part of the usage statement * * Print the "-k token" part of the usage statement. This argument may or * may not be mandatory (depending on the function) so we provide a * common print routine to centralize messages. */ void print_token_arg(void) { printf(HELP_FMT, "-k token", "token returned from error inject open"); } /** * check_token_arg * @brief Common routine to check if the "-k token" flag was used. * * This provides a common point for checking to see if the "-k token" * option was specified and generates a common error statement. */ int check_token_arg(void) { if (ei_token == -1) { perr(0, "Please specify the error inject token with the -k option"); return 1; } return 0; } /** * ei_usage * @brief Print the usage statement for errinjct */ static void ei_usage(void) { printf("Usage: %s FUNCTION [OPTIONS]\n", progname); printf("This will inject an error into the system via rtas\n"); ei_ext_usage(); } /** * check_librtas_returns * @brief check the return code from librtas * * Check the return code from a call to librtas. Librtas can return * values tat librtas specific values to indicate errors in librtas. * There is no method provided by librtas to do this so we have to do * it here. * * @param rc return code from a librtas call * @param ei_func functionality pointer */ void check_librtas_returns(int rc, ei_function *ei_func) { switch (rc) { case -1: /* Hardware Error */ perr(0, "RTAS: %s: Hardware error (-1)", ei_func->name); break; case -2: /* Thank you, come again */ perr(0, "RTAS: %s: Busy, try again later (-2)", ei_func->name); break; case -3: /* Arg error */ perr(0, "RTAS: %s: Argument error (-3)", ei_func->name); break; case -4: /* Call error */ perr(0, "RTAS: %s: The error injection facility is not open\n" "or you are not the one that opened it", ei_func->name); break; case -5: /* PCI injection not enabled */ perr(0, "RTAS: %s: PCI Error Injection is not enabled (not " "available)\n", ei_func->name); break; case -1001: /* RTAS_KERNEL_INT */ perr(0, "librtas: No Kernel Interface to Firmware"); break; case -1002: /* RTAS_KERNEL_IMP */ perr(0, "librtas: No Kernel Implementation of function %s", ei_func->name); break; case -1003: /* RTAS_PERM */ perr(0, "librtas: You must be root to access rtas calls"); break; case -1004: /* RTAS_NO_MEM */ perr(0, "librtas: Out of memory"); break; case -1005: /* RTAS_NO_LOMEM */ perr(0, "librtas: Kernel out of low memory"); break; case -1006: /* RTAS_FREE_ERR */ perr(0, "librtas: Attempt to free nonexistant rmo buffer"); break; case -1007: /* RTAS_TIMEOUT */ perr(0, "librtas: RTAS delay exceeded specified timeout"); break; case -1098: /* RTAS_IO_ASSERT */ perr(0, "librtas: %s: Unexpected I/O error", ei_func->name); break; case -1099: /* RTAS_UNKNOWN_OP */ perr(0, "librtas: No firmware implementation of function %s", ei_func->name); break; default: perr(0, "librtas returned an unknown error code (%d) for function %s", rc, ei_func->name); break; } } /** * open_rtas_errinjct * @brief Open the RTAS error injection facility * * @param ei_func errinjct functionality * @return 0 on success, !0 otherwise */ int open_rtas_errinjct(ei_function *ei_func) { int rc; rc = rtas_errinjct_open(&ei_token); if (rc != 0) { perr(0, "Could not open RTAS error injection facility"); if (rc == -4) perr(0, "the facility is already open, please\n" "specify the open token with the -k option"); else if (rc == -5) perr(0, "PCI Error Injection is not enabled."); else check_librtas_returns(rc, ei_func); } return rc; } /** * close_rtas_errinjct * @brief Close the RTAS error injection facility * * @param ei_func errinjct functionality * @return 0 on success, !0 otherwise */ int close_rtas_errinjct(ei_function *ei_func) { int rc; rc = rtas_errinjct_close(ei_token); if (rc != 0) { perr(0, "Could not close RTAS error injection facility"); check_librtas_returns(rc, ei_func); } return rc; } /** * bind_cpu * @brief bind errinjct to a cpu * * Bind ourselves to a particular cpu if the cpu binding capability * is present on this machine. * * The inability to bind to a cpu is not considered a failure condition, * we simply print a message stating that cpu binding is not available * and return success. * * @return 0 on success, !0 otherwise */ static int bind_cpu(void) { cpu_set_t mask; int rc; if (logical_cpu == -1) return 0; if (verbose) printf("Binding to logical cpu %d\n", logical_cpu); CPU_ZERO(&mask); CPU_SET(logical_cpu, &mask); rc = sched_setaffinity(getpid(), sizeof(mask), &mask); if (rc) perr(0, "Could not bind to logical cpu %d", logical_cpu); return rc; } /** * do_rtas_errinjct * @brief Perform the actual call to inject errors * * Perform the actual call to RTAS. This routine will also bind us to * a specific processor (if requested) and open RTAS error injection if an * open token is not specified. * * @param ei_func errinjct functionality * @return 0 on success, !0 otherwise */ int do_rtas_errinjct(ei_function *ei_func) { int rc = 0; int close_errinjct = 0; /* First see if we should bind ourselves to a processor */ rc = bind_cpu(); if (rc) return rc; /* Now, see if we need to open the RTAS errinjct facility */ if (ei_token == -1) { rc = open_rtas_errinjct(ei_func); if (rc != 0) return rc; close_errinjct = 1; } /* Make the RTAS call */ rc = rtas_errinjct(ei_func->rtas_token, ei_token, (char *)err_buf); if (rc != 0) { perr(0, "RTAS error injection failed!"); check_librtas_returns(rc, ei_func); printf("This error may have occurred because error injection\n" "is disabled for this partition. Please check the\n" "FSP and ensure you have error injection enabled.\n"); } else if (!be_quiet) { printf("Call to RTAS errinjct succeeded!\n\n"); } if (close_errinjct) rc = close_rtas_errinjct(ei_func); return rc; } /** * read_ei_tokens * @brief Gather the RTAS tokens stored in /proc for this machine. * * This will read the RTAS token values stored in /proc to determine * which RTAS error injection capabilities are avaialable on this machine * * @return 0 on success, !0 otherwise */ int read_ei_tokens(void) { char *buf; int len; int i, found; char *tmp_ptr; buf = read_file(EI_TOKEN_PROCFILE, &len); if (!buf) return 1; tmp_ptr = buf; while (tmp_ptr < buf + len) { found = 0; for (i = 0; i < NUM_ERRINJCT_FUNCS; i++) { if (strcmp(tmp_ptr, ei_funcs[i].name) == 0) { found = 1; tmp_ptr += strlen(tmp_ptr) + 1; ei_funcs[i].rtas_token = be32toh(*(int *)tmp_ptr); tmp_ptr += sizeof(int); break; } } if (found == 0) { if (verbose) perr(0, "Could not find errinjct function for rtas token \"%s\"", tmp_ptr); tmp_ptr += strlen(tmp_ptr) + 1 + sizeof(int); } } free(buf); return 0; } /** * sysfs_check * @brief Make sure sysfs is mounted at the expected /sys location * * Several places in errinjct need to look up data in sysfs. In this * routine we make sure sysfs is mounted in the expected location /sys * * @return 0 if sysfs is mounted at /sys, !0 otherwise */ int sysfs_check(void) { struct stat sbuf; int rc; rc = stat("/sys/class", &sbuf); /* posix semantics returns EOVERFLOW on sysfs in newer kernels */ if (rc && errno == EOVERFLOW) rc = 0; if (rc) perr(errno, "It appears that sysfs is not mounted at /sys.\n" "The error injection you requested requires sysfs,\n" "please check your system configuration and try again.\n"); return rc; } /** * read_file * @brief Open and read the contents of a file into an allocated buffer * * NOTE: Callers of this routine need to free the buffer allocated * by read_file. * * @param fname name of the file to read * @paran flen pointer to variable to return amount read * @returns pointer to allocated buffer on success, NULL on faiulure */ char *read_file(const char *fname, int *flen) { struct stat sbuf; char *buf; int fd, len; if (fname == NULL) return NULL; fd = open(fname, O_RDONLY); if (fd == -1) { perr(errno, "Could not open file %s", fname); return NULL; } if (fstat(fd, &sbuf) != 0) { perr(errno, "Could not get status of file %s", fname); close(fd); return NULL; } buf = malloc(sbuf.st_size); if (!buf) { perr(0, "Could not allocate buffer to read file %s\n", fname); close(fd); return NULL; } memset(buf, 0, sbuf.st_size); len = read(fd, buf, sbuf.st_size); close(fd); if (len <= 0) { perr(errno, "Error reading data from file %s\n", fname); free(buf); return NULL; } if (flen) *flen = len; return buf; } static struct option longopts[] = { { name: "dry-run", has_arg: 0, flag: NULL, val: 254 }, { name: "help", has_arg: 0, flag: NULL, val: 'H' }, { name: "verbose", has_arg: 0, flag: NULL, val: 'v' }, { name: "quiet", has_arg: 0, flag: NULL, val: 'q' }, { name: NULL } }; int main(int argc, char *argv[]) { ei_function *ei_func = NULL; const char *funcname; int c, rc; int i, fd; progname = argv[0]; if (argc == 1) { ei_usage(); exit(1); } /* Make sure the error injection facility is available */ fd = open(EI_IBM_ERRINJCT, O_RDONLY); if (fd == -1) { perr(0, "Could not open error injection facility,\n" "file \"%s\" does not exist", EI_IBM_ERRINJCT); close(fd); exit(1); } close(fd); /* The function name is always first */ funcname = argv[1]; for (i = 0; i < NUM_ERRINJCT_FUNCS; i++) { if (ei_funcs[i].func == NULL) continue; if ((strcmp(funcname, ei_funcs[i].name) == 0) || ((ei_funcs[i].alt_name != NULL) && (strcmp(funcname, ei_funcs[i].alt_name)) == 0)) { ei_func = &ei_funcs[i]; break; } } if (ei_func == NULL) { perr(0, "Could not find function \'%s\'", funcname); ei_ext_usage(); exit(1); } /* shift past function name */ argc--; argv++; while ((c = getopt_long(argc, argv, "+a:C:c:f:Hh:k:l:m:n:p:qs:v", longopts, NULL)) != -1) { switch (c) { case 254: dryrun = 1; break; case 'C': logical_cpu = atoi(optarg); break; case 'H': ext_help = 1; break; case 'k': ei_token = atoi(optarg); break; case 'q': be_quiet = 1; break; case 'v': /* If specified multiple times, * turn on librtas debug */ if (verbose) { debug++; rtas_set_debug(debug); } verbose = 1; break; case ':': break; default: rc = ei_func->arg(c, optarg); if (rc) { perr(0, "\"-%c\" is not a valid option for %s", c, ei_func->name); ext_help = 1; } break; } } /* Open the /proc/ppc64/rtas entry to get valid tokens */ rc = read_ei_tokens(); if (rc) exit(rc); memset(err_buf, 0, EI_BUFSZ); rc = ei_func->func(ei_func); exit(rc); } powerpc-utils-1.3.4/src/errinjct/errinjct.h000066400000000000000000000067061315235264300207510ustar00rootroot00000000000000/** * @file errinjct.h * @brief Hardware Error Injection Tool main * @author Nathan Fontenot * * This program can be used to simulate hardware error events. * It uses librtas to inject artificial errors into the system. * * Copyright (c) 2004 IBM Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _ERRINJCT_H #define _ERRINJCT_H #include #include #include extern int verbose; /**< verbose flag specified? */ extern int dryrun; /**< Are we doing a dry run */ extern int ei_token; /**< error injection token */ extern int logical_cpu; /**< logical cpu to bind to */ extern int ext_help; /**< print the extended help message */ extern int be_quiet; /**< Shhh... don't say anything */ extern char *progname; /**< argv[0] */ #define EI_BUFSZ 1024 extern uint err_buf[]; /**< buffer for RTAS call args */ /** * struct ei_function * @brief description of an error injection capabilty * * For each erro injection capability we maintain an ei_function * structure to define the capability. */ typedef struct ei_function_s { /*cmdline name*/ char *name; /*alternate cmdline name*/ char *alt_name; /*brief description of the capability*/ char *desc; /*RTAS token for this capability*/ int rtas_token; /*arg function*/ int (*arg)(char, char *); /*capability function handler*/ int (*func)(struct ei_function_s *); } ei_function; /* Error inject open functions (errinjct.c) */ int ei_open(ei_function *); int ei_open_arg(char, char *); /* Error inject close functions (errinjct.c) */ int ei_close(ei_function *); int ei_close_arg(char, char *); /* D-cache functions (dcache.c) */ int corrupted_dcache(ei_function *); int corrupted_dcache_arg(char, char *); /* I-cache functions (icache.c) */ int corrupted_icache(ei_function *); int corrupted_icache_arg(char, char *); /* Corrupted SLB functions (slb.c) */ int corrupted_slb(ei_function *); int corrupted_slb_arg(char, char *); /* Corrupted TLB functions (tlb.c) */ int corrupted_tlb(ei_function *); int corrupted_tlb_arg(char, char *); /* IOA Bus Error (EEH) (ioa_bus_error.c) */ int ioa_bus_error32(ei_function *); int ioa_bus_error64(ei_function *); int ioa_bus_error_arg(char, char *); /* Platform Specific (platform.c) */ int platform_specific(ei_function *); int platform_specific_arg(char, char *); #define NUM_ERRINJCT_FUNCS 17 /* errinjct.c */ int do_rtas_errinjct(ei_function *); void print_optional_args(void); void print_cpu_arg(void); int check_cpu_arg(void); void print_token_arg(void); int check_token_arg(void); void perr(int, const char *, ...); int open_rtas_errinjct(ei_function *); int close_rtas_errinjct(ei_function *); int sysfs_check(void); char *read_file(const char *, int *); #define HELP_FMT " %-15s%s\n" /**< common help format */ #endif /* _ERRINJCT_H */ powerpc-utils-1.3.4/src/errinjct/icache.c000066400000000000000000000076161315235264300203410ustar00rootroot00000000000000/** * @file icache.c * @brief Hardware Error Injection Tool I-cache module * @author Nathan Fontenot * @author Linas Vepstas * * Inject corrupted-icache-start and corrupted-icache-end errors. * * Copyright (c) 2004 IBM Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "errinjct.h" /** * @var action * @brief action code for I-cache error injections */ static int action = -1; /** * @var nature * @brief nature of I-cache error injection */ static int nature = -1; /** * @var action_codes * @brief descriptions of the I-cache actions codes */ static char *action_codes[] = { "Parity error", "I-ERAT partiy error", "Cache directory 0 parity error", "Cache directory 1 parity error" }; #define MAX_ICACHE_ACTION_CODE 3 /** * @var nature_codes * @brief descriptions of the I-cache nature codes */ static char *nature_codes[] = { "Single", "Solid", "Hang" }; #define MAX_ICACHE_NATURE_CODE 2 /** * corrupted_icache_usage * @brief Print the "corrupted I-cache" error injection usage statement * * @param ei_func errinjct functionality */ static void corrupted_icache_usage(ei_function *ei_func) { int i; printf("Usage: %s %s [OPTIONS]\n", progname, ei_func->name); printf(" %s %s [OPTIONS]\n", progname, ei_func->alt_name); printf("%s\n\n", ei_func->desc); printf("Mandatory Arguments:\n"); printf(HELP_FMT, "-a action", "type of I-cache error to inject"); for (i = 0; i <= MAX_ICACHE_ACTION_CODE; i++) printf("%22d: %s\n", i, action_codes[i]); printf(HELP_FMT, "-n nature", "nature of I-cache error to inject"); for (i = 0; i <= MAX_ICACHE_NATURE_CODE; i++) printf("%22d: %s\n", i, nature_codes[i]); print_cpu_arg(); print_token_arg(); print_optional_args(); } /** * corrupted_icache_arg * @brief check for "corruptred I-cache" cmdline args * * @param arg cmdline arg to check * @param optarg optional cmdline argument to 'arg' * @return 1 - indicates this is a corrupted I-cache arg * @return 0 - indicates this is not a corrupted I-cache arg */ int corrupted_icache_arg(char arg, char *optarg) { switch (arg) { case 'a': action = atoi(optarg); break; case 'n': nature = atoi(optarg); break; default: return 1; } return 0; } /** * corrupted_icache * @brief "corrupted I-cache" error injection handler * * @param ei_func errinjct functionality * @return 0 on success, !0 otherwise */ int corrupted_icache(ei_function *ei_func) { int rc; if (ext_help || check_cpu_arg() || check_token_arg()) { corrupted_icache_usage(ei_func); return 1; } if ((action < 0) || (action > 3)) { perr(0, "Invalid action code (%d)", action); corrupted_icache_usage(ei_func); return 1; } if ((nature < 0) || (nature > 2)) { perr(0, "Invalid nature code (%d)", nature); corrupted_icache_usage(ei_func); return 1; } err_buf[0] = action; err_buf[1] = nature; if (!be_quiet) { printf("Injecting a %s error\n", ei_func->name); printf("Action: %d - %s\n", action, action_codes[action]); printf("Nature: %d - %s\n", nature, nature_codes[nature]); } if (dryrun) return 0; rc = do_rtas_errinjct(ei_func); return rc; } powerpc-utils-1.3.4/src/errinjct/ioa_bus_error.c000066400000000000000000000362401315235264300217520ustar00rootroot00000000000000/** * @file ioa_bus_error.c * @brief Hardware Error Injection Tool IO Adapter Error module * @author Nathan Fontenot * @author Linas Vepstas * * Inject errors into an IO Adapter (PCI) bus slot. * * Copyright (c) 2004 IBM Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "errinjct.h" static int function = -1; /**< type of ioa bus error to inject */ static uint32_t phb_id_lo; /**< lo bits of PHB id */ static uint32_t phb_id_hi; /**< hi bits of PHB id */ static uint64_t bus_addr; /**< bus address to inject error on */ static uint32_t config_addr; /**< config address of adapter */ static uint64_t mask = 0x0; /**< mask */ static char *sysfsname; /**< sysfs name of adapter to inject to */ static char *loc_code; /**< location code of adapter to inject to */ #define IOA_BUSERR_MAXFUNC 19 #define BUFSZ 4000 /** * ioa_buserr_fnames * @brief list of IOA bus error functionalities * * List of types of errors to inject. Note that this list * must correspond 1-1 with the RPA numeric values sent into RTAS. * Do not reorder this list. */ static char *ioa_buserr_fnames[] = { "Load to PCI Memory Address Space - inject an Address Parity Error", "Load to PCI Memory Address Space - inject a Data Parity Error", "Load to PCI I/O Address Space - inject an Address Parity Error", "Load to PCI I/O Address Space - inject a Data Parity Error", "Load to PCI Configuration Space - inject an Address Parity Error", "Load to PCI Configuration Space - inject a Data Parity Error", "Store to PCI Memory Address Space - inject an Address Parity Error", "Store to PCI Memory Address Space - inject a Data Parity Error", "Store to PCI I/O Address Space - inject an Address Parity Error", "Store to PCI I/O Address Space - inject a Data Parity Error", "Store to PCI Configuration Space - inject an Address Parity Error", "Store to PCI Configuration Space - inject a Data Parity Error", "DMA read to PCI Memory Address Space - inject an Address Parity Error", "DMA read to PCI Memory Address Space - inject a Data Parity Error", "DMA read to PCI Memory Address Space - inject a Master Abort Error", "DMA read to PCI Memory Address Space - inject a Target Abort Error", "DMA write to PCI Memory Address Space - inject an Address Parity Error", "DMA write to PCI Memory Address Space - inject a Data Parity Error", "DMA write to PCI Memory Address Space - inject a Master Abort Error", "DMA write to PCI Memory Address Space - inject a Target Abort Error" }; /** * ioa_bus_error_usage * @brief print the "IOA bus error" error injection usage message * * @param ei_func errinjct functionality * @param show_codes flag to print the IOA bus error function names * @param is64bit Is this for a ioa-bus-error-64 call */ static void ioa_bus_error_usage(ei_function *ei_func, int show_codes, int is64bit) { int i; printf("Usage: %s %s [OPTIONS]\n", progname, ei_func->name); printf(" %s %s [OPTIONS]\n", progname, ei_func->alt_name); printf("%s\n", ei_func->desc); printf("This will inject an EEH bus error to the slot\n"); printf("A freeze condition should trigger on the next access to the adapter.\n\n"); printf("Mandatory arguments:\n"); printf(HELP_FMT, "-f function", "IOA bus error to inject"); printf("\n Specify a device either with the -s flag, or -p flag,\n"); printf(" or use the explicit BUID/config address flags.\n"); printf(HELP_FMT, "-s classpath", "look up device by sysfs classpath"); printf(HELP_FMT, "", "for example -s net/eth3 or -s scsi_host/host0\n"); printf(HELP_FMT, "-p loc-code", "look up device by location code"); printf(HELP_FMT, "", "for example -p \"U0.1-P2-I1\""); printf("\n"); printf(" Explicit BUID/config mandatory arguments:\n"); printf(HELP_FMT, "-c config_addr", "configure address of the IOA"); printf(HELP_FMT, "-h high_bits", "high bits of PHB unit id"); printf(HELP_FMT"\n", "-l lo_bits", "lo bits of PHB unit id"); print_optional_args(); if (is64bit) { printf(HELP_FMT, "-a addr", "64-bit address at which to report the error"); printf(HELP_FMT, "-m mask", "64-bit address mask (defaults to 0x0)"); } else { printf(HELP_FMT, "-a addr", "32-bit address at which to report the error"); printf(HELP_FMT, "-m mask", "32-bit address mask (defaults to 0x0)"); } print_cpu_arg(); print_token_arg(); if (show_codes) { printf("\nFunctions for %s:\n", ei_func->name); for (i = 0; i <= IOA_BUSERR_MAXFUNC; i++) printf("%3d - %s\n", i, ioa_buserr_fnames[i]); } } /** * ioa_bus_error_arg * @brief check for "IOA bus errors" cmdline args * * @param arg cmdline arg to check * @param optarg optional cmdline argument to 'arg' * @return 0 - indicates this is a IOA bus error arg * @return 1 - indicates this is not an IOA bus error arg */ int ioa_bus_error_arg(char arg, char *optarg) { switch (arg) { case 'a': bus_addr = strtoull(optarg, NULL, 16); break; case 'c': config_addr = strtoul(optarg, NULL, 16); break; case 'f': function = atoi(optarg); break; case 'h': phb_id_hi = strtoul(optarg, NULL, 16); break; case 'l': phb_id_lo = strtoul(optarg, NULL, 16); break; case 'm': mask = strtoull(optarg, NULL, 16); break; case 'p': loc_code = optarg; break; case 's': sysfsname = optarg; break; default: return 1; } return 0; } /** * get_config_addr_from_reg * @brief retrieve the config address from device-tree reg file * * Given the directory /proc/device-tree/pci@..., * yank out the config address out of the reg file * * @param devpath device-tree path of the reg file * @return 0 on failure, config address (!0) on success */ static uint32_t get_config_addr_from_reg(char *devpath) { char path[BUFSZ]; char *buf; uint32_t *be_caddr; uint32_t caddr = 0; strncpy(path, devpath, BUFSZ-5); strcat(path, "/reg"); buf = read_file(path, NULL); if (!buf) return 1; be_caddr = (uint32_t *)buf; caddr = be32toh(*be_caddr); free(buf); return caddr; } /** * parse_sysfsname * @brief parse a sysfs name for IOA bus error injections * * Users can specify a sysfs name on the cmdline for the adapter they want * to inject IOA bus errors into. This routine will parse the sysfsname * and retrieve the required data from sysfs to perform an IOA bus error * injection * * @return 0 on success, !0 otherwise */ static int parse_sysfsname(void) { char path[BUFSZ]; char *devspec; char *at; uint32_t addr; uint64_t phb_id; strcpy(path, "/sys/class/"); strcat(path, sysfsname); strcat(path, "/device"); if (!strncmp(sysfsname, "scsi_host", 9)) strcat(path, "/.."); strcat(path, "/devspec"); devspec = read_file(path, NULL); if (!devspec) return 1; /* Now we parse something like /pci@400000000112/pci@2/ethernet@1 for * BUID HI =4000 and LOW 00000112 */ at = strchr(devspec, '@'); if (!at || 0 == *at || 0 == *(++at)) { perr(errno, "Unable to parse devspec = %s\n", devspec); free(devspec); return 1; } phb_id = strtoull(at, NULL, 16); phb_id_hi = phb_id >> 32; phb_id_lo = phb_id & 0xFFFFFFFF; /* Obtain the config address from the device-tree reg file */ strcpy(path, "/proc/device-tree/"); strcat(path, devspec); addr = get_config_addr_from_reg(path); if (addr) { config_addr = addr; free(devspec); return 0; } free(devspec); return 1; } /** * recurse_hunt_file_contents * @brief search for a device with a given location code * * Walk directory structure recursively, * and try to find a device with a matchine ibm,loc-code. * If found, then copy the device-tree path into 'base_path' * and return a non-null pointer. * * (This return mechanism results in a few extra copies, * but so what, its perf critical, and memory management * is a whole lot easier this way.) * * @param base_path base path to begin search at * @param filename filename we are searchhing for * @param desired_file_contents contents we are searching for in "filename" * @param chase_link_cnt specify how far to chase links * @return pointer to base path to "filename" on success * @return NULL on failure */ static char *recurse_hunt_file_contents(char *base_path, const char *filename, const char *desired_file_contents, int chase_link_cnt) { char path[BUFSZ]; char *loco; strcpy(path, base_path); strcat(path, filename); loco = read_file(path, NULL); if (loco) { int ndesire = strlen(desired_file_contents); if (0 == strncmp(loco, desired_file_contents, ndesire)) { free(loco); return base_path; } } if (loco) free(loco); /* Either this dir did not contain a "filename" file, * or it did but the contents didn't match. Now, search the subdirs. */ DIR *dir = opendir(base_path); if (!dir) { perr(errno, "Couldn't open %s\n", base_path); return NULL; } while (1) { struct dirent *de = readdir(dir); if (!de) break; if (((DT_DIR == de->d_type) && ('.' != de->d_name[0])) || ((DT_LNK == de->d_type) && (0 < chase_link_cnt))) { /* Don't chase links forever, only go so deep. */ int depth = chase_link_cnt; if (DT_LNK == de->d_type) depth--; strcpy(path, base_path); strcat(path, "/"); strcat(path, de->d_name); char *found = recurse_hunt_file_contents(path, filename, desired_file_contents, depth); if (found) { closedir(dir); strcpy(base_path, found); return base_path; } } } closedir(dir); return NULL; } /** * hunt_loc_code * @brief Search for a specific location code * * Look for a specific IBM location code. * These are typically of the form U0.1-P2-I1/E1 or something like that. * Fill in the config addr, etc. based on what we find. * * @return 0 on success, !0 otherwise */ static int hunt_loc_code(void) { char path[BUFSZ]; char *match_dir; char *devspec; char *at; uint32_t addr; uint64_t phb_id; /* Try to find a device with a matching ibm,loc-code */ strcpy(path, "/proc/device-tree"); match_dir = recurse_hunt_file_contents(path, "/ibm,loc-code", loc_code, 0); if (NULL == match_dir) { perr(0, "Unable to find location code %s in device tree\n", loc_code); return 1; } devspec = path + strlen("/proc/device-tree"); /* Now we parse something like /pci@400000000112/pci@2/ethernet@1 for * BUID HI =4000 and LOW 00000112 */ at = strchr(devspec, '@'); if (!at || 0 == *at || 0 == *(++at)) { perr(errno, "Unable to parse devspec = %s\n", devspec); return 1; } phb_id = strtoull(at, NULL, 16); phb_id_hi = phb_id >> 32; phb_id_lo = phb_id & 0xFFFFFFFF; /* Try to get the config address from the dev-tree reg file. */ addr = get_config_addr_from_reg(path); if (addr) { config_addr = addr; return 0; } return 1; } /** * ioa_bus_error * @brief "IOA bus error" error injection handler * * @param ei_func errinjct functionality * @return 0 on success, !0 otherwise */ int ioa_bus_error(ei_function *ei_func, int is64bit) { int rc; if (ext_help) { ioa_bus_error_usage(ei_func, 1, is64bit); return 1; } /* Validate the function number */ if ((function < 0) || (function > IOA_BUSERR_MAXFUNC)) { ioa_bus_error_usage(ei_func, 1, is64bit); return 1; } if ((loc_code != NULL) && (sysfsname != NULL)) { perr(0, "Only specify one of the -p or -s options\n"); ioa_bus_error_usage(ei_func, 0, is64bit); } if (loc_code) { if (sysfs_check() != 0) return 1; rc = hunt_loc_code(); if (rc) { printf("Unable to find info for %s:\n", loc_code); if (is64bit) printf("ADDR MASK:\t\t%.16lx\n", mask); else printf("ADDR MASK:\t\t%.8lx\n", mask); printf("CONFIG ADDR:\t\t%x\n", config_addr); printf("PHB UNIT_ID:\t\t%x%.8x\n", phb_id_hi, phb_id_lo); printf("\nPlease try again or use the -s, -c, -h, and -l flags\n"); return 1; } } if (sysfsname) { if (sysfs_check() != 0) return 1; rc = parse_sysfsname(); if (rc) { printf("Unable to find info for %s:\n", sysfsname); if (is64bit) printf("ADDR MASK:\t\t%.16lx\n", mask); else printf("ADDR MASK:\t\t%.8lx\n", mask); printf("CONFIG ADDR:\t\t%x\n", config_addr); printf("PHB UNIT_ID:\t\t%x%.8x\n", phb_id_hi, phb_id_lo); printf("\nPlease try again or use the -p, -c, -h, and -l flags\n"); return 1; } } if ((config_addr == 0) || (phb_id_hi == 0) || (phb_id_lo == 0)) { printf("A sysfs device, slot location code, or\n"); printf("config address and PHB Unit ID are required inputs.\n"); printf("\nPlease try again, using the -s, -p or the -c, -h, and -l flags\n\n"); ioa_bus_error_usage(ei_func, 0, is64bit); return 1; } /* Get the "slot mode" config address, for DDR and PCI-E slots * that do not have an EADS bridge. */ uint32_t info; uint64_t phb_id = phb_id_hi; phb_id <<= 32; phb_id |= phb_id_lo; rc = rtas_get_config_addr_info2(config_addr, phb_id, 0, &info); if (rc == 0) config_addr = info; if (!be_quiet) { printf("Injecting an ioa-bus-error"); if (verbose || dryrun) { printf(" with the following data:\n\n"); if (is64bit) { printf("BUS ADDR:\t\t%.16lx\n", bus_addr); printf("ADDR MASK:\t\t%.16lx\n", mask); } else { printf("BUS ADDR:\t\t%.8lx\n", bus_addr); printf("ADDR MASK:\t\t%.8lx\n", mask); } printf("CONFIG ADDR:\t\t%x\n", config_addr); printf("PHB UNIT_ID:\t\t%x%.8x\n", phb_id_hi, phb_id_lo); printf("FUNCTION:\t\t%d\n", function); printf("%s\n", ioa_buserr_fnames[function]); } else { printf("...\n"); } } if (dryrun) return 0; if (is64bit) { err_buf[0] = htobe32(bus_addr >> 32); err_buf[1] = htobe32(bus_addr & 0xffffffff); err_buf[2] = htobe32(mask >> 32); err_buf[3] = htobe32(mask & 0xffffffff); err_buf[4] = htobe32(config_addr); err_buf[5] = htobe32(phb_id_hi); err_buf[6] = htobe32(phb_id_lo); err_buf[7] = htobe32(function); } else { err_buf[0] = htobe32(bus_addr); err_buf[1] = htobe32(mask); err_buf[2] = htobe32(config_addr); err_buf[3] = htobe32(phb_id_hi); err_buf[4] = htobe32(phb_id_lo); err_buf[5] = htobe32(function); } rc = do_rtas_errinjct(ei_func); if ((rc == 0) && verbose) printf("If the correct information was provided and there is\nactivity on the bus, the hardware should hit the error\nHowever, if incorrect information was provided or there\nis no bus activity, you may not get a hit.\n\n"); return rc; } int ioa_bus_error32(ei_function *ei_func) { return ioa_bus_error(ei_func, 0); } int ioa_bus_error64(ei_function *ei_func) { return ioa_bus_error(ei_func, 1); } powerpc-utils-1.3.4/src/errinjct/open_close.c000066400000000000000000000065051315235264300212470ustar00rootroot00000000000000/** * @file open_close.c * @brief Hardware error injection tool - open/close module * @author Nathan Fontenot * @author Linas Vepstas * * Open and close the RTAS error injection facitlity * * Copyright (c) 2004 IBM Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "errinjct.h" /** * ei_open_usage * @brief print the "open" error injection usage statement * * @param ei_func errinjct functionality */ static void ei_open_usage(ei_function *ei_func) { printf("Usage: %s %s\n", progname, ei_func->name); printf("%s\n\n", ei_func->desc); print_optional_args(); } /** * ei_open_arg * @brief check for "open" cmdline arg * * There are no additional args to open, return failure * * @param arg cmdline arg to check * @param optarg optional cmdline argument to 'arg' * @return 1, always */ int ei_open_arg(char arg, char *optarg) { return 1; } /** * ei_open * @brief "open" error injection handler * * @param ei_func pointer to errinjct functionality * @return 0 on success, !0 otherwise */ int ei_open(ei_function *ei_func) { int rc; if (ext_help) { ei_open_usage(ei_func); return 1; } if (verbose || dryrun) printf("Opening RTAS error injection facility\n"); if (dryrun) return 0; rc = open_rtas_errinjct(ei_func); if (rc == 0) printf("RTAS error injection facility open, token = %d\n", ei_token); return rc; } /** * ei_close_usage * @brief Print the "close" usage statement error injection * * @param ei_func pointer to errinjct functionality */ static void ei_close_usage(ei_function *ei_func) { printf("Usage: %s %s\n", progname, ei_func->name); printf("%s\n\n", ei_func->desc); printf("Mandatory argument:\n"); print_token_arg(); print_optional_args(); print_cpu_arg(); } /** * ei_close_arg * @brief check for "close" specific cmdline args * * The errinjct close functionality does not take any additional * args, always return 1 (failure). * * @param arg cmdline arg to check * @param optarg optional cmdline argument to 'arg' * @return 1, always */ int ei_close_arg(char arg, char *optarg) { return 1; } /** * ei_close * @brief Closes the RTAS error injection facility * * @param ei_func errinjct functionality * @return 0 on success, !0 otherwise */ int ei_close(ei_function *ei_func) { int rc; if (ext_help || check_token_arg()) { ei_close_usage(ei_func); return 1; } if (verbose || dryrun) printf("Closing RTAS error injection facility with token %d\n", ei_token); if (dryrun) return 0; rc = close_rtas_errinjct(ei_func); if ((rc == 0) && verbose) printf("RTAS error injection facility closed.\n"); return rc; } powerpc-utils-1.3.4/src/errinjct/platform.c000066400000000000000000000055371315235264300207510ustar00rootroot00000000000000/** * @file platform.c * @brief Hardware Error Injection Tool platform specific module * @author Nathan Fontenot * @author Linas Vepstas * * Inject platform-specific errors. * * Copyright (c) 2004 IBM Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include "errinjct.h" /** * @var fname * @brief file containg platform specific error injection data */ static char *fname; /** * platform_specific_usage * @brief print the "platform specific" error injection usage message * * @param ei_func errinjct functionality */ static void platform_specific_usage(ei_function *ei_func) { printf("Usage: %s %s [OPTIONS]\n", progname, ei_func->name); printf("%s\n\n", ei_func->desc); printf("Mandatory argument:\n"); printf(HELP_FMT, "-f fname", "file name to read platform specific"); printf(HELP_FMT, "", "error injection data from"); print_optional_args(); print_cpu_arg(); print_token_arg(); } /** * platform_specific_arg * @brief check for "platform specific" cmdline args * * @param arg cmdline arg to check * @param optarg optional cmdline argument to 'arg' * @return 0 - indicates this is a platform specific arg * @return 1 - indicates this is not a platform specific arg */ int platform_specific_arg(char arg, char *optarg) { switch (arg) { case 'f': fname = optarg; break; default: return 1; } return 0; } /** * platform_specific * @brief "platform specific" error injection handler * * @param ei_func errinjct functionality * @return 0 on success, !0 otherwise */ int platform_specific(ei_function *ei_func) { char *buf; int rc; if (ext_help) { platform_specific_usage(ei_func); return 1; } if (fname == NULL) { perr(0, "Please specify a file with the -f option"); platform_specific_usage(ei_func); return 1; } buf = read_file(fname, NULL); if (!buf) return 1; if (!be_quiet) printf("Injecting a %s error with data from %s\n", ei_func->name, fname); if (dryrun) { free(buf); return 0; } rc = do_rtas_errinjct(ei_func); free(buf); return rc; } powerpc-utils-1.3.4/src/errinjct/slb.c000066400000000000000000000055731315235264300177050ustar00rootroot00000000000000/** * @file slb.c * @brief Hardware Error Injection Tool slb module * @author Nathan Fontenot * @author Linas Vepstas * * Inject SLB errors. * * Copyright (c) 2004 IBM Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "errinjct.h" static unsigned long addr; /**< address at which to inject the error */ static int addr_flag; /**< indicates the address flag has been * specified */ /** * corrupted_slb_usage * @brief print the "corrupted slb" error inject usage message * * @param ei_func errinjct functionality */ static void corrupted_slb_usage(ei_function *ei_func) { printf("Usage: %s %s [OPTIONS]\n", progname, ei_func->name); printf(" %s %s [OPTIONS]\n", progname, ei_func->alt_name); printf("%s\n\n", ei_func->desc); printf("Mandatory Argument:\n"); printf(HELP_FMT, "-a addr", "effective address associated with the"); printf(HELP_FMT, "", "SLB entry to corrupt\n"); print_optional_args(); print_cpu_arg(); print_token_arg(); } /** * corrupted_alb_arg * @brief check for "corrupted alb" specific cmdline args * * @param arg cmdline arg to check * @param optarg optional argument to 'arg' * @return 0 - indicates this is a "corrupted slb" cmdline arg * @return 1 - indicates this is not a "corrupted slb" cmdline arg */ int corrupted_slb_arg(char arg, char *optarg) { switch (arg) { case 'a': addr = strtoul(optarg, NULL, 16); addr_flag = 1; break; default: return 1; } return 0; } /** * corrupted_slb * @brief "corrupted slb" error injection handler * * @param ei_func errinjct functionality * @return 0 on success, !0 otherwise */ int corrupted_slb(ei_function *ei_func) { int rc; if (ext_help) { corrupted_slb_usage(ei_func); return 1; } if (addr_flag == 0) { perr(0, "Please specify an address with the -a option"); corrupted_slb_usage(ei_func); return 1; } if (!be_quiet) { printf("Injecting a %s error\n", ei_func->name); printf("Effective address = 0x%lx\n", addr); } if (dryrun) return 0; err_buf[0] = addr; rc = do_rtas_errinjct(ei_func); return rc; } powerpc-utils-1.3.4/src/errinjct/tlb.c000066400000000000000000000044251315235264300177010ustar00rootroot00000000000000/** * @file tlb.c * @brief Hardware Error Injection Tool TLB module * @author Nathan Fontenot * @author Linas Vepstas * * Inject corrupted-tlb-start and corrupted-tlb-end errors. * * Copyright (c) 2004 IBM Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "errinjct.h" /** * corrupted_tlb_usage * @brief print the "corrupted tlb" error injection usage message * * @param ei_func errinjct functionality */ static void corrupted_tlb_usage(ei_function *ei_func) { printf("Usage: %s %s\n", progname, ei_func->name); printf(" %s %s\n", progname, ei_func->alt_name); printf("%s\n\n", ei_func->desc); printf("Mandatory arguments:\n"); print_cpu_arg(); print_token_arg(); print_optional_args(); } /** * corrupted_tlb_arg * @brief check for "corrupted tlb" specific cmdline args * * There are no additional args to "corrupted tlb" error injections, * thus we always return 1 (failure) * * @param arg cmdline arg to check * @param optarg optional argument to 'arg' * @return 1, always */ int corrupted_tlb_arg(char arg, char *optarg) { return 1; } /** * corrupted_tlb * @brief "corrupted tlb" error injection handler * * @param ei_func errinjct functionality * @return 0 on success, !0 otherwise */ int corrupted_tlb(ei_function *ei_func) { int rc; if (ext_help || check_cpu_arg() || check_token_arg()) { corrupted_tlb_usage(ei_func); return 1; } if (!be_quiet) { printf("Injecting a %s error on cpu %d\n", ei_func->name, logical_cpu); } if (dryrun) return 0; rc = do_rtas_errinjct(ei_func); return rc; } powerpc-utils-1.3.4/src/lparstat.c000066400000000000000000000305051315235264300171300ustar00rootroot00000000000000/** * @file lparstat.c * @brief lparstat command * * Copyright (c) 2011 International Business Machines * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * @author Nathan Fontenot */ #include #include #include #include #include #include #include #include "lparstat.h" #include "pseries_platform.h" #define LPARCFG_FILE "/proc/ppc64/lparcfg" #define SE_NOT_FOUND "???" #define SE_NOT_VALID "-" struct sysentry *get_sysentry(char *name) { struct sysentry *se = &system_data[0]; while (se->name[0] != '\0') { if (!strcmp(se->name, name)) return se; se++; } return NULL; } void get_sysdata(char *name, char **descr, char *value) { struct sysentry *se; se = get_sysentry(name); if (!se) { *descr = name; sprintf(value, SE_NOT_FOUND); return; } if (se->get) { se->get(se, value); } else if (se->value[0] == '\0') { sprintf(value, SE_NOT_VALID); } else { sprintf(value, "%s", se->value); } *descr = se->descr; } void get_time() { struct timeval t; struct sysentry *se; gettimeofday(&t, 0); se = get_sysentry("time"); sprintf(se->value, "%lld", (long long)t.tv_sec * 1000000LL + (long long)t.tv_usec); } long long elapsed_time() { long long newtime, oldtime = 0; struct sysentry *se; se = get_sysentry("time"); newtime = strtoll(se->value, NULL, 0); oldtime = strtoll(se->old_value, NULL, 0); return newtime - oldtime; } int get_time_base() { FILE *f; char buf[80]; char *tb = NULL; struct sysentry *se; f = fopen("/proc/cpuinfo", "r"); if (!f) { fprintf(stderr, "Could not open /proc/cpuinfo\n"); return -1; } while ((fgets(buf, 80, f)) != NULL) { if (!strncmp(buf, "timebase", 8)) { tb = strchr(buf, ':') + 2; break; } } fclose(f); if (!tb) return -1; se = get_sysentry("timebase"); sprintf(se->value, "%s", tb); return 0; } void get_cpu_physc(struct sysentry *unused_se, char *buf) { struct sysentry *se; float elapsed; float new_purr, old_purr; float timebase, physc; elapsed = elapsed_time() / 1000000.0; se = get_sysentry("timebase"); timebase = atoi(se->value); se = get_sysentry("purr"); new_purr = strtoll(se->value, NULL, 0); old_purr = strtoll(se->old_value, NULL, 0); physc = (new_purr - old_purr)/timebase/elapsed; sprintf(buf, "%.6f", physc); } void get_per_entc(struct sysentry *unused_se, char *buf) { char *descr; char physc[32]; char entc[32]; get_sysdata("DesEntCap", &descr, entc); get_sysdata("physc", &descr, physc); sprintf(buf, "%.6f", atof(physc) / atof(entc) * 100.0); } int parse_lparcfg() { FILE *f; char line[128]; char *first_line; f = fopen(LPARCFG_FILE, "r"); if (!f) { fprintf(stderr, "Could not open %s\n", LPARCFG_FILE); return -1; } /* parse the file skipping the first line */ first_line = fgets(line, 128, f); if (!first_line) { fclose(f); fprintf(stderr, "Could not read first line of %s\n", LPARCFG_FILE); return -1; } while (fgets(line, 128, f) != NULL) { char *name, *value, *nl; struct sysentry *se; if (line[0] == '\n') continue; name = &line[0]; value = strchr(line, '='); *value = '\0'; value++; nl = strchr(value, '\n'); *nl = '\0'; se = get_sysentry(name); if (se) strncpy(se->value, value, SYSDATA_VALUE_SZ); } fclose(f); return 0; } int parse_proc_ints() { FILE *f; char *line, *p; size_t n = 0; char *value; struct sysentry *se; long long int phint = 0; f = fopen("/proc/interrupts", "r"); if (!f) { fprintf(stderr, "Could not open /proc/interrupts\n"); return -1; } while (getline(&line, &n, f) != -1) { p = line; while (*p == ' ') p++; /* we just need the SPU line */ if (p[0] != 'S' || p[1] != 'P' || p[2] != 'U') continue; for (value = &p[5]; value[2] != 'S'; value += 11) { int v; v = atoi(value); phint += v; } break; } free(line); fclose(f); se = get_sysentry("phint"); sprintf(se->value, "%lld", phint); return 0; } int parse_proc_stat() { FILE *f; char line[128]; char *value; int i, entries = 6; long long statvals[entries]; struct sysentry *se; char *first_line; char *names[] = {"cpu_total", "cpu_user", "cpu_nice", "cpu_sys", "cpu_idle", "cpu_iowait"}; /* we just need the first line */ f = fopen("/proc/stat", "r"); if (!f) { fprintf(stderr, "Could not open /proc/stat\n"); return -1; } first_line = fgets(line, 128, f); fclose(f); if (!first_line) { fprintf(stderr, "Could not read first line of /proc/stat\n"); return -1; } statvals[0] = 0; value = line; for (i = 1; i <= (entries - 1); i++) { long long v; value = strchr(value, ' ') + 1; if (i == 1) value++; v = atoll(value); statvals[i] = v; statvals[0] += v; } for (i = 0; i < entries; i++) { se = get_sysentry(names[i]); sprintf(se->value, "%lld", statvals[i]); } se = get_sysentry("cpu_lbusy"); sprintf(se->value, "%lld", statvals[1] + statvals[3]); return 0; } void get_smt_state(struct sysentry *se, char *buf) { char *value = "?"; if (se->value[0] == '1') value = "Shared"; else value = "Dedicated"; sprintf(buf, "%s", value); } void get_capped_mode(struct sysentry *se, char *buf) { char *value = "?"; if (se->value[0] == '1') value = "Capped"; else value = "Uncapped"; sprintf(buf, "%s", value); } void get_percent_entry(struct sysentry *se, char *buf) { float value; value = atoi(se->value); sprintf(buf, "%.2f", (value /100)); } void get_phys_cpu_percentage(struct sysentry *se, char *buf) { struct sysentry *tmp_se; int entcap, active; tmp_se = get_sysentry("DesEntCap"); entcap = atoi(tmp_se->value); tmp_se = get_sysentry("partition_active_processors"); active = atoi(tmp_se->value); sprintf(buf, "%d", entcap/active); } void get_active_cpus_in_pool(struct sysentry *se, char *buf) { struct sysentry *tmp; tmp = get_sysentry("physical_procs_allocated_to_virtualization"); if (tmp) { sprintf(buf, "%d", atoi(tmp->value)); } else { tmp = get_sysentry("pool_capacity"); sprintf(buf, "%d", atoi(tmp->value)/100); } } void get_memory_mode(struct sysentry *se, char *buf) { struct sysentry *tmp; tmp = get_sysentry("entitled_memory_pool_number"); if (atoi(tmp->value) == 65535) sprintf(buf, "Dedicated"); else sprintf(buf, "Shared"); } void get_name(const char *file, char *buf) { FILE *f; char tmpbuf[64]; int rc; f = fopen(file, "r"); if(!f) { sprintf(buf, "%c", '\0'); return; } rc = fread(tmpbuf, 64, 1, f); fclose(f); if (!rc) sprintf(buf, "%s", tmpbuf); } void get_node_name(struct sysentry *se, char *buf) { char *nl; get_name("/proc/sys/kernel/hostname", buf); /* For some reason this doesn't get null-terminated and makes * for ugly output. */ nl = strchr(buf, '\n'); *nl = '\0'; } void get_partition_name(struct sysentry *se, char *buf) { return get_name("/proc/device-tree/ibm,partition-name", buf); } void get_mem_total(struct sysentry *se, char *buf) { FILE *f; char line[128]; char *mem, *nl, *first_line; f = fopen("/proc/meminfo", "r"); if (!f) { fprintf(stderr, "Could not open /proc/meminfo\n"); return; } first_line = fgets(line, 128, f); fclose(f); if (!first_line) { fprintf(stderr, "Could not read first line of /proc/meminfo\n"); return; } mem = strchr(line, ':'); do { mem++; } while (*mem == ' '); nl = strchr(mem, '\n'); *nl = '\0'; sprintf(buf, "%s", mem); } void get_smt_mode(struct sysentry *se, char *buf) { FILE *f; char line[128]; char *cmd = "/usr/sbin/ppc64_cpu --smt"; char *first_line; f = popen(cmd, "r"); if (!f) { fprintf(stderr, "Failed to execute %s\n", cmd); return; } first_line = fgets(line, 128, f); pclose(f); if (!first_line) { fprintf(stderr, "Could not read output of %s\n", cmd); return; } /* The output is either "SMT=x" or "SMT is off", we can cheat * by looking at line[8] for an 'f'. */ if (line[8] == 'f') sprintf(buf, "Off"); else sprintf(buf, "%c", line[4]); } long long get_cpu_time_diff() { long long old_total = 0, new_total = 0; struct sysentry *se; se = get_sysentry("cpu_total"); new_total = strtoll(se->value, NULL, 0); old_total = strtoll(se->old_value, NULL, 0); return new_total - old_total; } void get_cpu_stat(struct sysentry *se, char *buf) { float percent; long long total, old_val, new_val; total = get_cpu_time_diff(); new_val = atoll(se->value); old_val = atoll(se->old_value); percent = ((new_val - old_val)/(long double)total) * 100; sprintf(buf, "%.2f", percent); } void init_sysdata(void) { get_time(); parse_lparcfg(); parse_proc_stat(); parse_proc_ints(); get_time_base(); } void update_sysdata(void) { struct sysentry *se = &system_data[0]; while (se->name[0] != '\0') { memcpy(se->old_value, se->value, SYSDATA_VALUE_SZ); se++; } init_sysdata(); } int print_iflag_data() { char *fmt = "%-45s: %s\n"; char value[64]; char *descr; int i = 0; while (iflag_entries[i] != NULL) { get_sysdata(iflag_entries[i], &descr, value); #ifndef DEBUG if (strcmp(value, SE_NOT_VALID) && strcmp(value, SE_NOT_FOUND)) #endif fprintf(stdout, fmt, descr, value); i++; } return 0; } void print_default_output(int interval, int count) { char *fmt = "%5s %5s %5s %8s %8s %5s %5s %5s %5s\n"; char *descr; char buf[128]; int offset; char value[32]; char user[32], sys[32], wait[32], idle[32], physc[32], entc[32]; char lbusy[32], vcsw[32], phint[32]; memset(buf, 0, 128); get_sysdata("shared_processor_mode", &descr, value); offset = sprintf(buf, "type=%s ", value); get_sysdata("capped", &descr, value); offset += sprintf(buf + offset, "mode=%s ", value); get_sysdata("smt_state", &descr, value); offset += sprintf(buf + offset, "smt=%s ", value); get_sysdata("partition_active_processors", &descr, value); offset += sprintf(buf + offset, "lcpu=%s ", value); get_sysdata("MemTotal", &descr, value); offset += sprintf(buf + offset, "mem=%s ", value); get_sysdata("active_cpus_in_pool", &descr, value); offset += sprintf(buf + offset, "cpus=%s ", value); get_sysdata("DesEntCap", &descr, value); offset += sprintf(buf + offset, "ent=%s ", value); fprintf(stdout, "\nSystem Configuration\n%s\n\n", buf); fprintf(stdout, fmt, "\%user", "\%sys", "\%wait", "\%idle", "physc", "\%entc", "lbusy", "vcsw", "phint"); fprintf(stdout, fmt, "-----", "-----", "-----", "-----", "-----", "-----", "-----", "-----", "-----"); do { if (interval) { sleep(interval); update_sysdata(); } get_sysdata("cpu_user", &descr, user); get_sysdata("cpu_sys", &descr, sys); get_sysdata("cpu_iowait", &descr, wait); get_sysdata("cpu_idle", &descr, idle); get_sysdata("cpu_lbusy", &descr, lbusy); get_sysdata("dispatches", &descr, vcsw); get_sysdata("physc", &descr, physc); get_sysdata("per_entc", &descr, entc); get_sysdata("phint", &descr, phint); fprintf(stdout, fmt, user, sys, wait, idle, physc, entc, lbusy, vcsw, phint); fflush(stdout); } while (--count > 0); } static struct option long_opts[] = { {"version", no_argument, NULL, 'V'}, {0, 0, 0, 0}, }; int main(int argc, char *argv[]) { int interval = 0, count = 0; int c, opt_index = 0; int i_option = 0; if (get_platform() != PLATFORM_PSERIES_LPAR) { fprintf(stderr, "%s: is not supported on the %s platform\n", argv[0], platform_name); exit(1); } while ((c = getopt_long(argc, argv, "iV", long_opts, &opt_index)) != -1) { switch(c) { case 'i': i_option = 1; break; case 'V': printf("lparstat - %s\n", VERSION); return 0; case '?': default: break; } } /* see if there is an interval specified */ if (optind < argc) interval = atoi(argv[optind++]); /* check for count specified */ if (optind < argc) count = atoi(argv[optind++]); init_sysdata(); if (i_option) print_iflag_data(); else print_default_output(interval, count); return 0; } powerpc-utils-1.3.4/src/lparstat.h000066400000000000000000000210121315235264300171260ustar00rootroot00000000000000/** * @file lparstat.h * @brief lparstat command header * * Copyright (c) 2011 International Business Machines * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * @author Nathan Fontenot */ #define SYSDATA_VALUE_SZ 64 #define SYSDATA_NAME_SZ 64 #define SYSDATA_DESCR_SZ 128 struct sysentry { char value[SYSDATA_VALUE_SZ]; /* value from file */ char old_value[SYSDATA_VALUE_SZ]; /* previous value from file */ char name[SYSDATA_NAME_SZ]; /* internal name */ char descr[SYSDATA_DESCR_SZ]; /* description of data */ void (*get)(struct sysentry *, char *); }; extern void get_smt_state(struct sysentry *, char *); extern void get_capped_mode(struct sysentry *, char *); extern void get_memory_mode(struct sysentry *, char *); extern void get_percent_entry(struct sysentry *, char *); extern void get_phys_cpu_percentage(struct sysentry *, char *); extern void get_active_cpus_in_pool(struct sysentry *, char *); extern void get_partition_name(struct sysentry *, char *); extern void get_node_name(struct sysentry *, char *); extern void get_mem_total(struct sysentry *, char *); extern void get_smt_mode(struct sysentry *, char *); extern void get_cpu_stat(struct sysentry *, char *); extern void get_cpu_physc(struct sysentry *, char *); extern void get_per_entc(struct sysentry *, char *); struct sysentry system_data[] = { /* System Names */ {.name = "node_name", .descr = "Node Name", .get = &get_node_name}, {.name = "partition_name", .descr = "Partition Name", .get = &get_partition_name}, /* lparcfg data */ {.name = "serial_number", .descr = "Serial Number"}, {.name = "system_type", .descr = "System Model"}, {.name = "partition_id", .descr = "Partition Number"}, {.name = "group", .descr = "Partition Group-ID"}, {.name = "BoundThrds", .descr = "Bound Threads"}, {.name = "CapInc", .descr = "Capacity Increment", .get = &get_percent_entry}, {.name = "DisWheRotPer", .descr = "Dispatch Wheel Rotation Period"}, {.name = "MinEntCap", .descr = "Minimum Capacity", .get = &get_percent_entry}, {.name = "MinEntCapPerVP", .descr = "Minimum Entitled Capacity per Virtual Processor"}, {.name = "MinProcs", .descr = "Minimum Virtual CPUs"}, {.name = "partition_max_entitled_capacity", .descr = "Maximum Capacity", .get = &get_percent_entry}, {.name = "system_potential_processors", .descr = "Maximum System Processors"}, {.name = "DesEntCap", .descr = "Entitled Capacity", .get = &get_percent_entry}, {.name = "DesProcs", .descr = "Desired Processors"}, {.name = "DesVarCapWt", .descr = "Desired Variable Capacity Weight"}, {.name = "DedDonMode", .descr = "Dedicated Donation Mode"}, {.name = "partition_entitled_capacity", .descr = "Partition Entitled Capacity"}, {.name = "system_active_processors", .descr = "Active Physical CPUs in system"}, {.name = "pool", .descr = "Shared Pool ID"}, {.name = "pool_capacity", .descr = "Maximum Capacity of Pool", .get = &get_percent_entry}, {.name = "pool_idle_time", .descr = "Shared Processor Pool Idle Time"}, {.name = "pool_num_procs", .descr = "Shared Processor Pool Processors"}, {.name = "unallocated_capacity_weight", .descr = "Unallocated Weight"}, {.name = "capacity_weight", .descr = "Entitled Capacity of Pool"}, {.name = "capped", .descr = "Mode", .get = &get_capped_mode}, {.name = "unallocated_capacity", .descr = "Unallocated Processor Capacity"}, {.name = "physical_procs_allocated_to_virtualization", .descr = "Shared Physical CPUS in system"}, {.name = "max_proc_entitled_capacity", .descr = "Maximum Processor Capacity Available to Pool"}, {.name = "entitled_proc_capacity_available", .descr = "Entitled Capacity of Pool"}, {.name = "dispatches", .descr = "Virtual Processor Dispatch Counter"}, {.name = "dispatch_dispersions", .descr = "Virtual Processor Dispersions"}, {.name = "purr", .descr = "Processor Utilization Resource Register"}, {.name = "partition_active_processors", .descr = "Online Virtual CPUs"}, {.name = "partition_potential_processors", .descr = "Maximum Virtual CPUs"}, {.name = "shared_processor_mode", .descr = "Type", .get = &get_smt_state}, {.name = "slb_size", .descr = "SLB Entries"}, {.name = "MinMem", .descr = "Minimum Memory"}, {.name = "DesMem", .descr = "Desired Memory"}, {.name = "entitled_memory", .descr = "Total I/O Memory Entitlement"}, {.name = "mapped_entitled_memory", .descr = "Total I/O Mapped Entitled Memory"}, {.name = "entitled_memory_group_number", .descr = "Memory Group ID of LPAR"}, {.name = "entitled_memory_pool_number", .descr = "Memory Pool ID"}, {.name = "entitled_memory_pool_size", .descr = "Physical Memory in the Pool"}, {.name = "entitled_memory_weight", .descr = "Variable Memory Capacity Weight"}, {.name = "unallocated_entitled_memory_weight", .descr = "Unallocated Variable Memory Capacity Weight"}, {.name = "unallocated_io_mapping_entitlement", .descr = "Unallocated I/O Memory Entitlement"}, {.name = "entitled_memory_loan_request", .descr = "Entitled Memory Loan Request"}, {.name = "backing_memory", .descr = "Backing Memory"}, {.name = "cmo_enabled", .descr = "Active Memory Sharing Enabled"}, {.name = "cmo_faults", .descr = "Active Memory Sharing Page Faults"}, {.name = "cmo_fault_time_usec", .descr = "Active Memory Sharing Fault Time"}, {.name = "cmo_primary_psp", .descr = "Primary VIOS Partition ID"}, {.name = "cmo_secondary_psp", .descr = "Secondary VIOS Partition ID"}, {.name = "cmo_page_size", .descr = "Physical Page Size"}, /* /proc/meminfo */ {.name = "MemTotal", .descr = "Online Memory", .get = &get_mem_total}, /* ppc64_cpu --smt */ {.name = "smt_state", .descr = "SMT", .get = &get_smt_mode}, /* /proc/stat */ {.name = "cpu_total", .descr = "CPU Total Time"}, {.name = "cpu_user", .descr = "CPU User Time", .get = &get_cpu_stat}, {.name = "cpu_nice", .descr = "CPU Nice Time", .get = &get_cpu_stat}, {.name = "cpu_sys", .descr = "CPU System Time", .get = &get_cpu_stat}, {.name = "cpu_idle", .descr = "CPU Idle Time", .get = &get_cpu_stat}, {.name = "cpu_iowait", .descr = "CPU I/O Wait Time", .get = &get_cpu_stat}, {.name = "cpu_lbusy", .descr = "Logical CPU Utilization", .get = &get_cpu_stat}, /* placeholders for derived values */ {.name = "active_cpus_in_pool", .descr = "Active CPUs in Pool", .get = &get_active_cpus_in_pool}, {.name = "phys_cpu_percentage", .descr = "Physical CPU Percentage", .get = &get_phys_cpu_percentage}, {.name = "memory_mode", .descr = "Memory Mode", .get = &get_memory_mode}, {.name = "physc", .descr = "Physical CPU Consumed", .get = &get_cpu_physc}, {.name = "per_entc", .descr = "Entitled CPU Consumed", .get = &get_per_entc}, /* Time */ {.name = "time", .descr = "Time"}, /* /proc/cpuinfo */ {.name = "timebase", .descr = "Timebase"}, /* /proc/interrupts */ {.name = "phint", .descr = "Phantom Interrupts"}, {.name[0] = '\0'}, }; char *iflag_entries[] = { "node_name", "partition_name", "partition_id", "shared_processor_mode", "capped", "DesEntCap", "group", "pool", "partition_active_processors", "partition_potential_processors", "MinProcs", "MemTotal", "MinMem", "MaxMem", "MinEntCap", "partition_max_entitled_capacity", "CapInc", "max_system_cpus", "system_active_processors", "active_cpus_in_pool", "shared_cpus_in_system", "physical_procs_allocated_to_virtualization", "pool_capacity", "entitled_proc_capacity_available", "unallocated_capacity", "phys_cpu_percentage", "unallocated_capacity_weight", "memory_mode", "entitled_memory", "entitled_memory_weight", "entitled_memory_pool_number", "entitled_memory_pool_size", "hypervisor_page_size", "unallocated_entitled_memory_weight", "unallocated_io_mapping_entitlement", "entitled_memory_group_number", "desired_virt_cpus", "desired_memory", "DesVarCapWt", "desired_capacity", "target_mem_factor", "target_mem_size", NULL }; powerpc-utils-1.3.4/src/lsprop.c000066400000000000000000000126161315235264300166200ustar00rootroot00000000000000/* * Copyright (C) 1998 Paul Mackerras. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #if defined(__FreeBSD__) #include #else #include #endif int recurse; int maxbytes = 128; int words_per_line = 0; unsigned char *buf; void lsprop(FILE *f, char *name); void lsdir(char *name); static struct option long_opts[] = { {"version", no_argument, NULL, 'V'}, {"recurse", no_argument, NULL, 'R'}, {0, 0, 0, 0}, }; int main(int ac, char **av) { FILE *f; int i, opt_index = 0; struct stat sb; char *endp; while ((i = getopt_long(ac, av, "Rm:w:V", long_opts, &opt_index)) != EOF) { switch (i) { case 'R': recurse = 1; break; case 'm': maxbytes = strtol(optarg, &endp, 0); if (endp == optarg) { fprintf(stderr, "%s: bad argument (%s) to -m option\n", av[0], optarg); exit(1); } maxbytes = (maxbytes + 15) & -16; break; case 'w': words_per_line = strtol(optarg, &endp, 0); if (endp == optarg) { fprintf(stderr, "%s: bad argument (%s) to -w option\n", av[0], optarg); exit(1); } break; case 'V': printf("lsprop - %s\n", VERSION); return 0; } } buf = malloc(maxbytes); if (buf == 0) { fprintf(stderr, "%s: virtual memory exhausted\n", av[0]); exit(1); } if (optind == ac) lsdir("."); else for (i = optind; i < ac; ++i) { if (stat(av[i], &sb) < 0) { perror(av[i]); continue; } if (S_ISREG(sb.st_mode)) { f = fopen(av[i], "r"); if (f == NULL) { perror(av[i]); continue; } lsprop(f, av[i]); fclose(f); } else if (S_ISDIR(sb.st_mode)) { lsdir(av[i]); } } exit(0); } void lsdir(char *name) { DIR *d; struct dirent *de; char *p, *q; struct stat sb; FILE *f; int np = 0; d = opendir(name); if (d == NULL) { perror(name); return; } p = malloc(strlen(name) + 520); if (p == 0) { fprintf(stderr, "%s: virtual memory exhausted\n", name); closedir(d); return; } strcpy(p, name); q = p + strlen(p); while (q > p && q[-1] == '/') --q; if (q == p + 1 && p[0] == '.') q = p; else *q++ = '/'; while ((de = readdir(d)) != NULL) { if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue; strcpy(q, de->d_name); if (stat(p, &sb) < 0) { perror(p); continue; } if (S_ISREG(sb.st_mode)) { f = fopen(p, "r"); if (f == NULL) { perror(p); } else { lsprop(f, de->d_name); fclose(f); ++np; } } } if (recurse) { rewinddir(d); while ((de = readdir(d)) != NULL) { if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue; strcpy(q, de->d_name); if (lstat(p, &sb) < 0) { perror(p); continue; } if (S_ISDIR(sb.st_mode)) { if (np) printf("\n"); printf("%s:\n", p); lsdir(p); ++np; } } } free(p); closedir(d); } void lsprop(FILE *f, char *name) { int n, nw, npl, i, j; n = fread(buf, 1, maxbytes, f); if (n < 0) { printf("%s: read error\n", name); return; } printf("%-16s", name); if (strlen(name) > 16) printf("\n\t\t"); for (i = 0; i < n; ++i) if (buf[i] >= 0x7f || (buf[i] < 0x20 && buf[i] != '\r' && buf[i] != '\n' && buf[i] != '\t' && buf[i] != 0)) break; if (i == n && n != 0 && (n == 1 || buf[0] != 0) && buf[n-1] == 0) { printf(" \""); for (i = 0; i < n - 1; ++i) if (buf[i] == 0) printf("\"\n\t\t \""); else if (buf[i] == '\r' || buf[i] == '\n') printf("\n\t\t "); else putchar(buf[i]); putchar('"'); } else if ((n & 3) == 0) { nw = n >> 2; if (nw == 1) { i = be32toh(*(int *)buf); printf(" %.8x", i); if (i > -0x10000 && !(i >= 0 && i <= 9)) printf(" (%d)", i); } else { npl = words_per_line; if (npl <= 0) { if ((nw % 6) == 0) npl = 6; else if ((nw % 5) == 0) npl = 5; else npl = 4; } for (i = 0; i < nw; i += npl) { if (i != 0) printf("\n\t\t"); for (j = 0; j < npl && i + j < nw; ++j) printf(" %.8x", be32toh(((unsigned int *)buf)[i+j])); } } } else { for (i = 0; i < n; i += 16) { if (i != 0) printf("\n\t\t"); for (j = 0; j < 16 && i + j < n; ++j) printf(" %.2x", buf[i+j]); for (; j < 16; ++j) printf(" "); for (j = 0; j < 16 && i + j < n; ++j) if (buf[i+j] > 0x20 && buf[i+j] <= 0x7e) putchar(buf[i+j]); else putchar('.'); } } printf("\n"); if (n == maxbytes) { while ((i = fread(buf, 1, maxbytes, f)) > 0) n += i; if (n > maxbytes) printf("\t\t [%d bytes total]\n", n); } } powerpc-utils-1.3.4/src/nvram.c000066400000000000000000001246621315235264300164310ustar00rootroot00000000000000/** * @file nvram.c * @brief nvram access utility for powerpc platforms. */ /** * @mainpage nvram documentation * @section Copyright * Copyright (c) 2003, 2004, 2005 International Business Machines * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * @section Overview * The nvram command is used to print and modify data stored in the * non-volatile RAM (NVRAM) on powerpc systems. NVRAM on powerpc systems * is split into several partitions, each with their own format. * * The print options allow you to view the available partitions in NVRAM * and print their contents. * * The update options allow you to update certain partitions of NVRAM, * namely those containing name=value pairs. On many systems, the * following NVRAM partitions contain data formatted as name=value pairs: * common, of-config, and ibm,setupcfg. * * @author Nathan Fontenot * @author Michael Strosaker * @author Todd Inglett */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for ntohs */ #include #include #include #include #if defined(__FreeBSD__) #include #else #include #endif #include #include "nvram.h" /** * @var nvram_cmdname * @brief name used to invoke thre nvram command (argv[0]) */ char *nvram_cmdname; static int verbose; static struct option long_options[] = { {"verbose", optional_argument, NULL, 'v'}, {"print-config", optional_argument, NULL, 'o'}, {"zero", optional_argument, NULL, '0'}, {"print-vpd", optional_argument, NULL, 'V'}, {"print-all-vpd", optional_argument, NULL, 'W'}, {"print-err-log", no_argument, NULL, 'e'}, {"print-event-scan", no_argument, NULL, 'E'}, {"partitions", no_argument, NULL, 'P'}, {"dump", required_argument, NULL, 'd'}, {"ascii", required_argument, NULL, 'a'}, {"unzip", required_argument, NULL, 'z'}, {"nvram-file", required_argument, NULL, 'n'}, {"nvram-size", required_argument, NULL, 's'}, {"update-config", required_argument, NULL, 'u'}, {"help", no_argument, NULL, 'h'}, {"partition", required_argument, NULL, 'p'}, {0,0,0,0} }; /** * help * @brief print the help/usage message for nvram */ static void help(void) { printf("nvram options:\n" " --print-config[=var]\n" " print value of a config variable, or print all variables in\n" " the specified (or all) partitions\n" " --zero | -0\n" " terminate config pairs with a NUL character\n" " --update-config =\n" " update the config variable in the specified partition; the -p\n" " option must also be specified\n" " -p \n" " specify a partition; required with --update-config option,\n" " optional with --print-config option\n" " --print-vpd\n" " print VPD\n" " --print-all-vpd\n" " print VPD, including vendor specific data\n" " --print-err-log\n" " print checkstop error log\n" " --print-event-scan\n" " print event scan log\n" " --partitions\n" " print NVRAM paritition header info\n" " --dump \n" " raw dump of partition (use --partitions to see names)\n" " --ascii \n" " print partition contents as ASCII text\n" " --unzip \n" " decompress and print compressed data from partition\n" " --nvram-file \n" " specify alternate nvram data file (default is /dev/nvram)\n" " --nvram-size\n" " specify size of nvram data, must in multiples of 16 Bytes\n" " (for repair operations)\n" " --verbose (-v)\n" " be (more) verbose\n" " --help\n" " print what you are reading right now.\n" ); } /** * @def ERR_MSG * @brief define to denote error messages */ #define ERR_MSG 0 /** * @def WARN_MSG * @brief define to denote warning messages */ #define WARN_MSG 1 /** * @def MAXLINE * @brief maximum line length */ #define MAXLINE 512 /** * _msg * @brief print a message to stderr with the specified prefix * * @param msg_type either ERR_MSG or WARN_MSG * @param fmt formatted string a la printf() * @param ap initialized varaiable arg list */ void _msg(int msg_type, const char *fmt, va_list ap) { int n; char buf[MAXLINE]; n = snprintf(buf, sizeof(buf), "%s: %s", nvram_cmdname, (msg_type == WARN_MSG ? "WARNING: " : "ERROR: ")); vsnprintf(buf + n, sizeof(buf) - n, fmt, ap); fflush(stderr); fputs(buf, stderr); fflush(NULL); } /** * err_msg * @brief print an error message to stderr * * @param fmt formatted string a la printf() */ void err_msg(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void err_msg(const char *fmt, ...) { va_list ap; va_start(ap, fmt); _msg(ERR_MSG, fmt, ap); va_end(ap); } /** * warn_msg * @brief print a warning message to stderr * * @param fmt formatted string a la printf() */ void warn_msg(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void warn_msg(const char *fmt, ...) { va_list ap; va_start(ap, fmt); _msg(WARN_MSG, fmt, ap); va_end(ap); } /** * nvram_read * @brief read in the contents of nvram * * @param nvram nvram struct to read data into * @return 0 on success, !0 on failure */ int nvram_read(struct nvram *nvram) { int len, remaining, chunk; char *p; /* read in small chunks */ p = nvram->data; remaining = nvram->nbytes; chunk = (NVRAM_READ_SIZE < remaining) ? NVRAM_READ_SIZE : remaining; while ((len = read(nvram->fd, p, chunk)) > 0) { p+=len; remaining -= len; chunk = (NVRAM_READ_SIZE < remaining) ? NVRAM_READ_SIZE : remaining; } if (len == -1) { err_msg("cannot read \"%s\": %s\n", nvram->filename, strerror(errno)); return -1; } /* If we are using the DEFAULT_NVRAM_SZ value we to do a small bit of * fixup here. All of the remaining code assumes that nbytes contains * the actual size of nvram, not a guess-timated amount and bad things * ensue if it is not correct. */ if (nvram->nbytes == DEFAULT_NVRAM_SZ) { nvram->nbytes = nvram->nbytes - remaining; remaining = DEFAULT_NVRAM_SZ - (remaining + nvram->nbytes); } if (remaining) { warn_msg("expected %d bytes, but only read %d!\n", nvram->nbytes, nvram->nbytes - remaining); /* preserve the given nbytes, but zero the rest in case someone cares */ memset(p, 0, remaining); } if (verbose) printf("NVRAM size %d bytes\n", nvram->nbytes); return 0; } /** * checksum * @brief calculate the checksum for a partition header * * @param p pointer to partition header * @return calculated checksum */ static unsigned char checksum(struct partition_header *p) { unsigned int c_sum, c_sum2; unsigned short *sp = (unsigned short *)p->name; /* assume 6 shorts */ c_sum = p->signature + p->length + sp[0] + sp[1] + sp[2] + sp[3] + sp[4] + sp[5]; /* The sum probably may have spilled into the 3rd byte. Fold it back. */ c_sum = ((c_sum & 0xffff) + (c_sum >> 16)) & 0xffff; /* The sum cannot exceed 2 bytes. Fold it into a checksum */ c_sum2 = (c_sum >> 8) + (c_sum << 8); c_sum = ((c_sum + c_sum2) >> 8) & 0xff; return c_sum; } /** * dump_raw_data * @brief raw data dump of a partition. * * Note that data_len must be a multiple of 16 bytes which makes * for a cheap implementation. * * @param data pointer to data to be dumped * @param data_len length of data buffer to be dumped */ void dump_raw_data(char *data, int data_len) { int i, j; int offset = 0; char *h, *a; char *end = data + data_len; h = a = data; while (h < end) { printf("0x%08x ", offset); offset += 16; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { if (h <= end) printf("%02x", *h++); else printf(" "); } printf(" "); } printf("|"); for (i = 0; i < 16; i++) { if (a <= end) { if ((*a >= ' ') && (*a <= '~')) printf("%c", *a); else printf("."); a++; } else printf(" "); } printf("|\n"); } } /** * parse_of_common * @brief parse a config definition * * Parse an Open Firmware common config definition which * is of the form name=value and return its length. * * Note that the name will always be < 32 chars. OF does * not specify the max value length, but the value is binary * and must be unquoted. We assume 4k is enough. * * @param data pointer to start of raw data (NULL terminated) * @param data_len length of remaining raw data * @param outname buffer to write parsed name * @param outval buffer to write parsed output value * @return number of bytes parsed */ int parse_of_common(char *data, int data_len, char *outname, char *outval) { char *p, *np; char *p_end = data + data_len; for (p = data, np = outname; *p && *p != '='; p++) { *np++ = *p; if (np - outname > 32) break; /* don't overrun */ if (p >= p_end) { err_msg("partition corrupt: ran off end parsing name\n"); return 0; } } *np = '\0'; if (*p != '=') { err_msg("corrupt data: no = sign found or name > 31 chars\n"); return 0; } p++; /* Value needs to be unquoted */ for (np = outval; *p; p++) { if (*p == (char)0xff) { char ch, num; p++; if (p >= p_end) { err_msg("partition corrupt: ran off end parsing " "quoted value\n"); return 0; } num = *p & 0x7f; ch = (*p & 0x80) ? 0xff : 0; /* hi bit chooses ff or 00. */ if (np + num - outval > 4096) break; /* don't overrun */ /* repeat char */ while (num > 0) { *np++ = ch; num--; } } else { *np++ = *p; if (np - outval > 4096) break; /* don't overrun */ } if (p >= p_end) { err_msg("partition corrupt: ran off end parsing value\n"); return 0; } } *np = '\0'; if (*p) { err_msg("data value too long for this utility (>4k)\n"); return 0; /* ToDo: recover */ } return p - data; } /** * nvram_parse_partitions * @brief fill in the nvram structure with data from nvram * * Fill in the partition parts of the struct nvram. * This makes handling partitions easier for the rest of the code. * * The spec says that partitions are made up of 16 byte blocks and * the partition header must be 16 bytes. We verify that here. * * @param nvram pointer to nvram struct to fill out * @return 0 on success, !0 otherwise */ static int nvram_parse_partitions(struct nvram *nvram) { char *nvram_end = nvram->data + nvram->nbytes; char *p_start = nvram->data; struct partition_header *phead; unsigned char c_sum; if (sizeof(struct partition_header) != 16) { err_msg("partition_header struct is not 16 bytes\n"); return -1; } while (p_start < nvram_end) { phead = (struct partition_header *)p_start; nvram->parts[nvram->nparts++] = phead; c_sum = checksum(phead); if (c_sum != phead->checksum) warn_msg("this partition checksum should be %02x!\n", c_sum); phead->length = be16toh(phead->length); p_start += phead->length * NVRAM_BLOCK_SIZE; } if (verbose) printf("NVRAM contains %d partitions\n", nvram->nparts); return 0; } bool part_name_valid(const char *name) { if (strlen(name) > MAX_PART_NAME) { err_msg("partition name maximum length is %d\n", MAX_PART_NAME); return false; } return true; } /** * nvram_find_fd_partition * @brief Find a particular nvram partition using a file descriptor * * @param name name of the partition to find * @param nvram pointer to nvram struct to search * @return 0 on success, !0 otherwise */ static int nvram_find_fd_partition(struct nvram *nvram, char *name) { struct partition_header phead; int len; int found = 0; if (!part_name_valid(name)) return -1; if (lseek(nvram->fd, SEEK_SET, 0) == -1) { err_msg("could not seek to beginning of file %s\n", nvram->filename); return -1; } while (! found) { len = read(nvram->fd, &phead, sizeof(phead)); if (len == 0) { /* EOF */ err_msg("could not find %s partition in %s\n", name, nvram->filename); return -1; } else if (len != sizeof(phead)) { err_msg("Invalid read from %s: %s\n", nvram->filename, strerror(errno)); return -1; } if (! strncmp(phead.name, name, sizeof(phead.name))) found = 1; else { int offset = be16toh(phead.length) * NVRAM_BLOCK_SIZE - len; if (lseek(nvram->fd, offset, SEEK_CUR) == -1) { err_msg("seek error in file %s: %s\n", nvram->filename, strerror(errno)); return -1; } } } if (! found) { err_msg("could not find %s partition in %s\n", name, nvram->filename); return -1; } /* we found the correct partition seek back to the beginning of it */ if (lseek(nvram->fd, -len, SEEK_CUR) == -1) { err_msg("could not seek to %s partition\n", name); return -1; } return 0; } /** * nvram_find_partition * @brief Find a partition given a signature and name. * * If signature is zero (invalid) it is not used for matching. * If name is NULL it is ignored. * start is the partition in which to resume a search (NULL starts at the first * partition). * * @param signature partition signature to find * @param name partition name to find * @param start partition header to start search at * @param nvram nvram struct to search * @return pointer to partition header on success, NULL otherwise */ static struct partition_header * nvram_find_partition(struct nvram *nvram, unsigned char signature, char *name, struct partition_header *start) { struct partition_header *phead; int i; /* Get starting partition. This is not terribly efficient... */ if (start == NULL) { i = 0; if (verbose > 1) printf("find partition starts with zero\n"); } else { for (i = 0; i < nvram->nparts; i++) if (nvram->parts[i] == start) break; i++; /* start at next partition */ if (verbose > 1) printf("find partition starts with %d\n", i); } /* Search starting with partition i... */ while (i < nvram->nparts) { phead = nvram->parts[i]; if (signature == '\0' || signature == phead->signature) { if (name == NULL || strncmp(name, phead->name, sizeof(phead->name)) == 0) { return phead; } } i++; } return NULL; } /** * print_partition_table * @brief print a table of available partitions * * @param nvram nvram struct of partitions */ static void print_partition_table(struct nvram *nvram) { struct partition_header *phead; int i = 0; printf(" # Sig Chk Len Name\n"); for (i = 0; i < nvram->nparts; i++) { phead = nvram->parts[i]; printf("%2d %02x %02x %04x %.12s\n", i, phead->signature, phead->checksum, phead->length, phead->name); } } /** * getvalue * @brief Copy a value into a buf. * The first two bytes of the value is a length. * Return pointer to byte after the value. * * @param p pointer to value to copy * @param buf buffer to copy value into * @return pointer past the copied value in p */ static char * getvalue(char *p, char *buf) { int len = *p++; len |= ((*p++) << 8); memcpy(buf, p, len); buf[len] = '\0'; return p+len; } /** * getsmallvlaue * @brief Copy a value into a buf. * The first one bytes of the value is a length. * * @param p pointer to value to copy * @param buf buffer to copy value into * @return pointer past the copied value in p */ static char * getsmallvalue(char *p, char *buf) { int len = *p++; memcpy(buf, p, len); buf[len] = '\0'; return p+len; } /** * lookupfield * @brief translate a VPD field to human readable string * * Lookup a VPD field name (always 2 chars) and return a human * readable string. * * @param p VPD field name * @return pointer to human readable string on success, NULL otherwise */ static char * lookupfield(char *p) { int i; for (i = 0; (i < sizeof(descs) / sizeof(descs[0])); i++) { if (strcmp(p, descs[i].name) == 0) return descs[i].desc; } return NULL; } /** * printVPDfield * @brief Format and print a VPD field and return a ptr to the next field. * * @param p pointer to VPD field * @param show_all verbosity level * @return pointer to next VPD field */ static char * printVPDfield(char *p, int show_all) { char field[3]; char value[256]; char *fname; field[0] = p[0]; field[1] = p[1]; field[2] = 0; p+=2; p = getsmallvalue(p, value); if ((fname = lookupfield(field)) != NULL) printf(" %-20s %s\n", fname, value); else if (show_all) printf(" %-20s %s\n", field, value); return p; } /** * dump_vpd * @brief Dump Vital Product Data * * See Chapter 18: Expansion ROMs of the PCI spec. * * @param nvram nvram struct to retrieve VPD data from * @param show_all verbosity level */ int dump_vpd(struct nvram *nvram, int show_all) { struct partition_header *phead; char *p, *p_end; char value[4096]; phead = nvram_find_partition(nvram, NVRAM_SIG_HW, "ibm,vpd", NULL); if (!phead) { err_msg("there is no ibm,vpd partition!\n"); return -1; } p = (char *)(phead + 1); p_end = (char *)(phead + phead->length); while (*p && p < p_end) { if (*p == (char)0x82) { /* Identification string descriptor. */ p++; p = getvalue(p, value); printf("%s\n", value); /* print id string */ while (*p != 0x79) { /* loop until VPD end tag */ int vpdlen; char *vpd_endp; p++; vpdlen = *p++; vpdlen |= ((*p++) << 8); vpd_endp = p + vpdlen; while (p < vpd_endp) p = printVPDfield(p, show_all); } p++; /* printf("checksum byte=0x%x\n", *p); */ p++; } else if (*p == 0) { /* end tag */ break; } } if (*p && p < p_end) { warn_msg("found unknown descriptor byte 0x%x\n", *p); } return 0; } /** * dump_errlog * @brief Dump ibm,err-log partition which contains checkstop info. * * ToDo: this code needs more work. * See IBM RPA (IBM internal use only -- sorry). * * @param nvram nvram struct to dump errlog from * @return 0 on success, !0 otherwise */ int dump_errlog(struct nvram *nvram) { struct partition_header *phead; uint16_t *p, *p_end; /* Note: data is organized into 16bit big * endian (network byte order) */ int p_max; /* max index to go out of bounds of the partition */ int i, cpu; char checkstop_count; int offset; int num_cpus; int num_memctrls; int num_ioctrls; uint16_t *sys_regs; /* System specific registers * (e.g. bus arbitration chips, etc */ uint16_t *cpu_regs[MAX_CPUS+1]; uint16_t *ioctrl_data; phead = nvram_find_partition(nvram, NVRAM_SIG_SP, "ibm,err-log", NULL); if (!phead) { err_msg("there is no ibm,err-log partition!\n"); return -1; } p = (uint16_t *)(phead + 1); p_end = (uint16_t *)(phead + phead->length); p_max = p_end - p; /* max in 16bit values */ if (p_max < 4) { err_msg("Corrupt ibm,err-log partition in nvram\n"); return -1; } /* index 0 is checkstop count (high byte), semaphores (low byte) */ i = 0; /* index through short words */ checkstop_count = p[i] >> 8; if (checkstop_count) printf("Checkstops detected: %d\n", checkstop_count); else printf("No checkstops have been detected.\n"); /* index 1 is system specific register offset */ i++; offset = ntohs(p[i])/2+1; sys_regs = offset + i < p_max ? p + offset + i : 0; /* index 2 is number of cpus */ i++; num_cpus = ntohs(p[i]); printf("CPUS: %d\n", num_cpus); /* Next indexes are offsets to cpu specific regs */ for (cpu = 0; cpu < num_cpus; cpu++) { i++; if (cpu < MAX_CPUS) { offset = ntohs(p[i])/2+1; cpu_regs[cpu] = offset + i < p_max ? p + offset + i : 0; } } if (num_cpus > MAX_CPUS) num_cpus = MAX_CPUS; /* just in case... */ /* next index is number of memory controllers */ i++; num_memctrls = ntohs(p[i]); printf("Memory Controllers: %d\n", num_memctrls); /* next index is offset of memory controller data, we don't use * this so no need to save it. */ i++; /* ToDo: this may be a list of offsets...manual doesn't show that but only 1 seems odd */ /* next index is number of I/O Subsystem controllers */ i++; num_ioctrls = ntohs(p[i]); printf("I/O Controllers: %d\n", num_ioctrls); /* next index is offset of I/O Subsystem controller data */ i++; /* ToDo: this may be a list of offsets...manual doesn't show that but only 1 seems odd */ offset = ntohs(p[i])/2+1; ioctrl_data = offset + i < p_max ? p + offset + i : 0; /*** End of header ***/ /* Now dump sections collected by the header. */ if (sys_regs && num_cpus > 0) { /* ToDo: what is the length of the data? We dump until the first cpu data. */ printf("System Specific Registers\n"); dump_raw_data((char *)sys_regs, cpu_regs[0] - sys_regs); } /* artificial "next cpu" data for length */ cpu_regs[num_cpus] = ioctrl_data; for (cpu = 0; cpu < num_cpus; cpu++) { /*char buf[64];*/ int len; /* ToDo: what is the length of the data? We dump until the next cpu data. */ len = cpu_regs[cpu+1] - cpu_regs[cpu]; printf("CPU %d Register Data (len=%x, offset=%"PRIx64")\n", cpu, len, cpu_regs[cpu]-p); if (len < 4096) /* reasonable bound */ dump_raw_data((char *)cpu_regs[cpu], len); } return 0; } /** * dump_rtas_event_entry * @brief Dump event-scan data. * * Note: This is really only valid for PAPR machines. To ensure * the nvram command can run on all powerpc machines we dlopen the * the librtasevent library to dump the rtas event. * * @param data pointer to rtas error to dump * @param len length of data buffer * @return 0 on success, !0 otherwise */ int dump_rtas_event_entry(char *data, int len) { void *rtas_event; void *handle; void *(*parse_rtas_event)(); void (*rtas_print_event)(); void (*cleanup_rtas_event)(); handle = dlopen("/usr/lib/librtasevent.so", RTLD_LAZY); if (handle == NULL) return 1; parse_rtas_event = dlsym(handle, "parse_rtas_event"); if (parse_rtas_event == NULL) { dlclose(handle); return 1; } rtas_print_event = dlsym(handle, "rtas_print_event"); if (rtas_print_event == NULL) { dlclose(handle); return 1; } cleanup_rtas_event = dlsym(handle, "cleanup_rtas_event"); if (cleanup_rtas_event == NULL) { dlclose(handle); return 1; } rtas_event = parse_rtas_event(data, len); if (rtas_event == NULL) { dlclose(handle); return 1; } rtas_print_event(stdout, rtas_event, 0); cleanup_rtas_event(rtas_event); dlclose(handle); return 0; } /** * dump_eventscanlog * @brief Dump ibm,es-logs partition, which contains a service processor log * * See IBM RPA (IBM internal use only -- sorry). * * @param nvram nvram struct to get eventscan log from * @return 0 on success, !0 otherwise */ int dump_eventscanlog(struct nvram *nvram) { struct partition_header *phead; uint32_t *p, *p_end; /* Note: data is organized into 32bit big * endian (network byte order) */ int p_max; /* max index to go out of bounds of the partition */ int lognum; int num_logs; int rc; #define MAX_EVENTLOGS 100 uint32_t loghdr[MAX_EVENTLOGS+1]; phead = nvram_find_partition(nvram, NVRAM_SIG_SP, "ibm,es-logs", NULL); if (!phead) { err_msg("there is no ibm,es-logs partition!\n"); return -1; } p = (uint32_t *)(phead + 1); p_end = (uint32_t *)(phead + phead->length); p_max = p_end - p; /* max in 32bit values */ if (p_max < 1) { err_msg("Corrupt ibm,es-logs partition in nvram\n"); return -1; } num_logs = ntohl(*p); printf("Number of Logs: %d\n", num_logs); if (num_logs > MAX_EVENTLOGS) { num_logs = MAX_EVENTLOGS; warn_msg("limiting to %d log entries (program limit)\n", num_logs); } if (num_logs > p_max-1) { /* of course this leaves no room for log data (i.e. corrupt partition) */ num_logs = p_max-1; warn_msg("limiting to %d log entries (partition limit)\n", num_logs); } for (lognum = 0; lognum < num_logs; lognum++) { loghdr[lognum] = ntohl(p[lognum+1]); } /* artificial log entry (offset) to put a limit on the last log */ loghdr[num_logs] = p_max * sizeof(uint32_t); for (lognum = 0; lognum < num_logs; lognum++) { uint32_t hdr = loghdr[lognum]; int flags = (hdr >> 24) & 0xff; int logtype = (hdr >> 16) & 0xff; int start = hdr & 0xffff; int end = loghdr[lognum+1] & 0xffff; printf("Log Entry %d: flags: 0x%02x type: 0x%02x\n", lognum, flags, logtype); rc = dump_rtas_event_entry(((char *)p) + start, end - start); if (rc) { printf("==== Log %d ====\n", lognum); dump_raw_data(((char *)p) + start, end - start); } } return 0; } /** * dump_raw_partition * @brief Dump raw data of a partition. Mainly for debugging. * * @param nvram nvram struct containing partition * @param name name of partition to dump * @return 0 on success, !0 otherwise */ int dump_raw_partition(struct nvram *nvram, char *name) { struct partition_header *phead; phead = nvram_find_partition(nvram, 0, name, NULL); if (!phead) { err_msg("there is no %s partition!\n", name); return -1; } dump_raw_data((char *)phead, phead->length * NVRAM_BLOCK_SIZE); return 0; } /** * dump_ascii_partition * @brief ASCII data dump of a partition, excluding header * * @param nvram nvram struct containing partition * @param name name of partition to dump * @return 0 on success, !0 otherwise * * Partition subheaders, if any, are dumped along with the rest of the data. * We substitute periods for unprintable characters. */ int dump_ascii_partition(struct nvram *nvram, char *name) { struct partition_header *phead; char *start, *end, *c; phead = nvram_find_partition(nvram, 0, name, NULL); if (!phead) { err_msg("there is no %s partition!\n", name); return -1; } start = (char*) phead; end = start + phead->length * NVRAM_BLOCK_SIZE; start += sizeof(*phead); /* Skip partition header. */ for (c = start; c < end; c++) { if (isprint(*c) || isspace(*c)) putchar(*c); else putchar('.'); } /* Always end with a newline.*/ putchar('\n'); return 0; } int dump_zipped_text(char *zipped_text, unsigned int zipped_length) { z_stream strm; int result; char unzipped_text[4096]; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.avail_in = zipped_length; strm.next_in = (Bytef*) zipped_text; result = inflateInit(&strm); if (result != Z_OK) { err_msg("can't decompress text: inflateInit() returned %d\n", result); return -1; } do { strm.avail_out = 4096; strm.next_out = (Bytef*) unzipped_text; result = inflate(&strm, Z_NO_FLUSH); switch (result) { case Z_STREAM_ERROR: case Z_NEED_DICT: case Z_DATA_ERROR: case Z_MEM_ERROR: err_msg("can't decompress text: inflate() returned %d\n", result); (void) inflateEnd(&strm); return -1; } if (fwrite(unzipped_text, 4096 - strm.avail_out, 1, stdout) != 1) { err_msg("can't decompress text: fwrite() failed\n"); (void) inflateEnd(&strm); return -1; } } while (strm.avail_out == 0); (void) inflateEnd(&strm); return 0; } /** * unzip_partition * @brief Uncompress and print compressed data from a partition. * * @param nvram nvram struct containing partition * @param name name of partition to dump * @return 0 on success, !0 otherwise */ int unzip_partition(struct nvram *nvram, char *name) { struct partition_header *phead; char *start, *next; unsigned short zipped_length; phead = nvram_find_partition(nvram, 0, name, NULL); if (!phead) { err_msg("there is no %s partition!\n", name); return -1; } start = (char*) phead; next = start + sizeof(*phead); /* Skip partition header. */ next += sizeof(struct err_log_info); /* Skip sub-header. */ zipped_length = be16toh(*((unsigned short*) next)); next += sizeof(unsigned short); /* New format oops header, zipped_length > OOPS_PARTITION_SZ * signifies the version of new header. Find out new zipped length * and from where the compressed data starts. */ if (zipped_length > OOPS_PARTITION_SZ) { zipped_length = be16toh(*((unsigned short*) next)); next += sizeof(struct oops_log_info) - sizeof(unsigned short); } if ((next-start) + zipped_length > phead->length * NVRAM_BLOCK_SIZE) { err_msg("bogus size for compressed data in partition %s: %u\n", name, zipped_length); return -1; } return dump_zipped_text(next, zipped_length); } /** * print_of_config_part * @brief Print the name/value pairs of a partition * * @param pname partition name containing name/value pairs * @param nvram nvram struct containing partition to dump * @return 0 on success, !0 otherwise */ static int print_of_config_part(struct nvram *nvram, char *pname) { struct partition_header *phead; char *data; int i; phead = nvram_find_partition(nvram, 0, pname, NULL); if (phead == NULL) return -1; data = (char *)phead + sizeof(*phead); printf("\"%s\" Partition\n", pname); for (i = 0; i <= (strlen(pname) + 14); i++) printf("-"); printf("\n"); while (*data != '\0') { printf("%s\n", data); data += strlen(data) + 1; } printf("\n"); return 0; } /** * print_of_config * @brief Print the contents of an Open Firmware config partition * * This will print the name/value pair for a specified Open * Firmware config variable or print all of the name/value pairs * in the partition if the name is NULL. * * @param config_var config variable to print * @param pname partition name containing config_var * @param nvram nvram struct containing pname * @return 0 on success, !0 otherwise */ static int print_of_config(struct nvram *nvram, char *config_var, char *pname, int zero_terminator) { struct partition_header *phead; char *data, terminator; int i, varlen; int rc = -1; terminator = '\n'; if (zero_terminator) terminator = '\0'; /* if config_var is NULL , print the data from the * partition specified by pname or all of the * name/value pair partitions if pname is NULL. */ if (config_var == NULL) { if (pname == NULL) { for (i = 0; i < nvram->nparts; i++) { phead = nvram->parts[i]; (void)print_of_config_part(nvram, phead->name); } } else { for (i = 0; i < nvram->nparts; i++) { phead = nvram->parts[i]; if (strcmp(pname, phead->name) == 0) { (void)print_of_config_part(nvram, phead->name); rc = 0; } } if (rc) err_msg("There is no \"%s\" partition!\n", pname); } return rc; } /* the config_var is a variable name */ varlen = strlen(config_var); if (pname == NULL) { for (i = 0; i < nvram->nparts; i++) { phead = nvram->parts[i]; if (phead == NULL) continue; data = (char *)phead + sizeof(*phead); while (*data != '\0') { if ((data[varlen] == '=') && strncmp(config_var, data, varlen) == 0) { printf("%s%c", data + varlen + 1, terminator); rc = 0; } data += strlen(data) + 1; } } } else { phead = nvram_find_partition(nvram, 0, pname, NULL); if (phead == NULL) { err_msg("There is no \"%s\" partition.\n", pname); return -1; } data = (char *)phead + sizeof(*phead); while (*data != '\0') { if ((data[varlen] == '=') && strncmp(config_var, data, varlen) == 0) { printf("%s%c", data + varlen + 1, terminator); rc = 0; } data += strlen(data) + 1; } } return rc; } /** * update_config_var * @brief Update an Open Firmware config variable in nvram * * This will attempt to update the value half of a name/value * pair in the nvram config partition. If the name/value pair * is not found in the partition then the specified name/value pair * is added to the end of the data in the partition. * * @param config_var OF config variable to update * @param pname partition containing config_var * @param nvram nvram struct containing pname * @return 0 on success, !0 otherwise */ int update_of_config_var(struct nvram *nvram, char *config_var, char *pname) { struct partition_header *phead, *new_phead; char *new_config_value; char *data_offset; char *new_part; char *new_part_offset, *new_part_end; char *tmp_offset; int config_name_len; int len, rc, part_size; new_config_value = strchr(config_var, '='); if (!new_config_value) { err_msg("config variables must be in the format \"name=value\""); return -1; } new_config_value++; phead = nvram_find_partition(nvram, 0, pname, NULL); if (phead == NULL) { err_msg("there is no \"%s\" partition!\n", pname); return -1; } part_size = phead->length * NVRAM_BLOCK_SIZE; data_offset = (char *)((unsigned long)phead + sizeof(*phead)); new_part = malloc(part_size); if (new_part == NULL) { err_msg("cannot allocate space to update \"%s\" partition\n", pname); return -1; } memset(new_part, 0, part_size); /* get the length of then name of the config variable we are updating */ config_name_len = strstr(config_var, "=") - config_var; config_name_len++; /* now find this config variable in the partition */ while (*data_offset != '\0') { if (strncmp(data_offset, config_var, config_name_len) == 0) break; data_offset += strlen(data_offset) + 1; } /* Copy everything up to the config name we are modifying * to the new partition */ memcpy(new_part, phead, data_offset - (char *)phead); /* make sure the new config var will fit into the partition and add it */ new_phead = (struct partition_header *)new_part; new_phead->length = be16toh(new_phead->length); new_part_offset = new_part + (data_offset - (char *)phead); new_part_end = new_part + part_size; if ((new_part_offset + strlen(config_var) + 1) >= new_part_end) { err_msg("cannot update config var to\"%s\".\n" "\tThere is not enough room in the \"%s\" partition\n", config_var, pname); free(new_part); return -1; } if (strlen(new_config_value)) { strncpy(new_part_offset, config_var, strlen(config_var)); new_part_offset += strlen(config_var); *new_part_offset++ = '\0'; } /* Find the end of the name/value pairs in the partition so we * can copy them over to the new partition. */ data_offset += strlen(data_offset) + 1; tmp_offset = data_offset; while (*data_offset != '\0') { data_offset += strlen(data_offset) + 1; } /* we should now be pointing to a double NULL, verify this */ if ((data_offset[-1] != '\0') && (data_offset[0] != '\0')) { err_msg("the \"%s\" partition appears to be corrupt\n", pname); free(new_part); return -1; } /* go past double NULL */ data_offset++; /* verify that this will fit into the new partition */ if ((new_part_offset + (data_offset - tmp_offset)) > new_part_end) { err_msg("cannot update open firmware config var to \"%s\".\n" "\tThere is not enough room in the \"%s\" partition\n", config_var, pname); free(new_part); return -1; } memcpy(new_part_offset, tmp_offset, data_offset - tmp_offset); /* recalculate the checksum */ new_phead->checksum = checksum(new_phead); /* seek the position in the /dev/nvram for the common partition */ if (nvram_find_fd_partition(nvram, new_phead->name) != 0) { free(new_part); return -1; } /* write the partition out to nvram */ for (rc = 0, len = 0; len < part_size; len += rc) { rc = write(nvram->fd, new_part + len, part_size - len); if (rc <= 0) break; } if (len != part_size) { err_msg("only wrote %d bytes of the \"%s\" partition back\n" "\tto %s, expected to write %d bytes\n", len, pname, nvram->filename, part_size); } free(new_part); return 0; } int main (int argc, char *argv[]) { struct nvram nvram; struct stat sbuf; int ret = 0; int option_index; char *endp; char *of_config_var = NULL; int print_partitions = 0; int print_vpd = 0; int print_errlog = 0; int print_event_scan = 0; int print_config_var = 0; int zero_terminator = 0; char *dump_name = NULL; char *ascii_name = NULL; char *zip_name = NULL; char *update_config_var = NULL; char *config_pname = "common"; nvram_cmdname = argv[0]; if (argc == 1) { help(); exit(1); } /* initialize nvram struct */ memset(&nvram, 0, sizeof(struct nvram)); nvram.fd = -1; for (;;) { option_index = 0; ret = getopt_long(argc, argv, "+p:Vv::0", long_options, &option_index); if (ret == -1) break; switch (ret) { case 'h': help(); exit(0); case 'v': verbose += (optarg ? atoi(optarg) : 1); break; case 'd': /* dump */ dump_name = optarg; if (!part_name_valid(dump_name)) exit(1); break; case 'a': /* ASCII dump */ ascii_name = optarg; if (!part_name_valid(ascii_name)) exit(1); break; case 'z': /* dump compressed data */ zip_name = optarg; if (!part_name_valid(zip_name)) exit(1); break; case 'n': /* nvram-file */ nvram.filename = optarg; break; case 'o': /*print-config */ print_config_var = 1; of_config_var = optarg; break; case '0': zero_terminator = 1; break; case 'P': /* partitions */ print_partitions = 1; break; case 's': /* nvram-size */ nvram.nbytes = strtoul(optarg, &endp, 10); if (!*optarg || *endp) { err_msg("specify nvram-size as an integer\n"); exit(1); } if (nvram.nbytes % NVRAM_BLOCK_SIZE) { err_msg("nvram-size must be a multiple of 16 Bytes\n"); exit(1); } break; case 'V': /* print-vpd */ print_vpd = 1; break; case 'W': /* print-all-vpd */ print_vpd = 2; break; case 'e': /* print-err-log */ print_errlog = 1; break; case 'E': /* print-event-scan */ print_event_scan = 1; break; case 'u': /* update-config */ update_config_var = optarg; break; case 'p': /* update-config partition name */ config_pname = optarg; if (!part_name_valid(config_pname)) exit(1); break; case '?': exit(1); break; default: printf("huh?\n"); break; } } if (optind < argc) { err_msg("Could not parse the option %s correctly.\n", argv[optind]); help(); exit(-1); } ret = 0; if (nvram.filename) { nvram.fd = open(nvram.filename, O_RDWR); if (nvram.fd == -1) { err_msg("cannot open \"%s\": %s\n", nvram.filename, strerror(errno)); ret = -1; goto err_exit; } } else { nvram.filename = NVRAM_FILENAME1; nvram.fd = open(nvram.filename, O_RDWR); if (nvram.fd == -1) { int errno1 = errno; nvram.filename = NVRAM_FILENAME2; nvram.fd = open(nvram.filename, O_RDWR); if (nvram.fd == -1) { err_msg("cannot open \"%s\": %s\n", NVRAM_FILENAME1, strerror(errno1)); err_msg("cannot open \"%s\": %s\n", NVRAM_FILENAME2, strerror(errno)); ret = -1; goto err_exit; } } } if (fstat(nvram.fd, &sbuf) < 0) { err_msg("cannot stat %s: %s\n", nvram.filename, strerror(errno)); ret = -1; goto err_exit; } if (!nvram.nbytes) { ret = lseek(nvram.fd, 0, SEEK_END); if (ret < 0) { err_msg("cannot seek(END) %s: %s\n", nvram.filename, strerror(errno)); goto err_exit; } nvram.nbytes = ret; ret = lseek(nvram.fd, 0, SEEK_SET); if (ret < 0) { err_msg("cannot seek(SET) %s: %s\n", nvram.filename, strerror(errno)); goto err_exit; } } nvram.data = malloc(nvram.nbytes); if (nvram.data == NULL) { err_msg("cannot allocate space for nvram of %d bytes\n", nvram.nbytes); ret = -1; goto err_exit; } if (nvram_read(&nvram) != 0) { ret = -1; goto err_exit; } if (nvram_parse_partitions(&nvram) != 0) { ret = -1; goto err_exit; } if (print_partitions) print_partition_table(&nvram); if (update_config_var) { if (config_pname == NULL) { err_msg("you must specify the partition name with the -p option\n" "\twhen using the --update-config option\n"); goto err_exit; } if (update_of_config_var(&nvram, update_config_var, config_pname) != 0) ret = -1; } if (print_config_var) if (print_of_config(&nvram, of_config_var, config_pname, zero_terminator) != 0) ret = -1; if (print_vpd) if (dump_vpd(&nvram, print_vpd == 2) != 0) ret = -1; if (print_errlog) if (dump_errlog(&nvram) != 0) ret = -1; if (print_event_scan) if (dump_eventscanlog(&nvram) != 0) ret = -1; if (dump_name) if (dump_raw_partition(&nvram, dump_name) != 0) ret = -1; if (ascii_name) if (dump_ascii_partition(&nvram, ascii_name) != 0) ret = -1; if (zip_name) if (unzip_partition(&nvram, zip_name) != 0) ret = -1; err_exit: if (nvram.data) free(nvram.data); if (nvram.fd != -1) close(nvram.fd); return ret; } powerpc-utils-1.3.4/src/nvram.h000066400000000000000000000107541315235264300164320ustar00rootroot00000000000000/** * @file nvram.h * @brief nvram access utility for powerpc platforms. * * Copyright (c) 2003, 2004 International Business Machines * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * @author Nathan Fontenot * @author Michael Strosaker * @author Todd Inglett */ #ifndef _DEV_NVRAM_H_ #define _DEV_NVRAM_H_ #define NVRAM_SIG_SP 0x02 /**< support processor signature */ #define NVRAM_SIG_OF 0x50 /**< open firmware config signature */ #define NVRAM_SIG_FW 0x51 /**< general firmware signature */ #define NVRAM_SIG_HW 0x52 /**< hardware (VPD) signature */ #define NVRAM_SIG_SYS 0x70 /**< system env vars signature */ #define NVRAM_SIG_CFG 0x71 /**< config data signature */ #define NVRAM_SIG_ELOG 0x72 /**< error log signature */ #define NVRAM_SIG_VEND 0x7e /**< vendor defined signature */ #define NVRAM_SIG_FREE 0x7f /**< Free space signature */ #define NVRAM_SIG_OS 0xa0 /**< OS defined signature */ /** * @def printmap(ch) * @brief dertermines if 'ch' is a printable character */ #define printmap(ch) (isgraph(ch) ? (ch) : '.') #define NVRAM_BLOCK_SIZE 16 #define NVRAM_READ_SIZE 512 #define NVRAM_FILENAME1 "/dev/nvram" #define NVRAM_FILENAME2 "/dev/misc/nvram" #define DEFAULT_NVRAM_SZ (1024 * 1024) #define OOPS_PARTITION_SZ 4000 /** * @def MAX_CPUS * @brief maximum number of CPUS for errlog dumps */ #define MAX_CPUS 128 /** * @def MAX_PART_NAME * @brief maximum number of bytes in partition name */ #define MAX_PART_NAME 12 /** * @struct partition_header * @brief nvram partition header data */ struct partition_header { unsigned char signature; /**< partition signature */ unsigned char checksum; /**< partition checksum */ unsigned short length; /**< partition length */ char name[MAX_PART_NAME]; /**< partition name */ }; /* sub-header for error-log partitions */ struct err_log_info { int error_type; unsigned int seq_num; }; /* lnx,oops-log header */ struct oops_log_info { unsigned short version; unsigned short report_length; unsigned long long timestamp; }__attribute__((packed)); /* Internal representation of NVRAM. */ #define MAX_PARTITIONS 50 /** * @struct nvram * @brief internal representation of nvram data */ struct nvram { char *filename; /**< original filename */ int fd; /**< file descriptor */ int nparts; /**< number of partitions */ int nbytes; /**< size of data in bytes. This * cannot be changed * (i.e. hardware size) */ struct partition_header *parts[MAX_PARTITIONS]; /**< partition header pointers * into data */ char *data; /**< nvram contents */ }; /** * @var descs * @brief Array of VPD field names and descriptions */ static struct { char *name; char *desc; } descs[] = { {"PN", "Part Number"}, {"FN", "FRU Number"}, {"EC", "EC Level"}, {"MN", "Manufacture ID"}, {"SN", "Serial Number"}, {"LI", "Load ID"}, {"RL", "ROM Level"}, {"RM", "Alterable ROM Level"}, {"NA", "Network Address"}, {"DD", "Device Driver Level"}, {"DG", "Diagnostic Level"}, {"LL", "Loadable Microcode Level"}, {"VI", "Vendor ID/Device ID"}, {"FU", "Function Number"}, {"SI", "Subsystem Vendor ID/Device ID"}, {"VK", "Platform"}, /**< "RS6K" => VPD is present */ {"TM", "Model"}, /**< IBM specific? */ {"YL", "Location Code"}, /**< IBM specific? */ {"BR", "Brand"}, /**< IBM specific */ {"CI", "CEC ID"}, /**< IBM specific */ {"RD", "Rack ID"}, /**< IBM specific */ {"PA", "Op Panel Installed"}, /**< IBM specific */ {"NN", "Node Name"}, /**< IBM specific */ }; #endif powerpc-utils-1.3.4/src/ppc64_cpu.c000066400000000000000000001032001315235264300170720ustar00rootroot00000000000000/** * Copyright (C) 2007 Anton Blanchard IBM Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef WITH_LIBRTAS #include #include "librtas_error.h" #endif #ifdef HAVE_LINUX_PERF_EVENT_H #include #endif #include #define PPC64_CPU_VERSION "1.2" #define SYSFS_CPUDIR "/sys/devices/system/cpu/cpu%d" #define SYSFS_SUBCORES "/sys/devices/system/cpu/subcores_per_core" #define DSCR_DEFAULT_PATH "/sys/devices/system/cpu/dscr_default" #define INTSERV_PATH "/proc/device-tree/cpus/%s/ibm,ppc-interrupt-server#s" #define SYSFS_PATH_MAX 128 #define MAX_NR_CPUS 1024 #define DIAGNOSTICS_RUN_MODE 42 #define CPU_OFFLINE -1 #ifdef HAVE_LINUX_PERF_EVENT_H struct cpu_freq { int offline; int counter; pthread_t tid; unsigned long long freq; }; #ifndef __NR_perf_event_open #define __NR_perf_event_open 319 #endif #endif static int threads_per_cpu = 0; static int cpus_in_system = 0; static int threads_in_system = 0; static int do_info(void); static int test_sysattr(char *attribute, int perms) { char path[SYSFS_PATH_MAX]; int i; for (i = 0; i < threads_in_system; i++) { sprintf(path, SYSFS_CPUDIR"/%s", i, attribute); if (access(path, F_OK)) continue; if (access(path, perms)) return 0; } return 1; } static int sysattr_is_readable(char *attribute) { return test_sysattr(attribute, R_OK); } static int sysattr_is_writeable(char *attribute) { return test_sysattr(attribute, W_OK); } static int get_attribute(char *path, const char *fmt, int *value) { FILE *fp; int rc; rc = access(path, F_OK); if (rc) return -1; fp = fopen(path, "r"); if (!fp) return -1; rc = fscanf(fp, fmt, value); fclose(fp); if (rc == EOF) return -1; return 0; } static int set_attribute(const char *path, const char *fmt, int value) { int fd, rc, len; char *str; fd = open(path, O_WRONLY); if (fd < 0) return -1; len = asprintf(&str, fmt, value); if (len < 0) { rc = -1; goto close; } rc = write(fd, str, len); free(str); if (rc == len) rc = 0; close: close(fd); return rc; } static int cpu_online(int thread) { char path[SYSFS_PATH_MAX]; int rc, online; sprintf(path, SYSFS_CPUDIR"/online", thread); rc = get_attribute(path, "%d", &online); /* This attribute does not exist in kernels without hotplug enabled */ if (rc && errno == ENOENT) return 1; if (rc || !online) return 0; return 1; } static int get_system_attribute(char *attribute, const char *fmt, int *value, int *inconsistent) { char path[SYSFS_PATH_MAX]; int i, rc; int system_attribute = -1; for (i = 0; i < threads_in_system; i++) { int cpu_attribute; if (!cpu_online(i)) continue; sprintf(path, SYSFS_CPUDIR"/%s", i, attribute); rc = get_attribute(path, fmt, &cpu_attribute); if (rc) return rc; if (system_attribute == -1) system_attribute = cpu_attribute; else if (system_attribute != cpu_attribute) { *inconsistent = 1; return -1; } } *value = system_attribute; return 0; } static int set_system_attribute(char *attribute, const char *fmt, int state) { char path[SYSFS_PATH_MAX]; int i, rc; for (i = 0; i < threads_in_system; i++) { sprintf(path, SYSFS_CPUDIR"/%s", i, attribute); rc = set_attribute(path, fmt, state); /* When a CPU is offline some sysfs files are removed from the CPU * directory, for example smt_snooze_delay and dscr. The absence of the * file is not an error, so detect and clear the error when * set_attribute indicates ENOENT. */ if (rc == -1 && errno == ENOENT) rc = errno = 0; if (rc) return rc; } return 0; } static int dscr_default_exists(void) { struct stat sb; if (!stat(DSCR_DEFAULT_PATH, &sb)) return 1; return 0; } /* On newer systems we just set the default_dscr value instead of the cpu * specific dscr value. This is because the dscr value is now thread * specific. */ static int set_dscr(int state) { int rc; if (dscr_default_exists()) { if (access(DSCR_DEFAULT_PATH, W_OK)) { perror("Cannot set default dscr value"); return -2; } rc = set_attribute(DSCR_DEFAULT_PATH, "%x", state); } else { if (!sysattr_is_writeable("dscr")) { perror("Cannot set dscr"); return -2; } rc = set_system_attribute("dscr", "%x", state); } return rc; } static int get_dscr(int *value, int *inconsistent) { int rc; if (dscr_default_exists()) { if (access(DSCR_DEFAULT_PATH, R_OK)) { perror("Cannot retrieve default dscr"); return -2; } rc = get_attribute(DSCR_DEFAULT_PATH, "%x", value); } else { if (!sysattr_is_readable("dscr")) { perror("Cannot retrieve dscr"); return -2; } rc = get_system_attribute("dscr", "%x", value, inconsistent); } return rc; } static int set_smt_snooze_delay(int delay) { if (!sysattr_is_writeable("smt_snooze_delay")) { perror("Cannot set smt snooze delay"); return -2; } return set_system_attribute("smt_snooze_delay", "%d", delay); } static int get_smt_snooze_delay(int *delay, int *inconsistent) { if (!sysattr_is_readable("smt_snooze_delay")) { perror("Cannot retrieve smt snooze delay"); return -2; } return get_system_attribute("smt_snooze_delay", "%d", delay, inconsistent); } static int online_thread(const char *path) { return set_attribute(path, "%d", 1); } static int offline_thread(const char *path) { return set_attribute(path, "%d", 0); } static int is_subcore_capable(void) { return access(SYSFS_SUBCORES, F_OK) == 0; } static int num_subcores(void) { int rc, subcores; rc = get_attribute(SYSFS_SUBCORES, "%d", &subcores); if (rc) return -1; return subcores; } static int get_cpu_info(void) { DIR *d; struct dirent *de; int first_cpu = 1; int rc; int subcores; d = opendir("/proc/device-tree/cpus"); if (!d) return -1; while ((de = readdir(d)) != NULL) { if (!strncmp(de->d_name, "PowerPC", 7)) { if (first_cpu) { struct stat sbuf; char path[128]; sprintf(path, INTSERV_PATH, de->d_name); rc = stat(path, &sbuf); if (!rc) threads_per_cpu = sbuf.st_size / 4; first_cpu = 0; } cpus_in_system++; } } closedir(d); threads_in_system = cpus_in_system * threads_per_cpu; subcores = num_subcores(); if (is_subcore_capable() && subcores > 0) { threads_per_cpu /= subcores; cpus_in_system *= subcores; } return 0; } static int is_smt_capable(void) { struct stat sb; char path[SYSFS_PATH_MAX]; int i; for (i = 0; i < threads_in_system; i++) { sprintf(path, SYSFS_CPUDIR"/smt_snooze_delay", i); if (stat(path, &sb)) continue; return 1; } return 0; } static int get_one_smt_state(int core) { int primary_thread = core * threads_per_cpu; int smt_state = 0; int i; if (!sysattr_is_readable("online")) { perror("Cannot retrieve smt state"); return -2; } for (i = 0; i < threads_per_cpu; i++) { smt_state += cpu_online(primary_thread + i); } return smt_state; } static int get_smt_state(void) { int smt_state = -1; int i; for (i = 0; i < cpus_in_system; i++) { int cpu_state = get_one_smt_state(i); if (cpu_state == 0) continue; if (smt_state == -1) smt_state = cpu_state; if (smt_state != cpu_state) { smt_state = -1; break; } } return smt_state; } static int set_one_smt_state(int thread, int online_threads) { char path[SYSFS_PATH_MAX]; int i, rc = 0; for (i = 0; i < threads_per_cpu; i++) { snprintf(path, SYSFS_PATH_MAX, SYSFS_CPUDIR"/%s", thread + i, "online"); if (i < online_threads) rc = online_thread(path); else rc = offline_thread(path); /* The 'online' sysfs file returns EINVAL if set to the current * setting. As this is not an error, reset rc and errno to avoid * returning failure. */ if (rc == -1 && errno == EINVAL) rc = errno = 0; if (rc) break; } return rc; } static int set_smt_state(int smt_state) { int i, j, rc; int ssd, update_ssd = 1; int inconsistent = 0; int error = 0; if (!sysattr_is_writeable("online")) { perror("Cannot set smt state"); return -1; } rc = get_smt_snooze_delay(&ssd, &inconsistent); if (rc) update_ssd = 0; for (i = 0; i < threads_in_system; i += threads_per_cpu) { /* Online means any thread on this core running, so check all * threads in the core, not just the first. */ for (j = 0; j < threads_per_cpu; j++) { if (!cpu_online(i + j)) continue; rc = set_one_smt_state(i, smt_state); /* Record an error, but do not check result: if we * have failed to set this core, keep trying * subsequent ones. */ if (rc) error = 1; break; } } if (update_ssd) set_smt_snooze_delay(ssd); if (error) { fprintf(stderr, "One or more cpus could not be on/offlined\n"); return -1; } return rc; } static int is_dscr_capable(void) { struct stat sb; char path[SYSFS_PATH_MAX]; int i; if (dscr_default_exists()) return 1; for (i = 0; i < threads_in_system; i++) { sprintf(path, SYSFS_CPUDIR"/dscr", i); if (stat(path, &sb)) continue; return 1; } return 0; } void print_cpu_list(const cpu_set_t *cpuset, int cpuset_size) { int core; const char *comma = ""; for (core = 0; core < cpus_in_system; core++) { int begin = core; if (CPU_ISSET_S(core, cpuset_size, cpuset)) { while (CPU_ISSET_S(core+1, cpuset_size, cpuset)) core++; if (core > begin) printf("%s%d-%d", comma, begin, core); else printf("%s%d", comma, core); comma = ","; } } } static int do_smt(char *state, bool numeric) { int rc = 0; int smt_state = 0; if (!is_smt_capable()) { if (numeric) printf("SMT=1\n"); else fprintf(stderr, "Machine is not SMT capable\n"); return -1; } if (!state) { int thread, c; cpu_set_t *cpu_states[threads_per_cpu]; int cpu_state_size = CPU_ALLOC_SIZE(cpus_in_system); int start_cpu = 0, stop_cpu = cpus_in_system; for (thread = 0; thread < threads_per_cpu; thread++) { cpu_states[thread] = CPU_ALLOC(cpus_in_system); CPU_ZERO_S(cpu_state_size, cpu_states[thread]); } for (c = start_cpu; c < stop_cpu; c++) { int threads_online = get_one_smt_state(c); if (threads_online < 0) { rc = threads_online; goto cleanup_get_smt; } if (threads_online) CPU_SET_S(c, cpu_state_size, cpu_states[threads_online - 1]); } for (thread = 0; thread < threads_per_cpu; thread++) { if (CPU_COUNT_S(cpu_state_size, cpu_states[thread])) { if (smt_state == 0) smt_state = thread + 1; else if (smt_state > 0) smt_state = -1; /* mix of SMT modes */ } } if (smt_state == 1) { if (numeric) printf("SMT=1\n"); else printf("SMT is off\n"); } else if (smt_state == -1) { for (thread = 0; thread < threads_per_cpu; thread++) { if (CPU_COUNT_S(cpu_state_size, cpu_states[thread])) { printf("SMT=%d: ", thread + 1); print_cpu_list(cpu_states[thread], cpu_state_size); printf("\n"); } } } else { printf("SMT=%d\n", smt_state); } cleanup_get_smt: for (thread = 0; thread < threads_per_cpu; thread++) CPU_FREE(cpu_states[thread]); } else { if (!strcmp(state, "on")) smt_state = threads_per_cpu; else if (!strcmp(state, "off")) smt_state = 1; else smt_state = strtol(state, NULL, 0); if ((smt_state <= 0) || (smt_state > threads_per_cpu)) { printf("SMT=%s is not valid\n", state); return -1; } rc = set_smt_state(smt_state); } return rc; } static inline void do_threads_per_core() { printf("Threads per core: %d\n", threads_per_cpu); } static int do_subcores_per_core(char *state) { int rc = 0; int subcore_state = 0; /* Check SMT machine. */ if (!is_smt_capable()) { fprintf(stderr, "Machine is not SMT capable\n"); return -1; } /* Check subcore capable machine/kernel. */ if (!is_subcore_capable()) { fprintf(stderr, "Machine is not subcore capable\n"); return -1; } if (!state) { /* Display current status. */ subcore_state = num_subcores(); if (subcore_state < 0) { fprintf(stderr, "Could not read subcore state.\n"); return -1; } printf("Subcores per core: %d\n", subcore_state); } else { /* Kernel decides what values are valid, so no need to * check here. */ subcore_state = strtol(state, NULL, 0); rc = set_attribute(SYSFS_SUBCORES, "%d", subcore_state); if (rc) { fprintf(stderr, "Failed to set subcore option.\n"); return rc; } printf("Subcores per core set to %d\n", subcore_state); } return rc; } #define PTRACE_DSCR 44 static int do_dscr_pid(int dscr_state, pid_t pid) { int rc; rc = ptrace(PTRACE_ATTACH, pid, NULL, NULL); if (rc) { fprintf(stderr, "Could not attach to process %d to %s the " "DSCR value\n%s\n", pid, (dscr_state ? "set" : "get"), strerror(errno)); return rc; } wait(NULL); if (dscr_state) { rc = ptrace(PTRACE_POKEUSER, pid, PTRACE_DSCR << 3, dscr_state); if (rc) { fprintf(stderr, "Could not set the DSCR value for pid " "%d\n%s\n", pid, strerror(errno)); ptrace(PTRACE_DETACH, pid, NULL, NULL); return rc; } } rc = ptrace(PTRACE_PEEKUSER, pid, PTRACE_DSCR << 3, NULL); if (errno) { fprintf(stderr, "Could not get the DSCR value for pid " "%d\n%s\n", pid, strerror(errno)); rc = -1; } else { printf("DSCR for pid %d is %d\n", pid, rc); } ptrace(PTRACE_DETACH, pid, NULL, NULL); return rc; } static int do_dscr(char *state, pid_t pid) { int rc = 0; int dscr_state = 0; if (!is_dscr_capable()) { fprintf(stderr, "Machine is not DSCR capable\n"); return -1; } if (state) dscr_state = strtol(state, NULL, 0); if (pid != -1) return do_dscr_pid(dscr_state, pid); if (!state) { int dscr, inconsistent = 0; rc = get_dscr(&dscr, &inconsistent); if (rc) { if (inconsistent) printf("Inconsistent DSCR\n"); else printf("Could not retrieve DSCR\n"); } else { printf("DSCR is %d\n", dscr); } } else rc = set_dscr(dscr_state); return rc; } static int do_smt_snooze_delay(char *state) { int rc = 0; if (!is_smt_capable()) { fprintf(stderr, "Machine is not SMT capable\n"); return -1; } if (!state) { int ssd, inconsistent = 0; rc = get_smt_snooze_delay(&ssd, &inconsistent); if (rc) { if (inconsistent) printf("Inconsistent smt_snooze_delay\n"); else printf("Could not retrieve smt_snooze_delay\n"); } else { printf("smt_snooze_delay is %d\n", ssd); } } else { int delay; if (!strcmp(state, "off")) delay = -1; else delay = strtol(state, NULL, 0); rc = set_smt_snooze_delay(delay); } return rc; } #ifdef WITH_LIBRTAS static int do_run_mode(char *run_mode) { char mode[3]; int rc; if (getuid() != 0) { fprintf(stderr, "Cannot %s run mode: Permission denied\n", run_mode ? "set" : "get"); return -1; } if (!run_mode) { rc = rtas_get_sysparm(DIAGNOSTICS_RUN_MODE, 3, mode); if (rc) { if (rc == -3) { printf("Machine does not support diagnostic " "run mode\n"); } else if (is_librtas_error(rc)) { char buf[1024]; librtas_error(rc, &buf[0], 1024); printf("Could not retrieve current diagnostics " "mode,\n%s\n", buf); } else { printf("Could not retrieve current diagnostics " "mode\n"); } } else printf("run-mode=%d\n", mode[2]); } else { uint16_t *first_16_bits = (uint16_t *)mode; short rmode = atoi(run_mode); if (rmode < 0 || rmode > 3) { printf("Invalid run-mode=%d\n", rmode); return -1; } *first_16_bits = htobe16(1); mode[2] = rmode; rc = rtas_set_sysparm(DIAGNOSTICS_RUN_MODE, mode); if (rc) { if (rc == -3) { printf("Machine does not support diagnostic " "run mode\n"); } else if (rc == -9002) { printf("Machine is not authorized to set " "diagnostic run mode\n"); } else if (is_librtas_error(rc)) { char buf[1024]; librtas_error(rc, &buf[0], 1024); printf("Could not set diagnostics mode,\n%s\n", buf); } else { printf("Could not set diagnostics mode\n"); } } } return rc; } #else static int do_run_mode(char *run_mode) { printf("Run mode determination is not supported on this platfom.\n"); return -1; } #endif #ifdef HAVE_LINUX_PERF_EVENT_H static int setup_counters(struct cpu_freq *cpu_freqs) { int i; struct perf_event_attr attr; memset(&attr, 0, sizeof(attr)); attr.type = PERF_TYPE_HARDWARE; attr.config = PERF_COUNT_HW_CPU_CYCLES; attr.disabled = 1; attr.size = sizeof(attr); for (i = 0; i < threads_in_system; i++) { if (!cpu_online(i)) { cpu_freqs[i].offline = 1; continue; } cpu_freqs[i].counter = syscall(__NR_perf_event_open, &attr, -1, i, -1, 0); if (cpu_freqs[i].counter < 0) { if (errno == ENOSYS) fprintf(stderr, "frequency determination " "not supported with this kernel.\n"); else perror("Could not initialize performance " "counters"); return -1; } } return 0; } static void start_counters(struct cpu_freq *cpu_freqs) { int i; for (i = 0; i < threads_in_system; i++) { if (cpu_freqs[i].offline) continue; ioctl(cpu_freqs[i].counter, PERF_EVENT_IOC_ENABLE); } } static void stop_counters(struct cpu_freq *cpu_freqs) { int i; for (i = 0; i < threads_in_system; i++) { if (cpu_freqs[i].offline) continue; ioctl(cpu_freqs[i].counter, PERF_EVENT_IOC_DISABLE); } } static void read_counters(struct cpu_freq *cpu_freqs) { int i; for (i = 0; i < threads_in_system; i++) { size_t res; if (cpu_freqs[i].offline) continue; res = read(cpu_freqs[i].counter, &cpu_freqs[i].freq, sizeof(unsigned long long)); assert(res == sizeof(unsigned long long)); close(cpu_freqs[i].counter); } } static void check_threads(struct cpu_freq *cpu_freqs) { int i; for (i = 0; i < threads_in_system; i++) { if (cpu_freqs[i].offline) continue; /* Sending signal 0 with pthread_kill will just check for * the existance of the thread without actually sending a * signal, we use this to see if the thread exited. */ if (pthread_kill(cpu_freqs[i].tid, 0)) { /* pthread exited, mark it offline iso we don't use * it in our calculations and close its perf * counter. */ cpu_freqs[i].offline = 1; close(cpu_freqs[i].counter); } } } static void *soak(void *arg) { unsigned int cpu = (long)arg; cpu_set_t cpumask; CPU_ZERO(&cpumask); CPU_SET(cpu, &cpumask); if (sched_setaffinity(0, sizeof(cpumask), &cpumask)) { perror("sched_setaffinity"); pthread_exit(NULL); } while (1) ; /* Do Nothing */ } static char *power_mode(uint64_t mode) { switch (mode) { case 0x0001: return "Dynamic, Favor Performance\n"; case 0x0002: return "None\n"; case 0x0003: return "Static\n"; case 0x00ff: return "Dynamic, Favor Power\n"; default: return "Unknown"; } } static void report_system_power_mode(void) { FILE *f; char line[128]; f = fopen("/proc/ppc64/lparcfg", "r"); if (!f) return; while (fgets(line, 128, f) != NULL) { char *name, *value; uint64_t mode, system_mode, partition_mode; if ((line[0] == '\n') || (!strncmp(&line[0], "lparcfg", 7))) continue; name = &line[0]; value = strchr(line, '='); *value = '\0'; value++; if (strcmp(name, "power_mode_data")) continue; /* The power mode result is defined as * XXXX XXXX XXXX XXXX * XXXX : System Power Mode * XXXX : Partition Power Mode * They mode is the first 4 bytes of the value reported in * the lparcfg file. */ mode = strtoul(value, NULL, 16); system_mode = (mode >> 48) & 0xffff; partition_mode = mode & 0xffff; if (system_mode != partition_mode) { printf("System Power Savings Mode: %s", power_mode(system_mode)); printf("Partition Power Savings Mode: %s", power_mode(partition_mode)); } else { printf("Power Savings Mode: %s", power_mode(system_mode)); } } fclose(f); return; } /* We need an FD per CPU, with a few more for stdin/out/err etc */ static void setrlimit_open_files(void) { struct rlimit old_rlim, new_rlim; int new = threads_in_system + 8; getrlimit(RLIMIT_NOFILE, &old_rlim); if (old_rlim.rlim_cur > new) return; new_rlim.rlim_cur = new; new_rlim.rlim_max = old_rlim.rlim_max; setrlimit(RLIMIT_NOFILE, &new_rlim); } #define freq_calc(cycles, time) (1.0 * (cycles) / (time) / 1000000000ULL) static int do_cpu_frequency(int sleep_time) { int i, rc; unsigned long long min = -1ULL; unsigned long min_cpu = -1UL; unsigned long long max = 0; unsigned long max_cpu = -1UL; unsigned long long sum = 0; unsigned long count = 0; struct cpu_freq *cpu_freqs; setrlimit_open_files(); cpu_freqs = calloc(threads_in_system, sizeof(*cpu_freqs)); if (!cpu_freqs) return -ENOMEM; rc = setup_counters(cpu_freqs); if (rc) { free(cpu_freqs); return rc; } /* Start a soak thread on each CPU */ for (i = 0; i < threads_in_system; i++) { if (cpu_freqs[i].offline) continue; if (pthread_create(&cpu_freqs[i].tid, NULL, soak, (void *)(long)i)) { perror("pthread_create"); free(cpu_freqs); return -1; } } /* Wait for soak threads to start */ usleep(1000000); start_counters(cpu_freqs); /* Count for specified timeout in seconds */ usleep(sleep_time * 1000000); stop_counters(cpu_freqs); check_threads(cpu_freqs); read_counters(cpu_freqs); for (i = 0; i < threads_in_system; i++) { unsigned long long frequency; if (cpu_freqs[i].offline) continue; frequency = cpu_freqs[i].freq; if (frequency < min) { min = frequency; min_cpu = i; } if (frequency > max) { max = frequency; max_cpu = i; } sum += frequency; count++; } report_system_power_mode(); printf("min:\t%.3f GHz (cpu %ld)\n", freq_calc(min, sleep_time), min_cpu); printf("max:\t%.3f GHz (cpu %ld)\n", freq_calc(max, sleep_time), max_cpu); printf("avg:\t%.3f GHz\n\n", freq_calc((sum / count), sleep_time)); free(cpu_freqs); return 0; } #else static int do_cpu_frequency(int sleep_time) { printf("CPU Frequency determination is not supported on this " "platfom.\n"); return EINVAL; } #endif static inline void do_cores_present() { printf("Number of cores present = %d\n", cpus_in_system); } static int set_all_threads_off(int cpu, int smt_state) { int i; char path[SYSFS_PATH_MAX]; int rc = 0; for (i = cpu + smt_state - 1; i >= cpu; i--) { snprintf(path, SYSFS_PATH_MAX, SYSFS_CPUDIR"/%s", i, "online"); rc = offline_thread(path); if (rc == -1) printf("Unable to take cpu%d offline", i); } return rc; } static int set_one_core(int smt_state, int core, int state) { int rc = 0; int cpu = core * threads_per_cpu; if (state) { rc = set_one_smt_state(cpu, smt_state); if (rc == -1) printf("Unable to bring core %d online\n", core); } else { rc = set_all_threads_off(cpu, smt_state); if (rc == -1) printf("Unable to take core %d offline\n", core); } return rc; } static int do_online_cores(char *cores, int state) { int smt_state; int *core_state, *desired_core_state; int i, rc = 0; int core; char *str, *token, *end_token; bool first_core = true; if (cores) { if (!sysattr_is_writeable("online")) { perror("Cannot set cores online"); return -1; } } else { if (!sysattr_is_readable("online")) { perror("Cannot get online cores"); return -1; } } smt_state = get_smt_state(); core_state = calloc(cpus_in_system, sizeof(int)); if (!core_state) return -ENOMEM; for (i = 0; i < cpus_in_system ; i++) core_state[i] = (get_one_smt_state(i) > 0); if (!cores) { printf("Cores %s = ", state == 0 ? "offline" : "online"); for (i = 0; i < cpus_in_system; i++) { if (core_state[i] == state) { if (first_core) first_core = false; else printf(","); printf("%d", i); } } printf("\n"); free(core_state); return 0; } if (smt_state == -1) { printf("Bad or inconsistent SMT state: use ppc64_cpu --smt=on|off to set all\n" "cores to have the same number of online threads to continue.\n"); do_info(); return -1; } desired_core_state = calloc(cpus_in_system, sizeof(int)); if (!desired_core_state) { free(core_state); return -ENOMEM; } for (i = 0; i < cpus_in_system; i++) /* * Not specified on command-line */ desired_core_state[i] = -1; str = cores; while (1) { token = strtok(str, ","); if (!token) break; /* reuse the same string */ str = NULL; core = strtol(token, &end_token, 0); if (token == end_token || '\0' != *end_token) { printf("Invalid core to %s: %s\n", state == 0 ? "offline" : "online", token); rc = -1; continue; } if (core >= cpus_in_system || core < 0) { printf("Invalid core to %s: %d\n", state == 0 ? "offline" : "online", core); rc = -1; continue; } desired_core_state[core] = state; } if (rc) { free(core_state); free(desired_core_state); return rc; } for (i = 0; i < cpus_in_system; i++) { if (desired_core_state[i] != -1) { rc = set_one_core(smt_state, i, state); if (rc) break; } } free(core_state); free(desired_core_state); return rc; } static int do_cores_on(char *state) { int smt_state; int *core_state; int cores_now_online = 0; int i, rc; int number_to_have, number_to_change = 0, number_changed = 0; int new_state; char *end_state; if (state) { if (!sysattr_is_writeable("online")) { perror("Cannot set cores online"); return -1; } } else { if (!sysattr_is_readable("online")) { perror("Cannot get online cores"); return -1; } } core_state = calloc(cpus_in_system, sizeof(int)); if (!core_state) return -ENOMEM; for (i = 0; i < cpus_in_system ; i++) { core_state[i] = (get_one_smt_state(i) > 0); if (core_state[i]) cores_now_online++; } if (!state) { printf("Number of cores online = %d\n", cores_now_online); free(core_state); return 0; } smt_state = get_smt_state(); if (smt_state == -1) { printf("Bad or inconsistent SMT state: use ppc64_cpu --smt=on|off to set all\n" "cores to have the same number of online threads to continue.\n"); do_info(); return -1; } if (!strcmp(state, "all")) { number_to_have = cpus_in_system; } else { number_to_have = strtol(state, &end_state, 0); /* No digits found or trailing characters */ if (state == end_state || '\0' != *end_state) { printf("Invalid number of cores to online: %s\n", state); free(core_state); return -1; } } if (number_to_have == cores_now_online) { free(core_state); return 0; } if (number_to_have > cpus_in_system) { printf("Cannot online more cores than are present.\n"); do_cores_present(); free(core_state); return -1; } if (number_to_have > cores_now_online) { number_to_change = number_to_have - cores_now_online; new_state = 1; } else { number_to_change = cores_now_online - number_to_have; new_state = 0; } if (new_state) { for (i = 0; i < cpus_in_system; i++) { if (!core_state[i]) { rc = set_one_core(smt_state, i, new_state); if (!rc) number_changed++; if (number_changed >= number_to_change) break; } } } else { for (i = cpus_in_system - 1; i > 0; i--) { if (core_state[i]) { rc = set_one_core(smt_state, i, new_state); if (!rc) number_changed++; if (number_changed >= number_to_change) break; } } } if (number_changed != number_to_change) { cores_now_online = 0; for (i = 0; i < cpus_in_system ; i++) { if (cpu_online(i * threads_per_cpu)) cores_now_online++; } printf("Failed to set requested number of cores online.\n" "Requested: %d cores, Onlined: %d cores\n", number_to_have, cores_now_online); free(core_state); return -1; } free(core_state); return 0; } static int do_info(void) { int i, j, thread_num; char online; int subcores = 0; if (is_subcore_capable()) subcores = num_subcores(); for (i = 0; i < cpus_in_system; i++) { if (subcores > 1) { if (i % subcores == 0) printf("Core %3d:\n", i/subcores); printf(" Subcore %3d: ", i); } else { printf("Core %3d: ", i); } for (j = 0; j < threads_per_cpu; j++) { thread_num = i*threads_per_cpu + j; online = cpu_online(thread_num) ? '*' : ' '; printf("%4d%c ", thread_num, online); } printf("\n"); } return 0; } static void usage(void) { printf( "Usage: ppc64_cpu [command] [options]\n" "ppc64_cpu --smt [-n] # Get current SMT state. [-n] shows numeric output\n" "ppc64_cpu --smt={on|off} # Turn SMT on/off\n" "ppc64_cpu --smt=X # Set SMT state to X\n\n" "ppc64_cpu --cores-present # Get the number of cores present\n" "ppc64_cpu --cores-on # Get the number of cores currently online\n" "ppc64_cpu --cores-on=X # Put exactly X cores online\n" "ppc64_cpu --cores-on=all # Put all cores online\n\n" "ppc64_cpu --online-cores=X[,Y...] # Put specified cores online\n\n" "ppc64_cpu --offline-cores=X[,Y,...] # Put specified cores offline\n\n" "ppc64_cpu --dscr # Get current DSCR system setting\n" "ppc64_cpu --dscr= # Change DSCR system setting\n" "ppc64_cpu --dscr [-p ] # Get DSCR setting for process \n" "ppc64_cpu --dscr= [-p ] # Change DSCR setting for process \n\n" "ppc64_cpu --smt-snooze-delay # Get current smt-snooze-delay setting\n" "ppc64_cpu --smt-snooze-delay= # Change smt-snooze-delay setting\n\n" "ppc64_cpu --run-mode # Get current diagnostics run mode\n" "ppc64_cpu --run-mode= # Set current diagnostics run mode\n\n" "ppc64_cpu --frequency [-t