diff options
Diffstat (limited to 'lib/ipmi_picmg.c')
| -rw-r--r-- | lib/ipmi_picmg.c | 2371 | 
1 files changed, 2371 insertions, 0 deletions
| diff --git a/lib/ipmi_picmg.c b/lib/ipmi_picmg.c new file mode 100644 index 0000000..d1c82b2 --- /dev/null +++ b/lib/ipmi_picmg.c @@ -0,0 +1,2371 @@ +/* +  Copyright (c) Kontron. All right reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Kontron, or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * DELL COMPUTERS ("DELL") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL + * DELL OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF DELL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/ipmi_picmg.h> +#include <ipmitool/ipmi_fru.h>		/* for access to link descriptor defines */ +#include <ipmitool/ipmi_strings.h> +#include <ipmitool/log.h> + +#define PICMG_EXTENSION_ATCA_MAJOR_VERSION  2 +#define PICMG_EXTENSION_AMC0_MAJOR_VERSION  4 +#define PICMG_EXTENSION_UTCA_MAJOR_VERSION  5 + + +#define PICMG_EKEY_MODE_QUERY          0 +#define PICMG_EKEY_MODE_PRINT_ALL      1 +#define PICMG_EKEY_MODE_PRINT_ENABLED  2 +#define PICMG_EKEY_MODE_PRINT_DISABLED 3 + +#define PICMG_EKEY_MAX_CHANNEL          16 +#define PICMG_EKEY_MAX_FABRIC_CHANNEL   15 +#define PICMG_EKEY_MAX_INTERFACE 3 + +#define PICMG_EKEY_AMC_MAX_CHANNEL  16 +#define PICMG_EKEY_AMC_MAX_DEVICE   15 /* 4 bits */ + + +typedef enum picmg_bused_resource_mode { +	PICMG_BUSED_RESOURCE_SUMMARY, +} t_picmg_bused_resource_mode ; + + +typedef enum picmg_card_type { +	PICMG_CARD_TYPE_CPCI, +	PICMG_CARD_TYPE_ATCA, +	PICMG_CARD_TYPE_AMC, +	PICMG_CARD_TYPE_RESERVED +} t_picmg_card_type ; + +/* This is the version of the PICMG Extenstion */ +static t_picmg_card_type PicmgCardType = PICMG_CARD_TYPE_RESERVED; + +void +ipmi_picmg_help (void) +{ +	lprintf(LOG_NOTICE, "PICMG commands:"); +	lprintf(LOG_NOTICE, " properties           - get PICMG properties"); +	lprintf(LOG_NOTICE, " frucontrol           - FRU control"); +	lprintf(LOG_NOTICE, " addrinfo             - get address information"); +	lprintf(LOG_NOTICE, " activate             - activate a FRU"); +	lprintf(LOG_NOTICE, " deactivate           - deactivate a FRU"); +	lprintf(LOG_NOTICE, " policy get           - get the FRU activation policy"); +	lprintf(LOG_NOTICE, " policy set           - set the FRU activation policy"); +	lprintf(LOG_NOTICE, " portstate get        - get port state"); +	lprintf(LOG_NOTICE, +			" portstate getdenied  - get all denied[disabled] port description"); +	lprintf(LOG_NOTICE, +			" portstate getgranted - get all granted[enabled] port description"); +	lprintf(LOG_NOTICE, +			" portstate getall     - get all port state description"); +	lprintf(LOG_NOTICE, " portstate set        - set port state"); +	lprintf(LOG_NOTICE, " amcportstate get     - get port state"); +	lprintf(LOG_NOTICE, " amcportstate set     - set port state"); +	lprintf(LOG_NOTICE, " led prop             - get led properties"); +	lprintf(LOG_NOTICE, " led cap              - get led color capabilities"); +	lprintf(LOG_NOTICE, " led get              - get led state"); +	lprintf(LOG_NOTICE, " led set              - set led state"); +	lprintf(LOG_NOTICE, " power get            - get power level info"); +	lprintf(LOG_NOTICE, " power set            - set power level"); +	lprintf(LOG_NOTICE, " clk get              - get clk state"); +	lprintf(LOG_NOTICE, +			" clk getdenied        - get all(up to 16) denied[disabled] clock descriptions"); +	lprintf(LOG_NOTICE, +			" clk getgranted       - get all(up to 16) granted[enabled] clock descriptions"); +	lprintf(LOG_NOTICE, +			" clk getall           - get all(up to 16) clock descriptions"); +	lprintf(LOG_NOTICE, " clk set              - set clk state"); +	lprintf(LOG_NOTICE, +			" busres summary       - display brief bused resource status info"); +} + + +struct sAmcAddrMap { +	unsigned char ipmbLAddr; +	char*         amcBayId; +	unsigned char siteNum; +} amcAddrMap[] = { +	{0xFF, "reserved", 0}, +	{0x72, "A1"      , 1}, +	{0x74, "A2"      , 2}, +	{0x76, "A3"      , 3}, +	{0x78, "A4"      , 4}, +	{0x7A, "B1"      , 5}, +	{0x7C, "B2"      , 6}, +	{0x7E, "B3"      , 7}, +	{0x80, "B4"      , 8}, +	{0x82, "reserved", 0}, +	{0x84, "reserved", 0}, +	{0x86, "reserved", 0}, +	{0x88, "reserved", 0}, +}; + +/* is_amc_channel - wrapper to convert user input into integer + * AMC Channel range seems to be <0..255>, bits [7:0] + * + * @argv_ptr: source string to convert from; usually argv + * @amc_chan_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_amc_channel(const char *argv_ptr, uint8_t *amc_chan_ptr) +{ +	if (!argv_ptr || !amc_chan_ptr) { +		lprintf(LOG_ERR, "is_amc_channel(): invalid argument(s)."); +		return (-1); +	} +	if (str2uchar(argv_ptr, amc_chan_ptr) == 0) { +		return 0; +	} +	lprintf(LOG_ERR, "Given AMC Channel '%s' is invalid.", argv_ptr); +	return (-1); +} +/* is_amc_dev - wrapper to convert user input into integer. + * AMC Dev ID limits are uknown. + * + * @argv_ptr: source string to convert from; usually argv + * @amc_dev_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_amc_dev(const char *argv_ptr, int32_t *amc_dev_ptr) +{ +	if (!argv_ptr || !amc_dev_ptr) { +		lprintf(LOG_ERR, "is_amc_dev(): invalid argument(s)."); +		return (-1); +	} +	if (str2int(argv_ptr, amc_dev_ptr) == 0 && *amc_dev_ptr >= 0) { +		return 0; +	} +	lprintf(LOG_ERR, "Given PICMG Device '%s' is invalid.", +			argv_ptr); +	return (-1); +} +/* is_amc_intf - wrapper to convert user input into integer. + * AMC Interface (ID) limits are uknown. + * + * @argv_ptr: source string to convert from; usually argv + * @amc_intf_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_amc_intf(const char *argv_ptr, int32_t *amc_intf_ptr) +{ +	if (!argv_ptr || !amc_intf_ptr) { +		lprintf(LOG_ERR, "is_amc_intf(): invalid argument(s)."); +		return (-1); +	} +	if (str2int(argv_ptr, amc_intf_ptr) == 0 && *amc_intf_ptr >= 0) { +		return 0; +	} +	lprintf(LOG_ERR, "Given PICMG Interface '%s' is invalid.", +			argv_ptr); +	return (-1); +} +/* is_amc_port - wrapper to convert user input into integer. + * AMC Port limits are uknown. + * + * @argv_ptr: source string to convert from; usually argv + * @amc_port_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_amc_port(const char *argv_ptr, int32_t *amc_port_ptr) +{ +	if (!argv_ptr || !amc_port_ptr) { +		lprintf(LOG_ERR, "is_amc_port(): invalid argument(s)."); +		return (-1); +	} +	if (str2int(argv_ptr, amc_port_ptr) == 0 && *amc_port_ptr >= 0) { +		return 0; +	} +	lprintf(LOG_ERR, "Given PICMG Port '%s' is invalid.", argv_ptr); +	return (-1); +} +/* is_clk_acc - wrapper to convert user input into integer. + * Clock Accuracy limits are uknown[1byte by spec]. + * + * @argv_ptr: source string to convert from; usually argv + * @clk_acc_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_clk_acc(const char *argv_ptr, uint8_t *clk_acc_ptr) +{ +	if (!argv_ptr || !clk_acc_ptr) { +		lprintf(LOG_ERR, "is_clk_acc(): invalid argument(s)."); +		return (-1); +	} +	if (str2uchar(argv_ptr, clk_acc_ptr) == 0) { +		return 0; +	} +	lprintf(LOG_ERR, "Given Clock Accuracy '%s' is invalid.", +			argv_ptr); +	return (-1); +} +/* is_clk_family - wrapper to convert user input into integer. + * Clock Family limits are uknown[1byte by spec]. + * + * @argv_ptr: source string to convert from; usually argv + * @clk_family_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_clk_family(const char *argv_ptr, uint8_t *clk_family_ptr) +{ +	if (!argv_ptr || !clk_family_ptr) { +		lprintf(LOG_ERR, "is_clk_family(): invalid argument(s)."); +		return (-1); +	} +	if (str2uchar(argv_ptr, clk_family_ptr) == 0) { +		return 0; +	} +	lprintf(LOG_ERR, "Given Clock Family '%s' is invalid.", +			argv_ptr); +	return (-1); +} +/* is_clk_freq - wrapper to convert user input into integer. + * Clock Frequency limits are uknown, but specification says + * 3Bytes + 1B checksum + * + * @argv_ptr: source string to convert from; usually argv + * @clk_freq_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_clk_freq(const char *argv_ptr, uint32_t *clk_freq_ptr) +{ +	if (!argv_ptr || !clk_freq_ptr) { +		lprintf(LOG_ERR, "is_clk_freq(): invalid argument(s)."); +		return (-1); +	} +	if (str2uint(argv_ptr, clk_freq_ptr) == 0) { +		return 0; +	} +	lprintf(LOG_ERR, "Given Clock Frequency '%s' is invalid.", +			argv_ptr); +	return (-1); +} +/* is_clk_id - wrapper to convert user input into integer. + * Clock ID limits are uknown, however it's 1B by specification and I've + * found two ranges: <1..5> or <0..15> + * + * @argv_ptr: source string to convert from; usually argv + * @clk_id_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_clk_id(const char *argv_ptr, uint8_t *clk_id_ptr) +{ +	if (!argv_ptr || !clk_id_ptr) { +		lprintf(LOG_ERR, "is_clk_id(): invalid argument(s)."); +		return (-1); +	} +	if (str2uchar(argv_ptr, clk_id_ptr) == 0) { +		return 0; +	} +	lprintf(LOG_ERR, "Given Clock ID '%s' is invalid.", argv_ptr); +	return (-1); +} +/* is_clk_index - wrapper to convert user input into integer. + * Clock Index limits are uknown[1B by spec] + * + * @argv_ptr: source string to convert from; usually argv + * @clk_index_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_clk_index(const char *argv_ptr, uint8_t *clk_index_ptr) +{ +	if (!argv_ptr || !clk_index_ptr) { +		lprintf(LOG_ERR, "is_clk_index(): invalid argument(s)."); +		return (-1); +	} +	if (str2uchar(argv_ptr, clk_index_ptr) == 0) { +		return 0; +	} +	lprintf(LOG_ERR, "Given Clock Index '%s' is invalid.", argv_ptr); +	return (-1); +} +/* is_clk_resid - wrapper to convert user input into integer. + * Clock Resource Index(?) limits are uknown, but maximum seems to be 15. + * + * @argv_ptr: source string to convert from; usually argv + * @clk_resid_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_clk_resid(const char *argv_ptr, int8_t *clk_resid_ptr) +{ +	if (!argv_ptr || !clk_resid_ptr) { +		lprintf(LOG_ERR, "is_clk_resid(): invalid argument(s)."); +		return (-1); +	} +	if (str2char(argv_ptr, clk_resid_ptr) == 0 +			&& *clk_resid_ptr > (-1)) { +		return 0; +	} +	lprintf(LOG_ERR, "Given Resource ID '%s' is invalid.", +			clk_resid_ptr); +	return (-1); +} +/* is_clk_setting - wrapper to convert user input into integer. + * Clock Setting is a 1B bitfield: + * x [7:4] - reserved + * x [3] - state - 0/1 + * x [2] - direction - 0/1 + * x [1:0] - PLL ctrl - 00/01/10/11[Reserved] + * + * @argv_ptr: source string to convert from; usually argv + * @clk_setting_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_clk_setting(const char *argv_ptr, uint8_t *clk_setting_ptr) +{ +	if (!argv_ptr || !clk_setting_ptr) { +		lprintf(LOG_ERR, "is_clk_setting(): invalid argument(s)."); +		return (-1); +	} +	if (str2uchar(argv_ptr, clk_setting_ptr) == 0) { +		return 0; +	} +	/* FIXME - validate bits 4-7 are 0 ? */ +	lprintf(LOG_ERR, "Given Clock Setting '%s' is invalid.", argv_ptr); +	return (-1); +} +/* is_enable - wrapper to convert user input into integer. + * Valid input range for Enable is <0..1>. + * + * @argv_ptr: source string to convert from; usually argv + * @enable_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_enable(const char *argv_ptr, uint8_t *enable_ptr) +{ +	if (!argv_ptr || !enable_ptr) { +		lprintf(LOG_ERR, "is_enable(): invalid argument(s)."); +		return (-1); +	} +	if (str2uchar(argv_ptr, enable_ptr) == 0 +			&& (*enable_ptr == 0 || *enable_ptr == 1)) { +		return 0; +	} +	lprintf(LOG_ERR, "Given Enable '%s' is invalid.", argv_ptr); +	return (-1); +} +/* is_enable - wrapper to convert user input into integer. + * LED colors:  + * - valid <1..6>, <0xE..0xF> + * - reserved [0, 7] + * - undefined <8..D> + * + * @argv_ptr: source string to convert from; usually argv + * @enable_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_led_color(const char *argv_ptr, uint8_t *led_color_ptr) +{ +	if (!argv_ptr || !led_color_ptr) { +		lprintf(LOG_ERR, "is_led_color(): invalid argument(s)."); +		return (-1); +	} +	if (str2uchar(argv_ptr, led_color_ptr) != 0) { +		lprintf(LOG_ERR, "Given LED Color '%s' is invalid.", +				argv_ptr); +		lprintf(LOG_ERR, +				"LED Color must be from ranges: <1..6>, <0xE..0xF>"); +		return (-1); +	} +	if ((*led_color_ptr >= 1 && *led_color_ptr <= 6) +			|| (*led_color_ptr >= 0xE && *led_color_ptr <= 0xF)) { +		return 0; +	} +	lprintf(LOG_ERR, "Given LED Color '%s' is out of range.", argv_ptr); +	lprintf(LOG_ERR, "LED Color must be from ranges: <1..6>, <0xE..0xF>"); +	return (-1); +} +/* is_led_duration - wrapper to convert user input into integer. + * LED duration range is <1..127> + * + * @argv_ptr: source string to convert from; usually argv + * @enable_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_led_duration(const char *argv_ptr, uint8_t *led_duration_ptr) +{ +	if (!argv_ptr || !led_duration_ptr) { +		lprintf(LOG_ERR, "is_led_duration(): invalid argument(s)."); +		return (-1); +	} +	if (str2uchar(argv_ptr, led_duration_ptr) == 0 +			&& *led_duration_ptr > 0 && *led_duration_ptr <= 127) { +		return 0; +	} +	lprintf(LOG_ERR, "Given LED Duration '%s' is invalid", argv_ptr); +	return (-1); +} +/* is_led_function - wrapper to convert user input into integer. + * LED functions, however, might differ by OEM: + * - 0x00 - off override + * - <0x01..0xFA> - blinking override + * - 0xFB - lamp test state + * - 0xFC - state restored to local ctrl state + * - <0xFD..0xFE> - reserved + * - 0xFF - on override + * + * @argv_ptr: source string to convert from; usually argv + * @led_fn_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_led_function(const char *argv_ptr, uint8_t *led_fn_ptr) +{ +	if (!argv_ptr || !led_fn_ptr) { +		lprintf(LOG_ERR, "is_led_function(): invalid argument(s)."); +		return (-1); +	} +	if (str2uchar(argv_ptr, led_fn_ptr) == 0 +			&& (*led_fn_ptr < 0xFD || *led_fn_ptr > 0xFE)) { +		return 0; +	} +	lprintf(LOG_ERR, "Given LED Function '%s' is invalid.", argv_ptr); +	return (-1); +} +/* is_led_id - wrapper to convert user input into integer. + * LED ID range seems to be <0..255> + * + * @argv_ptr: source string to convert from; usually argv + * @led_id_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_led_id(const char *argv_ptr, uint8_t *led_id_ptr) +{ +	if (!argv_ptr || !led_id_ptr) { +		lprintf(LOG_ERR, "is_led_id(): invalid argument(s)."); +		return (-1); +	} +	if (str2uchar(argv_ptr, led_id_ptr) == 0) { +		return 0; +	} +	lprintf(LOG_ERR, "Given LED ID '%s' is invalid.", argv_ptr); +	return (-1); +} +/* is_link_group - wrapper to convert user input into integer. + * Link Grouping ID limis are unknown, bits [31:24] by spec. + * + * @argv_ptr: source string to convert from; usually argv + * @link_grp_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_link_group(const char *argv_ptr, uint8_t *link_grp_ptr) +{ +	if (!argv_ptr || !link_grp_ptr) { +		lprintf(LOG_ERR, "is_link_group(): invalid argument(s)."); +		return (-1); +	} +	if (str2uchar(argv_ptr, link_grp_ptr) == 0) { +		return 0; +	} +	lprintf(LOG_ERR, "Given Link Group '%s' is invalid.", argv_ptr); +	return (-1); +} +/* is_link_type - wrapper to convert user input into integer. + * Link Type limits are unknown, bits [19:12] + * + * @argv_ptr: source string to convert from; usually argv + * @link_type_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_link_type(const char *argv_ptr, uint8_t *link_type_ptr) +{ +	if (!argv_ptr || !link_type_ptr) { +		lprintf(LOG_ERR, "is_link_type(): invalid argument(s)."); +		return (-1); +	} +	if (str2uchar(argv_ptr, link_type_ptr) == 0) { +		return 0; +	} +	lprintf(LOG_ERR, "Given Link Type '%s' is invalid.", argv_ptr); +	return (-1); +} +/* is_link_type_ext - wrapper to convert user input into integer. + * Link Type Extension limits are unknown, bits [23:20] => <0..15> ? + * + * @argv_ptr: source string to convert from; usually argv + * @link_type_ext_ptr: pointer where to store result + * returns: zero on success, other values mean error + */ +int +is_link_type_ext(const char *argv_ptr, uint8_t *link_type_ext_ptr) +{ +	if (!argv_ptr || !link_type_ext_ptr) { +		lprintf(LOG_ERR, "is_link_type_ext(): invalid argument(s)."); +		return (-1); +	} +	if (str2uchar(argv_ptr, link_type_ext_ptr) != 0 +			|| *link_type_ext_ptr > 15) { +		lprintf(LOG_ERR, +				"Given Link Type Extension '%s' is invalid.", +				argv_ptr); +		return (-1); +	} +	return 0; +} + +int +ipmi_picmg_getaddr(struct ipmi_intf * intf, int argc, char ** argv) +{ +	struct ipmi_rs * rsp; +	struct ipmi_rq req; +	unsigned char msg_data[5]; + +	memset(&req, 0, sizeof(req)); +	req.msg.netfn = IPMI_NETFN_PICMG; +	req.msg.cmd = PICMG_GET_ADDRESS_INFO_CMD; +	req.msg.data = msg_data; +	req.msg.data_len = 2; +	msg_data[0] = 0;   /* picmg identifier */ +	msg_data[1] = 0;   /* default fru id */ + +	if(argc > 0) { +		if (is_fru_id(argv[0], &msg_data[1]) != 0) { +			return (-1); +		} +	} + +	rsp = intf->sendrecv(intf, &req); +	if (!rsp) { +		lprintf(LOG_ERR, "Error. No valid response received."); +		return (-1); +	} else if (rsp->ccode) { +		lprintf(LOG_ERR, "Error getting address information CC: 0x%02x", +				rsp->ccode); +		return (-1); +	} + +	printf("Hardware Address : 0x%02x\n", rsp->data[1]); +	printf("IPMB-0 Address   : 0x%02x\n", rsp->data[2]); +	printf("FRU ID           : 0x%02x\n", rsp->data[4]); +	printf("Site ID          : 0x%02x\n", rsp->data[5]); + +	printf("Site Type        : "); +	switch (rsp->data[6]) { +	case PICMG_ATCA_BOARD: +		printf("ATCA board\n"); +		break; +	case PICMG_POWER_ENTRY: +		printf("Power Entry Module\n"); +		break; +	case PICMG_SHELF_FRU: +		printf("Shelf FRU\n"); +		break; +	case PICMG_DEDICATED_SHMC: +		printf("Dedicated Shelf Manager\n"); +		break; +	case PICMG_FAN_TRAY: +		printf("Fan Tray\n"); +		break; +	case PICMG_FAN_FILTER_TRAY: +		printf("Fan Filter Tray\n"); +		break; +	case PICMG_ALARM: +		printf("Alarm module\n"); +		break; +	case PICMG_AMC: +		printf("AMC"); +		printf("  -> IPMB-L Address: 0x%02x\n", amcAddrMap[rsp->data[5]].ipmbLAddr); +		break; +	case PICMG_PMC: +		printf("PMC\n"); +		break; +	 case PICMG_RTM: +		printf("RTM\n"); +		break; +	default: +		if (rsp->data[6] >= 0xc0 && rsp->data[6] <= 0xcf) { +			printf("OEM\n"); +		} else { +			printf("unknown\n"); +		} +	} + +	return 0; +} + +int +ipmi_picmg_properties(struct ipmi_intf * intf, int show ) +{ +	unsigned char PicmgExtMajorVersion; +	struct ipmi_rs * rsp; +	struct ipmi_rq req; +	unsigned char msg_data; + +	memset(&req, 0, sizeof(req)); +	req.msg.netfn    = IPMI_NETFN_PICMG; +	req.msg.cmd      = PICMG_GET_PICMG_PROPERTIES_CMD; +	req.msg.data     = &msg_data; +	req.msg.data_len = 1; +	msg_data = 0; + +	rsp = intf->sendrecv(intf, &req); +	if (!rsp  || rsp->ccode) { +		lprintf(LOG_ERR, "Error getting address information."); +		return -1; +	} + +	if( show ) +	{ +		printf("PICMG identifier	: 0x%02x\n", rsp->data[0]); +		printf("PICMG Ext. Version : %i.%i\n",	 rsp->data[1]&0x0f, +															 (rsp->data[1]&0xf0) >> 4); +		printf("Max FRU Device ID	: 0x%02x\n", rsp->data[2]); +		printf("FRU Device ID		: 0x%02x\n", rsp->data[3]); +	} + +   /* We cache the major extension version ... +      to know how to format some commands */ +	PicmgExtMajorVersion = rsp->data[1]&0x0f; + +	if( PicmgExtMajorVersion == PICMG_CPCI_MAJOR_VERSION  ) {  +		PicmgCardType = PICMG_CARD_TYPE_CPCI; +   } +	else if(  PicmgExtMajorVersion == PICMG_ATCA_MAJOR_VERSION) { +		PicmgCardType = PICMG_CARD_TYPE_ATCA; +   } +	else if(  PicmgExtMajorVersion == PICMG_AMC_MAJOR_VERSION) { +		PicmgCardType = PICMG_CARD_TYPE_AMC; +   } +     +	return 0; +} + + + +#define PICMG_FRU_DEACTIVATE	(unsigned char) 0x00 +#define PICMG_FRU_ACTIVATE	(unsigned char) 0x01 + +int +ipmi_picmg_fru_activation(struct ipmi_intf * intf, int argc, char ** argv, unsigned char state) +{ +	struct ipmi_rs * rsp; +	struct ipmi_rq req; + +	struct picmg_set_fru_activation_cmd cmd; + +	memset(&req, 0, sizeof(req)); +	req.msg.netfn    = IPMI_NETFN_PICMG; +	req.msg.cmd      = PICMG_FRU_ACTIVATION_CMD; +	req.msg.data     = (unsigned char*) &cmd; +	req.msg.data_len = 3; + +	cmd.picmg_id  = 0;						/* PICMG identifier */ +	if (is_fru_id(argv[0], &(cmd.fru_id)) != 0) { +		return (-1); +	} +	cmd.fru_state = state; + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp  || rsp->ccode) { +		lprintf(LOG_ERR, "Error activation/deactivation of FRU."); +		return -1; +	} +	if (rsp->data[0] != 0x00) { +		lprintf(LOG_ERR, "Error activation/deactivation of FRU."); +	} + +	return 0; +} + + +int +ipmi_picmg_fru_activation_policy_get(struct ipmi_intf * intf, int argc, char ** argv) +{ +	struct ipmi_rs * rsp; +	struct ipmi_rq req; + +	unsigned char msg_data[4]; + +	memset(&req, 0, sizeof(req)); +	req.msg.netfn    = IPMI_NETFN_PICMG; +	req.msg.cmd      = PICMG_GET_FRU_POLICY_CMD; +	req.msg.data     = msg_data; +	req.msg.data_len = 2; + +	msg_data[0] = 0;								/* PICMG identifier */ +	if (is_fru_id(argv[0], &msg_data[1]) != 0) { +		return (-1); +	} + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp) { +		lprintf(LOG_ERR, "No valid response received."); +		return -1; +	} +	if (rsp->ccode) { +		lprintf(LOG_ERR, "FRU activation policy get failed with CC code 0x%02x", +				rsp->ccode); +		return -1; +	} + +	printf(" %s\n", ((rsp->data[1] & 0x01) == 0x01) ? +	                           "activation locked" : "activation not locked"); +	printf(" %s\n", ((rsp->data[1] & 0x02) == 0x02) ? +	                            "deactivation locked" : "deactivation not locked"); + +	return 0; +} + +int +ipmi_picmg_fru_activation_policy_set(struct ipmi_intf * intf, int argc, char ** argv) +{ +	struct ipmi_rs * rsp; +	struct ipmi_rq req; + +	unsigned char msg_data[4]; + +	memset(&req, 0, sizeof(req)); +	req.msg.netfn    = IPMI_NETFN_PICMG; +	req.msg.cmd      = PICMG_SET_FRU_POLICY_CMD; +	req.msg.data     = msg_data; +	req.msg.data_len = 4; + +	msg_data[0] = 0;								            /* PICMG identifier */ +	if (is_fru_id(argv[0], &msg_data[1]) != 0) { +		return (-1); +	} +	if (str2uchar(argv[1], &msg_data[2]) != 0 || msg_data[2] > 1) { +		/* FRU Lock Mask */ +		lprintf(LOG_ERR, "Given FRU Lock Mask '%s' is invalid.", +				argv[1]); +		return (-1); +	} +	if (str2uchar(argv[2], &msg_data[3]) != 0 || msg_data[3] > 1) { +		/* FRU Act Policy */ +		lprintf(LOG_ERR, +				"Given FRU Activation Policy '%s' is invalid.", +				argv[2]); +		return (-1); +	} +	msg_data[2]&= 0x03; +	msg_data[3]&= 0x03; + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp) { +		lprintf(LOG_ERR, "No valid response received."); +		return -1; +	} + +	if (rsp->ccode) { +		lprintf(LOG_ERR, "FRU activation policy set failed with CC code 0x%02x", +				rsp->ccode); +		return -1; +	} + +	return 0; +} + +#define PICMG_MAX_LINK_PER_CHANNEL 4 + +int +ipmi_picmg_portstate_get(struct ipmi_intf * intf, int32_t interface, +		uint8_t channel, int mode) +{ +	struct ipmi_rs * rsp = NULL; +	struct ipmi_rq req; + +	unsigned char msg_data[4]; + +	struct fru_picmgext_link_desc* d; /* descriptor pointer for rec. data */ + +	memset(&req, 0, sizeof(req)); + +	req.msg.netfn    = IPMI_NETFN_PICMG; +	req.msg.cmd      = PICMG_GET_PORT_STATE_CMD; +	req.msg.data     = msg_data; +	req.msg.data_len = 2; + +	msg_data[0] = 0x00;						/* PICMG identifier */ +	msg_data[1] = (interface & 0x3)<<6;	/* interface      */ +	msg_data[1] |= (channel & 0x3F);	/* channel number */ + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp) { +		lprintf(LOG_ERR, "No valid response received."); +		return -1; +	} + +	if (rsp->ccode) { +		if( mode == PICMG_EKEY_MODE_QUERY ){ +			lprintf(LOG_ERR, "FRU portstate get failed with CC code 0x%02x", +					rsp->ccode); +		} +		return -1; +	} + +	if (rsp->data_len >= 6) { +		int index; +		/* add support for more than one link per channel */ +		for(index=0;index<PICMG_MAX_LINK_PER_CHANNEL;index++){ +			if( rsp->data_len > (1+ (index*5))){ +				d = (struct fru_picmgext_link_desc *) &(rsp->data[1 + (index*5)]); + +				if +				( +					mode == PICMG_EKEY_MODE_PRINT_ALL +					|| +					mode == PICMG_EKEY_MODE_QUERY +					|| +					( +						mode == PICMG_EKEY_MODE_PRINT_ENABLED +						&& +						rsp->data[5 + (index*5) ] == 0x01 +					) +					|| +					( +						mode == PICMG_EKEY_MODE_PRINT_DISABLED +						&& +						rsp->data[5 + (index*5) ] == 0x00 +					) +				) +				{ +					printf("      Link Grouping ID:     0x%02x\n", d->grouping); +					printf("      Link Type Extension:  0x%02x\n", d->ext); +					printf("      Link Type:            0x%02x  ", d->type); +					if (d->type == 0 || d->type == 0xff) +					{ +						printf("Reserved %d\n",d->type); +					} +					else if (d->type >= 0x06 && d->type <= 0xef) +					{ +						printf("Reserved\n"); +					} +					else if (d->type >= 0xf0 && d->type <= 0xfe) +					{ +						printf("OEM GUID Definition\n"); +					} +					else +					{ +						switch (d->type) +						{ +							case FRU_PICMGEXT_LINK_TYPE_BASE: +								printf("PICMG 3.0 Base Interface 10/100/1000\n"); +							break; +							case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET: +								printf("PICMG 3.1 Ethernet Fabric Interface\n"); +							break; +							case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND: +								printf("PICMG 3.2 Infiniband Fabric Interface\n"); +							break; +							case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR: +								printf("PICMG 3.3 Star Fabric Interface\n"); +							break; +							case  FRU_PICMGEXT_LINK_TYPE_PCIE: +								printf("PCI Express Fabric Interface\n"); +							break; +							default: +							printf("Invalid\n"); +							break; +						} +					} +					printf("      Link Designator: \n"); +					printf("        Port Flag:          0x%02x\n", d->desig_port); +					printf("        Interface:          0x%02x - ", d->desig_if); +					switch (d->desig_if) +					{ +						case FRU_PICMGEXT_DESIGN_IF_BASE: +							printf("Base Interface\n"); +						break; +						case FRU_PICMGEXT_DESIGN_IF_FABRIC: +							printf("Fabric Interface\n"); +						break; +						case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL: +							printf("Update Channel\n"); +						break; +						case FRU_PICMGEXT_DESIGN_IF_RESERVED: +							printf("Reserved\n"); +						break; +						default: +							printf("Invalid"); +						break; +					} +					printf("        Channel Number:     0x%02x\n", d->desig_channel); +					printf("      STATE:                %s\n", +							( rsp->data[5 +(index*5)] == 0x01) ?"enabled":"disabled"); +					printf("\n"); +				} +			} +		} +	} +	else +	{ +		lprintf(LOG_ERR, "Unexpected answer, can't print result."); +	} + +	return 0; +} + + +int +ipmi_picmg_portstate_set(struct ipmi_intf * intf, int32_t interface, +		uint8_t channel, int32_t port, uint8_t type, +		uint8_t typeext, uint8_t group, uint8_t enable) +{ +	struct ipmi_rs * rsp; +	struct ipmi_rq req; + +	unsigned char msg_data[6]; + +	memset(&req, 0, sizeof(req)); + +	req.msg.netfn    = IPMI_NETFN_PICMG; +	req.msg.cmd      = PICMG_SET_PORT_STATE_CMD; +	req.msg.data     = msg_data; +	req.msg.data_len = 6; + +	msg_data[0] = 0x00;												/* PICMG identifier */ +	msg_data[1] = (channel & 0x3f) | ((interface & 3) << 6); +	msg_data[2] = (port & 0xf) | ((type & 0xf) << 4); +	msg_data[3] = ((type >> 4) & 0xf) | ((typeext & 0xf) << 4); +	msg_data[4] = group & 0xff; +	msg_data[5] = (enable & 0x01); /* enable/disable */ + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp) { +		lprintf(LOG_ERR, "No valid response received."); +		return -1; +	} + +	if (rsp->ccode) { +		lprintf(LOG_ERR, "Picmg portstate set failed with CC code 0x%02x", +				rsp->ccode); +		return -1; +	} + +	return 0; +} + + + +/* AMC.0 commands */ + +#define PICMG_AMC_MAX_LINK_PER_CHANNEL 4 + +int +ipmi_picmg_amc_portstate_get(struct ipmi_intf * intf, int32_t device, +		uint8_t channel, int mode) +{ +	struct ipmi_rs * rsp; +	struct ipmi_rq req; + +	unsigned char msg_data[4]; + +	struct fru_picmgext_amc_link_info* d; /* descriptor pointer for rec. data */ + +	memset(&req, 0, sizeof(req)); + +	req.msg.netfn	  = IPMI_NETFN_PICMG; +	req.msg.cmd		  = PICMG_AMC_GET_PORT_STATE_CMD; +	req.msg.data	  = msg_data; + +	/* FIXME : add check for AMC or carrier device */ +	if(device == -1 || PicmgCardType != PICMG_CARD_TYPE_ATCA ){ +		req.msg.data_len = 2;	/* for amc only channel */ +	}else{ +		req.msg.data_len = 3;	/* for carrier channel and device */ +	} + +	msg_data[0] = 0x00;						/* PICMG identifier */ +	msg_data[1] = channel ; +	msg_data[2] = device ; + + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp) { +		lprintf(LOG_ERR, "No valid response received."); +		return -1; +	} + +	if (rsp->ccode) { +		if( mode == PICMG_EKEY_MODE_QUERY ){ +			lprintf(LOG_ERR, "Amc portstate get failed with CC code 0x%02x", +					rsp->ccode); +		} +		return -1; +	} + +	if (rsp->data_len >= 5) { +		int index; + +		/* add support for more than one link per channel */ +		for(index=0;index<PICMG_AMC_MAX_LINK_PER_CHANNEL;index++){ + +			if( rsp->data_len > (1+ (index*4))){ +				unsigned char type; +				unsigned char ext; +				unsigned char grouping; +				unsigned char port; +				unsigned char enabled; +				d = (struct fru_picmgext_amc_link_info *)&(rsp->data[1 + (index*4)]); + + +				/* Removed endianness check here, probably not required +					as we dont use bitfields  */ +				port = d->linkInfo[0] & 0x0F; +				type = ((d->linkInfo[0] & 0xF0) >> 4 )|(d->linkInfo[1] & 0x0F ); +				ext  = ((d->linkInfo[1] & 0xF0) >> 4 ); +				grouping = d->linkInfo[2]; + + +				enabled =  rsp->data[4 + (index*4) ]; + +				if +				( +					mode == PICMG_EKEY_MODE_PRINT_ALL +					|| +					mode == PICMG_EKEY_MODE_QUERY +					|| +					( +						mode == PICMG_EKEY_MODE_PRINT_ENABLED +						&& +						enabled == 0x01 +					) +					|| +					( +						mode == PICMG_EKEY_MODE_PRINT_DISABLED +						&& +						enabled	== 0x00 +					) +				) +				{ +					if(device == -1 || PicmgCardType != PICMG_CARD_TYPE_ATCA ){ +						printf("   Link device :         AMC\n"); +					}else{ +                  printf("   Link device :         0x%02x\n", device ); +					} + +					printf("   Link Grouping ID:     0x%02x\n", grouping); + +					if (type == 0 || type == 1 ||type == 0xff) +					{ +						printf("   Link Type Extension:  0x%02x\n", ext); +						printf("   Link Type:            Reserved\n"); +					} +					else if (type >= 0xf0 && type <= 0xfe) +					{ +						printf("   Link Type Extension:  0x%02x\n", ext); +						printf("   Link Type:            OEM GUID Definition\n"); +					} +					else +					{ +						if (type <= FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE ) +						{ +							printf("   Link Type Extension:  %s\n", +                                      amc_link_type_ext_str[type][ext]); +							printf("   Link Type:            %s\n", +                                      amc_link_type_str[type]); +						} +						else{ +							printf("   Link Type Extension:  0x%02x\n", ext); +							printf("   Link Type:            undefined\n"); +						} +					} +					printf("   Link Designator: \n"); +					printf("      Channel Number:    0x%02x\n", channel); +					printf("      Port Flag:         0x%02x\n", port ); +					printf("   STATE:                %s\n", +                              ( enabled == 0x01 )?"enabled":"disabled"); +					printf("\n"); +				} +			} +		} +	} +	else +	{ +		lprintf(LOG_NOTICE,"ipmi_picmg_amc_portstate_get"\ +							"Unexpected answer, can't print result"); +	} + +	return 0; +} + + +int +ipmi_picmg_amc_portstate_set(struct ipmi_intf * intf, uint8_t channel, +		int32_t port, uint8_t type, uint8_t typeext, +		uint8_t group, uint8_t enable, int32_t device) +{ +	struct ipmi_rs	 * rsp; +	struct ipmi_rq	 req; +	unsigned char	 msg_data[7]; + +	memset(&req, 0, sizeof(req)); + +	req.msg.netfn	  = IPMI_NETFN_PICMG; +	req.msg.cmd		  = PICMG_AMC_SET_PORT_STATE_CMD; +	req.msg.data	  = msg_data; + +	msg_data[0]	 = 0x00;						 /* PICMG identifier*/ +	msg_data[1]	 = channel;					 /* channel id */ +	msg_data[2]	 = port & 0xF;				 /* port flags */ +	msg_data[2] |= (type & 0x0F)<<4;		 /* type	 */ +	msg_data[3]	 = (type & 0xF0)>>4;		 /* type */ +	msg_data[3] |= (typeext & 0x0F)<<4;	 /* extension */ +	msg_data[4]	 = (group & 0xFF);		 /* group */ +	msg_data[5]	 = (enable & 0x01);		 /* state */ +	req.msg.data_len = 6; + +	/* device id - only for carrier needed */ +	if (device >= 0) { +		msg_data[6]	 = device; +		req.msg.data_len = 7; +	} + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp) { +		lprintf(LOG_ERR, "No valid response received."); +		return -1; +	} + +	if (rsp->ccode) { +		lprintf(LOG_ERR, "Amc portstate set failed with CC code 0x%02x", +				rsp->ccode); +		return -1; +	} + +	return 0; +} + + +int +ipmi_picmg_get_led_properties(struct ipmi_intf * intf, int argc, char ** argv) +{ +	struct ipmi_rs * rsp; +	struct ipmi_rq req; + +	unsigned char msg_data[6]; + +	memset(&req, 0, sizeof(req)); + +	req.msg.netfn = IPMI_NETFN_PICMG; +	req.msg.cmd	  = PICMG_GET_FRU_LED_PROPERTIES_CMD; +	req.msg.data  = msg_data; +	req.msg.data_len = 2; + +	msg_data[0] = 0x00;									/* PICMG identifier */ +	if (is_fru_id(argv[0], &msg_data[1]) != 0) { +		return (-1); +	} + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp) { +		lprintf(LOG_ERR, "No valid response received."); +		return -1; +	} + +	if (rsp->ccode) { +		lprintf(LOG_ERR, "LED get properties failed with CC code 0x%02x", +				rsp->ccode); +		return -1; +	} + +	printf("General Status LED Properties:  0x%2x\n", rsp->data[1] ); +	printf("App. Specific  LED Count:       0x%2x\n", rsp->data[2] ); + +	return 0; +} + +int +ipmi_picmg_get_led_capabilities(struct ipmi_intf * intf, int argc, char ** argv) +{ +	int i; +	struct ipmi_rs * rsp; +	struct ipmi_rq req; + +	unsigned char msg_data[6]; + +	memset(&req, 0, sizeof(req)); + +	req.msg.netfn = IPMI_NETFN_PICMG; +	req.msg.cmd	  = PICMG_GET_LED_COLOR_CAPABILITIES_CMD; +	req.msg.data  = msg_data; +	req.msg.data_len = 3; + +	msg_data[0] = 0x00;									/* PICMG identifier */ +	if (is_fru_id(argv[0], &msg_data[1]) != 0 +			|| is_led_id(argv[1], &msg_data[2]) != 0) { +		return (-1); +	} + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp) { +		lprintf(LOG_ERR, "No valid response received."); +		return -1; +	} + +	if (rsp->ccode) { +		lprintf(LOG_ERR, "LED get capabilities failed with CC code 0x%02x", +				rsp->ccode); +		return -1; +	} + +	printf("LED Color Capabilities: "); +	for ( i=0 ; i<8 ; i++ ) { +		if ( rsp->data[1] & (0x01 << i) ) { +			printf("%s, ", led_color_str[ i ]); +		} +	} +	printf("\n"); + +	printf("Default LED Color in\n"); +	printf("      LOCAL control:  %s\n", led_color_str[ rsp->data[2] ] ); +	printf("      OVERRIDE state: %s\n", led_color_str[ rsp->data[3] ] ); + +	return 0; +} + +int +ipmi_picmg_get_led_state(struct ipmi_intf * intf, int argc, char ** argv) +{ +	struct ipmi_rs * rsp; +	struct ipmi_rq req; + +	unsigned char msg_data[6]; + +	memset(&req, 0, sizeof(req)); + +	req.msg.netfn = IPMI_NETFN_PICMG; +	req.msg.cmd	  = PICMG_GET_FRU_LED_STATE_CMD; +	req.msg.data  = msg_data; +	req.msg.data_len = 3; + +	msg_data[0] = 0x00;									/* PICMG identifier */ +	if (is_fru_id(argv[0], &msg_data[1]) != 0 +			|| is_led_id(argv[1], &msg_data[2]) != 0) { +		return (-1); +	} + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp) { +		lprintf(LOG_ERR, "No valid response received."); +		return -1; +	} + +	if (rsp->ccode) { +		lprintf(LOG_ERR, "LED get state failed with CC code 0x%02x", rsp->ccode); +		return -1; +	} + +	printf("LED states:						  %x	", rsp->data[1] ); +	if (rsp->data[1] == 0x1) +		printf("[LOCAL CONTROL]\n"); +	else if (rsp->data[1] == 0x2) +		printf("[OVERRIDE]\n"); +	else if (rsp->data[1] == 0x4) +		printf("[LAMPTEST]\n"); +	else +		printf("\n"); + +	printf("  Local Control function:     %x  ", rsp->data[2] ); +	if (rsp->data[2] == 0x0) +		printf("[OFF]\n"); +	else if (rsp->data[2] == 0xff) +		printf("[ON]\n"); +	else +		printf("[BLINKING]\n"); + +	printf("  Local Control On-Duration:  %x\n", rsp->data[3] ); +	printf("  Local Control Color:        %x  [%s]\n", rsp->data[4], led_color_str[ rsp->data[4] ]); + +	/* override state or lamp test */ +	if (rsp->data[1] == 0x02) { +		printf("  Override function:     %x  ", rsp->data[5] ); +		if (rsp->data[2] == 0x0) +			printf("[OFF]\n"); +		else if (rsp->data[2] == 0xff) +			printf("[ON]\n"); +		else +			printf("[BLINKING]\n"); + +		printf("  Override On-Duration:  %x\n", rsp->data[6] ); +		printf("  Override Color:        %x  [%s]\n", rsp->data[7], led_color_str[ rsp->data[7] ]); + +	}else if (rsp->data[1] == 0x06) { +		printf("  Override function:     %x  ", rsp->data[5] ); +		if (rsp->data[2] == 0x0) +			printf("[OFF]\n"); +		else if (rsp->data[2] == 0xff) +			printf("[ON]\n"); +		else +			printf("[BLINKING]\n"); +		printf("  Override On-Duration:  %x\n", rsp->data[6] ); +		printf("  Override Color:        %x  [%s]\n", rsp->data[7], led_color_str[ rsp->data[7] ]); +		printf("  Lamp test duration:    %x\n", rsp->data[8] ); +	} + +	return 0; +} + +int +ipmi_picmg_set_led_state(struct ipmi_intf * intf, int argc, char ** argv) +{ +	struct ipmi_rs * rsp; +	struct ipmi_rq req; + +	unsigned char msg_data[6]; + +	memset(&req, 0, sizeof(req)); + +	req.msg.netfn = IPMI_NETFN_PICMG; +	req.msg.cmd	  = PICMG_SET_FRU_LED_STATE_CMD; +	req.msg.data  = msg_data; +	req.msg.data_len = 6; + +	msg_data[0] = 0x00;									/* PICMG identifier */ +	if (is_fru_id(argv[0], &msg_data[1]) != 0 +			|| is_led_id(argv[1], &msg_data[2]) != 0 +			|| is_led_function(argv[2], &msg_data[3]) != 0 +			|| is_led_duration(argv[3], &msg_data[4]) != 0 +			|| is_led_color(argv[4], &msg_data[5]) != 0) { +		return (-1); +	} + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp) { +		lprintf(LOG_ERR, "No valid response received."); +		return -1; +	} + +	if (rsp->ccode) { +		lprintf(LOG_ERR, "LED set state failed with CC code 0x%02x", rsp->ccode); +		return -1; +	} + + +	return 0; +} + +int +ipmi_picmg_get_power_level(struct ipmi_intf * intf, int argc, char ** argv) +{ +	int i; +	struct ipmi_rs * rsp; +	struct ipmi_rq req; + +	unsigned char msg_data[6]; + +	memset(&req, 0, sizeof(req)); + +	req.msg.netfn = IPMI_NETFN_PICMG; +	req.msg.cmd	  = PICMG_GET_POWER_LEVEL_CMD; +	req.msg.data  = msg_data; +	req.msg.data_len = 3; + +	msg_data[0] = 0x00;									/* PICMG identifier */ +	if (is_fru_id(argv[0], &msg_data[1]) != 0) { +		return (-1); +	} +	/* PICMG Power Type - <0..3> */ +	if (str2uchar(argv[1], &msg_data[2]) != 0 || msg_data[2] > 3) { +		lprintf(LOG_ERR, "Given Power Type '%s' is invalid", +				argv[1]); +		return (-1); +	} + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp) { +		lprintf(LOG_ERR, "No valid response received."); +		return -1; +	} + +	if (rsp->ccode) { +		lprintf(LOG_ERR, "Power level get failed with CC code 0x%02x", rsp->ccode); +		return -1; +	} + +	printf("Dynamic Power Configuration: %s\n", (rsp->data[1]&0x80)==0x80?"enabled":"disabled" ); +	printf("Actual Power Level:          %i\n", (rsp->data[1] & 0xf)); +	printf("Delay to stable Power:       %i\n", rsp->data[2]); +	printf("Power Multiplier:            %i\n", rsp->data[3]); + + +	for ( i = 1; i+3 < rsp->data_len ; i++ ) { +		printf("   Power Draw %i:            %i\n", i, (rsp->data[i+3]) * rsp->data[3] / 10); +	} +	return 0; +} + +int +ipmi_picmg_set_power_level(struct ipmi_intf * intf, int argc, char ** argv) +{ +	struct ipmi_rs * rsp; +	struct ipmi_rq req; + +	unsigned char msg_data[6]; + +	memset(&req, 0, sizeof(req)); + +	req.msg.netfn = IPMI_NETFN_PICMG; +	req.msg.cmd	  = PICMG_SET_POWER_LEVEL_CMD; +	req.msg.data  = msg_data; +	req.msg.data_len = 4; + +	msg_data[0] = 0x00;					/* PICMG identifier	 */ +	if (is_fru_id(argv[0], &msg_data[1]) != 0) { +		return (-1); +	} +	/* PICMG Power Level - <0x00..0x14>, [0xFF] */ +	if (str2uchar(argv[1], &msg_data[2]) != 0 +			|| (msg_data[2] > 0x14 && msg_data[2] != 0xFF)) { +		lprintf(LOG_ERR, +				"Given PICMG Power Level '%s' is invalid.", +				argv[1]); +		return (-1); +	} +	/* PICMG Present-to-desired - <0..1> */ +	if (str2uchar(argv[2], &msg_data[3]) != 0 || msg_data[3] > 1) { +		lprintf(LOG_ERR, +				"Given PICMG Present-to-desired '%s' is invalid.", +				argv[2]); +		return (-1); +	} + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp) { +		lprintf(LOG_ERR, "No valid response received."); +		return -1; +	} + +	if (rsp->ccode) { +		lprintf(LOG_ERR, "Power level set failed with CC code 0x%02x", rsp->ccode); +		return -1; +	} + +	return 0; +} + +int +ipmi_picmg_bused_resource(struct ipmi_intf * intf, t_picmg_bused_resource_mode mode) +{ +	struct ipmi_rs * rsp; +	struct ipmi_rq req; + +	unsigned char msg_data[6]; +	memset(&req, 0, sizeof(req)); + +   int status = 0; +   switch ( mode ) { +      case PICMG_BUSED_RESOURCE_SUMMARY: +      { +         t_picmg_busres_resource_id resource; +         t_picmg_busres_board_cmd_types cmd =PICMG_BUSRES_BOARD_CMD_QUERY; + +         req.msg.netfn	  = IPMI_NETFN_PICMG; +         req.msg.cmd	     = PICMG_BUSED_RESOURCE_CMD; +         req.msg.data	  = msg_data; +         req.msg.data_len = 3; + +         /* IF BOARD +            query for all resources +         */ +         for( resource=PICMG_BUSRES_METAL_TEST_BUS_1;resource<=PICMG_BUSRES_SYNC_CLOCK_GROUP_3;resource+=(t_picmg_busres_resource_id)1 ) { +            msg_data[0] = 0x00;					/* PICMG identifier */ +            msg_data[1] = (unsigned char) cmd; +            msg_data[2] = (unsigned char) resource; +            rsp = intf->sendrecv(intf, &req); + +            if (!rsp) { +               printf("bused resource control: no response\n"); +               return -1; +            } + +            if (rsp->ccode) { +               printf("bused resource control: returned CC code 0x%02x\n", rsp->ccode); +               return -1; +            } else { +               printf("Resource 0x%02x '%-26s' : 0x%02x [%s] \n" ,  +                       resource, val2str(resource,picmg_busres_id_vals), +                       rsp->data[1], oemval2str(cmd,rsp->data[1], +                      picmg_busres_board_status_vals)); +            } +         } +      } +      break; +      default : +      break; +   } + +   return status; +} + +int +ipmi_picmg_fru_control(struct ipmi_intf * intf, int argc, char ** argv) +{ +	struct ipmi_rs * rsp; +	struct ipmi_rq req; + +	unsigned char msg_data[6]; + +	memset(&req, 0, sizeof(req)); + +	req.msg.netfn	  = IPMI_NETFN_PICMG; +	req.msg.cmd	  = PICMG_FRU_CONTROL_CMD; +	req.msg.data	  = msg_data; +	req.msg.data_len = 3; + +	msg_data[0] = 0x00;					/* PICMG identifier */ +	if (is_fru_id(argv[0], &msg_data[1]) != 0) { +		return (-1); +	} +	/* FRU Control Option, valid range: <0..4> */ +	if (str2uchar(argv[1], &msg_data[2]) != 0 || msg_data[2] > 4) { +		lprintf(LOG_ERR, +				"Given FRU Control Option '%s' is invalid.", +				argv[1]); +		return (-1); +	} + +	printf("FRU Device Id: %d FRU Control Option: %s\n", msg_data[1],  \ +				val2str( msg_data[2], picmg_frucontrol_vals)); + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp) { +		lprintf(LOG_ERR, "No valid response received."); +		return -1; +	} + +	if (rsp->ccode) { +		lprintf(LOG_ERR, "frucontrol failed with CC code 0x%02x", rsp->ccode); +		return -1; +	} else { +      printf("frucontrol: ok\n"); +	} + + + +	return 0; +} + + +int +ipmi_picmg_clk_get(struct ipmi_intf * intf, uint8_t clk_id, int8_t clk_res, +		int mode) +{ +	struct ipmi_rs * rsp; +	struct ipmi_rq req; + +	unsigned char enabled; +	unsigned char direction; + +	unsigned char msg_data[6]; + +	memset(&req, 0, sizeof(req)); + +	req.msg.netfn = IPMI_NETFN_PICMG; +	req.msg.cmd   = PICMG_AMC_GET_CLK_STATE_CMD; +	req.msg.data  = msg_data; + +	msg_data[0] = 0x00;									/* PICMG identifier	 */ +	msg_data[1] = clk_id; + +	if(clk_res == -1 || PicmgCardType != PICMG_CARD_TYPE_ATCA ){ +		req.msg.data_len = 2;	/* for amc only channel */ +	}else{ +		req.msg.data_len = 3;	/* for carrier channel and device */ +      msg_data[2] = clk_res; +	} + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp) { +		lprintf(LOG_ERR, "No valid response received."); +		return -1; +	} + +	if (rsp->ccode && (mode == PICMG_EKEY_MODE_QUERY) ) { +		lprintf(LOG_ERR, "Clk get failed with CC code 0x%02x", rsp->ccode); +		return -1; +	} + +	if (rsp->ccode == 0 ) { +		enabled	 = (rsp->data[1]&0x8)!=0; +		direction = (rsp->data[1]&0x4)!=0; + +		if +		(  +			mode == PICMG_EKEY_MODE_QUERY + 			|| + 			mode == PICMG_EKEY_MODE_PRINT_ALL + 			|| + 			( + 				mode == PICMG_EKEY_MODE_PRINT_DISABLED + 				&& + 				enabled == 0 + 			) + 			|| + 			( + 				mode == PICMG_EKEY_MODE_PRINT_ENABLED + 				&& + 				enabled == 1 +         )	 +		) { +			if( PicmgCardType != PICMG_CARD_TYPE_AMC ) { +				printf("CLK resource id   : %3d [ %s ]\n", clk_res , +					oemval2str( ((clk_res>>6)&0x03), (clk_res&0x0F), +														picmg_clk_resource_vals));				 +			} else { +				printf("CLK resource id   : N/A [ AMC Module ]\n"); +				clk_res = 0x40; /* Set */ +			}  +         printf("CLK id            : %3d [ %s ]\n", clk_id, +					oemval2str( ((clk_res>>6)&0x03), clk_id , +														picmg_clk_id_vals));				 + + +			printf("CLK setting       : 0x%02x\n", rsp->data[1]); +			printf(" - state:     %s\n", (enabled)?"enabled":"disabled"); +			printf(" - direction: %s\n", (direction)?"Source":"Receiver"); +			printf(" - PLL ctrl:  0x%x\n", rsp->data[1]&0x3); + +		   if(enabled){ +		      unsigned long freq = 0; +		      freq = (  rsp->data[5] <<  0 +		              | rsp->data[6] <<  8 +		              | rsp->data[7] << 16 +		              | rsp->data[8] << 24 ); +		      printf("  - Index:  %3d\n", rsp->data[2]); +		      printf("  - Family: %3d [ %s ] \n", rsp->data[3],  +						val2str( rsp->data[3], picmg_clk_family_vals)); +		      printf("  - AccLVL: %3d [ %s ] \n", rsp->data[4],  +						oemval2str( rsp->data[3], rsp->data[4], +											picmg_clk_accuracy_vals)); +		 +		      printf("  - Freq:   %ld\n", freq); +		   } +		} +	} +	return 0; +} + + +int +ipmi_picmg_clk_set(struct ipmi_intf * intf, int argc, char ** argv) +{ +	struct ipmi_rs * rsp; +	struct ipmi_rq req; + +	unsigned char msg_data[11] = {0}; +	uint32_t freq = 0; + +	memset(&req, 0, sizeof(req)); + +	req.msg.netfn = IPMI_NETFN_PICMG; +	req.msg.cmd	  = PICMG_AMC_SET_CLK_STATE_CMD; +	req.msg.data  = msg_data; + +	msg_data[0] = 0x00;									/* PICMG identifier	 */ +	if (is_clk_id(argv[0], &msg_data[1]) != 0 +			|| is_clk_index(argv[1], &msg_data[2]) != 0 +			|| is_clk_setting(argv[2], &msg_data[3]) != 0 +			|| is_clk_family(argv[3], &msg_data[4]) != 0 +			|| is_clk_acc(argv[4], &msg_data[5]) != 0 +			|| is_clk_freq(argv[5], &freq) != 0) { +		return (-1); +	} + +	msg_data[6] = (freq >> 0)& 0xFF;		/* freq					 */ +	msg_data[7] = (freq >> 8)& 0xFF;		/* freq					 */ +	msg_data[8] = (freq >>16)& 0xFF;		/* freq					 */ +	msg_data[9] = (freq >>24)& 0xFF;		/* freq					 */ + +	req.msg.data_len = 10; +   if( PicmgCardType == PICMG_CARD_TYPE_ATCA  ) +   { +      if( argc > 7) +      { +         req.msg.data_len = 11; +		 if (is_clk_resid(argv[6], &msg_data[10]) != 0) { +			 return (-1); +		 } +      } +      else +      { +         lprintf(LOG_ERR, "Missing resource id for atca board."); +         return -1; +      } +   } + +#if 1 +printf("## ID:      %d\n", msg_data[1]); +printf("## index:   %d\n", msg_data[2]); +printf("## setting: 0x%02x\n", msg_data[3]); +printf("## family:  %d\n", msg_data[4]); +printf("## acc:     %d\n", msg_data[5]); +printf("## freq:    %ld\n", freq ); +printf("## res:     %d\n", msg_data[10]); +#endif + +	rsp = intf->sendrecv(intf, &req); + +	if (!rsp) { +		lprintf(LOG_ERR, "No valid response received."); +		return -1; +	} + +	if (rsp->ccode) { +		lprintf(LOG_ERR, "Clk set failed with CC code 0x%02x", rsp->ccode); +		return -1; +	} + +	return 0; +} + + + +int +ipmi_picmg_main (struct ipmi_intf * intf, int argc, char ** argv) +{ +	int rc = 0; +	int showProperties = 0; + +	if (argc == 0 || (!strncmp(argv[0], "help", 4))) { +		ipmi_picmg_help(); +		return 0; +	} + +	/* Get PICMG properties is called to obtain version information */ +	if (argc !=0 && !strncmp(argv[0], "properties", 10)) { +		showProperties =1; +	} +	rc = ipmi_picmg_properties(intf,showProperties); + +	/* address info command */ +	if (!strncmp(argv[0], "addrinfo", 8)) { +		rc = ipmi_picmg_getaddr(intf, argc-1, &argv[1]); +	} +	else if (!strncmp(argv[0], "busres", 6)) { +		if (argc > 1) { +			if (!strncmp(argv[1], "summary", 7)) { +				ipmi_picmg_bused_resource(intf, PICMG_BUSED_RESOURCE_SUMMARY ); +			} +		} else { +			lprintf(LOG_NOTICE, "usage: busres summary"); +      } +	} +	/* fru control command */ +	else if (!strncmp(argv[0], "frucontrol", 10)) { +		if (argc > 2) { +			rc = ipmi_picmg_fru_control(intf, argc-1, &(argv[1])); +		} +		else { +			lprintf(LOG_NOTICE, "usage: frucontrol <FRU-ID> <OPTION>"); +			lprintf(LOG_NOTICE, "   OPTION:"); +			lprintf(LOG_NOTICE, "      0      - Cold Reset"); +			lprintf(LOG_NOTICE, "      1      - Warm Reset"); +			lprintf(LOG_NOTICE, "      2      - Graceful Reboot"); +			lprintf(LOG_NOTICE, "      3      - Issue Diagnostic Interrupt"); +			lprintf(LOG_NOTICE, "      4      - Quiesce [AMC only]"); +			lprintf(LOG_NOTICE, "      5-255  - Reserved"); + +			return -1; +		} + +	} + +	/* fru activation command */ +	else if (!strncmp(argv[0], "activate", 8)) { +		if (argc > 1) { +			rc = ipmi_picmg_fru_activation(intf, argc-1, &(argv[1]), PICMG_FRU_ACTIVATE); +		} +		else { +			lprintf(LOG_ERR, "Specify the FRU to activate."); +			return -1; +		} +	} + +	/* fru deactivation command */ +	else if (!strncmp(argv[0], "deactivate", 10)) { +		if (argc > 1) { +			rc = ipmi_picmg_fru_activation(intf, argc-1, &(argv[1]), PICMG_FRU_DEACTIVATE); +		}else { +			lprintf(LOG_ERR, "Specify the FRU to deactivate."); +			return -1; +		} +	} + +	/* activation policy command */ +	else if (!strncmp(argv[0], "policy", 6)) { +		if (argc > 1) { +			if (!strncmp(argv[1], "get", 3)) { +				if (argc > 2) { +					rc = ipmi_picmg_fru_activation_policy_get(intf, argc-1, &(argv[2])); +				} else { +					lprintf(LOG_NOTICE, "usage: get <fruid>"); +				} +			} else if (!strncmp(argv[1], "set", 3)) { +				if (argc > 4) { +					rc = ipmi_picmg_fru_activation_policy_set(intf, argc-1, &(argv[2])); +				} else { +					lprintf(LOG_NOTICE, "usage: set <fruid> <lockmask> <lock>"); +					lprintf(LOG_NOTICE, +							"    lockmask:  [1] affect the deactivation locked bit"); +					lprintf(LOG_NOTICE, +							"               [0] affect the activation locked bit"); +					lprintf(LOG_NOTICE, +							"    lock:      [1] set/clear deactivation locked"); +					lprintf(LOG_NOTICE, "               [0] set/clear locked"); +				} +			} +			else { +				lprintf(LOG_ERR, "Specify FRU."); +				return -1; +			} +		} else { +			lprintf(LOG_ERR, "Wrong parameters."); +			return -1; +		} +	} + +	/* portstate command */ +	else if (!strncmp(argv[0], "portstate", 9)) { + +		lprintf(LOG_DEBUG,"PICMG: portstate API"); + +		if (argc > 1) { +			if (!strncmp(argv[1], "get", 3)) { +				int32_t iface; +				uint8_t channel = 0; + +				lprintf(LOG_DEBUG,"PICMG: get"); + +				if(!strncmp(argv[1], "getall", 6)) { +					for(iface=0;iface<=PICMG_EKEY_MAX_INTERFACE;iface++) { +						for(channel=1;channel<=PICMG_EKEY_MAX_CHANNEL;channel++) { +							if(!(( iface == FRU_PICMGEXT_DESIGN_IF_FABRIC ) && +							      ( channel > PICMG_EKEY_MAX_FABRIC_CHANNEL ) )) +							{ +								rc = ipmi_picmg_portstate_get(intf,iface,channel, +								        PICMG_EKEY_MODE_PRINT_ALL); +							} +						} +					} +				} +				else if(!strncmp(argv[1], "getgranted", 10)) { +					for(iface=0;iface<=PICMG_EKEY_MAX_INTERFACE;iface++) { +						for(channel=1;channel<=PICMG_EKEY_MAX_CHANNEL;channel++) { +							rc = ipmi_picmg_portstate_get(intf,iface,channel, +							            PICMG_EKEY_MODE_PRINT_ENABLED); +						} +					} +				} +				else if(!strncmp(argv[1], "getdenied", 9)){ +					for(iface=0;iface<=PICMG_EKEY_MAX_INTERFACE;iface++) { +						for(channel=1;channel<=PICMG_EKEY_MAX_CHANNEL;channel++) { +							rc = ipmi_picmg_portstate_get(intf,iface,channel, +							           PICMG_EKEY_MODE_PRINT_DISABLED); +						} +					} +				} +				else if (argc > 3){ +					if (is_amc_intf(argv[2], &iface) != 0 +							|| is_amc_channel(argv[3], &channel) != 0) { +						return (-1); +					} +					lprintf(LOG_DEBUG,"PICMG: requesting interface %d",iface); +					lprintf(LOG_DEBUG,"PICMG: requesting channel %d",channel); + +					rc = ipmi_picmg_portstate_get(intf,iface,channel, +					            PICMG_EKEY_MODE_QUERY ); +				} +				else { +					lprintf(LOG_NOTICE, "<intf> <chn>|getall|getgranted|getdenied"); +				} +			} +			else if (!strncmp(argv[1], "set", 3)) { +					if (argc == 9) { +						int32_t interface = 0; +						int32_t port = 0; +						uint8_t channel = 0; +						uint8_t enable = 0; +						uint8_t group = 0; +						uint8_t type = 0; +						uint8_t typeext = 0; +						if (is_amc_intf(argv[2], &interface) != 0 +								|| is_amc_channel(argv[3], &channel) != 0 +								|| is_amc_port(argv[4], &port) != 0 +								|| is_link_type(argv[5], &type) != 0 +								|| is_link_type_ext(argv[6], &typeext) != 0 +								|| is_link_group(argv[7], &group) != 0 +								|| is_enable(argv[8], &enable) != 0) { +							return (-1); +						} + +						lprintf(LOG_DEBUG,"PICMG: interface %d",interface); +						lprintf(LOG_DEBUG,"PICMG: channel %d",channel); +						lprintf(LOG_DEBUG,"PICMG: port %d",port); +						lprintf(LOG_DEBUG,"PICMG: type %d",type); +						lprintf(LOG_DEBUG,"PICMG: typeext %d",typeext); +						lprintf(LOG_DEBUG,"PICMG: group %d",group); +						lprintf(LOG_DEBUG,"PICMG: enable %d",enable); + +						rc = ipmi_picmg_portstate_set(intf, interface, +						    channel, port, type, typeext  ,group ,enable); +					} +					else { +						lprintf(LOG_NOTICE, +								"<intf> <chn> <port> <type> <ext> <group> <1|0>"); +						return -1; +					} +			} +		} +		else { +			lprintf(LOG_NOTICE, "<set>|<getall>|<getgranted>|<getdenied>"); +			return -1; +		} +	} +	/* amc portstate command */ +	else if (!strncmp(argv[0], "amcportstate", 12)) { + +		lprintf(LOG_DEBUG,"PICMG: amcportstate API"); + +		if (argc > 1) { +			if (!strncmp(argv[1], "get", 3)){ +				int32_t device; +				uint8_t channel; + +				lprintf(LOG_DEBUG,"PICMG: get"); + +				if(!strncmp(argv[1], "getall", 6)){ +					int maxDevice = PICMG_EKEY_AMC_MAX_DEVICE; +					if( PicmgCardType != PICMG_CARD_TYPE_ATCA ){ +						maxDevice = 0; +					} +					for(device=0;device<=maxDevice;device++){ +						for(channel=0;channel<=PICMG_EKEY_AMC_MAX_CHANNEL;channel++){ +							rc = ipmi_picmg_amc_portstate_get(intf,device,channel, +																	PICMG_EKEY_MODE_PRINT_ALL); +						} +					} +				} +				else if(!strncmp(argv[1], "getgranted", 10)){ +					int maxDevice = PICMG_EKEY_AMC_MAX_DEVICE; +					if( PicmgCardType != PICMG_CARD_TYPE_ATCA ){ +						maxDevice = 0; +					} +					for(device=0;device<=maxDevice;device++){ +						for(channel=0;channel<=PICMG_EKEY_AMC_MAX_CHANNEL;channel++){ +							rc = ipmi_picmg_amc_portstate_get(intf,device,channel, +																  PICMG_EKEY_MODE_PRINT_ENABLED); +						} +					} +				} +				else if(!strncmp(argv[1], "getdenied", 9)){ +					int maxDevice = PICMG_EKEY_AMC_MAX_DEVICE; +					if( PicmgCardType != PICMG_CARD_TYPE_ATCA ){ +						maxDevice = 0; +					} +					for(device=0;device<=maxDevice;device++){ +						for(channel=0;channel<=PICMG_EKEY_AMC_MAX_CHANNEL;channel++){ +							rc = ipmi_picmg_amc_portstate_get(intf,device,channel, +                                                 PICMG_EKEY_MODE_PRINT_DISABLED); +						} +					} +				} +				else if (argc > 2){ +					if (is_amc_channel(argv[2], &channel) != 0) { +						return (-1); +					} +					if (argc > 3){ +						if (is_amc_dev(argv[3], &device) != 0) { +							return (-1); +						} +					}else{ +					   device = -1; +				    } +					lprintf(LOG_DEBUG,"PICMG: requesting device %d",device); +					lprintf(LOG_DEBUG,"PICMG: requesting channel %d",channel); + +					rc = ipmi_picmg_amc_portstate_get(intf,device,channel, +                                             PICMG_EKEY_MODE_QUERY ); +				} +				else { +					lprintf(LOG_NOTICE, "<chn> <device>|getall|getgranted|getdenied"); +				} +			} +			else if (!strncmp(argv[1], "set", 3)) { +				if (argc > 7) { +					int32_t device = -1; +					int32_t port = 0; +					uint8_t channel = 0; +					uint8_t enable = 0; +					uint8_t group = 0; +					uint8_t type = 0; +					uint8_t typeext = 0; +					if (is_amc_channel(argv[2], &channel) != 0 +							|| is_amc_port(argv[3], &port) != 0 +							|| is_link_type(argv[4], &type) !=0 +							|| is_link_type_ext(argv[5], &typeext) != 0 +							|| is_link_group(argv[6], &group) != 0 +							|| is_enable(argv[7], &enable) != 0) { +						return (-1); +					} +					if(argc > 8){ +						if (is_amc_dev(argv[8], &device) != 0) { +							return (-1); +						} +					} + +					lprintf(LOG_DEBUG,"PICMG: channel %d",channel); +					lprintf(LOG_DEBUG,"PICMG: portflags %d",port); +					lprintf(LOG_DEBUG,"PICMG: type %d",type); +					lprintf(LOG_DEBUG,"PICMG: typeext %d",typeext); +					lprintf(LOG_DEBUG,"PICMG: group %d",group); +					lprintf(LOG_DEBUG,"PICMG: enable %d",enable); +					lprintf(LOG_DEBUG,"PICMG: device %d",device); + +					rc = ipmi_picmg_amc_portstate_set(intf, channel, port, type, +                                               typeext, group, enable, device); +				} +				else { +					lprintf(LOG_NOTICE, +							"<chn> <portflags> <type> <ext> <group> <1|0> [<device>]"); +					return -1; +				} +			} +		} +		else { +			lprintf(LOG_NOTICE, "<set>|<get>|<getall>|<getgranted>|<getdenied>"); +			return -1; +		} +	} +	/* ATCA led commands */ +	else if (!strncmp(argv[0], "led", 3)) { +		if (argc > 1) { +			if (!strncmp(argv[1], "prop", 4)) { +				if (argc > 2) { +					rc = ipmi_picmg_get_led_properties(intf, argc-1, &(argv[2])); +				} +				else { +					lprintf(LOG_NOTICE, "led prop <FRU-ID>"); +				} +			} +			else if (!strncmp(argv[1], "cap", 3)) { +				if (argc > 3) { +					rc = ipmi_picmg_get_led_capabilities(intf, argc-1, &(argv[2])); +				} +				else { +					lprintf(LOG_NOTICE, "led cap <FRU-ID> <LED-ID>"); +				} +			} +			else if (!strncmp(argv[1], "get", 3)) { +				if (argc > 3) { +					rc = ipmi_picmg_get_led_state(intf, argc-1, &(argv[2])); +				} +				else { +					lprintf(LOG_NOTICE, "led get <FRU-ID> <LED-ID>"); +				} +			} +			else if (!strncmp(argv[1], "set", 3)) { +				if (argc > 6) { +					rc = ipmi_picmg_set_led_state(intf, argc-1, &(argv[2])); +				} +				else { +					lprintf(LOG_NOTICE, +							"led set <FRU-ID> <LED-ID> <function> <duration> <color>"); +					lprintf(LOG_NOTICE, "   <FRU-ID>"); +					lprintf(LOG_NOTICE, "   <LED-ID>    0:         Blue LED"); +					lprintf(LOG_NOTICE, "               1:         LED 1"); +					lprintf(LOG_NOTICE, "               2:         LED 2"); +					lprintf(LOG_NOTICE, "               3:         LED 3"); +					lprintf(LOG_NOTICE, "               0x04-0xFE: OEM defined"); +					lprintf(LOG_NOTICE, +							"               0xFF:      All LEDs under management control"); +					lprintf(LOG_NOTICE, "   <function>  0:       LED OFF override"); +					lprintf(LOG_NOTICE, +							"               1 - 250: LED blinking override (off duration)"); +					lprintf(LOG_NOTICE, "               251:     LED Lamp Test"); +					lprintf(LOG_NOTICE, +							"               252:     LED restore to local control"); +					lprintf(LOG_NOTICE, "               255:     LED ON override"); +					lprintf(LOG_NOTICE, +							"   <duration>  1 - 127: LED Lamp Test / on duration"); +					lprintf(LOG_NOTICE, "   <color>     0:   reserved"); +					lprintf(LOG_NOTICE, "               1:   BLUE"); +					lprintf(LOG_NOTICE, "               2:   RED"); +					lprintf(LOG_NOTICE, "               3:   GREEN"); +					lprintf(LOG_NOTICE, "               4:   AMBER"); +					lprintf(LOG_NOTICE, "               5:   ORANGE"); +					lprintf(LOG_NOTICE, "               6:   WHITE"); +					lprintf(LOG_NOTICE, "               7:   reserved"); +					lprintf(LOG_NOTICE, "               0xE: do not change"); +					lprintf(LOG_NOTICE, "               0xF: use default color"); +				} +			} +			else { +				lprintf(LOG_NOTICE, "prop | cap | get | set"); +			} +		} +	} +	/* power commands */ +	else if (!strncmp(argv[0], "power", 5)) { +		if (argc > 1) { +			if (!strncmp(argv[1], "get", 3)) { +				if (argc > 3) { +					rc = ipmi_picmg_get_power_level(intf, argc-1, &(argv[2])); +				} +				else { +					lprintf(LOG_NOTICE, "power get <FRU-ID> <type>"); +					lprintf(LOG_NOTICE, "   <type>   0 : steady state power draw levels"); +					lprintf(LOG_NOTICE, +							"            1 : desired steady state draw levels"); +					lprintf(LOG_NOTICE, "            2 : early power draw levels"); +					lprintf(LOG_NOTICE, "            3 : desired early levels"); + +					return -1; +				} +			} +			else if (!strncmp(argv[1], "set", 3)) { +				if (argc > 4) { +					rc = ipmi_picmg_set_power_level(intf, argc-1, &(argv[2])); +				} +				else { +					lprintf(LOG_NOTICE, "power set <FRU-ID> <level> <present-desired>"); +					lprintf(LOG_NOTICE, "   <level>  0 :        Power Off"); +					lprintf(LOG_NOTICE, "            0x1-0x14 : Power level"); +					lprintf(LOG_NOTICE, "            0xFF :     do not change"); +					lprintf(LOG_NOTICE, +							"\n   <present-desired> 0: do not change present levels"); +					lprintf(LOG_NOTICE, +							"                     1: copy desired to present level"); + +					return -1; +				} +			} +			else { +				lprintf(LOG_NOTICE, "<set>|<get>"); +				return -1; +			} +		} +		else { +			lprintf(LOG_NOTICE, "<set>|<get>"); +			return -1; +		} +	}/* clk commands*/ +	else if (!strncmp(argv[0], "clk", 3)) { +		if (argc > 1) { +			if (!strncmp(argv[1], "get", 3)) { +				int8_t clk_res = -1;             +				uint8_t clk_id; +				uint8_t max_res = 15; + +				if( PicmgCardType == PICMG_CARD_TYPE_AMC ) { +					max_res = 0; +				} + +				if(!strncmp(argv[1], "getall", 6)) { +					if( verbose ) { printf("Getting all clock state\n") ;}	 +					for(clk_res=0;clk_res<=max_res;clk_res++) { +						for(clk_id=0;clk_id<=15;clk_id++) { +								rc = ipmi_picmg_clk_get(intf,clk_id,clk_res, +								        PICMG_EKEY_MODE_PRINT_ALL); +						} +					} +				} +				else if(!strncmp(argv[1], "getdenied", 6)) { +					if( verbose ) { printf("Getting disabled clocks\n") ;}	 +					for(clk_res=0;clk_res<=max_res;clk_res++) { +						for(clk_id=0;clk_id<=15;clk_id++) { +								rc = ipmi_picmg_clk_get(intf,clk_id,clk_res, +								        PICMG_EKEY_MODE_PRINT_DISABLED); +						} +					} +				} +				else if(!strncmp(argv[1], "getgranted", 6)) { +					if( verbose ) { printf("Getting enabled clocks\n") ;}	 +					for(clk_res=0;clk_res<=max_res;clk_res++) { +						for(clk_id=0;clk_id<=15;clk_id++) { +								rc = ipmi_picmg_clk_get(intf,clk_id,clk_res, +								        PICMG_EKEY_MODE_PRINT_ENABLED); +						} +					} +				} +				else if (argc > 2) { +					if (is_clk_id(argv[2], &clk_id) != 0) { +						return (-1); +					} +					if (argc > 3) { +						if (is_clk_resid(argv[3], &clk_res) != 0) { +							return (-1); +						} +					} + +					rc = ipmi_picmg_clk_get(intf, clk_id, clk_res, +							PICMG_EKEY_MODE_QUERY ); +				} +				else { +					lprintf(LOG_NOTICE, "clk get"); +					lprintf(LOG_NOTICE, +							"<CLK-ID> [<DEV-ID>] |getall|getgranted|getdenied"); +					return -1; +				} +			} +			else if (!strncmp(argv[1], "set", 3)) { +				if (argc > 7) { +					rc = ipmi_picmg_clk_set(intf, argc-1, &(argv[2])); +				} +				else { +					lprintf(LOG_NOTICE, +							"clk set <CLK-ID> <index> <setting> <family> <acc-lvl> <freq> [<DEV-ID>]"); + +					return -1; +				} +			} +			else { +				lprintf(LOG_NOTICE, "<set>|<get>|<getall>|<getgranted>|<getdenied>"); +				return -1; +			} +		} +		else { +			lprintf(LOG_NOTICE, "<set>|<get>|<getall>|<getgranted>|<getdenied>"); +			return -1; +		} +	} + +	else if(showProperties == 0 ){ + +		ipmi_picmg_help(); +		return -1; +	} + +	return rc; +} + +uint8_t +ipmi_picmg_ipmb_address(struct ipmi_intf *intf) { +	struct ipmi_rq req; +	struct ipmi_rs *rsp; +	char msg_data; + +	if (!intf->picmg_avail) { +		return 0; +	} +	memset(&req, 0, sizeof(req)); +	req.msg.netfn = IPMI_NETFN_PICMG; +	req.msg.cmd = PICMG_GET_ADDRESS_INFO_CMD; +	msg_data    = 0x00; +	req.msg.data = &msg_data; +	req.msg.data_len = 1; +	msg_data = 0; + +	rsp = intf->sendrecv(intf, &req); +	if (rsp && !rsp->ccode) { +		return rsp->data[2]; +	} +	if (rsp) { +		lprintf(LOG_DEBUG, "Get Address Info failed: %#x %s", +			rsp->ccode, val2str(rsp->ccode, completion_code_vals)); +	} else { +		lprintf(LOG_DEBUG, "Get Address Info failed: No Response"); +	} +	return 0; +} + +uint8_t +picmg_discover(struct ipmi_intf *intf) { +	/* Check if PICMG extension is available to use the function  +	 * GetDeviceLocator to retreive i2c address PICMG hack to set  +	 * right IPMB address, If extension is not supported, should  +	 * not give any problems +	 *  PICMG Extension Version 2.0 (PICMG 3.0 Revision 1.0 ATCA) to +	 *  PICMG Extension Version 2.3 (PICMG 3.0 Revision 3.0 ATCA) +	 *  PICMG Extension Version 4.1 (PICMG 3.0 Revision 3.0 AMC) +	 */ + +	/* First, check if PICMG extension is available and supported */ +	struct ipmi_rq req; +	struct ipmi_rs *rsp; +	char msg_data; + +	if (intf->picmg_avail == 0) { +		memset(&req, 0, sizeof(req)); +		req.msg.netfn = IPMI_NETFN_PICMG; +		req.msg.cmd = PICMG_GET_PICMG_PROPERTIES_CMD; +		msg_data    = 0x00; +		req.msg.data = &msg_data; +		req.msg.data_len = 1; +		msg_data = 0; + +		lprintf(LOG_INFO, "Running Get PICMG Properties my_addr %#x, transit %#x, target %#x", +			intf->my_addr, intf->transit_addr, intf->target_addr); +		rsp = intf->sendrecv(intf, &req); +		if (rsp && !rsp->ccode) { +			if ( (rsp->data[0] == 0) && +					((rsp->data[1] & 0x0F) == PICMG_ATCA_MAJOR_VERSION +					|| (rsp->data[1] & 0x0F) == PICMG_AMC_MAJOR_VERSION) )	{ +				intf->picmg_avail = 1; +				lprintf(LOG_INFO, "Discovered PICMG Extension %d.%d", +						(rsp->data[1] & 0x0f), (rsp->data[1] >> 4)); +			}  +		} else { +			if (rsp == NULL) { +				lprintf(LOG_INFO,"No Response from Get PICMG Properties"); +			} else { +				lprintf(LOG_INFO,"Error Response %#x from Get PICMG Properities", rsp->ccode); +			} +		} +	} +	if (intf->picmg_avail == 0) { +		lprintf(LOG_INFO, "No PICMG Extenstion discovered"); +	} +	return intf->picmg_avail; +} | 
