./ledmon-0.79/000755 001750 001750 00000000000 12245410773 013707 5ustar00ldorauldorau000000 000000 ./ledmon-0.79/Makefile000664 001750 001750 00000002512 12245410736 015350 0ustar00ldorauldorau000000 000000 # # Intel(R) Enclosure LED Utilities # Copyright (C) 2009-2013 Intel Corporation. # # This program is free software; you can redistribute it and/or modify it # under the terms and conditions of the GNU General Public License, # version 2, as published by the Free Software Foundation. # # This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. # # Installation directory DESTDIR?= .PHONY: ledmon ledctl man all default: all ledmon: $(MAKE) -C src ledmon ledctl: $(MAKE) -C src ledctl man: $(MAKE) -C doc all all: ledmon ledctl man install: all $(MAKE) -C src DESTDIR=$(DESTDIR) install $(MAKE) -C doc DESTDIR=$(DESTDIR) install uninstall: $(MAKE) -C src DESTDIR=$(DESTDIR) uninstall $(MAKE) -C doc DESTDIR=$(DESTDIR) uninstall clean: $(MAKE) -C src clean $(MAKE) -C doc clean mrproper: $(MAKE) -C src mrproper $(MAKE) -C doc clean TAGS_FILES=$(shell ls Makefile src/Makefile */*.[ch]) TAGS: $(TAGS_FILES) @etags $(TAGS_FILES) ./ledmon-0.79/config/000775 001750 001750 00000000000 12245410736 015155 5ustar00ldorauldorau000000 000000 ./ledmon-0.79/config/config.h000664 001750 001750 00000002675 12245410736 016605 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _CONFIG_H_INCLUDED_ #define _CONFIG_H_INCLUDED_ #include /** */ #define _HAVE_DMALLOC_H 0 /** * @brief Sets errno variable and returns. * * This macro sets the errno variable and makes function return -1. * * @param[in] __val integer value to be set. * * @return The macro does not return a value. */ #define __set_errno_and_return(__val) { errno = (__val); return -1; } /** */ #define PATH_DELIM '/' /** */ #define PATH_DELIM_STR "/" /** */ #define PATH_SEP ':' /** */ #define PATH_SEP_STR ":" /** */ #define END_LINE ('\n') /** */ #define END_LINE_STR "\n" #endif /* _CONFIG_H_INCLUDED_ */ ./ledmon-0.79/COPYING000664 001750 001750 00000043127 12245410736 014752 0ustar00ldorauldorau000000 000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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) 19yy 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) 19yy 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 Library General Public License instead of this License. ./ledmon-0.79/README000664 001750 001750 00000002356 12245410751 014573 0ustar00ldorauldorau000000 000000 This package contains the Enclosure LED Utilities, version 0.79 Copyright (C) 2009-2013 Intel Corporation. All files in this package can be freely distributed and used according to the terms of the GNU General Public License, version 2. See http://www.gnu.org/ for details. 1. Compiling the package. ------------------------- Run "make" command to compile the package. 2. (Un)installing the package. -------------------------- Run "make install" to install the package. The default location for ledctl and ledmon applications is /usr/sbin directory. The default location for documentation is /usr/share/man directory. Run "make DESTDIR= install" to prepend 'path' to the default install location. The ledctl and ledmon applications will be installed in $DESTDIR/usr/sbin directory and the manual pages will be installed in $DESTDIR/usr/share/man directory. Run "make uninstall" to uninstall the package from default location. Set DESTDIR variable to uninstall the package from non-default location. 3. Release notes. -------------------------- a. Enclosure LED Utilities is meant as a part of RHEL and SLES linux distributions. b. For backplane enclosures attached to ISCI controller support is limited to Intel(R) Intelligent Backplane. ./ledmon-0.79/src/000775 001750 001750 00000000000 12245410751 014474 5ustar00ldorauldorau000000 000000 ./ledmon-0.79/src/ledctl.c000664 001750 001750 00000055707 12245410751 016125 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if _HAVE_DMALLOC_H #include #endif #include "status.h" #include "list.h" #include "cntrl.h" #include "sysfs.h" #include "ibpi.h" #include "block.h" #include "utils.h" #include "version.h" #include "scsi.h" #include "ahci.h" /** * @brief An IBPI state structure. * * This structure connects an IBPI pattern and block devices. It is used by * _determine() function to figure the correct pattern out. */ struct ibpi_state { enum ibpi_pattern ibpi; void *block_list; }; /** * @brief List of IBPI patterns. * * This variable holds a pointer to a list of IBPI patterns the user requested * to be visualized. Each element on the list is struct ibpi_state type. There's * only one instance of each IBPI pattern on the list (no duplicates). */ static void *ibpi_list = NULL; /** * @brief IBPI pattern names. * * This is internal array holding names of IBPI pattern. Logging routines use * this entries to translate enumeration type values into the string. */ const char *ibpi_str[] = { [IBPI_PATTERN_UNKNOWN] = "", [IBPI_PATTERN_NORMAL] = "NORMAL", [IBPI_PATTERN_ONESHOT_NORMAL] = "", [IBPI_PATTERN_DEGRADED] = "ICA", [IBPI_PATTERN_REBUILD] = "REBUILD", [IBPI_PATTERN_REBUILD_P] = "REBUILD", [IBPI_PATTERN_FAILED_ARRAY] = "IFA", [IBPI_PATTERN_HOTSPARE] = "HOTSPARE", [IBPI_PATTERN_PFA] = "PFA", [IBPI_PATTERN_FAILED_DRIVE] = "FAILURE", [IBPI_PATTERN_LOCATE] = "LOCATE", [IBPI_PATTERN_LOCATE_OFF] = "LOCATE_OFF" }; /** * Internal variable of ledctl utility. It is the pattern used to print out * information about the version of ledctl utility. */ static char *ledctl_version = "Intel(R) Enclosure LED Control Application %d.%d\n" "Copyright (C) 2009-2013 Intel Corporation.\n"; /** * Internal variable of monitor service. It is used to help parse command line * short options. */ static char *shortopt = "c:hvl:"; /** * Internal enumeration type. It is used to help parse command line arguments. */ enum longopt { OPT_CONFIG, OPT_HELP, OPT_LOG, OPT_VERSION }; /** * Internal array with option tokens. It is used to help parse command line * long options. */ static struct option longopt[] = { [OPT_CONFIG] = {"config", required_argument, NULL, 'c'}, [OPT_HELP] = {"help", no_argument, NULL, 'h'}, [OPT_LOG] = {"log", required_argument, NULL, 'l'}, [OPT_VERSION] = {"version", no_argument, NULL, 'v'}, {NULL, no_argument, NULL, '\0'} }; /** * @brief Finalizes LED control utility. * * This is internal function of ledctl utility. The function cleans up a memory * allocated for the application and closes all opened handles. This function is * design to be registered as on_exit() handler function. * * @param[in] status exit status of the ledctl application. * @param[in] ignored function ignores this argument. * * @return The function does not return a value. */ static void _ledctl_fini(int __attribute__ ((unused)) status, void *__attribute__ ((unused)) ignore) { sysfs_fini(); if (ibpi_list) list_fini(ibpi_list); log_close(); } /** * @brief Displays the credits. * * This is internal function of ledctl utility. It prints out the name and * version of the program. It displays the copyright notice and information * about the author and license, too. * * @return The function does not return a value. */ static void _ledctl_version(void) { printf(ledctl_version, VERSION_MAJOR, VERSION_MINOR); printf("\nThis is free software; see the source for copying conditions." \ " There is NO warranty;\nnot even for MERCHANTABILITY or FITNESS" \ " FOR A PARTICULAR PURPOSE.\n\n"); } /** * @brief Displays the help. * * This is internal function of ledctl utility. The function prints the name * and version of the program out. It displays the usage and available options * and its arguments (if any). Each option is described. This is an extract * from user manual page. * * @return The function does not return a value. */ static void _ledctl_help(void) { printf(ledctl_version, VERSION_MAJOR, VERSION_MINOR); printf("\nUsage: %s [OPTIONS] pattern=list_of_devices ...\n\n", progname); printf("Mandatory arguments for long options are mandatory for" \ " short options, too.\n\n"); printf ("--log=PATH,\t-l PATH\t\t Use local log file instead\n" \ "\t\t\t\t /var/log/ledctl.log global file.\n"); printf("--config=PATH,\t-c PATH\t\t Use alternate configuration" \ " file (not yet\n\t\t\t\t implemented).\n"); printf("--help,\t\t-h\t\t Displays this help text.\n"); printf ("--version,\t-v\t\t Displays version and license information.\n\n"); printf("Patterns:\n" "\tCommon patterns are:\n" "\t\tlocate, locate_off, normal, off, degraded, rebuild,\n" "" "\t\trebuild_p, failed_array, hotspare, pfa, failure,\n" "\t\tdisk_failed\n" "\tSES-2 only patterns:\n" "\t\tses_abort, ses_rebuild, ses_ifa, ses_ica, ses_cons_check,\n" "\t\tses_hotspare, ses_rsvd_dev, ses_ok, ses_ident, ses_rm,\n" "\t\tses_insert, ses_missing, ses_dnr, ses_active,\n" "\t\tses_enbale_bb, ses_enable_ba, ses_devoff, ses_fault\n" "\tAutomatic translation form IBPI into SES-2:\n" "\t\tlocate=ses_ident, locate_off=~ses_ident,\n" "\t\tnormal=ses_ok, off=ses_ok, degraded=ses_ica,\n" "\t\trebuild=ses_rebuild rebuild_p=ses_rebuild,\n" "\t\tfailed_array=ses_ifa, hotspare=ses_hotspare\n" "\t\tpfa=ses_rsvd_dev, failure=ses_fault,\n" "\t\tdisk_failed=ses_fault\n"); printf("Refer to ledctl(8) man page for more detailed description.\n"); printf("Bugs should be reported at: " \ "http://sourceforge.net/p/ledmon/bugs \n"); } /** * @brief Puts new IBPI state on the list. * * This is internal function of ledctl utility. The function creates a new entry * of the list with IBPI patterns. Each IBPI state has a list of block devices * attached. The function initializes this list and sets empty. * * @param[in] ibpi an IBPI pattern to add. * * @return Pointer to the created element if successful, otherwise function * returns NULL. The NULL pointer means either initialization * of list for block devices failed or putting new element * no IBPI state list failed. */ static void *_ibpi_state_init(enum ibpi_pattern ibpi) { struct ibpi_state state; if (list_init(&state.block_list) != STATUS_SUCCESS) return NULL; state.ibpi = ibpi; return list_put(ibpi_list, &state, sizeof(struct ibpi_state)); } /** * @brief Sets an IBPI state. * * This is internal function of ledctl utility. The function sets an IBPI state * for a block device. If existing pattern has higher priority then state * requested the function does nothing. * * @param[in] block pointer to block device structure. * @param[in] ibpi IBPI pattern/state to be set. * * @return The function does not return a value. */ static void _set_state(struct block_device **block, enum ibpi_pattern ibpi) { if ((*block)->ibpi < ibpi) (*block)->ibpi = ibpi; } /** * @brief Sets a state of block device. * * This is internal function of ledctl utility. The function sets * an IBPI pattern for block devices. The function is design to be used * as action parameter of list_for_each() function. * * @param[in] state pointer to structure holding the IBPI pattern * identifier and list of block devices. * * @return The function does not return a value. */ static void _determine(struct ibpi_state *state) { if (list_is_empty(state->block_list) == 0) { list_for_each_parm(state->block_list, _set_state, state->ibpi); } else { log_warning ("IBPI %s: missing block device(s)... pattern ignored.", ibpi_str[state->ibpi]); } } /** * @brief Determines a state of block devices. * * This is internal function of ledctl utility. The functions goes through list * of IBPI states and calls _determine() function for each element. If the list * is empty the function logs a warning message and does nothing. * * @param[in] ibpi_list pointer to list of IBPI states. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. * The following status codes function returns: * * STATUS_LIST_EMPTY the specified list has no elements. * STATUS_NULL_POINTER ibpi_list is NULL. */ static status_t _ibpi_state_determine(void *ibpi_list) { if (list_is_empty(ibpi_list) == 0) return list_for_each(ibpi_list, _determine); log_error("missing operand(s)... run %s --help for details.", progname); return STATUS_LIST_EMPTY; } /** * @brief Tests the IBPI state. * * This is internal function of ledctl utility. The function checks if the given * IBPI state is already on the list. The function is designed to be used as the * 'test' argument of list_first_that() function. * * @param[in] state pointer to IBPI state structure. * @param[in] ibpi IBPI state is being searched. * * @return 1 if the IBPI state matches, otherwise the function returns 0. */ static int _ibpi_find(struct ibpi_state *state, enum ibpi_pattern ibpi) { return (state->ibpi == ibpi); } /** * @brief Sets the path to configuration file. * * This is internal function of monitor service. This function sets the path and * name of configuration file. The function is checking whether the given path * is valid or it is invalid and should be ignored. * * @param[in] path the new location and name of config file. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. */ static status_t _set_config_path(const char *path) { (void)path; return STATUS_SUCCESS; } /** * @brief Sets the path to local log file. * * This is internal function of ledctl utility. This function sets the path and * file name of log file. The function checks if the specified path is valid. If * the path is invalid then the function does nothing. * * @param[in] path new location and name of log file. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. */ static status_t _set_log_path(const char *path) { char temp[PATH_MAX]; if (realpath(path, temp) == NULL) { if ((errno != ENOENT) && (errno != ENOTDIR)) return STATUS_INVALID_PATH; } if (log_open(temp) < 0) return STATUS_FILE_OPEN_ERROR; return STATUS_SUCCESS; } /** * @brief Gets a pointer to IBPI state structure. * * This is internal function of ledctl utility. The function retrieves an entry * to an IBPI state structure from ibpi_list list. If such an entry does not * exist the memory is allocated and entry is added to the list. * * @param[in] name a name of IBPI pattern i.e. taken from command * line interface. It might be 'locate', 'normal', * 'locate_off', 'off', 'ica', 'degraded', 'rebuild', * 'rebuild_p', 'ifa', 'failed_array', 'hotspare', * 'pfa', 'failure' or 'disk_failed' string. * * @return Pointer to IBPI state structure if successful, otherwise the function * returns NULL. The NULL pointer means either the invalid status name * has been given or there's not enough memory available in the system * to allocate the structure. */ static struct ibpi_state *_ibpi_state_get(const char *name) { struct ibpi_state *state = NULL; enum ibpi_pattern ibpi; if (strcmp(name, "locate") == 0) { ibpi = IBPI_PATTERN_LOCATE; } else if (strcmp(name, "locate_off") == 0) { ibpi = IBPI_PATTERN_LOCATE_OFF; } else if (strcmp(name, "normal") == 0) { ibpi = IBPI_PATTERN_NORMAL; } else if (strcmp(name, "off") == 0) { ibpi = IBPI_PATTERN_NORMAL; } else if ((strcmp(name, "ica") == 0) || (strcmp(name, "degraded") == 0)) { ibpi = IBPI_PATTERN_DEGRADED; } else if (strcmp(name, "rebuild") == 0) { ibpi = IBPI_PATTERN_REBUILD; } else if (strcmp(name, "rebuild_p") == 0) { ibpi = IBPI_PATTERN_REBUILD_P; } else if ((strcmp(name, "ifa") == 0) || (strcmp(name, "failed_array") == 0)) { ibpi = IBPI_PATTERN_FAILED_ARRAY; } else if (strcmp(name, "hotspare") == 0) { ibpi = IBPI_PATTERN_HOTSPARE; } else if (strcmp(name, "pfa") == 0) { ibpi = IBPI_PATTERN_PFA; } else if ((strcmp(name, "failure") == 0) || (strcmp(name, "disk_failed") == 0)) { ibpi = IBPI_PATTERN_FAILED_DRIVE; } else if (strcmp(name, "ses_abort") == 0) { ibpi = SES_REQ_ABORT; } else if (strcmp(name, "ses_rebuild") == 0) { ibpi = SES_REQ_REBUILD; } else if (strcmp(name, "ses_ifa") == 0) { ibpi = SES_REQ_IFA; } else if (strcmp(name, "ses_ica") == 0) { ibpi = SES_REQ_ICA; } else if (strcmp(name, "ses_cons_check") == 0) { ibpi = SES_REQ_CONS_CHECK; } else if (strcmp(name, "ses_hotspare") == 0) { ibpi = SES_REQ_HOSTSPARE; } else if (strcmp(name, "ses_rsvd_dev") == 0) { ibpi = SES_REQ_RSVD_DEV; } else if (strcmp(name, "ses_ok") == 0) { ibpi = SES_REQ_OK; } else if (strcmp(name, "ses_ident") == 0) { ibpi = SES_REQ_IDENT; } else if (strcmp(name, "ses_rm") == 0) { ibpi = SES_REQ_RM; } else if (strcmp(name, "ses_insert") == 0) { ibpi = SES_REQ_INS; } else if (strcmp(name, "ses_missing") == 0) { ibpi = SES_REQ_MISSING; } else if (strcmp(name, "ses_dnr") == 0) { ibpi = SES_REQ_DNR; } else if (strcmp(name, "ses_active") == 0) { ibpi = SES_REQ_ACTIVE; } else if (strcmp(name, "ses_enbale_bb") == 0) { ibpi = SES_REQ_EN_BB; } else if (strcmp(name, "ses_enable_ba") == 0) { ibpi = SES_REQ_EN_BA; } else if (strcmp(name, "ses_devoff") == 0) { ibpi = SES_REQ_DEV_OFF; } else if (strcmp(name, "ses_fault") == 0) { ibpi = SES_REQ_FAULT; } else { return NULL; } state = list_first_that(ibpi_list, _ibpi_find, ibpi); if (state == NULL) state = _ibpi_state_init(ibpi); return state; } /** * This is internal function of ledctl utility. The function checks if the * given block device is the one we looking for. This function is design * to be used as 'test' parameter for list_first_that() function. * * @param[in] block pointer to block device structure, the * element on block_list of sysfs structure. * @param[in] path path to block device in sysfs tree we are * looking for. * * @return 1 if the block device is found, otherwise the function returns 0. */ static int _block_device_search(struct block_device *block, const char *path) { return (strcmp(block->sysfs_path, path) == 0); } /** * @brief Adds a block device to a block list. * * This is internal function of ledctl utility. Each IBPI state has list of * block devices attached to. The function puts a pointer to a block device * on that list. First the function determines the canonical version of the * given path and checks if it is correct. If the path to /dev directory is * given the function finds out the correct entry in sysfs tree. * * @param[in] state pointer to IBPI state structure the block * device will be added to. * @param[in] block pointer to block device structure. * * @return The function does not return a value. */ static status_t _ibpi_state_add_block(struct ibpi_state *state, char *name) { struct stat st; char temp[PATH_MAX], path[PATH_MAX]; void *blk1, *blk2; if ((realpath(name, temp) == NULL) && (errno != ENOTDIR)) return STATUS_INVALID_PATH; if (strstr(temp, "/dev/") != NULL) { if (stat(temp, &st) < 0) return STATUS_STAT_ERROR; sprintf(temp, "/sys/dev/block/%d:%d", major(st.st_rdev), minor(st.st_rdev)); if ((realpath(temp, path) == NULL) && (errno != ENOTDIR)) return STATUS_INVALID_PATH; } else { str_cpy(path, temp, PATH_MAX); } blk1 = sysfs_block_device_first_that(_block_device_search, path); if (blk1 == NULL) { log_error("%s: device not supported", name); return STATUS_NOT_SUPPORTED; } blk2 = list_first_that(state->block_list, _block_device_search, path); if (blk2 == NULL) { if (list_put(state->block_list, &blk1, sizeof(void *)) == NULL) return STATUS_OUT_OF_MEMORY; } else { log_info("%s: %s: device already on the list.", ibpi_str[state->ibpi], path); } return STATUS_SUCCESS; } /** * @brief Command line parser - operands. * * This is internal function of ledctl utility. The function parses operands of * ledctl application. The operands section contains the pattern name and a list * of block devices associated with each pattern. There are two different * formats for the operand. First format is pattern={ dev_list }, where elements * are space separated on the dev_list. Second format is pattern=dev1,dev2,... * where elements are comma separated on the list of devices. * * @param[in] argc number of elements in argv array. * @param[in] argv command line arguments. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. */ static status_t _cmdline_ibpi_parse(int argc, char *argv[]) { while (optind < argc) { struct ibpi_state *state = NULL; char *p = argv[optind++]; char *t; t = strchrnul(p, '='); if (*t != '\0') { *(t++) = '\0'; state = _ibpi_state_get(p); if (state != NULL) { if (*t == '{') { while ((t = argv[optind++]) != NULL) { if (*t == '}') break; _ibpi_state_add_block(state, t); } } else { while (*(p = t) != '\0') { t = strchrnul(p, ','); if (*t != '\0') *(t++) = '\0'; _ibpi_state_add_block(state, p); } } } } if (state == NULL) { log_error("%s - unknown pattern name.", p); exit(STATUS_INVALID_STATE); } } return STATUS_SUCCESS; } /** * @brief Command line parser - options. * * This is internal function of ledctl utility. The function parses options of * ledctl application. Refer to ledctl help in order to get more information * about ledctl command line options. * * @param[in] argc number of elements in argv array. * @param[in] argv command line arguments. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. */ static status_t _cmdline_parse(int argc, char *argv[]) { int opt, opt_index = -1; status_t status = STATUS_SUCCESS; do { opt = getopt_long(argc, argv, shortopt, longopt, &opt_index); if (opt == -1) break; switch (opt) { case 'v': _ledctl_version(); exit(EXIT_SUCCESS); case 'h': _ledctl_help(); exit(EXIT_SUCCESS); case 'c': status = _set_config_path(optarg); break; case 'l': status = _set_log_path(optarg); break; case ':': case '?': default: log_debug("[opt='%c', opt_index=%d]", opt, opt_index); break; } opt_index = -1; if (status != STATUS_SUCCESS) return status; } while (1); return STATUS_SUCCESS; } /** * @brief Sends a LED control message. * * This is internal function of ledctl utility. The function sends LED control * message to controller in order to control LED in enclosure. The pattern to * send is stored in block device structure. * * @param[in] device a pointer to block device structure. * * @return The function does not return a value. */ static void _send_cntrl_message(struct block_device *device) { /* turn off all unset LEDs */ if (device->ibpi == IBPI_PATTERN_UNKNOWN) device->ibpi = IBPI_PATTERN_NORMAL; device->send_fn(device, device->ibpi); device->flush_fn(device); } /** * @brief Determine and send IBPI pattern. * * This is internal function of ledctl utility. The function determines a state * of block device based on ibpi_list list. Then it sends a LED control message * to controller to visualize the pattern. * * @param[in] sysfs pointer to sysfs structure holding information * about the existing controllers, block devices, * and software RAID devices. * @param[in] ibpi_list TBD * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. */ static status_t _ledctl_execute(void *ibpi_list) { if (_ibpi_state_determine(ibpi_list) != STATUS_SUCCESS) return STATUS_IBPI_DETERMINE_ERROR; return sysfs_block_device_for_each(_send_cntrl_message); } /** * @brief Application's entry point. * * This is the entry point of ledctl utility. This function does all the work. * It allocates and initializes all used structures. Registers on_exit() * handlers. * Then the function parses command line options and commands given and scans * sysfs tree for controllers, block devices and RAID devices. If no error is * the function send LED control messages according to IBPI pattern set. * * @param[in] argc number of elements in argv array, number of * command line arguments. * @param[in] argv array of command line arguments. The last * element on the list is NULL pointer. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. */ int main(int argc, char *argv[]) { status_t status; set_invocation_name(argv[0]); openlog(progname, LOG_PERROR, LOG_USER); if (getuid() != 0) { log_error("Only root can run this application."); return STATUS_NOT_A_PRIVILEGED_USER; } if (on_exit(_ledctl_fini, progname)) exit(STATUS_ONEXIT_ERROR); if (_cmdline_parse(argc, argv)) exit(STATUS_CMDLINE_ERROR); status = list_init(&ibpi_list); if (status != STATUS_SUCCESS) { log_debug("main(): list_init() failed (status=%s).", strstatus(status)); exit(STATUS_LIST_INIT_ERROR); } status = sysfs_init(); if (status != STATUS_SUCCESS) { log_debug("main(): sysfs_init() failed (status=%s).", strstatus(status)); exit(STATUS_SYSFS_INIT_ERROR); } status = sysfs_scan(); if (status != STATUS_SUCCESS) { log_debug("main(): sysfs_scan() failed (status=%s).", strstatus(status)); exit(STATUS_SYSFS_SCAN_ERROR); } status = _cmdline_ibpi_parse(argc, argv); if (status != STATUS_SUCCESS) { log_debug("main(): _ibpi_parse() failed (status=%s).", strstatus(status)); exit(STATUS_INVALID_STATE); } return _ledctl_execute(ibpi_list); } ./ledmon-0.79/src/cntrl.h000664 001750 001750 00000005532 12245410751 015774 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _CNTRL_H_INCLUDED_ #define _CNTRL_H_INCLUDED_ /** * This enumeration type lists all supported storage controller types. */ enum cntrl_type { CNTRL_TYPE_UNKNOWN = 0, CNTRL_TYPE_DELLSSD, CNTRL_TYPE_SCSI, CNTRL_TYPE_AHCI }; /** * @brief Storage controller device structure. * * This structure describes a storage controller device existing in the system. */ struct cntrl_device { /** * Path to the device in sysfs tree. */ char *sysfs_path; /** * Type of storage controller device. */ enum cntrl_type cntrl_type; /** * Flag if scsi controller driver is "isci" */ int isci_present; struct _host_type { /** * ibpi state buffer for directly attached devices */ void *ibpi_state_buffer; /** * outbound raw byte stream */ unsigned char bitstream[4]; /** * bitstream's flush flag */ int flush; /** * host identifier for different hba instances */ int host_id; /** * pointer to next structure */ struct _host_type *next; } *hosts; }; /** * @brief Allocates a new controller device structure. * * This function allocates memory for a new structure of storage controller * device. It reads the sysfs entries and populates structure fields. * The function registers only supported storage controllers. * * @param[in] path path to storage controller in sysfs tree. * * @return Pointer to storage controller structure if successful, otherwise the * function returns NULL pointer. The NULL pointer means that controller * device is not supported. */ struct cntrl_device *cntrl_device_init(const char *path); /** * @brief Releases a controller device structure. * * This function releases memory allocated for controller device structure. * To be more specific it only frees memory allocated for the fields of the * structure. It is due to the way list is implemented for the purpose of this * utility. * * @param[in] device pointer to controller device structure. * * @return The function does not return a value. */ void cntrl_device_fini(struct cntrl_device *device); #endif /* _CNTRL_H_INCLUDED_ */ ./ledmon-0.79/src/slave.c000664 001750 001750 00000005760 12245410751 015762 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #if _HAVE_DMALLOC_H #include #endif #include "status.h" #include "ibpi.h" #include "utils.h" #include "list.h" #include "sysfs.h" #include "block.h" #include "slave.h" /** */ static unsigned char _get_state(const char *path) { char *p, *t, *s; unsigned char result = SLAVE_STATE_UNKNOWN; s = p = get_text(path, "state"); if (p) { while (s) { t = strchr(s, ','); if (t) *(t++) = '\0'; if (strcmp(s, "spare") == 0) result |= SLAVE_STATE_SPARE; else if (strcmp(s, "in_sync") == 0) result |= SLAVE_STATE_IN_SYNC; else if (strcmp(s, "faulty") == 0) result |= SLAVE_STATE_FAULTY; else if (strcmp(s, "write_mostly") == 0) result |= SLAVE_STATE_WRITE_MOSTLY; else if (strcmp(s, "blocked") == 0) result |= SLAVE_STATE_BLOCKED; s = t; } free(p); } return result; } /** */ static unsigned int _get_errors(const char *path) { return get_int(path, 0, "errors"); } /** */ static unsigned int _get_slot(const char *path) { unsigned int result = -1; char *p = get_text(path, "slot"); if (p) { if (strcmp(p, "none") != 0) result = atoi(p); free(p); } return result; } /** */ static int _compare(struct block_device *device, const char *path) { return (strcmp(device->sysfs_path, path) == 0); } /** */ static struct block_device *_get_block(const char *path, void *block_list) { char temp[PATH_MAX]; char link[PATH_MAX]; struct block_device *device = NULL; str_cpy(temp, path, PATH_MAX); str_cat(temp, "/block", PATH_MAX); if (realpath(temp, link)) device = list_first_that(block_list, _compare, link); return device; } /** */ struct slave_device *slave_device_init(const char *path, void *block_list) { struct slave_device *device = NULL; struct block_device *block; block = _get_block(path, block_list); if (block) { device = malloc(sizeof(struct slave_device)); if (device) { device->raid = NULL; device->state = _get_state(path); device->slot = _get_slot(path); device->errors = _get_errors(path); device->block = block; } } return device; } /** */ void slave_device_fini(struct slave_device *device) { (void)device; /* Function reserved for future improvements. */ } ./ledmon-0.79/src/Makefile000664 001750 001750 00000005116 12245410751 016137 0ustar00ldorauldorau000000 000000 # # Intel(R) Enclosure LED Utilities # Copyright (C) 2009-2013 Intel Corporation. # # This program is free software; you can redistribute it and/or modify it # under the terms and conditions of the GNU General Public License, # version 2, as published by the Free Software Foundation. # # This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. # # Installation directory prefix. DESTDIR?= # Installation directory of ledctl application. LEDCTL_INSTDIR=$(DESTDIR)/usr/sbin # Installation directory of ledmon application. LEDMON_INSTDIR=$(DESTDIR)/usr/sbin # Output directory for object files. OUTDIR?=$(shell pwd)/_build # Build components common to both of applications. OBJECTS=\ $(OUTDIR)/ahci.o \ $(OUTDIR)/block.o \ $(OUTDIR)/cntrl.o \ $(OUTDIR)/enclosure.o \ $(OUTDIR)/list.o \ $(OUTDIR)/raid.o \ $(OUTDIR)/scsi.o \ $(OUTDIR)/slave.o \ $(OUTDIR)/status.o \ $(OUTDIR)/sysfs.o \ $(OUTDIR)/smp.o \ $(OUTDIR)/dellssd.o \ $(OUTDIR)/utils.o # Build components of ledmon application. LEDMON_OBJECTS=\ $(OUTDIR)/ledmon.o \ $(OUTDIR)/pidfile.o \ $(OBJECTS) # Build components of ledctl application. LEDCTL_OBJECTS=\ $(OUTDIR)/ledctl.o \ $(OBJECTS) CFLAGS=-O0 -g -Wall DEFFLAGS=-D_DEBUG -D_GNU_SOURCE -D_BSD_SOURCE -DDMALLOC_DISABLE INCFLAGS=-I../config LDFLAGS=-O0 -g $(DEFFLAGS) -lsgutils2 SOURCES:=$(shell find -name "*.[cC]" -print) default: all ledmon: $(OUTDIR)/.depend $(LEDMON_OBJECTS) $(CC) $(LDFLAGS) $(LDLIBS) $(LEDMON_OBJECTS) -o $@ ledctl: $(OUTDIR)/.depend $(LEDCTL_OBJECTS) $(CC) $(LDFLAGS) $(LDLIBS) $(LEDCTL_OBJECTS) -o $@ $(OUTDIR)/%.o: %.c $(CC) $(CFLAGS) $(DEFFLAGS) $(INCFLAGS) -c $< -o $@ all: $(OUTDIR)/.depend ledmon ledctl uninstall: rm -f $(LEDMON_INSTDIR)/ledmon rm -f $(LEDCTL_INSTDIR)/ledctl install: all install -D ./ledmon $(LEDMON_INSTDIR)/ledmon install -D ./ledctl $(LEDCTL_INSTDIR)/ledctl clean: rm -rf $(OUTDIR) depend dep: $(OUTDIR)/.depend mrproper: clean rm -f ledmon ledctl $(OUTDIR)/.depend: $(SOURCES) mkdir -p $(OUTDIR) $(CC) $(CFLAGS) $(DEFFLAGS) $(INCFLAGS) -M $^ | sed 's/^[a-z,0-9]/$(subst /,\/,$(OUTDIR))\/&/' > $(OUTDIR)/.depend ifeq ($(filter install uninstall depend clean mrproper,$(MAKECMDGOALS)),) -include $(OUTDIR)/.depend endif ./ledmon-0.79/src/ibpi.h000664 001750 001750 00000006702 12245410751 015575 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _IBPI_H_INCLUDED_ #define _IBPI_H_INCLUDED_ /** * @brief IBPI pattern identifies. * * The IBPI specification lists the following pattern names: * * - NORMAL - either drive is present or missing, activity LED does not * matter. The rest of the LEDs are off. * - FAIL - a block device has failed or is missing. Failure LED is * active and the behavior is depended on implementation * of enclosure management processor. * - REBUILD(_P) - this means a RAID device is recovering or rebuilding * its data. Depending on implementation of enclosure * management processor appropriate LED is blinking or solid. * - ICA - In a Critical Array, this means a RAID device is degraded and * there's no spare device available. * - IFA - In a Failed Array, this means a RAID device is damaged and * cannot be recovered or rebuild. * - PFA - Predict Failure Analysis state means that a block device will * fail soon, so it must be replaced with working one. * - LOCATE - turns Locate LED on to identify a block device or slot. * * Additionally the following patterns has been introduced, just for the purpose * of LED control utility. * * - UNKNOWN - unknown IBPI pattern and it means do not control LEDs for * a device it is set (no LED management). * - ONESHOT_NORMAL - this state means that ledmon just started and it does not * know anything about existing patterns set, so it will off all * the LEDs just in case of any problem in the future. The state * is set, when a RAID device disappears, too. Oneshot means * as soon application applies the state it will change * to UNKNOWN. */ enum ibpi_pattern { IBPI_PATTERN_UNKNOWN = 0, IBPI_PATTERN_NONE, /* used only to initialize ibpi_prev */ IBPI_PATTERN_NORMAL, IBPI_PATTERN_ONESHOT_NORMAL, IBPI_PATTERN_DEGRADED, IBPI_PATTERN_HOTSPARE, IBPI_PATTERN_REBUILD, IBPI_PATTERN_REBUILD_P, IBPI_PATTERN_FAILED_ARRAY, IBPI_PATTERN_PFA, IBPI_PATTERN_FAILED_DRIVE, IBPI_PATTERN_LOCATE, IBPI_PATTERN_LOCATE_OFF, /* Below are SES-2 codes. Note that by default most IBPI messages are * translated into SES when needed but SES codes can be added also. */ SES_REQ_ABORT, SES_REQ_REBUILD, SES_REQ_IFA, SES_REQ_ICA, SES_REQ_CONS_CHECK, SES_REQ_HOSTSPARE, SES_REQ_RSVD_DEV, SES_REQ_OK, SES_REQ_IDENT, SES_REQ_RM, SES_REQ_INS, SES_REQ_MISSING, SES_REQ_DNR, SES_REQ_ACTIVE, SES_REQ_EN_BB, SES_REQ_EN_BA, SES_REQ_DEV_OFF, SES_REQ_FAULT }; extern const char *ibpi_str[]; #endif /* _IBPI_H_INCLUDED_ */ ./ledmon-0.79/src/raid.c000664 001750 001750 00000010524 12245410751 015561 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #if _HAVE_DMALLOC_H #include #endif #include "status.h" #include "ibpi.h" #include "utils.h" #include "list.h" #include "sysfs.h" #include "block.h" #include "raid.h" #include "slave.h" /** */ static enum raid_state _get_array_state(const char *path) { enum raid_state state = RAID_STATE_UNKNOWN; char *p = get_text(path, "md/array_state"); if (p) { if (strcmp(p, "clear") == 0) state = RAID_STATE_CLEAR; else if (strcmp(p, "inactive") == 0) state = RAID_STATE_INACTIVE; else if (strcmp(p, "suspended") == 0) state = RAID_STATE_SUSPENDED; else if (strcmp(p, "readonly") == 0) state = RAID_STATE_READONLY; else if (strcmp(p, "read-auto") == 0) state = RAID_STATE_READ_AUTO; else if (strcmp(p, "clean") == 0) state = RAID_STATE_CLEAN; else if (strcmp(p, "active") == 0) state = RAID_STATE_ACTIVE; else if (strcmp(p, "write-pending") == 0) state = RAID_STATE_WRITE_PENDING; else if (strcmp(p, "active-idle") == 0) state = RAID_STATE_ACTIVE_IDLE; free(p); } return state; } /** */ static enum raid_action _get_sync_action(const char *path) { enum raid_action action = RAID_ACTION_UNKNOWN; char *p = get_text(path, "md/sync_action"); if (p) { if (strcmp(p, "idle") == 0) action = RAID_ACTION_IDLE; else if (strcmp(p, "reshape") == 0) action = RAID_ACTION_RESHAPE; else if (strcmp(p, "frozen") == 0) action = RAID_ACTION_FROZEN; else if (strcmp(p, "resync") == 0) action = RAID_ACTION_RESYNC; else if (strcmp(p, "check") == 0) action = RAID_ACTION_CHECK; else if (strcmp(p, "recover") == 0) action = RAID_ACTION_RECOVER; else if (strcmp(p, "repair") == 0) action = RAID_ACTION_REPAIR; free(p); } return action; } /** */ static enum raid_level _get_level(const char *path) { enum raid_level result = RAID_LEVEL_UNKNOWN; char *p = get_text(path, "md/level"); if (p) { if (strcmp(p, "raid0") == 0) result = RAID_LEVEL_0; else if (strcmp(p, "raid1") == 0) result = RAID_LEVEL_1; else if (strcmp(p, "raid10") == 0) result = RAID_LEVEL_10; else if (strcmp(p, "raid4") == 0) result = RAID_LEVEL_4; else if (strcmp(p, "raid5") == 0) result = RAID_LEVEL_5; else if (strcmp(p, "raid6") == 0) result = RAID_LEVEL_6; else if (strcmp(p, "linear") == 0) result = RAID_LEVEL_LINEAR; else if (strcmp(p, "faulty") == 0) result = RAID_LEVEL_FAULTY; free(p); } return result; } /** */ struct raid_device *raid_device_init(const char *path, unsigned int device_num, enum device_type type) { struct raid_device *device = NULL; enum raid_state state; const char *debug_dev; state = _get_array_state(path); if (state > RAID_STATE_CLEAR) { device = malloc(sizeof(struct raid_device)); if (device) { device->sysfs_path = strdup(path); device->device_num = device_num; device->sync_action = _get_sync_action(path); device->array_state = state; device->level = _get_level(path); device->slave_list = NULL; device->degraded = get_int(path, -1, "md/degraded"); device->raid_disks = get_int(path, 0, "md/raid_disks"); device->type = type; debug_dev = strrchr(path, '/'); debug_dev = debug_dev ? debug_dev + 1 : path; log_debug("(%s) path: %s, level=%d, state=%d, " \ "degraded=%d, disks=%d, type=%d", __func__, debug_dev, device->level, state, device->degraded, device->raid_disks, type); } } return device; } /** */ void raid_device_fini(struct raid_device *device) { if (device) { if (device->sysfs_path) free(device->sysfs_path); /* free(device); */ } } ./ledmon-0.79/src/smp.c000664 001750 001750 00000041275 12245410751 015450 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2011-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if _HAVE_DMALLOC_H #include #endif #include "ibpi.h" #include "status.h" #include "list.h" #include "block.h" #include "cntrl.h" #include "scsi.h" #include "enclosure.h" #include "sysfs.h" #include "utils.h" #include "smp.h" #define GPIO_TX_GP1 0x01 struct gpio_tx_register_byte { unsigned char activity:3; unsigned char locate:2; unsigned char error:3; } __attribute__ ((__packed__)); struct gpio_tx_register_byte gpio_tx_table[4]; #define INIT_IBPI(act, loc, err) \ { .error = err, \ .locate = loc, \ .activity = act \ } static const struct gpio_rx_table { struct gpio_tx_register_byte pattern; int support_mask; } ibpi2sgpio[] = { [IBPI_PATTERN_UNKNOWN] = { INIT_IBPI(0,0,0), 1 }, /* OK */ [IBPI_PATTERN_ONESHOT_NORMAL] = { INIT_IBPI(0,0,0), 1 }, /* OK */ [IBPI_PATTERN_NORMAL] = { INIT_IBPI(0,0,0), 1 }, /* OK */ [IBPI_PATTERN_DEGRADED] = { INIT_IBPI(0,0,0), 0 }, /* NO */ [IBPI_PATTERN_REBUILD] = { INIT_IBPI(0,1,1), 1 }, /* OK */ [IBPI_PATTERN_REBUILD_P] = { INIT_IBPI(0,0,0), 0 }, /* NO */ [IBPI_PATTERN_FAILED_ARRAY] = { INIT_IBPI(0,0,0), 0 }, /* NO */ [IBPI_PATTERN_HOTSPARE] = { INIT_IBPI(0,0,0), 0 }, /* NO */ [IBPI_PATTERN_PFA] = { INIT_IBPI(0,0,0), 0 }, /* NO */ [IBPI_PATTERN_FAILED_DRIVE] = { INIT_IBPI(0,0,1), 1 }, /* OK */ [IBPI_PATTERN_LOCATE] = { INIT_IBPI(0,1,0), 1 }, /* OK */ [IBPI_PATTERN_LOCATE_OFF] = { INIT_IBPI(0,0,0), 1 } /* OK */ }; struct smp_read_response_frame_header { uint8_t frame_type; /* =0x41 */ uint8_t function; /* =0x02 for read, 0x82 for write */ uint8_t function_result; uint8_t reserved; uint32_t read_data[0]; /* variable length of data */ /* uint32_t crc; */ } __attribute__ ((__packed__)); struct smp_write_response_frame { uint8_t frame_type; /* =0x41 */ uint8_t function; /* =0x02 for read, 0x82 for write */ uint8_t function_result; uint8_t reserved; uint32_t crc; } __attribute__ ((__packed__)); struct smp_read_request_frame { uint8_t frame_type; /* =0x40 */ uint8_t function; /* =0x02 for read, 0x82 for write */ uint8_t register_type; uint8_t register_index; uint8_t register_count; uint8_t reserved[3]; uint32_t crc; } __attribute__ ((__packed__)); struct smp_write_request_frame_header { uint8_t frame_type; /* =0x40 */ uint8_t function; /* =0x02 for read, 0x82 for write */ uint8_t register_type; uint8_t register_index; uint8_t register_count; uint8_t reserved[3]; uint32_t data[0]; /* variable length of data */ /* uint32_t crc; */ } __attribute__ ((__packed__)); struct sgpio_cfg_0_frame { uint8_t reserved; uint8_t reserved1:4; uint8_t version:4; uint8_t gp_register_count:4; uint8_t cfg_register_count:3; uint8_t enable:1; uint8_t supported_drive_cnt; } __attribute__ ((__packed__)); struct sgpio_cfg_1_frame { uint8_t reserved; uint8_t blink_gen_a:4; uint8_t blink_gen_b:4; uint8_t forced_act_off:4; uint8_t max_act_on:4; uint8_t stretch_act_off:4; uint8_t stretch_act_on:4; } __attribute__ ((__packed__)); /** * to_sas_gpio_gp_bit - given the gpio frame data find the byte/bit position of 'od' * @od: od bit to find * @data: incoming bitstream (from frame) * @index: requested data register index (from frame) * @count: total number of registers in the bitstream (from frame) * @bit: bit position of 'od' in the returned byte * * returns NULL if 'od' is not in 'data' * * From SFF-8485 v0.7: * "In GPIO_TX[1], bit 0 of byte 3 contains the first bit (i.e., OD0.0) * and bit 7 of byte 0 contains the 32nd bit (i.e., OD10.1). * * In GPIO_TX[2], bit 0 of byte 3 contains the 33rd bit (i.e., OD10.2) * and bit 7 of byte 0 contains the 64th bit (i.e., OD21.0)." * * The general-purpose (raw-bitstream) RX registers have the same layout * although 'od' is renamed 'id' for 'input data'. * * SFF-8489 defines the behavior of the LEDs in response to the 'od' values. */ static unsigned char *to_sas_gpio_gp_bit(unsigned int od, unsigned char *data, unsigned char index, unsigned char count, unsigned char *bit) { unsigned int reg; unsigned char byte; /* gp registers start at index 1 */ if (index == 0) return NULL; index--; /* make index 0-based */ if (od < index * 32) return NULL; od -= index * 32; reg = od >> 5; if (reg >= count) return NULL; od &= (1 << 5) - 1; byte = 3 - (od >> 3); *bit = od & ((1 << 3) - 1); return &data[reg * 4 + byte]; } int try_test_sas_gpio_gp_bit(unsigned int od, unsigned char *data, unsigned char index, unsigned char count) { unsigned char *byte; unsigned char bit; byte = to_sas_gpio_gp_bit(od, data, index, count, &bit); if (!byte) return -1; return (*byte >> bit) & 1; } int try_set_sas_gpio_gp_bit(unsigned int od, unsigned char *data, unsigned char index, unsigned char count) { unsigned char *byte; unsigned char bit; byte = to_sas_gpio_gp_bit(od, data, index, count, &bit); if (!byte) return 0; *byte |= 1 << bit; return 1; } int try_clear_sas_gpio_gp_bit(unsigned int od, unsigned char *data, unsigned char index, unsigned char count) { unsigned char *byte; unsigned char bit; byte = to_sas_gpio_gp_bit(od, data, index, count, &bit); if (!byte) return 0; *byte &= ~(1 << bit); return 1; } /** * set_raw_pattern - turn a tx register into a tx_gp bitstream * * takes @dev_idx (phy index) and a @pattern (error, locate, activity) * tuple and modifies the bitstream in @data accordingly */ int set_raw_pattern(unsigned int dev_idx, unsigned char *data, const struct gpio_tx_register_byte *pattern) { int od_offset = dev_idx * 3; int rc = 0; if (pattern->activity) rc += try_set_sas_gpio_gp_bit(od_offset + 0, data, GPIO_TX_GP1, 1); else rc += try_clear_sas_gpio_gp_bit(od_offset + 0, data, GPIO_TX_GP1, 1); if (pattern->locate) rc += try_set_sas_gpio_gp_bit(od_offset + 1, data, GPIO_TX_GP1, 1); else rc += try_clear_sas_gpio_gp_bit(od_offset + 1, data, GPIO_TX_GP1, 1); if (pattern->error) rc += try_set_sas_gpio_gp_bit(od_offset + 2, data, GPIO_TX_GP1, 1); else rc += try_clear_sas_gpio_gp_bit(od_offset + 2, data, GPIO_TX_GP1, 1); return rc == 3; } /** * @brief open device for smp protocol */ static int _open_smp_device(const char *filename) { char buf[PATH_MAX]; FILE *df; int hba_fd; int dmaj, dmin; snprintf(buf, sizeof(buf), "%s/dev", filename); df = fopen(buf, "r"); if (!df) return -1; if (fgets(buf, sizeof(buf), df) < 0) { fclose(df); return -1; } if (sscanf(buf, "%d:%d", &dmaj, &dmin) != 2) { fclose(df); return -1; } fclose(df); snprintf(buf, sizeof(buf), "/var/tmp/led.%d.%d.%d", dmaj, dmin, getpid()); if (mknod(buf, S_IFCHR | S_IRUSR | S_IWUSR, makedev(dmaj, dmin)) < 0) return -1; hba_fd = open(buf, O_RDWR); unlink(buf); if (hba_fd < 0) return -1; return hba_fd; } /** * @brief close smp device */ static int _close_smp_device(int fd) { return close(fd); } /* smp constants */ #define SMP_FRAME_TYPE_REQ 0x40 #define SMP_FRAME_TYPE_RESP 0x41 #define SMP_FUNC_GPIO_READ 0x02 #define SMP_FUNC_GPIO_WRITE 0x82 #define SMP_FRAME_CRC_LEN sizeof(uint32_t) #define SMP_DATA_CHUNK_SIZE sizeof(uint32_t) /* gpio constants */ /* gpio register types */ #define GPIO_REG_TYPE_CFG 0x00 #define GPIO_REG_TYPE_RX 0x01 #define GPIO_REG_TYPE_RX_GP 0x02 #define GPIO_REG_TYPE_TX 0x03 #define GPIO_REG_TYPE_TX_GP 0x04 /* gpio register indexes */ #define GPIO_REG_IND_CFG_0 0x00 #define GPIO_REG_IND_CFG_1 0x01 #define GPIO_REG_IND_RX_0 0x00 #define GPIO_REG_IND_RX_1 0x01 #define GPIO_REG_IND_TX_0 0x00 #define GPIO_REG_IND_TX_1 0x01 #define SG_RESPONSE_TIMEOUT (5 * 1000) /* 1000 as miliseconds multiplier */ #define SCSI_MAX_CDB_LENGTH 0x10 #define GPIO_STATUS_OK 0x00 #define GPIO_STATUS_FAILURE 0x80 /** @brief use sg protocol in order to send data directly to hba driver */ static int _send_smp_frame(int hba, void *data, size_t data_size, void *response, size_t *response_size) { struct sg_io_v4 sg_frame; uint8_t request_buf[SCSI_MAX_CDB_LENGTH]; int response_status = 0; /* wrap the frame into sg structure */ memset(&sg_frame, 0, sizeof(sg_frame)); sg_frame.guard = 'Q'; sg_frame.protocol = BSG_PROTOCOL_SCSI; sg_frame.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT; sg_frame.request_len = sizeof(request_buf); sg_frame.request = (uintptr_t) request_buf; sg_frame.dout_xfer_len = data_size; sg_frame.dout_xferp = (uintptr_t) data; sg_frame.din_xfer_len = *response_size; sg_frame.din_xferp = (uintptr_t) response; sg_frame.timeout = SG_RESPONSE_TIMEOUT; /* send ioctl */ if (ioctl(hba, SG_IO, &sg_frame) < 0) return -1; /* return status */ if (sg_frame.driver_status) response_status = sg_frame.driver_status; else if (sg_frame.transport_status) response_status = sg_frame.transport_status; else if (sg_frame.device_status) response_status = sg_frame.device_status; *response_size = sg_frame.din_xfer_len - sg_frame.din_resid; return response_status; } /* 1024 bytes for data, 4 for crc */ #define MAX_SMP_FRAME_DATA 1024 #define MAX_SMP_FRAME_LEN (sizeof(struct smp_write_request_frame_header) + \ MAX_SMP_FRAME_DATA + SMP_FRAME_CRC_LEN) /** @brief prepare full smp frame ready to send to hba @note len is a number of 32bit words */ static int _start_smp_write_gpio(int hba, struct smp_write_request_frame_header *header, void *data, size_t len) { uint8_t buf[MAX_SMP_FRAME_LEN]; struct smp_write_response_frame response; size_t response_size = sizeof(response); int status; memset(&response, 0, sizeof(response)); /* create full frame */ if (len * SMP_DATA_CHUNK_SIZE > MAX_SMP_FRAME_DATA) __set_errno_and_return(EINVAL); memset(buf, 0, sizeof(buf)); memcpy(buf, header, sizeof(*header)); memcpy(buf + sizeof(*header), data, len * SMP_DATA_CHUNK_SIZE); status = _send_smp_frame(hba, buf, sizeof(*header) + len * SMP_DATA_CHUNK_SIZE + SMP_FRAME_CRC_LEN, &response, &response_size); /* if frame is somehow malformed return failure */ if (status != GPIO_STATUS_OK || response.frame_type != SMP_FRAME_TYPE_RESP || response.function != header->function) { return GPIO_STATUS_FAILURE; } return response.function_result; } /** @brief prepare smp frame header */ static int _smp_write_gpio(const char *path, int smp_reg_type, int smp_reg_index, int smp_reg_count, void *data, size_t len) { struct smp_write_request_frame_header header; int status; header.frame_type = SMP_FRAME_TYPE_REQ; header.function = SMP_FUNC_GPIO_WRITE; header.register_type = smp_reg_type; header.register_index = smp_reg_index; header.register_count = smp_reg_count; memset(header.reserved, 0, sizeof(header.reserved)); int fd = _open_smp_device(path); status = _start_smp_write_gpio(fd, &header, data, len); _close_smp_device(fd); return status; } #define BLINK_GEN_1HZ 8 #define BLINK_GEN_2HZ 4 #define BLINK_GEN_4HZ 2 #define DEFAULT_FORCED_ACTIVITY_OFF 1 #define DEFAULT_MAXIMUM_ACTIVITY_ON 2 #define DEFAULT_STRETCH_ACTIVITY_OFF 0 #define DEFAULT_STRETCH_ACTIVITY_ON 0 #define DEFAULT_ISCI_SUPPORTED_DEVS 4 /* one data chunk is 32bit long */ #define SMP_DATA_CHUNKS 1 struct gpio_tx_register_byte *get_bdev_ibpi_buffer(struct block_device *bdevice) { if (bdevice && bdevice->host) return bdevice->host->ibpi_state_buffer; return NULL; } /** */ int scsi_smp_fill_buffer(struct block_device *device, enum ibpi_pattern ibpi) { const char *sysfs_path = device->cntrl_path; struct gpio_tx_register_byte *gpio_tx; if (sysfs_path == NULL) __set_errno_and_return(EINVAL); if ((ibpi < IBPI_PATTERN_NORMAL) || (ibpi > IBPI_PATTERN_LOCATE_OFF)) __set_errno_and_return(ERANGE); if (!device->cntrl) { log_debug("No ctrl dev for '%s'", strstr(sysfs_path, "host")); __set_errno_and_return(ENODEV); } if (device->cntrl->cntrl_type != CNTRL_TYPE_SCSI) { log_debug("No SCSI ctrl dev '%s'", strstr(sysfs_path, "host")); __set_errno_and_return(EINVAL); } if (!device->cntrl->isci_present) { log_debug("No ISCI ctrl for '%s'", strstr(sysfs_path, "host")); __set_errno_and_return(ENODEV); } if (!device->host) { log_debug("No host for '%s'", strstr(sysfs_path, "host")); __set_errno_and_return(ENODEV); } if (!ibpi2sgpio[ibpi].support_mask) { char *c = strrchr(device->sysfs_path, '/'); if (c++) { log_debug ("pattern %s not supported for device (/dev/%s)", ibpi_str[ibpi], c); fprintf(stderr, "%s(): pattern %s not supported for device (/dev/%s)\n", __func__, ibpi_str[ibpi], c); } else { log_debug("pattern %s not supported for device %s", ibpi_str[ibpi], device->sysfs_path); fprintf(stderr, "%s(): pattern %s not supported for device\n\t(%s)\n", __func__, ibpi_str[ibpi], device->sysfs_path); } __set_errno_and_return(ENOTSUP); } gpio_tx = get_bdev_ibpi_buffer(device); if (!gpio_tx) { log_debug("%s(): no IBPI buffer. Skipping.", __func__); __set_errno_and_return(ENODEV); } /* update bit stream for this device */ set_raw_pattern(device->phy_index, &device->host->bitstream[0], &ibpi2sgpio[ibpi].pattern); /* write only if state has changed */ if (ibpi != device->ibpi_prev) device->host->flush = 1; return 1; } int scsi_smp_write_buffer(struct block_device *device) { const char *sysfs_path = device->cntrl_path; if (sysfs_path == NULL) __set_errno_and_return(EINVAL); if (!device->host) __set_errno_and_return(ENODEV); if (device->host->flush) { device->host->flush = 0; /* re-transmit the bitstream */ return _smp_write_gpio(sysfs_path, GPIO_REG_TYPE_TX_GP, GPIO_TX_GP1, 1, &device->host->bitstream[0], SMP_DATA_CHUNKS); } else return 1; } /** */ void init_smp(const char *path, struct cntrl_device *device) { struct _host_type *hosts; int i; if (!device) return; if (!device->isci_present) return; for (hosts = device->hosts; hosts; hosts = hosts->next) { /* already initialized */ if (hosts->ibpi_state_buffer) continue; hosts->ibpi_state_buffer = calloc(DEFAULT_ISCI_SUPPORTED_DEVS, sizeof(struct gpio_tx_register_byte)); if (!hosts->ibpi_state_buffer) continue; for (i = 0; i < DEFAULT_ISCI_SUPPORTED_DEVS; i++) set_raw_pattern(i, &hosts->bitstream[0], &ibpi2sgpio [IBPI_PATTERN_ONESHOT_NORMAL].pattern); hosts->flush = 0; } } /** */ int isci_cntrl_init_smp(const char *path, struct cntrl_device *cntrl) { char *path2 = NULL; char *c; int host, port = 0; struct dirent *de; DIR *d; if (!cntrl) return port; if (!cntrl->isci_present) return port; /* Other case - just init controller. */ if (path && strstr(path, "port-")) { path2 = strdup(path); if (!path2) return port; c = strstr(path2, "port-"); if (!c) { /* Should not happen. */ log_debug("%s() missing 'port' in path '%s'", __func__, path2); free(path2); return port; } c = strchr(c, '/'); if (!c) { free(path2); return port; } *c = 0; /* And now path2 has only up to 'port-...' string. */ /* this should open port-XX:X directory * FIXME: for enclosure it may be port-XX:Y:Z but it's a second * occurrence * * We may try this on the missing device. * */ d = opendir(path2); if (!d) { log_debug("%s() Error dir open '%s', path ='%s'", __func__, path2, path); free(path2); return port; } while ((de = readdir(d))) { if ((strcmp(de->d_name, ".") == 0) || (strcmp(de->d_name, "..")) == 0) { continue; } if (strncmp(de->d_name, "phy-", strlen("phy-")) == 0) { /* Need link called "phy-XX:Y * Y is real phy we need. * This can also be found * in phy_identifier file */ sscanf(de->d_name, "phy-%d:%d", &host, &port); break; } } closedir(d); free(path2); } init_smp(path, cntrl); return port; } ./ledmon-0.79/src/dellssd.c000664 001750 001750 00000015241 12245410751 016275 0ustar00ldorauldorau000000 000000 /* * Dell Backplane LED control * Copyright (C) 2011, Dell Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #include #include #include #include #include #include #if _HAVE_DMALLOC_H #include #endif #include "status.h" #include "ibpi.h" #include "utils.h" #include "list.h" #include "sysfs.h" #include "block.h" #include "slave.h" #include "raid.h" #include "cntrl.h" #include "scsi.h" #include "smp.h" #include "ahci.h" #include "dellssd.h" #define BP_PRESENT (1L << 0) #define BP_ONLINE (1L << 1) #define BP_HOTSPARE (1L << 2) #define BP_IDENTIFY (1L << 3) #define BP_REBUILDING (1L << 4) #define BP_FAULT (1L << 5) #define BP_PREDICT (1L << 6) #define BP_CRITICALARRAY (1L << 9) #define BP_FAILEDARRAY (1L << 10) static const unsigned int ibpi2ssd[] = { [IBPI_PATTERN_UNKNOWN] = BP_ONLINE, [IBPI_PATTERN_ONESHOT_NORMAL] = BP_ONLINE, [IBPI_PATTERN_NORMAL] = BP_ONLINE, [IBPI_PATTERN_DEGRADED] = BP_CRITICALARRAY|BP_ONLINE, [IBPI_PATTERN_REBUILD] = BP_REBUILDING|BP_ONLINE, [IBPI_PATTERN_REBUILD_P] = BP_REBUILDING|BP_ONLINE, [IBPI_PATTERN_FAILED_ARRAY] = BP_FAILEDARRAY|BP_ONLINE, [IBPI_PATTERN_HOTSPARE] = BP_HOTSPARE|BP_ONLINE, [IBPI_PATTERN_PFA] = BP_PREDICT|BP_ONLINE, [IBPI_PATTERN_FAILED_DRIVE] = BP_FAULT|BP_ONLINE, [IBPI_PATTERN_LOCATE] = BP_IDENTIFY|BP_ONLINE, [IBPI_PATTERN_LOCATE_OFF] = BP_ONLINE }; #define BMC_SA 0x20 #define DELL_OEM_NETFN 0x30 #define DELL_OEM_STORAGE_CMD 0xD5 #define DELL_OEM_STORAGE_GETDRVMAP 0x07 #define DELL_OEM_STORAGE_SETDRVSTATUS 0x04 static int ipmi_open() { int fd; fd = open("/dev/ipmi0", O_RDWR); if (fd >= 0) return fd; fd = open("/dev/ipmidev/0", O_RDWR); if (fd >= 0) return fd; fd = open("/dev/ipmidev0", O_RDWR); if (fd >= 0) return fd; fd = open("/dev/bmc", O_RDWR); if (fd >= 0) return fd; return -1; } static int ipmicmd(int sa, int lun, int netfn, int cmd, int datalen, void *data, int resplen, int *rlen, void *resp) { static int msgid; struct ipmi_system_interface_addr saddr; struct ipmi_ipmb_addr iaddr; struct ipmi_addr raddr; struct ipmi_req req; struct ipmi_recv rcv; fd_set rfd; int fd, rc; uint8_t tresp[resplen + 1]; fd = ipmi_open(); if (fd < 0) return -1; memset(&req, 0, sizeof(req)); memset(&rcv, 0, sizeof(rcv)); if (sa == BMC_SA) { memset(&saddr, 0, sizeof(saddr)); saddr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; saddr.channel = IPMI_BMC_CHANNEL; saddr.lun = 0; req.addr = (void *)&saddr; req.addr_len = sizeof(saddr); } else { memset(&iaddr, 0, sizeof(iaddr)); iaddr.addr_type = IPMI_IPMB_ADDR_TYPE; iaddr.channel = 0; iaddr.slave_addr = sa; iaddr.lun = lun; req.addr = (void *)&iaddr; req.addr_len = sizeof(iaddr); } /* Issue command */ req.msgid = ++msgid; req.msg.netfn = netfn; req.msg.cmd = cmd; req.msg.data_len = datalen; req.msg.data = data; rc = ioctl(fd, IPMICTL_SEND_COMMAND, (void *)&req); if (rc != 0) { perror("send"); goto end; } /* Wait for Response */ FD_ZERO(&rfd); FD_SET(fd, &rfd); rc = select(fd + 1, &rfd, NULL, NULL, NULL); if (rc < 0) { perror("select"); goto end; } /* Get response */ rcv.msg.data = tresp; rcv.msg.data_len = resplen + 1; rcv.addr = (void *)&raddr; rcv.addr_len = sizeof(raddr); rc = ioctl(fd, IPMICTL_RECEIVE_MSG_TRUNC, (void *)&rcv); if (rc != 0 && errno == EMSGSIZE) printf("too short..\n"); if (rc != 0 && errno != EMSGSIZE) { fprintf(stderr, "%d ", errno); perror("recv"); goto end; } if (rcv.msg.data[0]) printf("IPMI Error: %.2x\n", rcv.msg.data[0]); rc = 0; *rlen = rcv.msg.data_len - 1; memcpy(resp, rcv.msg.data + 1, *rlen); end: close(fd); return rc; } static int ipmi_setled(int b, int d, int f, int state) { uint8_t data[20], rdata[20]; int rc, rlen, bay, slot, devfn; bay = 0xFF; slot = 0xFF; devfn = (((d & 0x1F) << 3) | (f & 0x7)); /* Get mapping of BDF to bay:slot */ memset(data, 0, sizeof(data)); memset(rdata, 0, sizeof(rdata)); data[0] = 0x01; /* get */ data[1] = DELL_OEM_STORAGE_GETDRVMAP; /* storage map */ data[2] = 0x06; /* length lsb */ data[3] = 0x00; /* length msb */ data[4] = 0x00; /* offset lsb */ data[5] = 0x00; /* offset msb */ data[6] = b; /* bus */ data[7] = devfn; /* devfn */ rc = ipmicmd(BMC_SA, 0, DELL_OEM_NETFN, DELL_OEM_STORAGE_CMD, 8, data, 20, &rlen, rdata); if (!rc) { bay = rdata[7]; slot = rdata[8]; } if (bay == 0xFF || slot == 0xFF) return 0; /* Set Bay:Slot to Mask */ memset(data, 0, sizeof(data)); memset(rdata, 0, sizeof(rdata)); data[0] = 0x00; /* set */ data[1] = DELL_OEM_STORAGE_SETDRVSTATUS; /* set drive status */ data[2] = 0x0e; /* length lsb */ data[3] = 0x00; /* length msb */ data[4] = 0x00; /* offset lsb */ data[5] = 0x00; /* offset msb */ data[6] = 0x0e; /* length lsb */ data[7] = 0x00; /* length msb */ data[8] = bay; /* bayid */ data[9] = slot; /* slotid */ data[10] = state & 0xff; /* state LSB */ data[11] = state >> 8; /* state MSB */ rc = ipmicmd(BMC_SA, 0, DELL_OEM_NETFN, DELL_OEM_STORAGE_CMD, 20, data, 20, &rlen, rdata); return 0; } char *dellssd_get_path(const char *path, const char *cntrl_path) { return strdup(cntrl_path); } int dellssd_write(struct block_device *device, enum ibpi_pattern ibpi) { int mask, bus, dev, fun; char *t; /* write only if state has changed */ if (ibpi == device->ibpi_prev) return 1; if ((ibpi < IBPI_PATTERN_NORMAL) || (ibpi > IBPI_PATTERN_LOCATE_OFF)) __set_errno_and_return(ERANGE); mask = ibpi2ssd[ibpi]; t = strrchr(device->cntrl_path, '/'); if (t != NULL) { /* Extract PCI bus:device.function */ if (sscanf(t + 1, "%*x:%x:%x.%x", &bus, &dev, &fun) == 3) ipmi_setled(bus, dev, fun, mask); } return 0; } ./ledmon-0.79/src/utils.h000664 001750 001750 00000026070 12245410751 016012 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _UTILS_H_INCLUDED_ #define _UTILS_H_INCLUDED_ /** * Maximum number of bytes in temporary buffer. It is used for local variables. */ #define BUFFER_MAX 128 /** * Maximum number of bytes in write buffer. It is used for local variables when * function needs to write a sysfs attribute. */ #define WRITE_BUFFER_SIZE 1024 /** * Verbose level for messages out from application. */ enum verbose_level { VERB_QUIET = 0, VERB_ERROR, VERB_WARN, VERB_INFO, VERB_DEBUG, VERB_ALL }; /** * Global variable indicates current level of verbosity. */ extern enum verbose_level verbose; /** * This structure describes a device identifier. It consists of major and minor * attributes of device. */ struct device_id { int major, minor; }; /** * This global variable holds the name of binary file an application has been * executed from. */ extern char *progname; /** * @brief Reads integer value from a text file. * * This function assumes that the only text in a file is requested number to * read. In case of an error while reading from file the function will return * a value stored in defval argument. * * @param[in] path location of a file to be read. * @param[in] defval default value to return in case the file * does not exist. * @param[in] name name of a file to be read. * * @return Value read from a file if successful, otherwise a value stored in * defval argument. */ int get_int(const char *path, int defval, const char *name); /** * @brief Reads 64-bit unsigned integer from a text file. * * This function assumes that the only text in a file is requested number to * read. In case of an error while reading from file the function will return * a value stored in defval argument. * * @param[in] path Path where a file is located. * @param[in] defval Default value to be returned in case of error. * @param[in] name Name of a file to be read. * * @return Value read from a file if successful, otherwise a value stored in * defval argument. */ uint64_t get_uint64(const char *path, uint64_t defval, const char *name); /** * @brief Reads a content of a text file. * * This function reads a text file and return pointer to memory where the text * has been stored. The memory allocated by the function must be release as soon * as application does not require the content. Use free() function to give * allocated memory back to the system. * * @param[in] path Path where a file is located. * @param[in] name Name of a file to be read. * * @return Pointer to memory buffer if successful, otherwise NULL pointer. */ char *get_text(const char *path, const char *name); /** * @brief Writes a text to file. * * This function writes a text to a file and return the number of bytes written. * If the file does not exist or the value is incorrect the function returns -1 * and errno has additional error information. * * @param[in] path Location of file to write. * @param[in] name Name of file to write. * @param[in] value Text to write to a file. * * @return The number of bytes written or -1 if an error occurred. */ int put_text(const char *path, const char *name, const char *value); /** * @brief Writes an integer value to a text file. * * This function writes an integer value to a text file. If the file does not * exist or the value is out of range the function returns -1 and errno variable * has additional error information. * * @param[in] path Location of file to write. * @param[in] name Name of file to write. * @param[in] value Integer value to write to a file. * * @return The number of bytes written or -1 if an error occurred. */ int put_int(const char *path, const char *name, int value); /** * @brief Scans directory for files. * * This function reads a directory specified in path argument and puts found * file on a list. The function puts a canonical paths on the list, however it * does not resolve any symbolic link. * * @param[in] path Path to directory to read. * * @return List containing content of the given directory. Each element on the * list is canonical path. */ void *scan_dir(const char *path); /** * @brief Writes a text to file. * * This function writes content of text buffer to file. If the file does not * exist or a content is invalid the function returns -1 and errno variable has * additional error information. * * @param[in] path Location and name of file to write to. * @param[in] buf Pointer to text buffer to write to a file. * * @return Number of bytes written if successful, otherwise -1 for an error. */ int buf_write(const char *path, const char *buf); /** * @brief Reads the content of a text file. * * The function reads the content of a text file and stores it to memory buffer * allocated. The function determines a size of the file and allocates required * amount of memory. User is required to free allocated memory as soon as * application does not require the content. Use free() function to give memory * back to the system pool. The function replaces last end-of-line character * with '\0' character. * * @param[in] path Path and name of file to read. * * @return Pointer to memory block if successful, otherwise NULL pointer. */ char *buf_read(const char *path); /** * @brief Gets major and minor of device. * * The function reads from text buffer the major and minor of block device. * * @param[in] buf Pointer to text buffer to interpret. * @param[out] did Placeholder where major and minor will be * stored. * * @return The function does not return a value. */ void get_id(const char *buf, struct device_id *did); /** * @brief Open a local log file. * * The function opens a file to write log messages. If the given file does not * exist the new one will be created. If the file already exist the file will be * opened in append mode and the pointer will be set at the end of a file. * * @param[in] path Location and name of a log file. * * @return The function returns 0 if successful, otherwise -1 and errno variable * has additional error information. */ int log_open(const char *path); /** * @brief Close a local log file. * * The function closes a local log file. If the file has not been opened the * function does nothing. * * @return The function does not return a value. */ void log_close(void); /** * @brief Logs an error message. * * The function logs a message at error level of verbosity. * * @param[in] buf Buffer containing format of a message. * @param[in] ... Additional arguments according to format of * a message. * * @return The function does not return a value. */ void log_error(const char *buf, ...); /** * @brief Logs a debug message. * * The function logs a message at debug level of verbosity. * * @param[in] buf Buffer containing format of a message. * @param[in] ... Additional arguments according to format of * a message. * * @return The function does not return a value. */ void log_debug(const char *buf, ...); /** * @brief Logs a warning message. * * The function logs a message at warning level of verbosity. * * @param[in] buf Buffer containing format of a message. * @param[in] ... Additional arguments according to format of * a message. * * @return The function does not return a value. */ void log_warning(const char *buf, ...); /** * @brief Logs a information message. * * The function logs a message at info level of verbosity. * * @param[in] buf Buffer containing format of a message. * @param[in] ... Additional arguments according to format of * a message. * * @return The function does not return a value. */ void log_info(const char *buf, ...); /** */ void set_invocation_name(char *invocation_name); /** * @brief Copies a text buffer. * * This function copies source text buffer to destination buffer. The function * always return a null-terminated buffer even if src does not fit in dest. * * @param[out] dest Pointer to destination buffer. * @param[in] src Pointer to source buffer. * @param[in] size Capacity of destination buffer in bytes. * * @return Pointer to destination buffer even if function failed. */ char *str_cpy(char *dest, const char *src, size_t size); /** * @brief Duplicates a text buffer. * * This function duplicates a text buffer. It allocates a new memory block and * copies the content of source buffer to new location. If pointer to source * buffer is NULL the function will return NULL, too. The caller is required to * free allocated memory as soon as content is not needed. * * @param[in] src Source buffer to duplicate the content. * * @return Pointer to allocated memory block if successful, otherwise NULL. */ char *str_dup(const char *src); /** * @brief Concatenates text buffers. * * This function appends source buffer to destination buffer. It is similar to * strncat() standard C function except it always returns null-terminated * buffer. Second difference is that function calculates itself the amount * of free space in destination buffer. If source does not fit in dest * then as many bytes are copied as can be fit in destination buffer minus 1 * for null-character. Otherwise the source is copied to destination * including null-character. * * @param[in,out] dest Pointer to destination buffer. * @param[in] src Pointer to source buffer. * @param[in] size Capacity of destination buffer. * * @return Pointer to destination buffer even if function failed. */ char *str_cat(char *dest, const char *src, size_t size); /** */ char *truncate_path_component_rev(const char *path, int index); /** */ char *get_path_component_rev(const char *path, int index); /** * @brief Extracts the 'hostX' part from path. */ char *get_path_hostN(const char *path); #endif /* _UTILS_H_INCLUDED_ */ ./ledmon-0.79/src/ses.h000664 001750 001750 00000005302 12245410751 015437 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ /* Size of buffer for SES-2 Messages. */ #define SES_ALLOC_BUFF 4096 #define ENCL_CFG_DIAG_STATUS 0x01 #define ENCL_CTRL_DIAG_STATUS 0x02 #define ENCL_CTRL_DIAG_CFG 0x02 #define ENCL_EL_DESCR_STATUS 0x07 #define ENCL_ADDITIONAL_EL_STATUS 0x0a #define SCSI_PROTOCOL_SAS 6 #define SES_DEVICE_SLOT 0x01 #define SES_ARRAY_DEVICE_SLOT 0x17 static inline void _clr_msg(unsigned char *u) { u[0] = u[1] = u[2] = u[3] = 0; } static inline void _set_abrt(unsigned char *u) { u[1] |= (1 << 0); } static inline void _set_rebuild(unsigned char *u) { u[1] |= (1 << 1); } static inline void _set_ifa(unsigned char *u) { u[1] |= (1 << 2); } static inline void _set_ica(unsigned char *u) { u[1] |= (1 << 3); } static inline void _set_cons_check(unsigned char *u) { u[1] |= (1 << 4); } static inline void _set_hspare(unsigned char *u) { u[1] |= (1 << 5); } static inline void _set_rsvd_dev(unsigned char *u) { u[1] |= (1 << 6); } static inline void _set_ok(unsigned char *u) { u[1] |= (1 << 7); } static inline void _set_ident(unsigned char *u) { u[2] |= (1 << 1); } static inline void _clr_ident(unsigned char *u) { u[2] &= ~(1 << 1); } static inline void _set_rm(unsigned char *u) { u[2] |= (1 << 2); } static inline void _set_ins(unsigned char *u) { u[2] |= (1 << 3); } static inline void _set_miss(unsigned char *u) { u[2] |= (1 << 4); } static inline void _set_dnr(unsigned char *u) { u[2] |= (1 << 6); } static inline void _set_actv(unsigned char *u) { u[2] |= (1 << 7); } static inline void _set_enbb(unsigned char *u) { u[3] |= (1 << 2); } static inline void _set_enba(unsigned char *u) { u[3] |= (1 << 3); } static inline void _set_off(unsigned char *u) { u[3] |= (1 << 4); } static inline void _set_fault(unsigned char *u) { u[3] |= (1 << 5); } struct ses_pages { unsigned char *page1; int page1_len; unsigned char *page2; int page2_len; unsigned char *page10; int page10_len; unsigned char *page1_types; int page1_types_len; int components; }; ./ledmon-0.79/src/sysfs.c000664 001750 001750 00000043221 12245410751 016011 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #include #include #include #if _HAVE_DMALLOC_H #include #endif #include "status.h" #include "ibpi.h" #include "list.h" #include "utils.h" #include "sysfs.h" #include "block.h" #include "slave.h" #include "raid.h" #include "enclosure.h" #include "cntrl.h" /** */ #define SYSFS_CLASS_BLOCK "/sys/block" #define SYSFS_CLASS_ENCLOSURE "/sys/class/enclosure" #define SYSFS_PCI_DEVICES "/sys/bus/pci/devices" /** * This is internal variable global to sysfs module only. The variable holds * pointer to list of block devices registered in the system. Use sysfs_init() * function to initialize the variable. Use sysfs_scan() function to populate * the list. Use sysfs_reset() function to delete the content of the list. * Use sysfs_fini() function to delete the content of the list and release * memory allocated for the list. */ static void *sysfs_block_list = NULL; /** * This is internal variable global to sysfs module only. The variable holds * pointer to list of RAID volumes registered in the system. Use sysfs_init() * function to initialize the variable. Use sysfs_scan() function to populate * the list. Use sysfs_reset() function to delete the content of the list. * Use sysfs_fini() function to delete the content of the list and release * memory allocated for the list. */ static void *volum_list = NULL; /** * This is internal variable global to sysfs module only. The variable holds * pointer to list of storage controller devices registered in the system and * supported by Intel(R) Enclosure LEDs Control Utility. Use sysfs_init() * function to initialize the variable. Use sysfs_scan() function to populate * the list. Use sysfs_reset() function to delete the content of the list. * Use sysfs_fini() function to delete the content of the list and release * memory allocated for the list. */ static void *cntrl_list = NULL; /** * This is internal variable global to sysfs module only. The variable holds * pointer to list of slave devices registered in the system. Use sysfs_init() * function to initialize the variable. Use sysfs_scan() function to populate * the list. Use sysfs_reset() function to delete the content of the list. * Use sysfs_fini() function to delete the content of the list and release * memory allocated for the list. */ static void *slave_list = NULL; /** * This is internal variable global to sysfs module only. The variable holds * pointer to list of RAID containers registered in the system. Use sysfs_init() * function to initialize the variable. Use sysfs_scan() function to populate * the list. Use sysfs_reset() function to delete the content of the list. * Use sysfs_fini() function to delete the content of the list and release * memory allocated for the list. */ static void *cntnr_list = NULL; /** * This is internal variable global to sysfs module only. The variable holds the * pointer to list of enclosures registered in the system. */ static void *enclo_list = NULL; /** * @brief Determine device type. * * This is internal function of sysfs module. The function determines a type of * RAID device either it is VOLUME or CONTAINER device. The information required * if read from 'metadata_version' attribute from sysfs. External and native * RAID devices are reported as volumes with no distinction between both types. * * @param[in] path Path to RAID device in sysfs tree. * * @return Type of RAID device if successful, otherwise DEVICE_TYPE_UNKNOWN. */ static enum device_type _get_device_type(const char *path) { enum device_type result = DEVICE_TYPE_UNKNOWN; char *p = get_text(path, "md/metadata_version"); if (p != NULL) { if (strlen(p) > 0) { if (strncmp(p, "external:", 9) == 0) { if (p[9] == '/') result = DEVICE_TYPE_VOLUME; else result = DEVICE_TYPE_CONTAINER; } else { result = DEVICE_TYPE_VOLUME; } } free(p); } return result; } /** * @brief Gets device major and minor. * * This is internal function of sysfs module. The function retrieves major and * minor of device from sysfs attribute. Each block device has 'dev' attribute * where major and minor separated by colon are stored. * * @param[in] path Path to block device in sysfs tree. * @param[in] d_id Placeholder where major and minor of device * will be stored. If this argument is NULL the * behavior of function is unspecified. * * @return The function does not return a value. */ static void _get_id(const char *path, struct device_id *d_id) { char temp[PATH_MAX]; str_cpy(temp, path, PATH_MAX); str_cat(temp, "/dev", PATH_MAX); get_id(temp, d_id); } /** * @brief Adds slave device to RAID volume. * * This is internal function of sysfs module. The function puts slave device on * list of slave devices of RAID volume. The memory is allocated and structure * fields populated. RAID device is link to slave device. * * @param[in] path Path to 'md' directory of RAID device in sysfs * tree. * @param[in] raid Pointer to RAID device structure corresponding * to 'path' argument. * * @return The function does not return a value. */ static void _slave_vol_add(const char *path, struct raid_device *raid) { struct slave_device *device; char *t = rindex(path, '/'); if (strncmp(t + 1, "dev-", 4) == 0) { device = slave_device_init(path, sysfs_block_list); if (device) { device->raid = raid; list_put(slave_list, device, sizeof(struct slave_device)); free(device); } } } /** * @brief Matches two slave devices. * * This is internal function of sysfs module. The function compares two slave * devices together. Slave device is identical to other slave device if both if * both devices are associated with the same block device. * * @param[in] s1 Pointer to slave device to compare with. * @param[in] s2 Pointer to slave to compare to. * * @return 1 if slave devices matches, otherwise the function returns 0. */ static int _match(struct slave_device *s1, struct slave_device *s2) { return (s1->block == s2->block); } /** * @brief Checks for duplicate entries on list of slave devices. * * This is internal function of sysfs module. The functions checks if the given * slave device is already on list with slave devices. This function is used by * _slave_cnt_add() function to avoid duplicate entries. * * @param[in] slave Pointer to slave device structure to check. * * @return 1 the given device is on the list, otherwise the function returns 0. */ static int _is_duplicate(struct slave_device *slave) { return (list_first_that(slave_list, _match, slave) != NULL); } /** */ static void _slave_cnt_add(const char *path, struct raid_device *raid) { struct slave_device *device; char *t = rindex(path, '/'); if (strncmp(t + 1, "dev-", 4) == 0) { device = slave_device_init(path, sysfs_block_list); if (device) { if (!_is_duplicate(device)) { device->raid = raid; list_put(slave_list, device, sizeof(struct slave_device)); } else { slave_device_fini(device); } free(device); } } } /** */ static void _link_volum(struct raid_device *device) { char temp[PATH_MAX]; str_cpy(temp, device->sysfs_path, PATH_MAX); str_cat(temp, "/md", PATH_MAX); void *dir = scan_dir(temp); if (dir) { list_for_each_parm(dir, _slave_vol_add, device); list_fini(dir); } } /** */ static void _link_cntnr(struct raid_device *device) { char temp[PATH_MAX]; str_cpy(temp, device->sysfs_path, PATH_MAX); str_cat(temp, "/md", PATH_MAX); void *dir = scan_dir(temp); if (dir) { list_for_each_parm(dir, _slave_cnt_add, device); list_fini(dir); } } /** */ static void _block_add(const char *path) { void *device = block_device_init(cntrl_list, path); if (device) { list_put(sysfs_block_list, device, sizeof(struct block_device)); free(device); } } /** */ static void _volum_add(const char *path, unsigned int device_num) { void *device = raid_device_init(path, device_num, DEVICE_TYPE_VOLUME); if (device) { list_put(volum_list, device, sizeof(struct raid_device)); free(device); } } /** */ static void _cntnr_add(const char *path, unsigned int device_num) { void *device = raid_device_init(path, device_num, DEVICE_TYPE_CONTAINER); if (device) { list_put(cntnr_list, device, sizeof(struct raid_device)); free(device); } } /** */ static void _raid_add(const char *path) { struct device_id device_id; _get_id(path, &device_id); if (device_id.major == 9) { switch (_get_device_type(path)) { case DEVICE_TYPE_VOLUME: _volum_add(path, device_id.minor); break; case DEVICE_TYPE_CONTAINER: _cntnr_add(path, device_id.minor); break; case DEVICE_TYPE_UNKNOWN: break; } } } /** */ static void _cntrl_add(const char *path) { void *device = cntrl_device_init(path); if (device) { list_put(cntrl_list, device, sizeof(struct cntrl_device)); free(device); } } /** */ static void _enclo_add(const char *path) { void *device = enclosure_device_init(path); if (device) { list_put(enclo_list, device, sizeof(struct enclosure_device)); free(device); } } /** */ static void _check_raid(const char *path) { char *t = strrchr(path, '/'); if (strncmp(t + 1, "md", 2) == 0) _raid_add(path); } /** */ static void _check_cntrl(const char *path) { char link[PATH_MAX]; if (realpath(path, link) != NULL) _cntrl_add(link); } /** */ static void _check_enclo(const char *path) { char link[PATH_MAX]; if (realpath(path, link) != NULL) _enclo_add(link); } /** */ static status_t _scan_block(void) { void *dir = scan_dir(SYSFS_CLASS_BLOCK); if (dir) { list_for_each(dir, _block_add); list_fini(dir); } return STATUS_SUCCESS; } /** */ static status_t _scan_raid(void) { void *dir = scan_dir(SYSFS_CLASS_BLOCK); if (dir) { list_for_each(dir, _check_raid); list_fini(dir); } return STATUS_SUCCESS; } /** */ static status_t _scan_cntrl(void) { void *dir = scan_dir(SYSFS_PCI_DEVICES); if (dir) { list_for_each(dir, _check_cntrl); list_fini(dir); } return STATUS_SUCCESS; } /** */ static status_t _scan_slave(void) { list_for_each(volum_list, _link_volum); list_for_each(cntnr_list, _link_cntnr); return STATUS_SUCCESS; } /** */ static status_t _scan_enclo(void) { void *dir = scan_dir(SYSFS_CLASS_ENCLOSURE); if (dir) { list_for_each(dir, _check_enclo); list_fini(dir); } return STATUS_SUCCESS; } /** */ static int _is_failed_array(struct raid_device *raid) { if (raid->degraded > 0) { switch (raid->level) { case RAID_LEVEL_1: case RAID_LEVEL_10: return (raid->degraded == raid->raid_disks); case RAID_LEVEL_4: case RAID_LEVEL_5: return (raid->degraded > 1); case RAID_LEVEL_6: return (raid->degraded > 2); case RAID_LEVEL_LINEAR: case RAID_LEVEL_UNKNOWN: case RAID_LEVEL_0: break; case RAID_LEVEL_FAULTY: return 1; } } return -1; } /** */ static void _set_block_state(struct block_device *block, enum ibpi_pattern ibpi) { char *debug_dev = strrchr(block->sysfs_path, '/'); debug_dev = debug_dev ? debug_dev + 1 : block->sysfs_path; log_debug("(%s): device: %s, state: %s", __func__, debug_dev, ibpi_str[ibpi]); if (block->ibpi < ibpi) block->ibpi = ibpi; } /** */ static void _set_array_state(struct raid_device *raid, struct block_device *block) { switch (raid->sync_action) { case RAID_ACTION_UNKNOWN: case RAID_ACTION_IDLE: case RAID_ACTION_FROZEN: _set_block_state(block, IBPI_PATTERN_NORMAL); break; case RAID_ACTION_CHECK: case RAID_ACTION_RESHAPE: _set_block_state(block, IBPI_PATTERN_REBUILD_P); break; case RAID_ACTION_RESYNC: case RAID_ACTION_REPAIR: _set_block_state(block, IBPI_PATTERN_REBUILD); break; case RAID_ACTION_RECOVER: break; } } /** */ static void _determine(struct slave_device *device) { if ((device-> state & (SLAVE_STATE_BLOCKED | SLAVE_STATE_WRITE_MOSTLY)) != 0) { _set_block_state(device->block, IBPI_PATTERN_NORMAL); } else if ((device->state & SLAVE_STATE_FAULTY) != 0) { _set_block_state(device->block, IBPI_PATTERN_FAILED_DRIVE); } else if ((device->state & SLAVE_STATE_SPARE) != 0) { if (_is_failed_array(device->raid) == 0) _set_block_state(device->block, IBPI_PATTERN_REBUILD); else _set_block_state(device->block, IBPI_PATTERN_HOTSPARE); } else if ((device->state & SLAVE_STATE_IN_SYNC) != 0) { switch (_is_failed_array(device->raid)) { case 0: _set_block_state(device->block, IBPI_PATTERN_DEGRADED); break; case 1: _set_block_state(device->block, IBPI_PATTERN_FAILED_ARRAY); break; } _set_array_state(device->raid, device->block); } } /** */ status_t sysfs_init(void) { sysfs_block_list = NULL; volum_list = NULL; cntrl_list = NULL; slave_list = NULL; cntnr_list = NULL; enclo_list = NULL; if (list_init(&sysfs_block_list) != STATUS_SUCCESS) return STATUS_BLOCK_LIST_ERROR; if (list_init(&volum_list) != STATUS_SUCCESS) return STATUS_VOLUM_LIST_ERROR; if (list_init(&cntrl_list) != STATUS_SUCCESS) return STATUS_CNTRL_LIST_ERROR; if (list_init(&slave_list) != STATUS_SUCCESS) return STATUS_SLAVE_LIST_ERROR; if (list_init(&cntnr_list) != STATUS_SUCCESS) return STATUS_CNTNR_LIST_ERROR; if (list_init(&enclo_list) != STATUS_SUCCESS) return STATUS_ENCLO_LIST_ERROR; return STATUS_SUCCESS; } /** */ void sysfs_fini(void) { if (sysfs_block_list) { list_for_each(sysfs_block_list, block_device_fini); list_fini(sysfs_block_list); } if (volum_list) { list_for_each(volum_list, raid_device_fini); list_fini(volum_list); } if (cntrl_list) { list_for_each(cntrl_list, cntrl_device_fini); list_fini(cntrl_list); } if (slave_list) { list_for_each(slave_list, slave_device_fini); list_fini(slave_list); } if (cntnr_list) { list_for_each(cntnr_list, raid_device_fini); list_fini(cntnr_list); } if (enclo_list) { list_for_each(enclo_list, enclosure_device_fini); list_fini(enclo_list); } } /** */ status_t sysfs_reset(void) { if (sysfs_block_list) { list_for_each(sysfs_block_list, block_device_fini); list_delete(sysfs_block_list); } if (volum_list) { list_for_each(volum_list, raid_device_fini); list_delete(volum_list); } if (cntrl_list) { list_for_each(cntrl_list, cntrl_device_fini); list_delete(cntrl_list); } if (slave_list) { list_for_each(slave_list, slave_device_fini); list_delete(slave_list); } if (cntnr_list) { list_for_each(cntnr_list, raid_device_fini); list_delete(cntnr_list); } if (enclo_list) { list_for_each(enclo_list, enclosure_device_fini); list_delete(enclo_list); } return STATUS_SUCCESS; } /** */ status_t sysfs_scan(void) { if (enclo_list == NULL) return STATUS_NULL_POINTER; if (_scan_enclo() != STATUS_SUCCESS) return STATUS_ENCLO_LIST_ERROR; if (cntrl_list == NULL) return STATUS_NULL_POINTER; if (_scan_cntrl() != STATUS_SUCCESS) return STATUS_CNTRL_LIST_ERROR; if (sysfs_block_list == NULL) return STATUS_NULL_POINTER; if (_scan_block() != STATUS_SUCCESS) return STATUS_BLOCK_LIST_ERROR; if (volum_list == NULL) return STATUS_NULL_POINTER; if (_scan_raid() != STATUS_SUCCESS) return STATUS_VOLUM_LIST_ERROR; if (slave_list == NULL) return STATUS_NULL_POINTER; if (_scan_slave() != STATUS_SUCCESS) return STATUS_SLAVE_LIST_ERROR; if (enclo_list == NULL) return STATUS_NULL_POINTER; return list_for_each(slave_list, _determine); } /* * The function reutrns list of enclosure devices attached to SAS/SCSI storage * controller(s). */ void *sysfs_get_enclosure_devices(void) { return list_head(enclo_list); } /* * The function returns list of controller devices present in the system. */ void *sysfs_get_cntrl_devices(void) { return list_head(cntrl_list); } /* * The function executes action() function for each block device on the list. * See sysfs.h for details. */ status_t __sysfs_block_device_for_each(action_t action, void *parm) { return __list_for_each(sysfs_block_list, action, parm); } /* * The function is looking for block device according to criteria defined by * 'test' function. See sysfs.h for details. */ void *__sysfs_block_device_first_that(test_t test, void *parm) { return __list_first_that(sysfs_block_list, test, parm); } /** */ static int _enclo_match(struct enclosure_device *device, const char *path) { return (device->sysfs_path != NULL) && (strncmp(device->sysfs_path, path, strlen(path)) == 0); } /* * The function checks if the given storage controller has enclosure device(s) * attached. */ int sysfs_enclosure_attached_to_cntrl(const char *path) { return (list_first_that(enclo_list, _enclo_match, path) != NULL); } /* * This function checks if driver type is isci. */ int sysfs_isci_driver(const char *path) { char buf[PATH_MAX]; char *link; int found = 0; str_cpy(buf, path, PATH_MAX); str_cat(buf, "/driver", PATH_MAX); link = realpath(buf, NULL); if (link && strstr(link, "/isci")) found = 1; free(link); return found; } ./ledmon-0.79/src/status.c000664 001750 001750 00000003675 12245410751 016176 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include "status.h" /** */ #define _S_CODE(__code) \ case __code: return #__code /** */ char *strstatus(status_t scode) { switch (scode) { _S_CODE(STATUS_SUCCESS); _S_CODE(STATUS_BUFFER_OVERFLOW); _S_CODE(STATUS_INVALID_NODE); _S_CODE(STATUS_OUT_OF_MEMORY); _S_CODE(STATUS_DATA_ERROR); _S_CODE(STATUS_INVALID_PATH); _S_CODE(STATUS_INVALID_SUBOPTION); _S_CODE(STATUS_NULL_POINTER); _S_CODE(STATUS_SIZE_ERROR); _S_CODE(STATUS_FILE_OPEN_ERROR); _S_CODE(STATUS_FILE_READ_ERROR); _S_CODE(STATUS_FILE_WRITE_ERROR); _S_CODE(STATUS_FILE_LOCK_ERROR); _S_CODE(STATUS_SYSFS_PATH_ERROR); _S_CODE(STATUS_SYSFS_INIT_ERROR); _S_CODE(STATUS_SYSFS_SCAN_ERROR); _S_CODE(STATUS_SYSFS_RESET_ERROR); _S_CODE(STATUS_DIR_OPEN_ERROR); _S_CODE(STATUS_LIST_INIT_ERROR); _S_CODE(STATUS_BLOCK_LIST_ERROR); _S_CODE(STATUS_VOLUM_LIST_ERROR); _S_CODE(STATUS_CNTRL_LIST_ERROR); _S_CODE(STATUS_SLAVE_LIST_ERROR); _S_CODE(STATUS_CNTNR_LIST_ERROR); _S_CODE(STATUS_LEDMON_INIT); _S_CODE(STATUS_LEDMON_RUNNING); _S_CODE(STATUS_ONEXIT_ERROR); _S_CODE(STATUS_INVALID_CONTROLLER); _S_CODE(STATUS_CMDLINE_ERROR); _S_CODE(STATUS_ENCLO_LIST_ERROR); default: return "???"; } } ./ledmon-0.79/src/sysfs.h000664 001750 001750 00000006327 12245410751 016024 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _SYSFS_H_INCLUDED_ #define _SYSFS_H_INCLUDED_ /** * @brief Initializes sysfs module. * * This function initializes sysfs module. The function allocates memory for * internal lists and initializes the lists. Application must call this function * before any sysfs module function. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. */ status_t sysfs_init(void); /** * @brief Finalizes sysfs module. * * This function releases memory allocated for sysfs module and its components. * Application must call this function at the very end of execution. * * @return The function does not return a value. */ void sysfs_fini(void); /** * @brief Resets the content of internal lists. * * This function releases memory allocated for elements of internal lists. The * function does not release memory allocated for the lists itself. Use * sysfs_fini() function instead to release memory allocated for internal lists. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. */ status_t sysfs_reset(void); /** * @brief Scans sysfs tree and populates internal lists. * * This function scans sysfs tree for storage controllers, block devices, RAID * devices, container devices, slave devices and enclosure devices registered * in the system. Only supported block and controller devices are put on a list. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. */ status_t sysfs_scan(void); /** * The function returns list of enclosure devices attached to SAS/SCSI storage * controller(s). */ void *sysfs_get_enclosure_devices(void); /** * The function returns list of controller devices present in the system. */ void *sysfs_get_cntrl_devices(void); /** * The function checks if the given storage controller is attached to enclosure * device(s). */ int sysfs_enclosure_attached_to_cntrl(const char *path); /** */ status_t sysfs_block_device_scan(void **block_list); /** */ #define sysfs_block_device_for_each(__action) \ __sysfs_block_device_for_each((action_t)(__action), (void *)0) /** */ status_t __sysfs_block_device_for_each(action_t action, void *parm); /** */ #define sysfs_block_device_first_that(__test, __parm) \ __sysfs_block_device_first_that((test_t)(__test), (void *)(__parm)) /** */ void *__sysfs_block_device_first_that(test_t action, void *parm); /* * This function checks if driver type is isci. */ int sysfs_isci_driver(const char *path); #endif /* _SYSFS_H_INCLUDED_ */ ./ledmon-0.79/src/status.h000664 001750 001750 00000003526 12245410751 016176 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _STATUS_H_INCLUDED_ #define _STATUS_H_INCLUDED_ /** */ typedef int status_t; /** */ enum status_code { STATUS_SUCCESS = 0, STATUS_BUFFER_OVERFLOW, STATUS_NULL_POINTER, STATUS_OUT_OF_MEMORY, STATUS_OUT_OF_RANGE, STATUS_INVALID_NODE, STATUS_DATA_ERROR, STATUS_IBPI_DETERMINE_ERROR, STATUS_INVALID_PATH, STATUS_INVALID_SUBOPTION, STATUS_INVALID_STATE, STATUS_SIZE_ERROR, STATUS_FILE_OPEN_ERROR, STATUS_FILE_READ_ERROR, STATUS_FILE_WRITE_ERROR, STATUS_FILE_LOCK_ERROR, STATUS_DIR_OPEN_ERROR, STATUS_SYSFS_PATH_ERROR, STATUS_SYSFS_INIT_ERROR, STATUS_SYSFS_SCAN_ERROR, STATUS_SYSFS_RESET_ERROR, STATUS_LIST_EMPTY, STATUS_LIST_INIT_ERROR, STATUS_BLOCK_LIST_ERROR, STATUS_VOLUM_LIST_ERROR, STATUS_CNTRL_LIST_ERROR, STATUS_SLAVE_LIST_ERROR, STATUS_CNTNR_LIST_ERROR, STATUS_INVALID_FORMAT, STATUS_LEDMON_INIT, STATUS_LEDMON_RUNNING, STATUS_ONEXIT_ERROR, STATUS_INVALID_CONTROLLER, STATUS_NOT_SUPPORTED, STATUS_STAT_ERROR, STATUS_CMDLINE_ERROR, STATUS_NOT_A_PRIVILEGED_USER, STATUS_ENCLO_LIST_ERROR }; /** */ char *strstatus(status_t scode); #endif /* _STATUS_H_INCLUDED_ */ ./ledmon-0.79/src/dellssd.h000664 001750 001750 00000001554 12245410751 016304 0ustar00ldorauldorau000000 000000 /* * Dell Backplane LED control * Copyright (C) 2011, Dell Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ int dellssd_write(struct block_device *device, enum ibpi_pattern ibpi); char *dellssd_get_path(const char *path, const char *cntrl_path); ./ledmon-0.79/src/scsi.c000664 001750 001750 00000043377 12245410751 015617 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #include #include #include #include #include #include #if _HAVE_DMALLOC_H #include #endif #include #include #include "ibpi.h" #include "status.h" #include "list.h" #include "block.h" #include "cntrl.h" #include "scsi.h" #include "enclosure.h" #include "sysfs.h" #include "utils.h" #include "ses.h" static int debug = 0; static void print_page10(struct ses_pages *); static void send_diag_slot(struct ses_pages *, int, const unsigned char *, int); static int ses_set_message(enum ibpi_pattern, unsigned char *); static inline int get_page2(int fd, unsigned char *p2, int *len) { int ret; /* Get Enclosure Status */ ret = sg_ll_receive_diag(fd, 1, ENCL_CTRL_DIAG_STATUS, p2, SES_ALLOC_BUFF, 0, debug); *len = (p2[2] << 8) + p2[3] + 4; return ret; } static inline int get_page1(int fd, unsigned char *p1, int *len) { int ret; /* Get Enclosure Status */ ret = sg_ll_receive_diag(fd, 1, ENCL_CFG_DIAG_STATUS, p1, SES_ALLOC_BUFF, 0, debug); *len = (p1[2] << 8) + p1[3] + 4; return ret; } static inline int get_page10(int fd, unsigned char *p10, int *len) { int ret; /* Get Enclosure Status */ ret = sg_ll_receive_diag(fd, 1, ENCL_ADDITIONAL_EL_STATUS, p10, SES_ALLOC_BUFF, 0, debug); *len = (p10[2] << 8) + p10[3] + 4; return ret; } static int process_page1(struct ses_pages *sp) { int num_encl; /* number of subenclosures */ unsigned char *ed; /* Enclosure Descriptor */ int len = 0; int sum_headers = 0; /* Number of Type descriptor headers */ int i = 0; int components = 0; /* Total number of components in enclosure */ /* How many enclosures is in the main enclosure? */ num_encl = sp->page1[1] + 1; sp->page1_len = (sp->page1[2] << 8) + sp->page1[3] + 4; /* Go to Enclosure Descriptor */ ed = sp->page1 + 8; for (i = 0; i < num_encl; i++, ed += len) { if (ed + 3 > sp->page1 + sp->page1_len) { log_debug ("SES: Error, response pare 1 truncated at %d\n", i); return 1; } sum_headers += ed[2]; len = ed[3] + 4; if (len < 40) { log_debug("SES: Response too short for page 1\n"); continue; } } sp->page1_types = ed; sp->page1_types_len = sum_headers; /* ed is on type descr header */ for (i = 0; i < sum_headers; i++, ed += 4) { if (ed > sp->page1 + sp->page1_len) { log_debug("SES: Response page 1 truncated at %d\n", i); return 1; } if (ed[0] == SES_DEVICE_SLOT || ed[0] == SES_ARRAY_DEVICE_SLOT) components += ed[1]; } sp->components = components; return 0; } static struct ses_pages *ses_init(void) { struct ses_pages *sp; sp = calloc(1, sizeof(*sp)); if (!sp) return NULL; sp->page1 = calloc(SES_ALLOC_BUFF, sizeof(*sp->page1)); if (!sp->page1) goto sp1; sp->page2 = calloc(SES_ALLOC_BUFF, sizeof(*sp->page2)); if (!sp->page2) goto sp2; sp->page10 = calloc(SES_ALLOC_BUFF, sizeof(*sp->page10)); if (!sp->page10) goto sp10; return sp; sp10: free(sp->page2); sp2: free(sp->page1); sp1: free(sp); return NULL; } static void ses_free(struct ses_pages *sp) { if (!sp) return; if (sp->page1) free(sp->page1); if (sp->page2) free(sp->page2); if (sp->page10) free(sp->page10); memset(sp, 0, sizeof(*sp)); free(sp); } static void dump_p10(unsigned char *p) { int i; printf("----------------------------------------------\n"); for (i = 0; i < 8; i++, p += 16) { printf("%p: %02x %02x %02x %02x %02x %02x %02x " \ "%02x %02x %02x %02x %02x %02x %02x %02x %02x\n", p, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); } } /* Enclosure is already opened. */ static int is_addr_in_encl(int fd, const char *addr, int *idx) { /* Get page10 and read address. If it fits, return 1. */ struct ses_pages *sp = ses_init(); unsigned char *add_desc = NULL, *types = NULL; unsigned char *ap = NULL, *addr_p = NULL; int i, j, len = 0; char addr_cmp[32]; if (!sp) return 0; /* Start processing */ /* Read configuration. */ if (get_page1(fd, sp->page1, &sp->page1_len)) goto err; if (process_page1(sp)) goto err; /* Get Enclosure Status - needed? */ if (get_page2(fd, sp->page2, &sp->page2_len)) goto err; /* Additional Element Status */ if (get_page10(fd, sp->page10, &sp->page10_len)) goto err; if (debug) print_page10(sp); /* Check Page10 for address. Extract index. */ ap = add_desc = sp->page10 + 8; types = sp->page1_types; for (i = 0; i < sp->page1_types_len; i++, types += 4) { if (types[0] == SES_DEVICE_SLOT || types[0] == SES_ARRAY_DEVICE_SLOT) { for (j = 0; j < types[1]; j++, ap += len) { if (debug) dump_p10(ap); /* Get Additional Element Status Descriptor */ /* length (x-1) */ len = ap[1] + 2; if ((ap[0] & 0xf) != SCSI_PROTOCOL_SAS) continue; /* need SAS PROTO */ /* It is a SAS protocol, go on */ if ((ap[0] & 0x10)) /* Check EIP */ addr_p = ap + 8; else addr_p = ap + 4; /* Process only PHY 0 descriptor. */ sprintf(addr_cmp, "%02x%02x%02x%02x%02x%02x%02x%02x", addr_p[12], addr_p[13], addr_p[14], addr_p[15], addr_p[16], addr_p[17], addr_p[18], addr_p[19]); if (!strcmp(addr + 2, addr_cmp)) { if (idx) *idx = ap[3]; ses_free(sp); return 1; } } } } err: ses_free(sp); return 0; } static char *_get_dev_sg(const char *path) { char *ret = NULL; DIR *d; struct dirent *de; /* /sys/class/enclosure/X/device/scsi_generic path is expected. */ d = opendir(path); if (!d) return NULL; while ((de = readdir(d))) { if ((strcmp(de->d_name, ".") == 0) || (strcmp(de->d_name, "..")) == 0) { continue; } break; /* */ } if (de) { ret = calloc(strlen("/dev/") + strlen(de->d_name) + 1, sizeof(*ret)); if (ret) { strcpy(ret, "/dev/"); strcat(ret, de->d_name); } } closedir(d); return ret; } /* SYSFS_ENCL//SCSI_GEN - path to sgX directory for enclosure. */ #define SYSFS_ENCL "/sys/class/enclosure" #define SCSI_GEN "device/scsi_generic" static int get_enclosure_fd(struct block_device *device, char *addr) { DIR *d = NULL; struct dirent *de = NULL; char *p = NULL; int len; char *dev = NULL; int fd = -1; /* There may be device path already filled */ if (device->encl_index != -1 && device->encl_dev[0] != 0) { fd = open(device->encl_dev, O_RDWR); if (fd == -1) { /* Enclosure device may change during extensive disks * hotplugging */ device->encl_index = -1; memset(device->encl_dev, 0, sizeof(device->encl_dev)); if (!addr) { /* If there is no SAS address then there is * no way to find enclosure device that this * drive 'was' in. */ return fd; } } else { return fd; } } if (!addr) { /* when there is no enclosure device and device index * then address should not be NULL */ return -1; } d = opendir(SYSFS_ENCL); if (!d) return -1; while ((de = readdir(d))) { if ((strcmp(de->d_name, ".") == 0) || (strcmp(de->d_name, "..")) == 0) { continue; } /* */ len = strlen(SCSI_GEN) + strlen(SYSFS_ENCL) + strlen(de->d_name) + 4; p = calloc(len, sizeof(*p)); if (!p) break; strcpy(p, SYSFS_ENCL); strcat(p, "/"); strcat(p, de->d_name); strcat(p, "/"); strcat(p, SCSI_GEN); dev = _get_dev_sg(p); free(p); if (!dev) break; fd = open(dev, O_RDWR); if (fd == -1) { free(dev); break; } if (is_addr_in_encl(fd, addr, &device->encl_index)) { strncpy(device->encl_dev, dev, PATH_MAX); free(dev); break; /* HIT */ } else { close(fd); fd = -1; } free(dev); } closedir(d); return fd; } static void put_enclosure_fd(int fd) { close(fd); } static void ses_send_to_idx(int fd, int idx, enum ibpi_pattern ibpi) { unsigned char msg[4] = { 0 }; struct ses_pages *sp; sp = ses_init(); if (!sp) return; /* Start processing */ /* Read configuration. */ if (get_page1(fd, sp->page1, &sp->page1_len)) goto err; if (process_page1(sp)) goto err; /* Get Enclosure Status */ if (get_page2(fd, sp->page2, &sp->page2_len)) goto err; if (ses_set_message(ibpi, msg)) goto err; /* unknown message */ send_diag_slot(sp, fd, msg, idx); err: ses_free(sp); return; } static void print_page10(struct ses_pages *sp) { unsigned char *ai = sp->page10 + 8; int i = 0, len = 0, eip = 0; unsigned char *sas = NULL; while (ai < sp->page10 + sp->page10_len) { printf("%s()[%d]: Inv: %d, EIP: %d, Proto: 0x%04x\n", __func__, i++, ((ai[0] & 0x80) >> 7), ((ai[0] & 0x10) >> 4), ai[0] & 0xf); printf("\tDescriptor len (x-1): %d\n", ai[1] + 1); eip = ai[0] && 0x10; if (eip) printf("\tElement Index: %d\n", ai[3]); len = ai[1] + 2; if ((ai[0] & 0xf) == SCSI_PROTOCOL_SAS) { if (eip) sas = ai + 4; else sas = ai + 2; printf("\tProtocol SAS:\n"); printf("\tNumber of phy descriptors: %d\n", sas[0]); printf("\tNot all phys: %d, descriptor type: 0x%1x\n", (sas[1] & 1), ((sas[1] & 0xc0) >> 6)); if (eip) { printf("\tDevice slot number: %d\n", sas[3]); sas += 2; } sas += 2; printf("\tDevice type: 0x%01x\n", ((sas[0] & 0x70) >> 4)); printf("\tSMP Initiator Port: 0x%01x\n", ((sas[2] & 2) >> 1)); printf("\tSTP Initiator Port: 0x%01x\n", ((sas[2] & 4) >> 2)); printf("\tSSP Initiator Port: 0x%01x\n", ((sas[2] & 8) >> 3)); printf("\tSATA DEVICE: 0x%01x\n", (sas[3] & 1)); printf("\tSMP Target Port: 0x%01x\n", ((sas[3] & 2) >> 1)); printf("\tSTP Target Port: 0x%01x\n", ((sas[3] & 4) >> 2)); printf("\tSSP Target Port: 0x%01x\n", ((sas[3] & 8) >> 3)); printf("\tSATA Port Selector: 0x%01x\n", ((sas[3] & 0X80) >> 7)); printf ("\tAttached SAS Address: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", sas[4], sas[5], sas[6], sas[7], sas[8], sas[9], sas[10], sas[11]); printf ("\tSAS Address: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", sas[12], sas[13], sas[14], sas[15], sas[16], sas[17], sas[18], sas[19]); printf("\tPHY Identified: 0x%01x\n", sas[20]); } else printf("\tProtocol not SAS: 0x%02x, skipping\n", (ai[0] & 0xf)); /* */ ai += len; } return; } static void send_diag_slot(struct ses_pages *sp, int fd, const unsigned char *info, int idx) { unsigned char *types = sp->page1_types; unsigned char *desc = sp->page2 + 8; /* Move do descriptors */ int i, j; int slot = 0; memset(desc, 0, sp->page2_len - 8); for (i = 0; i < sp->page1_types_len; i++, types += 4) { if (types[0] == 0x01 || types[0] == 0x17) { desc += 4; /* At first, skip overall header. */ for (j = 0; j < types[1]; j++, desc += 4) { if (slot++ == idx) { memcpy(desc, info, 4); /* set select */ desc[0] |= 0x80; /* keep PRDFAIL */ desc[0] |= 0x40; /* clear reserved flags */ desc[0] &= 0xf0; break; } } } } if (sg_ll_send_diag(fd, 0, 1, 0, 0, 0, 0, sp->page2, sp->page2_len, 0, debug)) { return; } return; } int ses_set_message(enum ibpi_pattern ibpi, unsigned char *u) { switch (ibpi) { case IBPI_PATTERN_UNKNOWN: case IBPI_PATTERN_ONESHOT_NORMAL: case IBPI_PATTERN_NORMAL: _clr_msg(u); _set_ok(u); break; case IBPI_PATTERN_FAILED_ARRAY: _set_ifa(u); break; case IBPI_PATTERN_DEGRADED: _set_ica(u); break; case IBPI_PATTERN_REBUILD: case IBPI_PATTERN_REBUILD_P: _set_rebuild(u); break; case IBPI_PATTERN_FAILED_DRIVE: _set_fault(u); break; case IBPI_PATTERN_LOCATE_OFF: _clr_ident(u); break; case IBPI_PATTERN_LOCATE: _set_ident(u); break; case IBPI_PATTERN_HOTSPARE: _set_hspare(u); break; case IBPI_PATTERN_PFA: _set_rsvd_dev(u); break; /* SES MESSAGES */ case SES_REQ_ABORT: _set_abrt(u); break; case SES_REQ_REBUILD: _set_rebuild(u); break; case SES_REQ_IFA: _set_ifa(u); break; case SES_REQ_ICA: _set_ica(u); break; case SES_REQ_CONS_CHECK: _set_cons_check(u); break; case SES_REQ_HOSTSPARE: _set_hspare(u); break; case SES_REQ_RSVD_DEV: _set_rsvd_dev(u); break; case SES_REQ_OK: _set_ok(u); break; case SES_REQ_IDENT: _set_ident(u); break; case SES_REQ_RM: _set_rm(u); break; case SES_REQ_INS: _set_ins(u); break; case SES_REQ_MISSING: _set_miss(u); break; case SES_REQ_DNR: _set_dnr(u); break; case SES_REQ_ACTIVE: _set_actv(u); break; case SES_REQ_EN_BB: _set_enbb(u); break; case SES_REQ_EN_BA: _set_enba(u); break; case SES_REQ_DEV_OFF: _set_off(u); break; case SES_REQ_FAULT: _set_fault(u); break; default: return 1; } return 0; } /* SAS_ADDR_PATH - path in sysfs where sas_address for disk can be found */ #define SAS_ADDR_PATH "/sys/class/sas_end_device/%s/" \ "device/sas_device/%s/sas_address" static char *get_drive_end_dev(const char *path) { char *s, *c, *p; c = strstr(path, "end_device"); if (!c) return NULL; s = strchr(c, '/'); if (!s) return NULL; p = calloc(s - c + 1, sizeof(*p)); if (!p) return NULL; strncpy(p, c, s - c); p[s - c] = 0; return p; } static char *get_drive_sas_addr(const char *path) { #define ADDR_LEN 64 int len = strlen(path); char *buff, *end_dev, addr[ADDR_LEN] = { 0 }; int fd; /* Make big buffer. */ buff = calloc(len * 2, sizeof(*buff)); if (!buff) return NULL; end_dev = get_drive_end_dev(path); if (!end_dev) { free(buff); return NULL; } (void)sprintf(buff, SAS_ADDR_PATH, end_dev, end_dev); fd = open(buff, O_RDONLY); if (fd == -1) { free(end_dev); free(buff); return NULL; } if (read(fd, addr, ADDR_LEN) == ADDR_LEN) { /* The value should be 19. */ free(end_dev); free(buff); close(fd); return NULL; } close(fd); len = strnlen(addr, ADDR_LEN); if (len && addr[len - 1] == '\n') addr[len - 1] = 0; else /* make sure that addr is null-terminated */ addr[len < ADDR_LEN ? len : ADDR_LEN - 1] = 0; free(end_dev); free(buff); return strdup(addr); } /** */ static int _slot_match(const char *slot_path, const char *device_path) { char temp[PATH_MAX], link[PATH_MAX]; str_cpy(temp, slot_path, PATH_MAX); str_cat(temp, "/device", PATH_MAX); if (realpath(temp, link) == NULL) return 0; return strncmp(link, device_path, strlen(link)) == 0; } /** */ static char *_slot_find(const char *enclo_path, const char *device_path) { void *dir; char *temp, *result = NULL; dir = scan_dir(enclo_path); if (dir) { temp = list_first_that(dir, _slot_match, device_path); if (temp) result = strdup(temp); list_fini(dir); } return result; } int scsi_get_enclosure(struct block_device *device) { char *addr; int fd = -1; if (!device || !device->sysfs_path) return 0; memset(device->encl_dev, 0, sizeof(device->encl_dev)); addr = get_drive_sas_addr(device->sysfs_path); if (addr == NULL) return 0; fd = get_enclosure_fd(device, addr); if (fd != -1) put_enclosure_fd(fd); if (addr) free(addr); return (fd == -1) ? 0 : 1; } /** */ int scsi_ses_write(struct block_device *device, enum ibpi_pattern ibpi) { int fd = -1; char *addr = NULL; if (!device || !device->sysfs_path) __set_errno_and_return(EINVAL); /* write only if state has changed */ if (ibpi == device->ibpi_prev) return 1; if ((ibpi < IBPI_PATTERN_NORMAL) || (ibpi > SES_REQ_FAULT)) __set_errno_and_return(ERANGE); /* Failed drive is special. Path in sysfs may be not available. * In other case re-read address. * */ if (ibpi != IBPI_PATTERN_FAILED_DRIVE) { addr = get_drive_sas_addr(device->sysfs_path); if (addr == NULL) { /* Device maybe gone during scan. */ log_warning ("Detected inconsistency. " \ "Marking device '%s' as failed.", strstr(device->sysfs_path, "host")); ibpi = IBPI_PATTERN_FAILED_DRIVE; device->ibpi = IBPI_PATTERN_FAILED_DRIVE; /* FIXME: at worst case we may lose all reference * to this drive and should remove it from list. * No API for do that now. */ } } fd = get_enclosure_fd(device, addr); if (fd != -1) { ses_send_to_idx(fd, device->encl_index, ibpi); put_enclosure_fd(fd); } else { log_warning ("Unable to send %s message to %s. Device is missing?", ibpi_str[ibpi], strstr(device->sysfs_path, "host")); } if (addr) free(addr); return 0; } /** */ char *sas_get_slot_path(const char *path, const char *ctrl_path) { char *host; char host_path[PATH_MAX] = { 0 }; size_t ctrl_path_len = strlen(ctrl_path); if (strncmp(path, ctrl_path, ctrl_path_len) != 0) return NULL; host = get_path_hostN(path); if (host) { snprintf(host_path, sizeof(host_path), "%s/%s/bsg/sas_%s", ctrl_path, host, host); free(host); } return str_dup(host_path); } /** */ static char *_get_enc_slot_path(const char *path) { struct enclosure_device *device; char *result = NULL; device = sysfs_get_enclosure_devices(); while (device) { result = _slot_find(device->sysfs_path, path); if (result != NULL) break; device = list_next(device); } return result; } /** */ char *scsi_get_slot_path(const char *path, const char *ctrl_path) { char *result = NULL; result = _get_enc_slot_path(path); if (!result) result = sas_get_slot_path(path, ctrl_path); return result; } ./ledmon-0.79/src/list.h000664 001750 001750 00000022425 12245410751 015625 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _LIST_H_INCLUDED_ #define _LIST_H_INCLUDED_ /** * This data-type represents a prototype of test function. Test function is used * by list_first_that() and list_last_that() functions as 'test' parameter. The * function should return 0 if search should continue, otherwise it should * return 1. */ typedef int (*test_t) (void *item, void *param); /** * This data-type represents a prototype of action function. Action function is * used by list_for_each() function as 'action' parameter. */ typedef void (*action_t) (void *item, void *param); /** */ #define list_for_each_parm(__list, __action, __parm) \ __list_for_each((void *)(__list), \ (action_t)(__action), (void *)(__parm)) /** */ #define list_for_each(__list, __action) \ __list_for_each((void *)(__list), (action_t)(__action), (void *)0) /** */ #define list_first_that_no_parm(__list, __test) \ __list_first_that((void *)(__list), (test_t)(__test), (void *)0) /** */ #define list_first_that(__list, __test, __parm) \ __list_first_that((void *)(__list), (test_t)(__test), (void *)(__parm)) /** * @brief Creates a list object. * * The function allocates memory for a new list object and initializes its * fields to reflect an empty state. * * @param [in,out] ptr placeholder where the pointer to the new list * will be stored. In case of an error the NULL * pointer is stored instead. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t error code. */ status_t list_init(void **ptr); /** * @brief Finalizes a list object. * * This function releases the memory allocated for a list object. The function * does not release the memory allocated by other function and stored * in elements. It only releases a placeholder where the elements are stored. * It is user responsibility to free allocated other memory before * this function is called. * * @param[in] ptr pointer to a list object. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. */ status_t list_fini(void *ptr); /** * @brief Removes an element from the list. * * This function removes an element from the list. It only detaches the element * and does not release the memory allocated for the element. To free memory * allocated for an element use list_delete() function instead. * * @param[in] ptr pointer to a list object. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. */ status_t list_remove(void *ptr); /** * @brief Deletes an element. * * This function removes and frees memory allocated for element. If element has * next element not NULL then function walks deep and frees this element, too. * To delete the specific element only use list_remove() function first. This * function does not release memory allocated by other functions i.e. strings. * It is user responsibility to free other memory allocated before this function * is called. In other way the memory leaking might be observed. */ status_t list_delete(void *ptr); /** * @brief Adds an element in front. * * This function adds an element to a list object. If the ptr is a list object * then function adds element to head of the list. If the ptr is a node object * function puts an element as previous element relatively to the given element. * * @param[in] ptr pointer to list object or to node object. * @param[in] data placeholder where the information to put on * a list is stored. * @param[in] size number of bytes stored in data parameter. * * @return Pointer to element on a list if successful, otherwise a NULL and * this means out of memory in the system. */ void *list_add(void *ptr, void *data, size_t size); /** * @brief Puts an element in back. * * This function puts an element on a list object. If the ptr is a list object * the function puts the element on tail of a list. If the ptr is a node object * the function puts the element as next element relatively to the given * element. * * @param[in] ptr pointer to list object or to node object. * @param[in] data placeholder where the information to put on * a list is stored. * @param[in] size number of bytes stored in data parameter. * * @return Pointer to element on a list if successful, otherwise a NULL and * this means out of memory in the system. */ void *list_put(void *ptr, void *data, size_t size); /** * @brief Reruns next element. * * This function returns next element relatively to the given element. * If the ptr is a list object the function returns a head of the list. * * @param[in] ptr pointer to a list object or to node object. * * @return Pointer to an element if successful. The NULL pointer means * that ptr is the last element on the list or if ptr is a list object * NULL means that there's no elements on the list. */ void *list_next(void *ptr); /** * @brief Returns previous element. * * This function returns previous element relatively to the given element. * If the ptr is a list object the function returns a tail of the list. * * @param[in] ptr pointer to a list object or to node object. * * @return Pointer to an element if successful. The NULL pointer means * that ptr is the first element on the list or if ptr is a list object * the NULL means that there's no elements on the list. */ void *list_prev(void *ptr); /** * @brief Returns head of a list. * * This function returns a head of a list. * * @param[in] ptr pointer to a list object or to node object. * * @return Pointer to an element if successful. The NULL pointer means that * there's no element on a list. */ void *list_head(void *ptr); /** * @brief Returns tail of a list. * * This function returns a tail of a list. * * @param[in] ptr pointer to a list object or to node object. * * @return Pointer to an element if successful. The NULL pointer means that * there's no element on a list. */ void *list_tail(void *ptr); /** * @brief Checks if a list is empty. * * This function checks if a list object has elements. * * @param[in] ptr pointer to a list object only. * * @return 1 if list is empty, otherwise the function returns 0. */ int list_is_empty(void *ptr); /** * @brief Walks through each element. * * This function invokes the action function for each element on a list. * Refer to action_t data-type for details about the function prototype. * * @param[in] ptr pointer to list object or node object. * @param[in] action pointer to an action function. * @param[in] parm additional parameter to pass directly to * 'action' function. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. */ status_t __list_for_each(void *ptr, action_t action, void *parm); /** * @brief Searches for an element. * * This function searches for an element on a list. The function 'test' is * called for each element on the list and if element matches the search will * stop. The function starts searching from head of the list and moves to * next element relatively. * * @param[in] ptr pointer to list object or node object. * @param[in] test pointer to an test function. * @param[in] parm additional parameter to pass directly to * 'test' function. * * @return Pointer to an element. If the function returns NULL that means there * is no such an element on a list. */ void *__list_last_that(void *ptr, test_t test, void *parm); /** * @brief Searches for an element backward. * * This function searches for an element on a list. The function 'test' is * called for each element on the list and if element matches the search will * stop. The function starts searching from tail of the list and moves to * previous element relatively. * * @param[in] ptr pointer to list object or node object. * @param[in] test pointer to an test function. * @param[in] parm additional parameter to pass directly to * 'test' function. * * @return Pointer to an element. If the function returns NULL that means there * is no such an element on a list. */ void *__list_first_that(void *ptr, test_t test, void *parm); #endif /* _LIST_H_INCLUDED_ */ ./ledmon-0.79/src/smp.h000664 001750 001750 00000005227 12245410751 015452 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2011-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _SMP_H_INCLUDED #define _SMP_H_INCLUDED /** * @brief Sends message to SES processor of an enclosure. * * This function send a message to an enclosure in order to control LEDs of * the given slot/component. It uses interface of ENCLOSURE kernel module to * control LEDs. * * @param[in] device Path to an enclosure device in sysfs. * @param[in] ibpi IBPI pattern to visualize. * * @return Number of characters written if successful or -1 in case of error * and errno is set to appropriate error code. */ int scsi_ses_write(struct block_device *device, enum ibpi_pattern ibpi); /** * @brief Write message to outbound raw byte stream buffer. * * @param[in] device Path to a smp device in sysfs. * @param[in] ibpi IBPI pattern to visualize. * * @return 1 if successful or -1 in case of error * and errno is set to appropriate error code. */ int scsi_smp_fill_buffer(struct block_device *device, enum ibpi_pattern ibpi); /** * @brief Sends message to SMP device. * * This function triggers gpio order to control LEDs of * the given component. * * @param[in] device Path to a smp device in sysfs. * * @return Number of bytes written to device if successful or -1 in case of error * and errno is set to appropriate error code. */ int scsi_smp_write_buffer(struct block_device *device); /** * @brief Init smp and gets phy index, * * @param[in] path Path to the device in sysfs. It can be NULL * to just initialize cntrl and not to get the * phy. * @param[in] cntrl Controller device to be initialized. * * @return Phy index on success if path and cntrl weren't NULL * 0 if error occurred or path was NULL. */ int isci_cntrl_init_smp(const char *path, struct cntrl_device *cntrl); #endif /* _SCSI_H_INCLUDED_ */ ./ledmon-0.79/src/version.h000664 001750 001750 00000002330 12245410751 016330 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _VERSION_H_INCLUDED_ #define _VERSION_H_INCLUDED_ /** * The major number of LEDCTL utilities package. This number may be overwrite * in makefile to reflect current version number. */ #ifndef VERSION_MAJOR #define VERSION_MAJOR 0 #endif /** * The minor number of LEDCTL utilities package. This number may be overwrite * in makefile to reflect current version number. */ #ifndef VERSION_MINOR #define VERSION_MINOR 79 #endif #endif /* _VERSION_H_INCLUDED_ */ ./ledmon-0.79/src/ahci.h000664 001750 001750 00000003456 12245410751 015561 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _AHCI_H_INCLUDED_ #define _AHCI_H_INCLUDED_ /** * @brief Gets sysfs path to SATA port. * * The function returns a path to SATA port in sysfs tree the given block device * is connected to. * * @param[in] path Path to block device in sysfs tree. * * @return Canonical path if successful, otherwise NULL pointer if an error occurred. */ char *ahci_get_port_path(const char *path); /** * @brief Sends LED control message using SGPIO. * * This function visualizes IBPI pattern on LEDs associated with a slot in * drive bay. This function is designed to send messaged to AHCI controller * only. * * @param[in] path Path in sysfs tree to slot in drive bay. * @param[in] ibpi IBPI pattern to visualize on LEDs associated * with the given slot. * * @return Number of bytes send to controller, -1 means error occurred and * errno has additional error information. */ int ahci_sgpio_write(struct block_device *path, enum ibpi_pattern ibpi); #endif /* _AHCI_H_INCLUDED_ */ ./ledmon-0.79/src/block.c000664 001750 001750 00000021525 12245410751 015737 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #include #include #include #include #include #include #if _HAVE_DMALLOC_H #include #endif #include "status.h" #include "ibpi.h" #include "utils.h" #include "list.h" #include "sysfs.h" #include "block.h" #include "slave.h" #include "raid.h" #include "cntrl.h" #include "scsi.h" #include "smp.h" #include "ahci.h" #include "dellssd.h" /* Global timestamp value. It shell be used to update a timestamp field of block device structure. See block.h for details. */ time_t timestamp = 0; /** * @brief Determines if disk is attached directly or via expander */ int dev_directly_attached(const char *path) { if (strstr(path, "/expander") == 0) return 1; return 0; } /** * @brief Determines a send function. * * This is the internal function of 'block device' module. The function tries to * determine a LED management protocol based on controller type and the given * path to block device in sysfs tree. First it checks whether to use * the default send function. If not it tries to read the content * of em_message_type field from sysfs tree and determines * the LED control protocol. * * @param[in] cntrl type of a controller a device is connected to. * @param[in] path path to a block device in sysfs tree. * * @return Pointer to send message function if successful, otherwise the function * returns the NULL pointer and it means either the controller does not * support enclosure management or LED control protocol * is not supported. */ static send_message_t _get_send_fn(struct cntrl_device *cntrl, const char *path) { send_message_t result = NULL; if (cntrl->cntrl_type == CNTRL_TYPE_AHCI) { result = ahci_sgpio_write; } else if (cntrl->cntrl_type == CNTRL_TYPE_SCSI && !dev_directly_attached(path)) { result = scsi_ses_write; } else if (cntrl->cntrl_type == CNTRL_TYPE_SCSI && dev_directly_attached(path)) { result = scsi_smp_fill_buffer; } else if (cntrl->cntrl_type == CNTRL_TYPE_DELLSSD) { result = dellssd_write; } return result; } static int do_not_flush(struct block_device *device) { return 1; } static flush_message_t _get_flush_fn(struct cntrl_device *cntrl, const char *path) { flush_message_t result = NULL; if (cntrl->cntrl_type == CNTRL_TYPE_SCSI && dev_directly_attached(path)) result = scsi_smp_write_buffer; else result = do_not_flush; return result; } /** * @brief Determines a host path to block device. * * This is the internal function of 'block device' module. The function * determines a host path to block device in sysfs. * * @param[in] path path to block device in sysfs. * @param[in] cntrl controller device the block * device is connected to. * * @return Pointer to memory block containing a host path. The memory block * should be freed if one don't need the content. */ static char *_get_host(char *path, struct cntrl_device *cntrl) { char *result = NULL; if (cntrl->cntrl_type == CNTRL_TYPE_SCSI) result = scsi_get_slot_path(path, cntrl->sysfs_path); else if (cntrl->cntrl_type == CNTRL_TYPE_AHCI) result = ahci_get_port_path(path); else if (cntrl->cntrl_type == CNTRL_TYPE_DELLSSD) result = dellssd_get_path(path, cntrl->sysfs_path); return result; } /** * @brief Checks if block device is connected to the given controller. * * This is the internal function of 'block device' module. It is design to be * used as test argument in list_first_that() function. The function checks if * a block device is connected to the given storage controller. * * @param[in] cntrl pointer to controller structure to compare to. * @param[in] path real path to block device in sysfs. * * @return 1 if a block device is connected to a controller, otherwise the * function will return 0. */ static int _compare(struct cntrl_device *cntrl, const char *path) { return (strncmp(cntrl->sysfs_path, path, strlen(cntrl->sysfs_path)) == 0); } /** * @brief Determines a storage controller. * * This is the internal function of 'block device' module. The function gets * a pointer to controller structure the device is connected to. * * @param[in] cntrl_list pointer to list of supported controllers. * @param[in] path path to block device in sysfs tree. * * @return Pointer to controller structure if successful, otherwise the function * returns NULL pointer. The NULL pointer means that block devices is * connected to unsupported storage controller. */ struct cntrl_device *block_get_controller(void *cntrl_list, char *path) { return list_first_that(cntrl_list, _compare, path); } struct _host_type *block_get_host(struct cntrl_device *cntrl, int host_id) { struct _host_type *hosts = NULL; if (!cntrl) return hosts; hosts = cntrl->hosts; while (hosts) { if (hosts->host_id == host_id) break; hosts = hosts->next; } return hosts; } /* * Allocates a new block device structure. See block.h for details. */ struct block_device *block_device_init(void *cntrl_list, const char *path) { struct cntrl_device *cntrl; char link[PATH_MAX], *host; struct block_device *device = NULL; send_message_t send_fn = NULL; flush_message_t flush_fn = NULL; int host_id = -1; char *host_name; if (realpath(path, link)) { cntrl = block_get_controller(cntrl_list, link); if (cntrl == NULL) return NULL; host = _get_host(link, cntrl); if (host == NULL) return NULL; host_name = get_path_hostN(link); if (host_name) { sscanf(host_name, "host%d", &host_id); free(host_name); } flush_fn = _get_flush_fn(cntrl, link); send_fn = _get_send_fn(cntrl, link); if (send_fn == NULL) { free(host); return NULL; } device = calloc(1, sizeof(*device)); if (device) { struct _host_type *hosts = cntrl->hosts; device->cntrl = cntrl; device->sysfs_path = strdup(link); device->cntrl_path = host; device->ibpi = IBPI_PATTERN_UNKNOWN; device->ibpi_prev = IBPI_PATTERN_NONE; device->send_fn = send_fn; device->flush_fn = flush_fn; device->timestamp = timestamp; device->host = NULL; device->host_id = host_id; device->encl_index = -1; while (hosts) { if (hosts->host_id == host_id) { device->host = hosts; break; } hosts = hosts->next; } if (cntrl->cntrl_type == CNTRL_TYPE_SCSI) { if (dev_directly_attached(link)) device->phy_index = isci_cntrl_init_smp(link, cntrl); else { device->phy_index = isci_cntrl_init_smp(link, cntrl); if (scsi_get_enclosure(device) == 0) { log_warning("Device " \ "initialization " \ "failed for '%s'", path); free(device->sysfs_path); free(device->cntrl_path); free(device); device = NULL; } } } } else free(host); } return device; } /** * Frees memory allocated for block device structure. See block.h for details. */ void block_device_fini(struct block_device *device) { if (device) { if (device->sysfs_path) free(device->sysfs_path); if (device->cntrl_path) free(device->cntrl_path); /* free(device); */ } } /* * Duplicates a block device structure. See block.h for details. */ struct block_device *block_device_duplicate(struct block_device *block) { struct block_device *result = NULL; if (block) { result = calloc(1, sizeof(*result)); if (result) { result->sysfs_path = strdup(block->sysfs_path); result->cntrl_path = strdup(block->cntrl_path); if (block->ibpi != IBPI_PATTERN_UNKNOWN) result->ibpi = block->ibpi; else result->ibpi = IBPI_PATTERN_ONESHOT_NORMAL; result->ibpi_prev = block->ibpi_prev; result->send_fn = block->send_fn; result->flush_fn = block->flush_fn; result->timestamp = block->timestamp; result->cntrl = block->cntrl; result->host = block->host; result->host_id = block->host_id; result->phy_index = block->phy_index; result->encl_index = block->encl_index; strcpy(result->encl_dev, block->encl_dev); } } return result; } ./ledmon-0.79/src/enclosure.c000664 001750 001750 00000004625 12245410751 016646 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #include #if _HAVE_DMALLOC_H #include #endif #include "enclosure.h" #include "utils.h" /** * @brief Gets SAS address of an enclosure device. * * This is internal function of enclosure module. The function reads a * SAS address of an enclosure from sysfs attribute. * * @param[in] path Path to enclosure device in sysfs tree. * * @return SAS address of an enclosure if successful, otherwise 0. */ static uint64_t _get_sas_address(const char *path) { char tmp[PATH_MAX], buf[BUFFER_MAX]; char *p, *s; str_cpy(tmp, path, PATH_MAX); p = strstr(tmp, "/expander"); if (p == NULL) return 0; s = strchr(p + 1, PATH_DELIM); if (s == NULL) return 0; *s = '\0'; str_cpy(buf, p, s - p + 1); str_cat(tmp, "/sas_device", PATH_MAX); str_cat(tmp, buf, PATH_MAX); return get_uint64(tmp, 0, "sas_address"); } /* * Allocates memory for enclosure device structure and initializes fields of * the structure. */ struct enclosure_device *enclosure_device_init(const char *path) { char temp[PATH_MAX]; struct enclosure_device *result = NULL; if (realpath(path, temp)) { result = malloc(sizeof(struct enclosure_device)); if (result == NULL) return NULL; result->sysfs_path = str_dup(temp); result->sas_address = _get_sas_address(temp); } return result; } /* * The function returns memory allocated for fields of enclosure structure to * the system. */ void enclosure_device_fini(struct enclosure_device *enclosure) { if (enclosure) { if (enclosure->sysfs_path) free(enclosure->sysfs_path); /* free(enclosure); */ } } ./ledmon-0.79/src/pidfile.c000664 001750 001750 00000004675 12245410751 016270 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #include #include #include #include #include #include #if _HAVE_DMALLOC_H #include #endif #include "status.h" #include "pidfile.h" #include "utils.h" /** */ status_t pidfile_create(const char *name) { char buf[PATH_MAX]; int fd, count; str_cpy(buf, "/var/run/", PATH_MAX); str_cat(buf, name, PATH_MAX); str_cat(buf, ".pid", PATH_MAX); fd = open(buf, O_WRONLY | O_CREAT, 0640); if (fd < 0) return STATUS_FILE_OPEN_ERROR; if (lockf(fd, F_TLOCK, 0) < 0) { close(fd); return STATUS_FILE_LOCK_ERROR; } sprintf(buf, "%d\n", getpid()); count = write(fd, buf, strlen(buf)); close(fd); return (count < 0) ? STATUS_FILE_WRITE_ERROR : STATUS_SUCCESS; } /** */ int pidfile_remove(const char *name) { char buf[PATH_MAX]; str_cpy(buf, "/var/run/", PATH_MAX); str_cat(buf, name, PATH_MAX); str_cat(buf, ".pid", PATH_MAX); return unlink(buf); } /** * @brief Test whether process with given pid is still alive * * @return STATUS_SUCCESS if proces is alive and other error if not or * if there is an error */ int ping_proc(pid_t pid) { char buf[PATH_MAX]; sprintf(buf, "kill -n 10 %d 2>/dev/null", pid); if (system(buf) == 0) return STATUS_SUCCESS; return STATUS_INVALID_PATH; } /** */ status_t pidfile_check(const char *name, pid_t *pid) { char path[PATH_MAX], *p; pid_t tp; str_cpy(path, "/var/run/", PATH_MAX); str_cat(path, name, PATH_MAX); str_cat(path, ".pid", PATH_MAX); p = buf_read(path); if (p == NULL) return STATUS_INVALID_PATH; tp = atoi(p); if (pid) *pid = tp; free(p); return ping_proc(tp); } ./ledmon-0.79/src/utils.c000664 001750 001750 00000021206 12245410751 016001 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if _HAVE_DMALLOC_H #include #endif #include "status.h" #include "list.h" #include "utils.h" /** */ #define DEFAULT_LOG_NAME "/var/log/%s.log" /** */ #define PREFIX_DEBUG " DEBUG: " #define PREFIX_WARNING "WARNING: " #define PREFIX_INFO " INFO: " #define PREFIX_ERROR " ERROR: " /** */ #define TIMESTAMP_PATTERN "0x%08x:0x%08x " /** */ enum verbose_level verbose = VERB_WARN; /** * Name of the executable. It is the last section of invocation path. */ char *progname = NULL; /** */ static FILE *s_log = NULL; /* * Function returns a content of a text file. See utils.h for details. */ char *get_text(const char *path, const char *name) { char temp[PATH_MAX]; str_cpy(temp, path, PATH_MAX); str_cat(temp, PATH_DELIM_STR, PATH_MAX); str_cat(temp, name, PATH_MAX); return buf_read(temp); } /* * Function returns 64-bit unsigned integer value read from a text file. See * utils.h for details. */ uint64_t get_uint64(const char *path, uint64_t defval, const char *name) { char *p = get_text(path, name); if (p) { sscanf(p, "0x%Lx", (long long unsigned int *)&defval); free(p); } return defval; } /* * Function returns integer value read from a text file. * See utils.h for details. */ int get_int(const char *path, int defval, const char *name) { char *p = get_text(path, name); if (p) { defval = atoi(p); free(p); } return defval; } /** */ void *scan_dir(const char *path) { struct dirent *dirent; void *result; char temp[PATH_MAX]; if (list_init(&result) != STATUS_SUCCESS) return NULL; DIR *dir = opendir(path); if (dir) { while ((dirent = readdir(dir)) != NULL) { if ((strcmp(dirent->d_name, ".") == 0) || (strcmp(dirent->d_name, "..")) == 0) { continue; } str_cpy(temp, path, PATH_MAX); str_cat(temp, PATH_DELIM_STR, PATH_MAX); str_cat(temp, dirent->d_name, PATH_MAX); list_put(result, temp, strlen(temp) + 1); } closedir(dir); } return result; } /** */ static int _is_virtual(int dev_type) { switch (dev_type) { case 0: /* sysfs */ case 3: /* procfs */ return 1; } return 0; } /** */ int buf_write(const char *path, const char *buf) { int fd, size = -1; if (path == NULL) __set_errno_and_return(EINVAL); if ((buf == NULL) || (strlen(buf) == 0)) __set_errno_and_return(ENODATA); fd = open(path, O_WRONLY); if (fd >= 0) { size = write(fd, buf, strlen(buf)); close(fd); } return size; } /** */ char *buf_read(const char *path) { struct stat st; int fd, size; char *buf, *t; if (stat(path, &st) < 0) return NULL; if (st.st_size == 0) { if (!_is_virtual(st.st_dev)) return NULL; st.st_size = st.st_blksize; } if (_is_virtual(st.st_dev)) st.st_size = st.st_blksize; t = buf = malloc(st.st_size); if (buf) { fd = open(path, O_RDONLY); if (fd >= 0) { size = read(fd, buf, st.st_size); close(fd); if (size > 0) t = strchrnul(buf, '\n'); } *t = '\0'; } return buf; } /** */ void get_id(const char *path, struct device_id *did) { char *t, *p; if (did && path) { did->major = did->minor = -1; p = buf_read(path); if (p) { t = strchr(p, ':'); if (t) { *(t++) = '\0'; did->major = atoi(p); did->minor = atoi(t); } free(p); } } } /** */ static void _log_timestamp(void) { struct timeval t; if (gettimeofday(&t, NULL) == 0) { fprintf(s_log, TIMESTAMP_PATTERN, (int)t.tv_sec, (int)t.tv_usec); } } /** */ static int _mkdir(const char *path) { char temp[PATH_MAX]; int status = -1; char *t = realpath(path, temp); while (t) { t = strchr(t + 1, PATH_DELIM); if (t) *t = '\0'; status = mkdir(temp, 0640); if (t) *t = PATH_DELIM; if ((status < 0) && (errno != EEXIST)) break; status = 0; } return status; } /** */ int log_open(const char *path) { if (s_log) log_close(); char *t = rindex(path, PATH_DELIM); if (t) *t = '\0'; int status = _mkdir(path); if (t) *t = PATH_DELIM; if (status == 0) { s_log = fopen(path, "a"); if (s_log == NULL) return -1; } return status; } /** */ void log_close(void) { if (s_log) { fflush(s_log); fclose(s_log); s_log = NULL; } closelog(); } /** */ static void _log_open_default(void) { char temp[PATH_MAX]; sprintf(temp, DEFAULT_LOG_NAME, progname); log_open(temp); } /** */ void log_debug(const char *buf, ...) { va_list vl; if (s_log == NULL) _log_open_default(); if (s_log && (verbose >= VERB_DEBUG)) { _log_timestamp(); fprintf(s_log, PREFIX_DEBUG); va_start(vl, buf); vfprintf(s_log, buf, vl); va_end(vl); fprintf(s_log, "\n"); fflush(s_log); } va_start(vl, buf); vsyslog(LOG_DEBUG, buf, vl); va_end(vl); } /** */ void log_error(const char *buf, ...) { va_list vl; if (s_log == NULL) _log_open_default(); if (s_log && (verbose >= VERB_ERROR)) { _log_timestamp(); fprintf(s_log, PREFIX_ERROR); va_start(vl, buf); vfprintf(s_log, buf, vl); va_end(vl); fprintf(s_log, END_LINE_STR); fflush(s_log); } va_start(vl, buf); vsyslog(LOG_ERR, buf, vl); va_end(vl); } /** */ void log_warning(const char *buf, ...) { va_list vl; if (s_log == NULL) _log_open_default(); if (s_log && (verbose >= VERB_WARN)) { _log_timestamp(); fprintf(s_log, PREFIX_WARNING); va_start(vl, buf); vfprintf(s_log, buf, vl); va_end(vl); fprintf(s_log, END_LINE_STR); fflush(s_log); } va_start(vl, buf); vsyslog(LOG_WARNING, buf, vl); va_end(vl); } /** */ void log_info(const char *buf, ...) { va_list vl; if (s_log == NULL) _log_open_default(); if (s_log && (verbose >= VERB_INFO)) { _log_timestamp(); fprintf(s_log, PREFIX_INFO); va_start(vl, buf); vfprintf(s_log, buf, vl); va_end(vl); fprintf(s_log, END_LINE_STR); fflush(s_log); } va_start(vl, buf); vsyslog(LOG_INFO, buf, vl); va_end(vl); } /** * @brief Sets program's short name. * * This is internal function of monitor service. It is used to extract the name * of executable file from command line argument. * * @param[in] invocation_name - the pointer to command line argument * with the invocation name. * * @return The function does not return a value. */ void set_invocation_name(char *invocation_name) { #ifdef program_invocation_short_name (void)invocation_name; progname = program_invocation_short_name; #else char *t = rindex(invocation_name, PATH_DELIM); if (t) progname = t + 1; else progname = invocation_name; #endif /* program_invocation_short_name */ } /** */ char *str_cpy(char *dest, const char *src, size_t size) { strncpy(dest, src, size - 1); dest[size - 1] = '\0'; return dest; } /** */ char *str_dup(const char *src) { if (src && (strlen(src) > 0)) return strdup(src); return NULL; } /** */ char *str_cat(char *dest, const char *src, size_t size) { int t = strlen(dest); strncat(dest, src, size - t); if (t + strlen(src) >= size) dest[size - 1] = '\0'; return dest; } char *get_path_hostN(const char *path) { char *c = NULL, *s = NULL, *p = strdup(path); if (!p) return NULL; c = strstr(p, "host"); if (!c) goto end; s = strchr(c, '/'); if (!s) goto end; *s = 0; s = strdup(c); end: free(p); return s; } char *get_path_component_rev(const char *path, int index) { int i; char *c = NULL, *p = strdup(path); char *result = NULL; for (i = 0; i <= index; i++) { if (c) *c = '\0'; c = strrchr(p, '/'); } if (c) result = strdup(c + 1); free(p); return result; } char *truncate_path_component_rev(const char *path, int index) { int i; char *c = NULL, *p = str_dup(path); if (!p) return NULL; for (i = 0; i <= index; i++) { if (c) *c = '\0'; c = strrchr(p, '/'); } c = strdup(p); free(p); return c; } ./ledmon-0.79/src/pidfile.h000664 001750 001750 00000001767 12245410751 016274 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _PIDFILE_H_INCLUDED_ #define _PIDFILE_H_INCLUDED_ /** */ status_t pidfile_create(const char *name); /** */ int pidfile_remove(const char *name); /** */ status_t pidfile_check(const char *name, pid_t *pid); #endif /* _PIDFILE_H_INCLUDED_ */ ./ledmon-0.79/src/ledmon.c000664 001750 001750 00000061472 12245410751 016130 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if _HAVE_DMALLOC_H #include #endif #include "status.h" #include "ibpi.h" #include "pidfile.h" #include "list.h" #include "utils.h" #include "sysfs.h" #include "block.h" #include "slave.h" #include "raid.h" #include "cntrl.h" #include "version.h" #include "scsi.h" #include "ahci.h" #include "smp.h" /** * Default suspend time between sysfs scan operations, given in seconds. */ #define DEFAULT_SLEEP_INTERVAL 10 /** * Minimum suspend time between sysfs scan operations, given in seconds. */ #define MINIMUM_SLEEP_INTERVAL 5 /** * @brief List of active block devices. * * This list holds all block devices attached to supported storage controllers. * Only devices which have enclosure management feature enabled are on the * list, other devices are ignored (except protocol is forced). */ static void *ledmon_block_list = NULL; /** * @brief Daemon process termination flag. * * This flag indicates that daemon process should terminate. User must send * SIGTERM to daemon in order to terminate the process gently. */ static sig_atomic_t terminate = 0; /** * @brief The interval between sysfs scans. * * This static variable holds the value of time interval used by the daemon to * set sleep between two scans of sysfs. The time interval is given in seconds. * The value is set to DEFAULT_SLEEP_INTERVAL by default and it can be change * with appropriate command line option. The minimum time interval is 5 seconds. */ static int sleep_interval = DEFAULT_SLEEP_INTERVAL; /** * @brief Name of IBPI patterns. * * This is internal array with names of IBPI patterns. Logging routines use this * entries to translate enumeration type into the string. */ const char *ibpi_str[] = { [IBPI_PATTERN_UNKNOWN] = "None", [IBPI_PATTERN_NORMAL] = "Off", [IBPI_PATTERN_ONESHOT_NORMAL] = "Oneshot Off", [IBPI_PATTERN_DEGRADED] = "In a Critical Array", [IBPI_PATTERN_REBUILD] = "Rebuild", [IBPI_PATTERN_REBUILD_P] = "Rebuild Preferred", [IBPI_PATTERN_FAILED_ARRAY] = "In a Failed Array", [IBPI_PATTERN_HOTSPARE] = "Hotspare", [IBPI_PATTERN_PFA] = "Predicted Failure Analysis", [IBPI_PATTERN_FAILED_DRIVE] = "Failure", [IBPI_PATTERN_LOCATE] = "Locate", [IBPI_PATTERN_LOCATE_OFF] = "Locate Off" }; /** * Internal variable of monitor service. It is the pattern used to print out * information about the version of monitor service. */ static char *ledmon_version = "Intel(R) Enclosure LED Monitor Service %d.%d\n" "Copyright (C) 2009-2013 Intel Corporation.\n"; /** * Internal variable of monitor service. It is used to help parse command line * short options. */ static char *shortopt = "t:c:hvl:"; /** * Internal enumeration type. It is used to help parse command line arguments. */ enum longopt { OPT_ALL, OPT_CONFIG, OPT_DEBUG, OPT_ERROR, OPT_HELP, OPT_INFO, OPT_INTERVAL, OPT_LOG, OPT_QUIET, OPT_VERSION, OPT_WARNING }; /** * Internal array with option tokens. It is used to help parse command line * long options. */ static struct option longopt[] = { [OPT_ALL] = {"all", no_argument, NULL, '\0'}, [OPT_CONFIG] = {"config", required_argument, NULL, 'c'}, [OPT_DEBUG] = {"debug", no_argument, NULL, '\0'}, [OPT_ERROR] = {"error", no_argument, NULL, '\0'}, [OPT_HELP] = {"help", no_argument, NULL, 'h'}, [OPT_INFO] = {"info", no_argument, NULL, '\0'}, [OPT_INTERVAL] = {"interval", required_argument, NULL, 't'}, [OPT_LOG] = {"log", required_argument, NULL, 'l'}, [OPT_QUIET] = {"quiet", no_argument, NULL, '\0'}, [OPT_VERSION] = {"version", no_argument, NULL, 'v'}, [OPT_WARNING] = {"warning", no_argument, NULL, '\0'}, {NULL, no_argument, NULL, '\0'} }; /** * @brief Monitor service finalize function. * * This is internal function of monitor service. It is used to finalize daemon * process i.e. free allocated memory, unlock and remove pidfile and close log * file and syslog. The function is registered as on_exit() handler. * * @param[in] status The function ignores this parameter. * @param[in] progname The name of the binary file. This argument * is passed via on_exit() function. * * @return The function does not return a value. */ static void _ledmon_fini(int __attribute__ ((unused)) status, void *progname) { sysfs_fini(); if (ledmon_block_list) { list_for_each(ledmon_block_list, block_device_fini); list_fini(ledmon_block_list); } log_close(); pidfile_remove(progname); } /** * @brief Puts exit status to a log file. * * This is internal function of monitor service. It is used to report an exit * status of the monitor service. The message is logged in to syslog and to log * file. The function is registered as on_exit() hander. * * @param[in] status Status given in the last call to exit() * function. * @param[in] ignore Pointer to placeholder where ignore flag is * stored. If flag is set 0 then parent process * is exiting, otherwise a child is exiting. * This argument must not be NULL pointer. * * @return The function does not return a value. */ static void _ledmon_status(int status, void *ignore) { if (*((int *)ignore) != 0) log_info("exit status is %s.", strstatus(status)); else if (status != STATUS_SUCCESS) log_error("parent exit status is %s.", strstatus(status)); } /** * @brief Displays the credits. * * This is internal function of monitor service. It prints out the name and * version of the program. It displays the copyright notice and information * about the author and license, too. * * @return The function does not return a value. */ static void _ledmon_version(void) { printf(ledmon_version, VERSION_MAJOR, VERSION_MINOR); printf("\nThis is free software; see the source for copying conditions." " There is NO warranty;\nnot even for MERCHANTABILITY or FITNESS" " FOR A PARTICULAR PURPOSE.\n\n"); } /** * @brief Displays the help. * * This is internal function of monitor service. The function prints the name * and version of the program out. It displays the usage and available options * and its arguments (if any). Each option is described. This is an extract * from user manual page. * * @return The function does not return a value. */ static void _ledmon_help(void) { printf(ledmon_version, VERSION_MAJOR, VERSION_MINOR); printf("\nUsage: %s [OPTIONS]\n\n", progname); printf("Mandatory arguments for long options are mandatory for short " "options, too.\n\n"); printf("--interval=VALUE\t\t Set time interval to VALUE seconds.\n" "\t\t\t\t The smallest interval is 5 seconds.\n"); printf("--config=PATH, -c PATH\t\t Use alternate configuration file " "(not yet\n\t\t\t\t implemented).\n"); printf ("--log=PATH\t\t\t Use local log file instead\n\t\t\t\t /var/log/" "ledmon.log global file.\n"); printf("--help\t\t\t\t Displays this help text.\n"); printf ("--version\t\t\t Displays version and license information.\n\n"); printf("Refer to ledmon(8) man page for more detailed description.\n"); printf("Bugs should be reported at: " "http://sourceforge.net/p/ledmon/bugs \n"); } /** * @brief Sets the path to configuration file. * * This is internal function of monitor service. This function sets the path and * name of configuration file. The function is checking whether the given path * is valid or it is invalid and should be ignored. * * @param[in] path the new location and name of config file. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. */ static status_t _set_config_path(const char *path) { (void)path; return STATUS_SUCCESS; } /** * @brief Sets the path to local log file. * * This is internal function of monitor service. This function sets the path and * file name of log file. The function checks if the specified path is valid. In * case of incorrect path the function does nothing. * * @param[in] path new location and name of log file. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. * The following status code are returned: * * STATUS_INVALID_PATH the given path is invalid. * STATUS_FILE_OPEN_ERROR unable to open a log file i.e. because of * insufficient privileges. */ static status_t _set_log_path(const char *path) { char temp[PATH_MAX]; if (realpath(path, temp) == NULL) { if ((errno != ENOENT) && (errno != ENOTDIR)) return STATUS_INVALID_PATH; } if (log_open(temp) < 0) return STATUS_FILE_OPEN_ERROR; return STATUS_SUCCESS; } /** * @brief Sets the value of sleep interval. * * This function is used by command line handler to set new value of time * interval, @see time_interval for details. * * @param[in] optarg String containing the new value of time * interval, given in command line option. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. */ static status_t _set_sleep_interval(const char *optarg) { sleep_interval = atoi(optarg); if (sleep_interval < MINIMUM_SLEEP_INTERVAL) { log_warning("sleep interval too small... using default."); sleep_interval = DEFAULT_SLEEP_INTERVAL; } return STATUS_SUCCESS; } /** * @brief Command line interface handler function. * * This is internal function of monitor service. This function interprets the * options and commands given to the program from command line interface. * * @param[in] argc - number of arguments. * @param[in] argv - array of command line arguments. * * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code. */ static status_t _cmdline_parse(int argc, char *argv[]) { int opt, opt_index = -1; status_t status = STATUS_SUCCESS; do { opt = getopt_long(argc, argv, shortopt, longopt, &opt_index); if (opt == -1) break; switch (opt) { case 0: switch (opt_index) { case OPT_ALL: verbose = VERB_ALL; break; case OPT_DEBUG: verbose = VERB_DEBUG; break; case OPT_ERROR: verbose = VERB_ERROR; break; case OPT_INFO: verbose = VERB_INFO; break; case OPT_QUIET: verbose = VERB_QUIET; break; case OPT_WARNING: verbose = VERB_WARN; break; } break; case 'l': status = _set_log_path(optarg); break; case 't': status = _set_sleep_interval(optarg); break; case 'c': status = _set_config_path(optarg); break; case 'v': _ledmon_version(); exit(EXIT_SUCCESS); case 'h': _ledmon_help(); exit(EXIT_SUCCESS); case ':': case '?': default: log_debug("[opt='%c', opt_index=%d]", opt, opt_index); break; } opt_index = -1; if (status != STATUS_SUCCESS) return status; } while (1); return STATUS_SUCCESS; } /** * @brief SIGTERM handler function. * * This is internal function of monitor service. * * @param[in] signum - the number of signal received. * * @return The function does not return a value. */ static void _ledmon_sig_term(int signum) { if (signum == SIGTERM) { log_info("SIGTERM caught - terminating daemon process."); terminate = 1; } } /** * @brief Configures signal handlers. * * This is internal function of monitor services. It sets to ignore SIGALRM, * SIGHUP and SIGPIPE signals. The function installs a handler for SIGTERM * signal. User must send SIGTERM to daemon process in order to shutdown the * daemon gently. * * @return The function does not return a value. */ static void _ledmon_setup_signals(void) { struct sigaction act; sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, SIGALRM); sigaddset(&sigset, SIGHUP); sigaddset(&sigset, SIGTERM); sigaddset(&sigset, SIGPIPE); sigaddset(&sigset, SIGUSR1); sigprocmask(SIG_BLOCK, &sigset, NULL); act.sa_handler = SIG_IGN; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGALRM, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGPIPE, &act, NULL); act.sa_handler = _ledmon_sig_term; sigaction(SIGTERM, &act, NULL); sigaction(SIGUSR1, &act, NULL); sigprocmask(SIG_UNBLOCK, &sigset, NULL); } /** * @brief Puts the calling process into sleep. * * This is internal function of monitor service. The function puts the calling * process into a sleep for the given amount of time (expressed in seconds). The * function will give control back to the process as soon as time elapses or * SIGTERM occurs. * * @param[in] seconds - the time interval given in seconds. * * @return The function does not return a value. */ static void _ledmon_wait(int seconds) { fd_set rd; int fd; struct timespec timeout; sigset_t sigset; sigprocmask(SIG_UNBLOCK, NULL, &sigset); sigdelset(&sigset, SIGTERM); timeout.tv_nsec = 0; timeout.tv_sec = seconds; FD_ZERO(&rd); fd = open("/proc/mdstat", O_RDONLY); if (fd) FD_SET(fd, &rd); pselect(fd + 1, NULL, NULL, &rd, &timeout, &sigset); if (fd >= 0) close(fd); } static int is_dellssd(struct block_device *bd) { return (bd->cntrl && bd->cntrl->cntrl_type == CNTRL_TYPE_DELLSSD); } /** * @brief Checks the presence of block device. * * This is internal function of monitor service. The function is checking * whether block device is already on the list or it is missing from the list. * The function is design to be used as 'test' parameter for list_find_first() * function. * * @param[in] blk1 - an element from a list to compare to. * @param[in] blk2 - a block device being searched. * * @return 0 if the block devices do not match, otherwise function returns 1. */ static int _compare(struct block_device *bd_old, struct block_device *bd_new) { int i = 0; if (!is_dellssd(bd_old) && bd_old->host_id == -1) { log_debug("Device %s : No host_id!", strstr(bd_old->sysfs_path, "host")); return 0; } if (!is_dellssd(bd_new) && bd_new->host_id == -1) { log_debug("Device %s : No host_id!", strstr(bd_new->sysfs_path, "host")); return 0; } if (!bd_old->cntrl) { log_debug("Device %s : No ctrl dev!", strstr(bd_old->sysfs_path, "host")); return 0; } if (bd_old->cntrl->cntrl_type != bd_new->cntrl->cntrl_type) return 0; switch (bd_old->cntrl->cntrl_type) { case CNTRL_TYPE_AHCI: /* Missing support for port multipliers. Compare just hostX. */ i = (bd_old->host_id == bd_new->host_id); break; case CNTRL_TYPE_SCSI: /* Host and phy is not enough. They might be DA or EA. */ if (dev_directly_attached(bd_old->sysfs_path) && dev_directly_attached(bd_new->sysfs_path)) { /* Just compare host & phy */ i = (bd_old->host_id == bd_new->host_id) && (bd_old->phy_index == bd_new->phy_index); break; } if (!dev_directly_attached(bd_old->sysfs_path) && !dev_directly_attached(bd_new->sysfs_path)) { /* Both expander attached */ i = (bd_old->host_id == bd_new->host_id) && (bd_old->phy_index == bd_new->phy_index); i = i && (bd_old->encl_index == bd_new->encl_index); break; } /* */ break; case CNTRL_TYPE_DELLSSD: default: /* Just compare names */ i = (strcmp(bd_old->sysfs_path, bd_new->sysfs_path) == 0); break; } return i; } /** * @brief Adds the block device to list. * * This is internal function of monitor service. The function adds a block * device to the ledmon_block_list list or if the device is already on the list * it updates the IBPI state of the given device. The function updates timestamp * value which indicates the time of last structure modification. The function * is design to be used as 'action' parameter of list_for_each() function. * Each change of state is logged to the file and to the syslog. * * @param[in] block Pointer to block device structure. * * @return The function does not return a value. */ static void _add_block(struct block_device *block) { struct block_device *temp; temp = list_first_that(ledmon_block_list, _compare, block); if (temp) { enum ibpi_pattern ibpi = temp->ibpi; temp->timestamp = block->timestamp; if (temp->ibpi == IBPI_PATTERN_ONESHOT_NORMAL) { temp->ibpi = IBPI_PATTERN_UNKNOWN; } else if (temp->ibpi != IBPI_PATTERN_FAILED_DRIVE) { if (block->ibpi == IBPI_PATTERN_UNKNOWN) { if ((temp->ibpi != IBPI_PATTERN_UNKNOWN) && (temp->ibpi != IBPI_PATTERN_NORMAL)) { temp->ibpi = IBPI_PATTERN_ONESHOT_NORMAL; } else { temp->ibpi = IBPI_PATTERN_UNKNOWN; } } else { temp->ibpi = block->ibpi; } } else { temp->ibpi = IBPI_PATTERN_ONESHOT_NORMAL; } if (ibpi != temp->ibpi) { log_info("CHANGE %s: from '%s' to '%s'.", temp->sysfs_path, ibpi_str[ibpi], ibpi_str[temp->ibpi]); } /* Check if name of the device changed.*/ /* It's possible for SCSI devices. */ if (strcmp(temp->sysfs_path, block->sysfs_path)) { log_info("NAME CHANGED %s to %s", strstr(temp->sysfs_path, "host"), strstr(block->sysfs_path, "host")); free(temp->sysfs_path); temp->sysfs_path = strdup(block->sysfs_path); } } else { /* Device not found, it's a new one! */ temp = block_device_duplicate(block); if (temp != NULL) { log_info("NEW %s: state '%s'.", temp->sysfs_path, ibpi_str[temp->ibpi]); list_put(ledmon_block_list, temp, sizeof(struct block_device)); free(temp); } } } /** * @brief Sends LED control message. * * This is internal function of monitor service. The function sends a LED * command to storage controller or enclosure device. The function checks * the time of last modification of block device structure. If the timestamp * is different then the current global timestamp this means the device is * missing due to hot-remove or hardware failure so it must be reported on * LEDs appropriately. Note that controller device and host attached to this * block device points to invalid pointer so it must be 'refreshed'. * * @param[in] block Pointer to block device structure. * * @return The function does not return a value. */ static void _send_msg(struct block_device *block) { if (!block->cntrl) { log_debug("Missing cntrl for dev: %s. Not sending anything.", strstr(block->sysfs_path, "host")); return; } if (block->timestamp != timestamp) { if (block->ibpi != IBPI_PATTERN_FAILED_DRIVE) { log_info("CHANGE %s: from '%s' to '%s'.", block->sysfs_path, ibpi_str[block->ibpi], ibpi_str[IBPI_PATTERN_FAILED_DRIVE]); block->ibpi = IBPI_PATTERN_FAILED_DRIVE; } else { log_debug("DETACHED DEV '%s' in failed state", strstr(block->sysfs_path, "host")); } } block->send_fn(block, block->ibpi); block->ibpi_prev = block->ibpi; } static void _flush_msg(struct block_device *block) { if (!block->cntrl) return; block->flush_fn(block); } static void _revalidate_dev(struct block_device *block) { /* Bring back controller and host to the device. */ block->cntrl = block_get_controller(sysfs_get_cntrl_devices(), block->cntrl_path); if (!block->cntrl) { log_debug("Failed to get controller for dev: %s, ctrl path: %s", block->sysfs_path, block->cntrl_path); return; } if (block->cntrl->cntrl_type == CNTRL_TYPE_SCSI && block->cntrl->isci_present) { block->host = block_get_host(block->cntrl, block->host_id); if (block->host) { isci_cntrl_init_smp(NULL, block->cntrl); } else { log_debug("Failed to get host for dev: %s, hostId: %d", block->sysfs_path, block->host_id); /* If hosts failed for isci, invalidate cntrl */ block->cntrl = NULL; } } return; } static void _invalidate_dev(struct block_device *block) { /* Those fields are valid only per 'session' - through single scan. */ block->cntrl = NULL; block->host = NULL; } static void _check_block_dev(struct block_device *block, int *restart) { /* Check SCSI device behind expander. */ if (block->cntrl->cntrl_type == CNTRL_TYPE_SCSI) { if (dev_directly_attached(block->sysfs_path) == 0) { if (block->ibpi == IBPI_PATTERN_FAILED_DRIVE && (block->encl_index == -1 || block->encl_dev[0] == 0)) { (*restart)++; log_debug("%s(): invalidating device: %s. " "No link to enclosure", __func__, strstr(block->sysfs_path, "host")); } } } return; } /** * @brief Sets a list of block devices and sends LED control messages. * * This is internal function of monitor service. Based on current layout of * sysfs tree the function extracts block devices and for each block device it * send LED control message to storage controller or enclosure. The message is * determine by appropriate field in block device's structure. See _add_block() * and _send_msg() functions description for more details. * * @return The function does not return a value. */ static void _ledmon_execute(void) { int restart = 0; /* ledmon_block_list needs restart? */ status_t status = STATUS_SUCCESS; /* Revalidate each device in the list. Bring back controller and host */ list_for_each(ledmon_block_list, _revalidate_dev); /* Scan all devices and compare them against saved list */ sysfs_block_device_for_each(_add_block); /* Send message to all devices in the list if needed. */ list_for_each(ledmon_block_list, _send_msg); /* Flush unsent messages from internal buffers. */ list_for_each(ledmon_block_list, _flush_msg); /* Check if there is any orphaned device. */ list_for_each_parm(ledmon_block_list, _check_block_dev, &restart); /* Invalidate each device in the list. Clear controller and host. */ list_for_each(ledmon_block_list, _invalidate_dev); if (restart) { /* there is at least one detached element in the list. */ list_for_each(ledmon_block_list, block_device_fini); list_fini(ledmon_block_list); status = list_init(&ledmon_block_list); if (status != STATUS_SUCCESS) { log_debug("%s(): list_init() failed (status=%s).", __func__, strstatus(status)); exit(EXIT_FAILURE); } } } /** */ int main(int argc, char *argv[]) { status_t status = STATUS_SUCCESS; int i; set_invocation_name(argv[0]); openlog(progname, LOG_PID | LOG_PERROR, LOG_DAEMON); if (getuid() != 0) { log_error("Only root can run this application."); return STATUS_NOT_A_PRIVILEGED_USER; } if (on_exit(_ledmon_status, &terminate)) return STATUS_ONEXIT_ERROR; if (_cmdline_parse(argc, argv) != STATUS_SUCCESS) return STATUS_CMDLINE_ERROR; if (pidfile_check(progname, NULL) == 0) { log_warning("daemon is running..."); return STATUS_LEDMON_RUNNING; } pid_t pid = fork(); if (pid < 0) { log_debug("main(): fork() failed (errno=%d).", errno); exit(EXIT_FAILURE); } if (pid > 0) exit(EXIT_SUCCESS); pid_t sid = setsid(); if (sid < 0) { log_debug("main(): setsid() failed (errno=%d).", errno); exit(EXIT_FAILURE); } for (i = getdtablesize() - 1; i >= 0; --i) close(i); int t = open("/dev/null", O_RDWR); dup(t); dup(t); umask(027); if (chdir("/") < 0) { log_debug("main(): chdir() failed (errno=%d).", errno); exit(EXIT_FAILURE); } if (pidfile_create(progname)) { log_debug("main(): pidfile_creat() failed."); exit(EXIT_FAILURE); } _ledmon_setup_signals(); if (on_exit(_ledmon_fini, progname)) exit(STATUS_ONEXIT_ERROR); status = list_init(&ledmon_block_list); if (status != STATUS_SUCCESS) { log_debug("main(): list_init() failed (status=%s).", strstatus(status)); exit(EXIT_FAILURE); } status = sysfs_init(); if (status != STATUS_SUCCESS) { log_debug("main(): sysfs_init() failed (status=%s).", strstatus(status)); exit(EXIT_FAILURE); } log_info("monitor service has been started..."); while (terminate == 0) { timestamp = time(NULL); status = sysfs_scan(); if (status != STATUS_SUCCESS) { log_debug("main(): sysfs_scan() failed (status=%s).", strstatus(status)); } else { _ledmon_execute(); status = sysfs_reset(); if (status != STATUS_SUCCESS) { log_debug("main(): sysfs_reset() failed " "(status=%s).", strstatus(status)); } } _ledmon_wait(sleep_interval); } exit(EXIT_SUCCESS); } ./ledmon-0.79/src/slave.h000664 001750 001750 00000002551 12245410751 015762 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _SLAVE_H_INCLUDED_ #define _SLAVE_H_INCLUDED_ /** */ #define SLAVE_STATE_UNKNOWN 0x00 #define SLAVE_STATE_IN_SYNC 0x01 #define SLAVE_STATE_SPARE 0x02 #define SLAVE_STATE_FAULTY 0x04 #define SLAVE_STATE_WRITE_MOSTLY 0x08 #define SLAVE_STATE_BLOCKED 0x10 /** */ struct slave_device { struct raid_device *raid; unsigned int errors; unsigned int slot; struct block_device *block; unsigned char state; }; /** */ struct slave_device *slave_device_init(const char *path, void *block_list); /** */ void slave_device_fini(struct slave_device *device); #endif /* _SLAVE_H_INCLUDED_ */ ./ledmon-0.79/src/enclosure.h000664 001750 001750 00000004771 12245410751 016655 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _ENCLOSURE_H_INCLUDED_ #define _ENCLOSURE_H_INCLUDED_ /** * @brief Enclosure device structure. * * This structure describes an enclosure device connected to one of * SAS controllers existing in the system. */ struct enclosure_device { /** * Path to an enclosure device in sysfs tree. This is controller base * canonical path. */ char *sysfs_path; /** * SAS address as identifier of an enclosure. */ uint64_t sas_address; }; /** * @brief Allocates memory for an enclosure device structure. * * This function allocates memory for a new structure describing an enclosure * device. It reads the sysfs entries and populates structure fields. * The function uses libsas abstraction layer to extract required information. * * @param[in] path Path to an enclosure device in sysfs tree. * The path begins with "/sys/class/enclosure/". * * @return Pointer to enclosure device structure if successful, otherwise the * function returns NULL pointer. The NULL pointer means either the * specified path is invalid or there's not enough memory in the system * to allocated new structure. */ struct enclosure_device *enclosure_device_init(const char *path); /** * @brief Releases an enclosure device structure. * * This function releases memory allocated for enclosure device structure. To be * more specific it only frees memory allocated for the fields of the structure. * It is due to the way list is implemented for the purpose of this utility. * * @param[in] device Pointer to enclosure device structure. * * @return The function does not return a value. */ void enclosure_device_fini(struct enclosure_device *enclosure); #endif /* _ENCLOSURE_H_INCLUDED_ */ ./ledmon-0.79/src/ahci.c000664 001750 001750 00000006102 12245410751 015543 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #include #include #include #if _HAVE_DMALLOC_H #include #endif #include "ibpi.h" #include "block.h" #include "ahci.h" #include "utils.h" /** * Time interval in u-seconds to wait before enclosure management message is being * sent to AHCI controller. */ #define EM_MSG_WAIT 1500 /** * This array maps IBPI pattern to value recognized by AHCI driver. The driver * uses this control number to issue SGPIO signals appropriately. */ static const unsigned int ibpi2sgpio[] = { [IBPI_PATTERN_UNKNOWN] = 0x00000000, [IBPI_PATTERN_ONESHOT_NORMAL] = 0x00000000, [IBPI_PATTERN_NORMAL] = 0x00000000, [IBPI_PATTERN_DEGRADED] = 0x00200000, [IBPI_PATTERN_REBUILD] = 0x00480000, [IBPI_PATTERN_REBUILD_P] = 0x00480000, [IBPI_PATTERN_FAILED_ARRAY] = 0x00280000, [IBPI_PATTERN_HOTSPARE] = 0x01800000, [IBPI_PATTERN_PFA] = 0x01400000, [IBPI_PATTERN_FAILED_DRIVE] = 0x00400000, [IBPI_PATTERN_LOCATE] = 0x00080000, [IBPI_PATTERN_LOCATE_OFF] = 0x00000000 }; /* * The function sends a LED control message to AHCI controller. It uses * SGPIO to control the LEDs. See ahci.h for details. */ int ahci_sgpio_write(struct block_device *device, enum ibpi_pattern ibpi) { char temp[WRITE_BUFFER_SIZE]; char path[PATH_MAX]; char *sysfs_path = device->cntrl_path; /* write only if state has changed */ if (ibpi == device->ibpi_prev) return 1; if (sysfs_path == NULL) __set_errno_and_return(EINVAL); if ((ibpi < IBPI_PATTERN_NORMAL) || (ibpi > IBPI_PATTERN_LOCATE_OFF)) __set_errno_and_return(ERANGE); sprintf(temp, "%u", ibpi2sgpio[ibpi]); str_cpy(path, sysfs_path, PATH_MAX); str_cat(path, "/em_message", PATH_MAX); usleep(EM_MSG_WAIT); return buf_write(path, temp) > 0; } /* * The function return path to SATA port in sysfs tree. See ahci.h for details. */ char *ahci_get_port_path(const char *path) { char tmp[PATH_MAX], buf[BUFFER_MAX]; char *p, *s; str_cpy(tmp, path, PATH_MAX); p = strstr(tmp, "/target"); if (p == NULL) return NULL; *p = '\0'; s = rindex(tmp, PATH_DELIM); if (s == NULL) return NULL; str_cpy(buf, s, BUFFER_MAX); str_cat(tmp, "/scsi_host", PATH_MAX); str_cat(tmp, buf, PATH_MAX); return str_dup(tmp); } ./ledmon-0.79/src/list.c000664 001750 001750 00000016453 12245410751 015624 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #include #include #include #if _HAVE_DMALLOC_H #include #endif #include "status.h" #include "list.h" #include "version.h" /** */ enum type { TYPE_LIST = 0, TYPE_NODE, }; /** */ struct node { struct node *next, *prev; void *list; enum type type; } __attribute__ ((packed)); /** */ struct list { struct node *head, *tail; enum type type; } __attribute__ ((packed)); /** */ #define _Type(_ptr) (*(((enum type *)(_ptr)) - 1)) /** */ #ifdef _DEBUG #define Check(_ptr, _type) assert(_Type(_ptr) == (_type)) #else /* _DEBUG */ #define Check(_item, _type) #endif /* _DEBUG */ /** */ #define _Node(_ptr) (((struct node *)(_ptr)) - 1) /** */ #define _List(_ptr) (((struct list *)(_ptr)) - 1) /** */ static struct node *_new(void *data, size_t size) { struct node *t; t = malloc(size + sizeof(struct node)); if (t != NULL) { t->list = NULL; t->type = TYPE_NODE; t->prev = NULL; t->next = NULL; memcpy(t + 1, data, size); } return t; } /** */ static void _delete(struct node *node) { struct node *next; while (node) { next = node->next; free(node); node = next; } } /** */ static void _fini(struct list *list) { _delete(list->head); free(list); } /** */ static void _list_delete(struct list *list) { _delete(list->head); list->head = list->tail = NULL; } /** */ static status_t _remove(struct node *node) { struct list *list; list = node->list; if (list == NULL) return STATUS_INVALID_NODE; if (node->prev) node->prev->next = node->next; else list->head = node->next; if (node->next) node->next->prev = node->prev; else list->tail = node->prev; node->list = NULL; node->next = NULL; node->prev = NULL; return STATUS_SUCCESS; } /** */ static struct node *_next(void *ptr) { switch (_Type(ptr)) { case TYPE_NODE: return _Node(ptr)->next; case TYPE_LIST: return _List(ptr)->head; } abort(); } /** */ static struct node *_prev(void *ptr) { switch (_Type(ptr)) { case TYPE_NODE: return _Node(ptr)->prev; case TYPE_LIST: return _List(ptr)->tail; } abort(); } /** */ static struct node *_get_last(struct node *node) { while (node) { if (node->next == NULL) break; node = node->next; } return node; } /** */ static struct node *_get_first(struct node *node) { while (node) { if (node->prev == NULL) break; node = node->prev; } return node; } /** */ static void _put_before(struct node *node, struct node *elem) { struct node *t; t = node->prev; node->prev = elem; elem->prev = t; if (t != NULL) t->next = elem; elem->next = node; elem->list = node->list; } /** */ static void _put_after(struct node *node, struct node *elem) { struct node *t; t = node->next; node->next = elem; elem->next = t; if (t != NULL) t->prev = elem; elem->prev = node; elem->list = node->list; } /** */ static void _put_front(struct list *list, struct node *elem) { if (list->head == NULL) list->tail = elem; else { elem->next = list->head; list->head->prev = elem; } list->head = elem; elem->list = list; } /** */ static void _put_back(struct list *list, struct node *elem) { if (list->tail == NULL) list->head = elem; else { elem->prev = list->tail; list->tail->next = elem; } list->tail = elem; elem->list = list; } /** */ static struct node *_tail(void *ptr) { switch (_Type(ptr)) { case TYPE_NODE: return _get_last(_Node(ptr)); case TYPE_LIST: return _List(ptr)->tail; } abort(); } /** */ static struct node *_head(void *ptr) { switch (_Type(ptr)) { case TYPE_NODE: return _get_first(_Node(ptr)); case TYPE_LIST: return _List(ptr)->head; } abort(); } /** */ status_t list_init(void **ptr) { struct list *t; t = malloc(sizeof(struct list)); if (t == NULL) return STATUS_OUT_OF_MEMORY; t->head = NULL; t->tail = NULL; t->type = TYPE_LIST; *ptr = t + 1; return STATUS_SUCCESS; } /** */ status_t list_fini(void *ptr) { if (ptr != NULL) { Check(ptr, TYPE_LIST); _fini(_List(ptr)); } return STATUS_SUCCESS; } /** */ status_t list_remove(void *ptr) { if (ptr == NULL) return STATUS_NULL_POINTER; Check(ptr, TYPE_NODE); return _remove(_Node(ptr)); } /** */ void *list_add(void *ptr, void *data, size_t size) { void *result = NULL; if (ptr && data && (size > 0)) { result = _new(data, size); if (result != NULL) { switch (_Type(ptr)) { case TYPE_LIST: _put_front(_List(ptr), result); break; case TYPE_NODE: _put_before(_Node(ptr), result); break; default: abort(); } } } return result + sizeof(struct node); } /** */ void *list_put(void *ptr, void *data, size_t size) { void *result = NULL; if (ptr && data && (size > 0)) { result = _new(data, size); if (result != NULL) { switch (_Type(ptr)) { case TYPE_LIST: _put_back(_List(ptr), result); break; case TYPE_NODE: _put_after(_Node(ptr), result); break; default: abort(); } } } return result + sizeof(struct node); } /** */ void *list_next(void *ptr) { if (ptr) { struct node *node = _next(ptr); if (node) return node + 1; } return NULL; } /** */ void *list_prev(void *ptr) { if (ptr) { struct node *node = _prev(ptr); if (node) return node + 1; } return NULL; } /** */ void *list_head(void *ptr) { if (ptr) { struct node *node = _head(ptr); if (node) return node + 1; } return NULL; } /** */ void *list_tail(void *ptr) { if (ptr) { struct node *node = _tail(ptr); if (node) return node + 1; } return NULL; } /** */ status_t list_delete(void *ptr) { if (ptr == NULL) return STATUS_NULL_POINTER; switch (_Type(ptr)) { case TYPE_NODE: _delete(_Node(ptr)); break; case TYPE_LIST: _list_delete(_List(ptr)); break; } return STATUS_SUCCESS; } /** */ int list_is_empty(void *ptr) { if (ptr == NULL) return STATUS_NULL_POINTER; Check(ptr, TYPE_LIST); return (_List(ptr)->head == NULL); } /** */ status_t __list_for_each(void *ptr, action_t action, void *parm) { assert(action != NULL); void *node = list_head(ptr); while (node != NULL) { action(node, parm); node = list_next(node); } return STATUS_SUCCESS; } /** */ void *__list_first_that(void *ptr, test_t test, void *parm) { assert(test != NULL); void *node = list_head(ptr); while (node) { if (test(node, parm)) break; node = list_next(node); } return node; } /** */ void *__list_last_that(void *ptr, test_t test, void *parm) { assert(test != NULL); void *node = list_tail(ptr); while (node) { if (test(node, parm)) break; node = list_prev(node); } return node; } ./ledmon-0.79/src/scsi.h000664 001750 001750 00000004674 12245410751 015621 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _SCSI_H_INCLUDED #define _SCSI_H_INCLUDED /** * @brief Gets a path to slot of an enclosure. * * This function returns a sysfs path to component of enclosure the device * belongs to. * * @param[in] path Canonical sysfs path to block device. * * @return A sysfs path to enclosure's component associated with the given * block device if successful, otherwise NULL pointer. */ char *scsi_get_slot_path(const char *path, const char *cntrl_path); /** * @brief Gets a path to slot of sas controller. * * This function returns a sysfs path to component of enclosure the device * belongs to. * * @param[in] path Canonical sysfs path to block device. * * @return A sysfs path to controller device associated with the given * block device if successful, otherwise NULL pointer. */ char *sas_get_slot_path(const char *path, const char *ctrl_path); /** * @brief Sends message to SES processor of an enclosure. * * This function send a message to an enclosure in order to control LEDs of * the given slot/component. It uses interface of ENCLOSURE kernel module to * control LEDs. * * @param[in] device Path to an enclosure device in sysfs. * @param[in] ibpi IBPI pattern to visualize. * * @return Number of characters written if successful or -1 in case of error * and errno is set to appropriate error code. */ int scsi_ses_write(struct block_device *device, enum ibpi_pattern ibpi); /** * @brief Fills encl_index and encl_dev. * * @param[in] device Path to block device. * * @return 1 on success, 0 otherwise. * */ int scsi_get_enclosure(struct block_device *device); #endif /* _SCSI_H_INCLUDED_ */ ./ledmon-0.79/src/cntrl.c000664 001750 001750 00000016204 12245410751 015765 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include #include #include #include #include #if _HAVE_DMALLOC_H #include #endif #include "status.h" #include "list.h" #include "cntrl.h" #include "utils.h" #include "sysfs.h" enum int_cntrl_type { INT_CNTRL_TYPE_UNKNOWN = CNTRL_TYPE_UNKNOWN, INT_CNTRL_TYPE_SCSI = CNTRL_TYPE_SCSI, INT_CNTRL_TYPE_AHCI = CNTRL_TYPE_AHCI, INT_CNTRL_TYPE_ISCI = CNTRL_TYPE_AHCI + 1, INT_CNTRL_TYPE_DELLSSD = CNTRL_TYPE_DELLSSD, }; /** */ static int _is_scsi_cntrl(const char *path) { uint64_t class; if (sysfs_enclosure_attached_to_cntrl(path) == 0) return 0; class = get_uint64(path, 0, "class"); return (class & 0xff0000L) == 0x010000L; } /** */ static int _is_isci_cntrl(const char *path) { uint64_t class; if (sysfs_isci_driver(path) == 0) return 0; class = get_uint64(path, 0, "class"); return (class & 0xff0000L) == 0x010000L; } /** */ static int _is_ahci_cntrl(const char *path) { char temp[PATH_MAX], link[PATH_MAX], *t; str_cpy(temp, path, PATH_MAX); str_cat(temp, "/driver", PATH_MAX); if (realpath(temp, link) == NULL) return 0; t = strrchr(link, '/'); if ((t != NULL) && (strcmp(t + 1, "ahci") != 0)) return 0; return get_uint64(path, 0, "vendor") == 0x8086L; } static int _is_dellssd_cntrl(const char *path) { uint64_t vdr, dev, svdr, cls; vdr = get_uint64(path, 0, "vendor"); dev = get_uint64(path, 0, "device"); cls = get_uint64(path, 0, "class"); svdr = get_uint64(path, 0, "subsystem_vendor"); return ((vdr == 0x1344L && dev == 0x5150L) || /* micron ssd */ (svdr == 0x1028 && cls == 0x10802)); /* nvmhci ssd */ } /** * @brief Determines the type of controller. * * This is internal function of 'controller device' module. The function * determines the type of controller device. It might be AHCI, SCSI or * UNKNOWN device type. * * @param[in] path path to controller device in sysfs tree. * * @return The type of controller device. If the type returned is * CNTRL_TYPE_UNKNOWN this means a controller device is not * supported. */ static enum int_cntrl_type _get_type(const char *path) { enum int_cntrl_type type = CNTRL_TYPE_UNKNOWN; if (_is_dellssd_cntrl(path)) type = CNTRL_TYPE_DELLSSD; if (_is_scsi_cntrl(path)) type = CNTRL_TYPE_SCSI; if (_is_isci_cntrl(path)) type = INT_CNTRL_TYPE_ISCI; if (_is_ahci_cntrl(path)) type = CNTRL_TYPE_AHCI; return type; } struct _host_type *alloc_host(int id, struct _host_type *next) { struct _host_type *host = NULL; host = malloc(sizeof(struct _host_type)); if (host) { host->host_id = id; host->ibpi_state_buffer = NULL; memset(host->bitstream, 0, sizeof(host->bitstream)); host->flush = 0; host->next = next; } return host; } void free_hosts(struct _host_type *h) { struct _host_type *t; while (h) { t = h->next; free(h->ibpi_state_buffer); free(h); h = t; } } void _find_host(const char *path, struct _host_type **hosts) { const int host_len = sizeof("host") - 1; char *p; int index = -1; struct _host_type *th; p = strrchr(path, '/'); if (!p++) return; if (strncmp(p, "host", host_len - 1) == 0) { index = atoi(p + host_len); th = alloc_host(index, (*hosts) ? (*hosts) : NULL); if (!th) return; *hosts = th; } } /** * @brief Get all instances of separate hosts on isci controller. * */ static struct _host_type *_cntrl_get_hosts(const char *path) { struct _host_type *hosts = NULL; void *dir = scan_dir(path); if (dir) { list_for_each_parm(dir, _find_host, &hosts); list_fini(dir); } return hosts; } /** * @brief Check if enclosure management is enabled. * * This is internal function of 'controller device' module. The function checks * whether enclosure management is enabled for AHCI controller. * * @param[in] path path to controller device in sysfs tree. * * @return 1 if enclosure management is enabled, otherwise the function returns 0. */ static unsigned int _ahci_em_messages(const char *path) { /* first, open ...driver/module/parameters/ahci_em_messages * then open /sys/module/libahci/parameters/ahci_em_messages * and check if it is set to enabled. * if so, check if 'holders' of libahci points the same driver name * as device given by path */ char buf[PATH_MAX]; char *link, *name; DIR *dh; struct dirent *de = NULL; /* old kernel (prior to 2.6.36) */ if (get_int(path, 0, "driver/module/parameters/ahci_em_messages") != 0) return 1; if (!get_int("", 0, "sys/module/libahci/parameters/ahci_em_messages")) return 0; if (snprintf(buf, sizeof(buf), "%s/%s", path, "driver") < 0) return 0; link = realpath(buf, NULL); if (!link) return 0; name = strrchr(link, '/'); if (!name++) { free(link); return 0; } /* check if the directory /sys/module/libahci/holders exists */ dh = opendir("/sys/module/libahci/holders"); if (dh) { /* name contain controller name (ie. ahci),*/ /* so check if libahci holds this driver */ while ((de = readdir(dh))) { if (!strcmp(de->d_name, name)) break; } closedir(dh); free(link); return de ? 1 : 0; } else { free(link); return 1; } } /* * Allocates memory for a new controller device structure. See cntrl.h for * details. */ struct cntrl_device *cntrl_device_init(const char *path) { unsigned int em_enabled; enum int_cntrl_type type; struct cntrl_device *device = NULL; type = _get_type(path); if (type != INT_CNTRL_TYPE_UNKNOWN) { switch (type) { case INT_CNTRL_TYPE_DELLSSD: case INT_CNTRL_TYPE_ISCI: case INT_CNTRL_TYPE_SCSI: em_enabled = 1; break; case INT_CNTRL_TYPE_AHCI: em_enabled = _ahci_em_messages(path); break; default: em_enabled = 0; } if (em_enabled) { device = malloc(sizeof(struct cntrl_device)); if (device) { if (type == INT_CNTRL_TYPE_ISCI) { device->isci_present = 1; device->hosts = _cntrl_get_hosts(path); type = CNTRL_TYPE_SCSI; } else { device->isci_present = 0; device->hosts = NULL; } device->cntrl_type = (enum cntrl_type)type; device->sysfs_path = strdup(path); } } else { log_error ("controller discovery: %s - enclosure " \ "management not supported.", path); } } return device; } /* * Frees memory allocated for controller device structure. See cntrl.h for * details. */ void cntrl_device_fini(struct cntrl_device *device) { if (device) { free(device->sysfs_path); free_hosts(device->hosts); } } ./ledmon-0.79/src/raid.h000664 001750 001750 00000003715 12245410751 015572 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _RAID_H_INCLUDED_ #define _RAID_H_INCLUDED_ /** */ enum raid_state { RAID_STATE_UNKNOWN = 0, RAID_STATE_CLEAR, RAID_STATE_INACTIVE, RAID_STATE_SUSPENDED, RAID_STATE_READONLY, RAID_STATE_READ_AUTO, RAID_STATE_CLEAN, RAID_STATE_ACTIVE, RAID_STATE_WRITE_PENDING, RAID_STATE_ACTIVE_IDLE }; /** */ enum raid_level { RAID_LEVEL_UNKNOWN = 0, RAID_LEVEL_0, RAID_LEVEL_1, RAID_LEVEL_10, RAID_LEVEL_4, RAID_LEVEL_5, RAID_LEVEL_6, RAID_LEVEL_FAULTY, RAID_LEVEL_LINEAR }; /** */ enum device_type { DEVICE_TYPE_UNKNOWN = 0, DEVICE_TYPE_VOLUME, DEVICE_TYPE_CONTAINER }; /** */ enum raid_action { RAID_ACTION_UNKNOWN = 0, RAID_ACTION_IDLE, RAID_ACTION_RESHAPE, RAID_ACTION_FROZEN, RAID_ACTION_RESYNC, RAID_ACTION_CHECK, RAID_ACTION_RECOVER, RAID_ACTION_REPAIR }; /** */ struct raid_device { enum device_type type; int device_num; char *sysfs_path; int raid_disks; void *slave_list; int degraded; enum raid_state array_state; enum raid_action sync_action; enum raid_level level; }; /** */ struct raid_device *raid_device_init(const char *path, unsigned int device_num, enum device_type type); /** */ void raid_device_fini(struct raid_device *device); #endif /* _RAID_H_INCLUDED_ */ ./ledmon-0.79/src/block.h000664 001750 001750 00000015475 12245410751 015753 0ustar00ldorauldorau000000 000000 /* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef _BLOCK_H_INCLUDED_ #define _BLOCK_H_INCLUDED_ struct block_device; /** * @brief Pointer to a send message function. * * The pointer to a function which knows how to send LED message to a driver of * storage controller using the given protocol. * * @param[in] path path in sysfs to a host device * @see block_device::cntrl_path. * @param[in] ibpi an IBPI pattern (state) to visualize. * * @return 1 if successful, otherwise the function returns 0. */ typedef int (*send_message_t) (struct block_device *device, enum ibpi_pattern ibpi); /** * @brief Pointer to a flush buffer function. * * @param[in] device pointer to a block device * * @return 1 if successful, otherwise the function returns 0. */ typedef int (*flush_message_t) (struct block_device *device); /** * @brief Describes a block device. * * This structure describes a block device. It does not describe virtual devices * or partitions on physical block devices. */ struct block_device { /** * Real path in sysfs tree. This means i.e. if /sys/block/sda is symbolic link * then the link will be read and path stored in sysfs_path field. This path * may not exist in sysfs if connection to physical drive is lost. This filed * cannot have NULL pointer assigned. */ char *sysfs_path; /** * The pointer to a function which sends a message to driver in order to * control LEDs in an enclosure or DAS system - @see send_message_t for details. * This field cannot have NULL pointer assigned. */ send_message_t send_fn; /** * The pointer to a function which flush buffers filled by send_fn. */ flush_message_t flush_fn; /** * Canonical path to block device where enclosure management fields are located. * This path is always accessible even if the connection to physical device * is lost. In case of AHCI controller it points to SATA phy. In case of SAS * this path points to SES entry associated with the slot in an enclosure. * This field cannot have NULL pointer assign. */ char *cntrl_path; /** * The current state of block device. This is an IBPI pattern and it is used * to visualize the state of block device. */ enum ibpi_pattern ibpi; /** * The previous state of block device. */ enum ibpi_pattern ibpi_prev; /** * The time stamp used to determine if the given block device still exist or * it failed and the device is no longer available. Every time IBPI pattern * is updated, the time-stamp is updated, too. */ time_t timestamp; /** * The pointer to storage controller structure the device is connected to. */ struct cntrl_device *cntrl; struct _host_type *host; int host_id; /** * The index of phy utilized by directly attached to controller block device. * It is meaningful if device is controlled by isci driver. */ int phy_index; /** * The index in Enclosure. This is what should be used when using SES-2. */ int encl_index; char encl_dev[PATH_MAX]; }; /** * @brief Creates a block device structure. * * This function allocates memory for a new structure of block device. It reads * the sysfs entries and populates the structure fields. It performs all this * actions only if the block device is connected to the one of supported storage * controllers and the controller has enclosure management services enabled. * * @param[in] cntrl_list pointer to a list of supported controller * devices. * @param[in] sysfs_path a path to block device in sysfs. * * @return Pointer to block device structure if successful, otherwise the function * returns the NULL pointer. */ struct block_device *block_device_init(void *cntrl_list, const char *path); /** * @brief Releases a block device structure. * * This function releases memory allocated for block device structure. * To be more specific it only frees memory allocated for the structure fields. * It is due to the way list is implemented for the purpose of this utility. * If one would like release block device structure not stored as a list node * it must call free() explicitly just after function block_device_fini() * is called. * * @param[in] device pointer to block device structure. * * @return The function does not return a value. */ void block_device_fini(struct block_device *device); /** * @brief Duplicates a block device structure. * * The function allocates memory for a block device structure and copies values * stored in fields of source block structure. The function allocates new memory * for all string fields in a copy structure. It is safe to release source block * structure just after it has been duplicated. * * @param[in] device pointer to source block device structure. * * @return Pointer to block device structure if successful, otherwise the function * returns the NULL pointer. */ struct block_device *block_device_duplicate(struct block_device *device); /** * @brief Determines a storage controller. * * This is the internal function of 'block device' module. The function gets * a pointer to controller structure the device is connected to. * * @param[in] cntrl_list pointer to list of supported controllers. * @param[in] path path to block device in sysfs tree. * * @return Pointer to controller structure if successful, otherwise the function * returns NULL pointer. The NULL pointer means that block devices is * connected to unsupported storage controller. */ struct cntrl_device *block_get_controller(void *cntrl_list, char *path); /** * The global timestamp variable. It is updated every time the sysfs is scanning * by an application. The value stored in this variable should be used to update * all timestamp stored in block device structures. */ extern time_t timestamp; /** * @brief Determines if block device is attached directly or via expander */ int dev_directly_attached(const char *path); /** * @brief Gets the host structure for given control device and host_id */ struct _host_type *block_get_host(struct cntrl_device *cntrl, int host_id); #endif /* _BLOCK_H_INCLUDED_ */ ./ledmon-0.79/doc/000775 001750 001750 00000000000 12245410751 014452 5ustar00ldorauldorau000000 000000 ./ledmon-0.79/doc/Makefile000664 001750 001750 00000003636 12245410751 016122 0ustar00ldorauldorau000000 000000 # # Intel(R) Enclosure LED Utilities # Copyright (C) 2009-2013 Intel Corporation. # # This program is free software; you can redistribute it and/or modify it # under the terms and conditions of the GNU General Public License, # version 2, as published by the Free Software Foundation. # # This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. # # Installation directory DESTDIR?= MAN_INSTDIR=$(DESTDIR)/usr/share/man MAN8_INSTDIR=$(MAN_INSTDIR)/man8 MAN5_INSTDIR=$(MAN_INSTDIR)/man5 RELEASE_DATE?="November 2013" RELEASE_VER?=0.79 default: all ledctl.conf.5.gz: ledctl.conf.pod pod2man -r "LEDCTL.CONF Version $(RELEASE_VER)" -d $(RELEASE_DATE) \ -s 5 -n ledctl.conf -c "Inter(R) Enclosure LED Utilities Config" $< | gzip -9f > $@ ledmon.8.gz: ledmon.pod pod2man -r "LEDMON Version $(RELEASE_VER)" -d $(RELEASE_DATE) \ -s 8 -n ledmon -c "Intel(R) Enclosure LED Monitor Service" $< | gzip -9f > $@ ledctl.8.gz: ledctl.pod pod2man -r "LEDCTL Version $(RELEASE_VER)" -d $(RELEASE_DATE) \ -s 8 -n ledctl -c "Intel(R) Enclosure LED Control Application" $< | gzip -9f > $@ install: all install -D -m 644 ./ledmon.8.gz $(MAN8_INSTDIR)/ledmon.8.gz install -D -m 644 ./ledctl.8.gz $(MAN8_INSTDIR)/ledctl.8.gz install -D -m 644 ./ledctl.conf.5.gz $(MAN5_INSTDIR)/ledctl.conf.5.gz uninstall: rm -f $(MAN8_INSTDIR)/ledmon.8.gz $(MAN8_INSTDIR)/ledctl.8.gz rm -f $(MAN5_INSTDIR)/ledctl.conf.5.gz all: ledctl.conf.5.gz ledmon.8.gz ledctl.8.gz clean: rm -f ledmon.8 ledmon.8.gz ledctl.8 ledctl.8.gz rm -f ledctl.conf.5 ledctl.conf.5.gz ./ledmon-0.79/doc/ledctl.pod000664 001750 001750 00000016613 12245410751 016434 0ustar00ldorauldorau000000 000000 # # Intel(R) Enclosure LED Utilities # Copyright (C) 2009-2013 Intel Corporation. # # This program is free software; you can redistribute it and/or modify it # under the terms and conditions of the GNU General Public License, # version 2, as published by the Free Software Foundation. # # This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. # =head1 NAME ledctl - Intel(R) LED control application for a storage enclosures. =head1 SYNOPSIS B [I] I=I ... =head1 DESCRIPTION The ledctl is an user space application designed to control LEDs associated with each slot in an enclosure or a drive bay. The LEDs of devices listed in I are set to the given pattern I and all other LEDs are turned off. User must have root privileges to use this application. There are two types of systems: 2-LEDs systems (Activity LED, Status LED) and 3-LEDs systems (Activity LED, Locate LED, Fail LED). The ledctl application uses SGPIO and SES-2 protocol to control LEDs. The program implements IBPI patterns of SFF-8489 specification for SGPIO. Please note some enclosures do not stick close to SFF-8489 specification. It might happen that enclosure's processor will accept an IBPI pattern but it will blink the LEDs at variance with SFF-8489 specification or it has limited number of patterns supported. LED management (AHCI) and S protocols are not supported. The ledctl application has been verified to work with Intel(R) storage controllers (i.e. Intel(R) AHCI controller and Intel(R) SAS controller). The application might work with storage controllers of other vendors (especially SCSI/SAS controllers). However, storage controllers of other vendors have not been tested. The ledmon application has the highest priority when accessing LEDs. It means that some patterns set by ledctl may have no effect if ledmon is running (except Locate pattern). The ledctl application is a part of Intel(R) Enclosure LED Utilities. =head2 Pattern Names The ledctl application accepts the following names for I argument according to SFF-8489 specification. =over 8 =item B Turns Locate LED associated with the given device(s) or empty slot(s) on. =item B Turns only Locate LED off. =item B Turns Status LED, Failure LED and Locate LED off. =item B Turns only Status LED and Failure LED off. =item B or B Visualizes "In a Critical Array" pattern. =item B or B Visualizes "Rebuild" pattern. =item B or B Visualizes "In a Failed Array" pattern. =item B Visualizes "Hotspare" pattern. =item B Visualizes "Predicted Failure Analysis" pattern. =item B or B Visualizes "Failure" pattern. =item B SES-2 R/R ABORD =item B SES-2 REBUILD/REMAP =item B SES-2 IN FAILED ARRAY =item B SES-2 IN CRIT ARRAY =item B SES-2 CONS CHECK =item B SES-2 HOT SPARE =item B SES-2 RSVD DEVICE =item B SES-2 OK =item B SES-2 IDENT =item B SES-2 REMOVE =item B SES-2 INSERT =item B SES-2 MISSING =item B SES-2 DO NOT REMOVE =item B SES-2 ACTIVE =item B SES-2 ENABLE BYP B =item B SES-2 ENABLE BYP A =item B SES-2 DEVICE OFF =item B SES-2 FAULT =back =head2 Patterns Translation When non SES-2 pattern is send to device in enclosure automatic translation is being done. =over 8 =item B I is translated to I =item B I is translated to I<~ses_ident> =item B I is translated to I =item B I is translated to I =item B I is translated to I =item B I is translated to I =item B I is translated to I =item B I is translated to I =item B I is translated to I =item B I is translated to I =item B I is translated to I =item B I is translated to I =back =head2 List of Devices The application accepts a list of devices in two formats. The first format is a list with comma separated elements. The second format is S in curly braces and elements are separated by space. See examples section bellow for details. A device is a path to file in /dev directory or in /sys/block directory. It may identify a block device, a RAID device or a container device. In case of a RAID device or a container device a state will be set for all block devices associated, respectively. The LEDs of devices listed in I are set to the given pattern I and all other LEDs are turned off. =head1 OPTIONS =over 8 =item B<-c> or B<--config>=I Sets a path to local configuration file. If this option is specified the global configuration file and user configuration file has no effect. =item B<-l> or B<--log>=I Sets a path to local log file. If this option is specified the global log file F is not used. =item B<-h> or B<--help> Prints this text out and exits. =item B<-v> or B<--version> Displays version of ledctl and information about the license and exits. =back =head1 FILES =over 8 =item F Global log file, used by all instances of ledctl application. To force logging to user defined file use I<-l> option switch. =item F<~/.ledctl> User configuration file, shared between ledmon and all ledctl application instances. =item F Global configuration file, shared between ledmon and all ledctl application instances. =back =head1 EXAMPLES The following example illustrates how to locate a single block device. ledctl locate=/dev/sda The following example illustrates how to turn Locate LED off for the same block device. ledctl locate_off=/dev/sda The following example illustrates how to locate disks of a RAID device and how to set rebuild pattern for two block devices at the same time. This example uses both formats of device list. ledctl locate=/dev/md127 rebuild={ /sys/block/sd[a-b] } The following example illustrates how to turn Status LED and Failure LED off for the given device(s). ledctl off={ /dev/sda /dev/sdb } The following example illustrates how to locate a three block devices. This example uses the first format of device list. ledctl locate=/dev/sda,/dev/sdb,/dev/sdc =head1 LICENSE Copyright (c) 2009-2013 Intel Corporation. This program is distributed under the terms of the GNU General Public License as published by the Free Software Foundation. See the built-in help for details on the License and the lack of warranty. =head1 SEE ALSO ledmon(8), ledctl.conf(5) =head1 AUTHOR This manual page was written by Artur Wojcik . It may be used by others. ./ledmon-0.79/doc/ledctl.conf.5.gz000664 001750 001750 00000004105 12245410751 017352 0ustar00ldorauldorau000000 000000 RXmSH_l"L#lZ10yZcidk44Y}X3=O`MZBd"3OzN$Գ{2$Hґ_h")ͤ<5oK23R ORk9 -%y"4${erd^Ls镵 `^(miJH,{(cy,G)TjőfʓyΖ(U(`ӗb)5(" PPy-%>:wծ8[wrN:(v{vwuw66/qaZk1uNȎ}h_ +[݀72փǖ|c Y*p:8q; V>V*d;#NiC)đU<[8ٶV~ZcRI$p4(^_RoTUWbS s?>N߽Wdd=gN]^(4r׳U^ZVUTeF2m=Jr7SUć+rrJr}By!72d|mM2g鶌oxq bnhڃDBHlO%cvy2bu#̂ó=:W1zQAu;ȋT^`|7!5Y g~^]*f"J<8N?ZUݟR68p3)Bke%򄥉H2Peѝ43u}PY٠{ T\Kp>#@4wٮY,^J\_3C"mĿ[[.C,irp+S{g1_\ T㛓)]{"l-v6}a5ݏ9bڏfy) ԇ)2@K|&>81|蘫NwL<*23[c̤ 0G[׌Y0|=(Q֩|_J^tG;Q t*:nn^upԱ-!Jɑ1s&I4eé;oG$*vhPIw+?=)e^{Y"(oDl,8p8D8\JP,:ť[r Wُg #fa0jSC(a߲#s jEa8 0 ( ZO~ a9/h48:aw+wx?9eύQOsn%@fE +!/HR3̽'`9!d8Xt"o.rqpˌ32ްùe0wMNeߎ^1<{[Ehw[ľSRqTi;UUg=#.5_a꒸`xԇEcBn+v{>’өrgx4MjsL9l\V!ӄ/+꾊 `]z!i)z0w΁dEy 7FzcL!' Vs .h#B7#3 r8S_ۯҌ]|hDaFfw3hf>;yg0$^a~c+Sl"*3(JE ghpb(&!Fy=ǃȉ;-89 3rZs6ڴpG$I?c}:#}6]亪<b=l@!+Kd+d ِ$%wDT|pfjpyxIY QECr|DO64zqyohr^ΠJh:I"2y'm Gv kuҀG}%xhC3:Cx9=\ KҏY ̠^@6P8Ie<R-0;i08X[Y61\hPA)p%a8jDB+TsgENb3{7v ݴb}Vb8Z ЂN$<#OWlt|Au^uN9[Mfv}ě?Cd^T~04ݳrm[ 7PjY}I7G(xe*˥{ZPlR8>u\d R:+HMnB I 'XڲFZp].eĴbtD߂rWQ3 ({8S5q"~T5TOP|lq mbNȍb}'Xw O7 M K`C솤LZ6_ oթsWU+W )˷53NL&n B*RXKQqHN3ڬAJ!fK\1wSNʊњm;HyUp|,]f'af*g-++-5Q߆s`EcipOC;{rIc){ߊS@G>(P:YA(Ln0= =2r|޿TGԷq [6U X }hE|$opJ0br f9^nh,Y*yP:&\OK"4Y5jg x[ RRTRCxW.+165($v8QCDž TKt &7\ P3øA $DÇ{0o|\U\\+Re-қkzU6䎒} E' c6gmʤf' 1H4 lfZ2SL֕=<<ޘ*iFR6.E\gr[0Ih5dj:GTKC*X5p!n,V%[R-B|ݺef0a{&pܨ 'Qm>%ۙ%Q=!Q+WI/4frWepEdH*9 Q)W"/{zPG}oi `gpwGV܃S`7I LPչд*eC/V:ubPzt:>VLjlw JfWL7yT|;\7n [q羑DLi.Jt]{،`}9/5So(Ͷԋ{-T~6MjE>=\]H~fÕ=;^ % 9ۚ<~=>OZN5z%R#6֌l]FI#.osv*Yp n)'7:2V?v#bj|z9G?aa;mWx[D(;?"ס~ыgeAsJ3KZ:U}oVv/кTW/Ҫ .G*ZdsZ]'R0LqV֝F_(E wu _.8 #,Q-*jV2fC-X8jĕsdk*~ TXR *T“W| %juP}6=dsǪ)cjW~[Oҗtu?Sz\\Ej[kpbR5w=?iKM;#Ђ#nPYj@?ډ娏L5sF O(e+@SФTqU h`(& `Rnx_.a}o4?1 Հ(ȱdO, 6z{:2m8 jXTsIMF=kjԷF=jgʤ:Lf)/f";jF} aڭ%O^9/` "Kt i[8x.vV\ְIXttx\@`Oii`Cƒ+@ nŮ(~W_)qݚ'~D? uS*ɧ6|ur^V@?[fki#~)lpp[rJHVc^Ӈ9Gr6^-紘x>m:=6::z 7zb"CDwMΰ>"č23F8@zyK lXإJ(-1ȕ 1*p)tѹ:cii2Ldv]:]W,0(߬Ll|fU s߻'C0OX /z b]>G (-Һ׉7B xHڐZekAhd)L:5ku"'9tMK ?b)Z&kâQWtp6P0ׁ"aDo22YI}D'΃"1]"dHL,:c2+YXRln IlMc+@0[^8>dL2+h6Y_.~OCRqqݡ7Z A}clwvB.w3kQ$vy߻ze/Wn{HvJ c2莿bkэp n뵫۽]r'Pt }% :w\0(а`vL& t".U&d_Wp@䠂3-DJZ^&7bY5m OcAq)JM! 5UICdbN`)T9dYYNLww58+`sZjehc9@/Ŵ؀d!'0^/I+PM,BUU TԚ$cT2EeN1༔ Z*15xӟĔ;ϿMqK8P%`yг;&aYX 1wL{ALOޟOK s[N iPFT5WRBQN2lN,u!wWĴ lIgn+3 VjNWߏ7:{Gx{~ja+Jvq~.]v_ė+WTONFC4;gUKw>bq\޿3:>Kzt#<8lQd#7@}vulhZ !!CZr;0w@_H@yo\oގ g# "vŻtk ƌr:T #_i4,"q5_mc! o<evܥ`]G[eĮ>M> Nnd|t2bN>q99z6TC h N?eg7bMڽaBUM_q}<:#Y}#⺫4CAm0JUY"^Q(e"awOfnr9>Z %^4?-w`ڶ`.]1zv26xˌ322<28_<-Qa,#TFx ݕhVNe@3>xMX~s@iv'LЯxPa-_6E(AYߕ6I, mLMջնǻ@O6Ԍ (@С72\<F*2Jr^3pLntWq"C C"duGFXLf6έfB%Ƿ?p3޼<jQNycZӚ(ZԢ$^Ab `3bv2} NvQnb~jNy8=׉4[`zCZ0Gp!p%t kJD%M`ˈ%F -ޢ2z :1[;ЙJw@N'⮸V!I]b%[ VbyYj;$$AeW4=8q;fPϲ?3ސyx%G6*T)7TTjm,LpCקfS69^^ӧiS2lӡY*јvA=pBP@pHxbwuU`:>R4 RfajܓH,0 cE䟬;SʈG,[&&YB^WVy* Ub"3H\O[OO.w 5;m#Kc63+ECjD6,a kIETFRg9D^=+8`}A Bӄ=R3:)mBcBRm( y<϶NN)O͉'ݑR3wf>`Hη]0)GPӗl~! HWj#!7:5Z;/ rIif%LK7I1 2S$9얇=$`?K^]kT8=<RA ,U'K^"~VS2dt|X|Agz\*m GA B}'r'26`V u8!.Sx* AhGY,Kt\.fnSBK"0V`-I2r&5r`yS8a=d1̒<ɪHO5:Dݧ<}dZL_[~y"!K6ɔY~ ,1j]'/r` bF<>ricmG2?lh@AnMQdAG[Ny'Ct b[.NStvI*xwU_zz~n~oxi0,?G[ٖ`qJqJu24 *xrMܙS~=U7{C*fZP\[tP u墔R̛ Ry,s9I#$#An$ Fq~z0An^s/,+mJM%22G.'ƞ,ytqQMaIiR&ď Iŕe/llSn./ledmon-0.79/doc/ledctl.conf.pod000664 001750 001750 00000002666 12245410751 017363 0ustar00ldorauldorau000000 000000 # # Intel(R) Enclosure LED Utilities # Copyright (C) 2009-2013 Intel Corporation. # # This program is free software; you can redistribute it and/or modify it # under the terms and conditions of the GNU General Public License, # version 2, as published by the Free Software Foundation. # # This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. # =head1 NAME ledctl.conf - Configuration file for Intel(R) Enclosure LED Utilities. =head1 DESCRIPTION This feature is not yet implemented. The Intel(R) Enclosure LED Utilities does not use a configuration file at the moment. The name and location of file has been reserved for feature improvements. =head1 LICENSE Copyright (c) 2009-2013 Intel Corporation. This program is distributed under the terms of the GNU General Public License as published by the Free Software Foundation. See the built-in help for details on the License and the lack of warranty. =head1 SEE ALSO ledmon(8), ledctl(8) =head1 AUTHOR This manual page was written by Artur Wojcik . It may be used by others. ./ledmon-0.79/doc/ledmon.pod000664 001750 001750 00000010331 12245410751 016432 0ustar00ldorauldorau000000 000000 # # Intel(R) Enclosure LED Utilities # Copyright (C) 2009-2013 Intel Corporation. # # This program is free software; you can redistribute it and/or modify it # under the terms and conditions of the GNU General Public License, # version 2, as published by the Free Software Foundation. # # This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. # =head1 NAME ledmon - Intel(R) LED monitor service for storage enclosures. =head1 SYNOPSIS B [I] =head1 DESCRIPTION The ledmon application is a daemon process used to monitor a state of software RAID devices (md only) or a state of block devices. The state is visualizing on LEDs associated to each slot in an enclosure or a drive bay. There are two types of system: 2-LEDs system (Activity LED, Status LED) and 3-LEDs system (Activity LED, Locate LED, Fail LED). This application has the highest priority when accessing the LEDs. The ledmon application uses SGPIO and SES-2 protocol to control LEDs. The program implements IBPI patterns of SFF-8489 specification for SGPIO. Please note some enclosures do not stick close to SFF-8489 specification. It might happen that enclosure processor will accept IBPI pattern but it will blink LEDs not according to SFF-8489 specification or it has limited number of patterns supported. LED management (AHCI) and SAF-TE protocols are not supported. There's no method provided to specify which RAID volume should be monitored and which not. The ledmon application monitors all RAID devices and visualizes their state. The ledmon application has been verified to work with Intel(R) storage controllers (i.e. Intel(R) AHCI controller and Intel(R) SAS controller). The application might work with storage controllers of other vendors (especially SAS/SCSI controllers). However storage controllers of other vendors have not been tested. The ledmon application is part of Intel(R) Enclosure LED Utilities. Only single instance of the application is allowed. =head1 OPTIONS =over 8 =item B<-c> or B<--config>=I Sets a path to local configuration file. If this option is specified the global configuration file and user configuration file has no effect. =item B<-l> or B<--log>=I Sets a path to local log file. If this option is specified the global log file F is not used. =item B<-t> or B<--interval>=I Sets time interval between scans of sysfs. The value is given in seconds. The minimum is 5 seconds the maximum is not specified. =item B<--quiet> or B<--error> or B<--warning> or B<--info> or B<--debug> or B<--all> Verbose level - 'quiet' means no logging at all and 'all' means to log everything. The levels are given in order. If user specifies more then one verbose option the last option comes into effect. =item B<-h> or B<--help> Prints this text out and exits. =item B<-v> or B<--version> Displays version of ledmon and information about the license and exits. =back =head1 FILES =over 8 =item F Global log file, used by ledmon application. To force logging to user defined file use I<-l> option switch. =item F<~/.ledctl> User configuration file, shared between ledmon and all ledctl application instances. =item F Global configuration file, shared between ledmon and all ledctl application instances. =back =head1 LICENSE Copyright (c) 2009-2013 Intel Corporation. This program is distributed under the terms of the GNU General Public License as published by the Free Software Foundation. See the build-in help for details on the License and the lack of warranty. =head1 BUGS The ledmon application does not recognize PFA state (Predicted Failure Analysis), hence the PFA pattern from SFF-8489 specification is not visualized. =head1 SEE ALSO ledctl(8), ledctl.conf(5) =head1 AUTHOR This manual page was written by Artur Wojcik . It may be used by others.