diff options
Diffstat (limited to 'lib/ipmi_kontronoem.c')
| -rw-r--r-- | lib/ipmi_kontronoem.c | 808 | 
1 files changed, 808 insertions, 0 deletions
| diff --git a/lib/ipmi_kontronoem.c b/lib/ipmi_kontronoem.c new file mode 100644 index 0000000..c154eda --- /dev/null +++ b/lib/ipmi_kontronoem.c @@ -0,0 +1,808 @@ +/* + * Copyright (c) 2004 Kontron Canada, Inc.  All Rights Reserved. + * + * Base on code from + * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights 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 Sun Microsystems, Inc. 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. + * SUN MICROSYSTEMS, INC. ("SUN") 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 + * SUN 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 SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * Tue Mar 7 14:36:12 2006 + * <stephane.filion@ca.kontron.com> + * + * This code implements an Kontron OEM proprietary commands. + */ + + +#include <string.h> +#include <ipmitool/helper.h> +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/ipmi_fru.h> + + +extern int verbose; +extern int read_fru_area(struct ipmi_intf * intf, struct fru_info *fru,  +                         uint8_t id, uint32_t offset, uint32_t length,  +                         uint8_t *frubuf); +extern int write_fru_area(struct ipmi_intf * intf, struct fru_info *fru,  +                          unsigned char id, unsigned int soffset,   +                          unsigned int doffset,  unsigned int length,  +                          unsigned char *pFrubuf); + +extern char * get_fru_area_str(uint8_t * data, uint32_t * offset); + + + +static void ipmi_kontron_help(void); +static int ipmi_kontron_set_serial_number(struct ipmi_intf * intf); +static int ipmi_kontron_set_mfg_date (struct ipmi_intf * intf); + +static void ipmi_kontron_nextboot_help(void); +static int ipmi_kontron_nextboot_set(struct ipmi_intf * intf, +                                     int argc, char **argv); + +static int ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf * intf, +                                                 unsigned char channel, +                                                 unsigned char size); + +int +ipmi_kontronoem_main(struct ipmi_intf * intf, int argc, char ** argv) +{ +   int rc = 0; + +   if (argc == 0) +      ipmi_kontron_help(); +   else if (strncmp(argv[0], "help", 4) == 0) +      ipmi_kontron_help(); + +   else if (!strncmp(argv[0], "setsn", 5)) +   { +      if(argc >= 1) +      { +         if(ipmi_kontron_set_serial_number(intf) > 0) +         { +            printf("FRU serial number setted successfully\n"); +         } +         else +         { +            printf("FRU serial number set failed\n"); +         } +      } +      else +      { +         printf("fru setsn\n"); +      } +   } +   else if (!strncmp(argv[0], "setmfgdate", 5)) +   { +      if(argc >= 1) +      { +         if(ipmi_kontron_set_mfg_date(intf) > 0) +         { +            printf("FRU manufacturing date setted successfully\n"); +         } +         else +         { +            printf("FRU manufacturing date set failed\n"); +         }       +      } +      else +      { +         printf("fru setmfgdate\n"); +      } +   } +   else if (!strncmp(argv[0], "nextboot", sizeof("nextboot")-1)) +   { +      if (argc > 1) +      { +         if ((rc = ipmi_kontron_nextboot_set(intf, argc-1, argv+1)) == 0) +         { +            printf("Nextboot set successfully\n"); +         } +         else +         { +            printf("Nextboot set failed\n"); +         }       +      } +      else +      { +         ipmi_kontron_nextboot_help(); +      } +   } + +   else  +   { +      printf("Invalid Kontron command: %s", argv[0]); +      ipmi_kontron_help(); +      rc = -1; +   } + +   return rc; +} + + +static void ipmi_kontron_help(void) +{ +   printf("Kontron Commands:  setsn setmfgdate nextboot\n"); +}    + + +int ipmi_kontronoem_set_large_buffer(struct ipmi_intf * intf, unsigned char size) +{ +   uint8_t error_occurs = 0; +   uint32_t prev_target_addr = intf->target_addr ; + +   if ( intf->target_addr > 0  && (intf->target_addr != intf->my_addr) ) +   { +      intf->target_addr = intf->my_addr; + +       printf("Set local big buffer\n"); +       if(ipmi_kontronoem_send_set_large_buffer( intf, 0x0e, size ) == 0) +       { +          printf("Set local big buffer:success\n"); +       } +       else +       { +          error_occurs = 1; +       } + +       if (error_occurs == 0) +       { +          if(ipmi_kontronoem_send_set_large_buffer( intf, 0x00, size ) == 0) +          { +             printf("IPMB was set\n"); +          } +          else +          { +             /* Revert back the previous set large buffer */ +             error_occurs = 1; +             ipmi_kontronoem_send_set_large_buffer( intf, 0x0e, 0 ); +          } +       } + +      /* Restore target address */ +       intf->target_addr = prev_target_addr; +   } + +   if (error_occurs == 0) +   { +      if(ipmi_kontronoem_send_set_large_buffer( intf, 0x0e, size ) == 0) +      { +         //printf("Set remote big buffer\n"); +      } +      else +      { +         if ( intf->target_addr > 0  && (intf->target_addr != intf->my_addr) ) +         { +            /* Error occurs revert back the previous set large buffer*/ +            intf->target_addr = intf->my_addr; + +            //ipmi_kontronoem_send_set_large_buffer( intf, 0x00, 0 ); +            ipmi_kontronoem_send_set_large_buffer( intf, 0x0e, 0 ); + +            intf->target_addr = prev_target_addr; +         } +      } +   } +   return error_occurs; +} + + +int ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf * intf, unsigned char channel,unsigned char size) +{ +   struct ipmi_rs *rsp; +   struct ipmi_rq req; +   uint8_t msg_data[2]; +   int i; +    +   memset(msg_data, 0, sizeof(msg_data)); +   msg_data[0] = channel/*0x0e*/;   // Currently running interface +   msg_data[1] = size; +    +   memset(&req, 0, sizeof(req)); +   req.msg.netfn = 0x3E; /* OEM NetFn */ +   req.msg.cmd = 0x82;   /* Set Channel Buffer Length - OEM */ +   req.msg.data = msg_data; +   req.msg.data_len = 2; +    +   req.msg.lun = 0x00; +       +   rsp = intf->sendrecv(intf, &req); +   if (rsp == NULL)  +   { +      printf("Cannot send large buffer command\n"); +      return(-1); +   } +   if (rsp->ccode > 0)  +   { +      printf("Invalid length for the selected interface (%s) %d\n",  +               val2str(rsp->ccode, completion_code_vals), rsp->ccode); +      return(-1); +   } +   return 0; +} + + +/* ipmi_fru_set_serial_number -  Set the Serial Number in FRU + * + * @intf:		ipmi interface + * @id:		fru id + * + * returns -1 on error + * returns 1 if successful + */ +static int +ipmi_kontron_set_serial_number(struct ipmi_intf * intf) +{ +   struct ipmi_rs *rsp; +   struct ipmi_rq req; +   struct fru_info fru; +   struct fru_header header; +   uint8_t msg_data[4]; +   char *sn; +   uint8_t sn_size, checksum; +   uint8_t  *fru_data; +   char *fru_area; +   uint32_t fru_data_offset, fru_data_offset_tmp, board_sec_len, prod_sec_len, i; +    +   sn = NULL; +   fru_data = NULL; +    +   memset(msg_data, 0, 4); +   msg_data[0] = 0xb4; +   msg_data[1] = 0x90; +   msg_data[2] = 0x91; +   msg_data[3] = 0x8b; +    +   memset(&req, 0, sizeof(req)); +   req.msg.netfn = 0x3E; +   req.msg.cmd = 0x0C; +   req.msg.data = msg_data; +   req.msg.data_len = 4; +    +    +   /* Set Lun, necessary for this oem command */ +   req.msg.lun = 0x03; + +       +   rsp = intf->sendrecv(intf, &req); +   if (rsp == NULL)  +   { +      printf(" Device not present (No Response)\n"); +      return -11; +   } +    +   if (rsp->ccode > 0)  +   { +      printf(" This option is not implemented for this board\n"); +      return -1; +   } +   +   sn_size = rsp->data_len; +    +   sn = malloc(sn_size + 1); +    +   if(sn == NULL) +   { +      printf("Out of memory!"); +      return -1; +   } + +   memset(sn, 0, sn_size + 1); +   memcpy(sn, rsp->data, sn_size); +    +   if(verbose >= 1) +   { +      printf("Original serial number is : [%s]\n", sn); +   } +    +       + +   memset(msg_data, 0, 4); +   msg_data[0] = 0; +    +   memset(&req, 0, sizeof(req)); +   req.msg.netfn = IPMI_NETFN_STORAGE; +   req.msg.cmd = GET_FRU_INFO; +   req.msg.data = msg_data; +   req.msg.data_len = 1; +    +   rsp = intf->sendrecv(intf, &req); +   if (rsp == NULL) { +      printf(" Device not present (No Response)\n"); +      free(sn); +      sn = NULL; +      return -1; +   } +   if (rsp->ccode > 0) { +      printf(" Device not present (%s)\n", +         val2str(rsp->ccode, completion_code_vals)); +      free(sn); +      sn = NULL; +      return(-1); +   } + +   memset(&fru, 0, sizeof(fru)); +   fru.size = (rsp->data[1] << 8) | rsp->data[0]; +   fru.access = rsp->data[2] & 0x1; + +   if (fru.size < 1) { +      printf(" Invalid FRU size %d", fru.size); +      free(sn); +      sn = NULL; +      return -1; +   } +  +   /* +    * retrieve the FRU header +    */ +   msg_data[0] = 0; +   msg_data[1] = 0; +   msg_data[2] = 0; +   msg_data[3] = 8; + +   memset(&req, 0, sizeof(req)); +   req.msg.netfn = IPMI_NETFN_STORAGE; +   req.msg.cmd = GET_FRU_DATA; +   req.msg.data = msg_data; +   req.msg.data_len = 4; + +   rsp = intf->sendrecv(intf, &req); +   if (rsp == NULL)  +   { +      printf(" Device not present (No Response)\n"); +      free(sn); +      sn = NULL; +      return(-1); +   } +   if (rsp->ccode > 0)  +   { +      printf(" Device not present (%s)\n", +             val2str(rsp->ccode, completion_code_vals)); +      free(sn); +      sn = NULL; +      return(-1); +   } + +   if (verbose > 1) +      printbuf(rsp->data, rsp->data_len, "FRU DATA"); + +   memcpy(&header, rsp->data + 1, 8); + +   if (header.version != 1)  +   { +      printf(" Unknown FRU header version 0x%02x", +         header.version); +      free(sn); +      sn = NULL; +      return(-1); +   }    +    +   /* Set the Board Section */ +   board_sec_len =   (header.offset.product * 8) - (header.offset.board * 8); + + +   fru_data = malloc( fru.size); + +   if(fru_data == NULL) +   { +      printf("Out of memory!"); +      free(sn); +      sn = NULL; +      return(-1); +   } + +   memset(fru_data, 0, fru.size);  +   if(read_fru_area(intf ,&fru ,0 ,(header.offset.board * 8) ,board_sec_len , fru_data) < 0) +   { +      free(sn); +      sn = NULL; +      free(fru_data); +      fru_data = NULL; +      return(-1); +   } +    +   /*Position at Board Manufacturer*/ +   fru_data_offset = (header.offset.board * 8) + 6; +   fru_area = get_fru_area_str(fru_data, &fru_data_offset); + +   /*Position at Board Product Name*/ +   fru_area = get_fru_area_str(fru_data, &fru_data_offset); + +   fru_data_offset_tmp = fru_data_offset; +    +   /*Position at Serial Number*/ +   fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp); + +   fru_data_offset ++; + +   if(strlen(fru_area) != sn_size) +   { +      printf("The length of the serial number in the FRU Board Area is wrong.\n"); +      free(sn); +      sn = NULL; +      free(fru_data); +      fru_data = NULL; +      return(-1); +   } +    +   /* Copy the new serial number in the board section saved in memory*/ +   memcpy(fru_data + fru_data_offset, sn, sn_size); +    +   checksum = 0; +   /* Calculate Header Checksum */ +   for( i = (header.offset.board * 8); i < (((header.offset.board * 8)+board_sec_len) - 2) ; i ++ ) +   { +      checksum += fru_data[i]; +   } +   checksum = (~checksum) + 1; + + +   fru_data[(header.offset.board * 8)+board_sec_len - 1] = checksum; +    +   /* Write the new FRU Board section */ +   if(write_fru_area(intf, &fru, 0, (header.offset.board * 8), (header.offset.board * 8), board_sec_len, fru_data) < 0) +   { +      free(sn); +      sn = NULL; +      free(fru_data); +      fru_data = NULL; +      return(-1); +   } +    +   /* Set the Product Section */ +   prod_sec_len =   (header.offset.multi * 8) - (header.offset.product * 8); + +   if(read_fru_area(intf ,&fru ,0 ,(header.offset.product * 8) ,prod_sec_len , fru_data) < 0) +   { +      free(sn); +      sn = NULL; +      free(fru_data); +      fru_data = NULL; +      return(-1); +   } +    +   /*Position at Product Manufacturer*/ +   fru_data_offset = (header.offset.product * 8) + 3; +   fru_area = get_fru_area_str(fru_data, &fru_data_offset); + +   /*Position at Product Name*/ +   fru_area = get_fru_area_str(fru_data, &fru_data_offset); +    +   /*Position at Product Part*/ +   fru_area = get_fru_area_str(fru_data, &fru_data_offset); +    +   /*Position at Product Version*/ +   fru_area = get_fru_area_str(fru_data, &fru_data_offset); +    +    + +   fru_data_offset_tmp = fru_data_offset; +    +   /*Position at Serial Number*/ +   fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp); + +   fru_data_offset ++; + +   if(strlen(fru_area) != sn_size) +   { +      free(sn); +      sn = NULL; +      free(fru_data); +      fru_data = NULL; +      printf("The length of the serial number in the FRU Product Area is wrong.\n"); +      return(-1); +       +   } +    +   /* Copy the new serial number in the product section saved in memory*/ +   memcpy(fru_data + fru_data_offset, sn, sn_size); +    +   checksum = 0; +   /* Calculate Header Checksum */ +   for( i = (header.offset.product * 8); i < (((header.offset.product * 8)+prod_sec_len) - 2) ; i ++ ) +   { +      checksum += fru_data[i]; +   } +   checksum = (~checksum) + 1; + + +   fru_data[(header.offset.product * 8)+prod_sec_len - 1] = checksum; +    +   /* Write the new FRU Board section */ +   if(write_fru_area(intf, &fru, 0, (header.offset.product * 8), (header.offset.product * 8), prod_sec_len, fru_data) < 0) +   { +      free(sn); +      sn = NULL; +      free(fru_data); +      fru_data = NULL; +      return -1; +   }    +    +   free(sn); +   sn = NULL; +   free(fru_data); +   fru_data = NULL; + +   return(1); + +} + + +/* ipmi_fru_set_mfg_date -  Set the Manufacturing Date in FRU + * + * @intf:		ipmi interface + * @id:		fru id + * + * returns -1 on error + * returns 1 if successful + */ +static int +ipmi_kontron_set_mfg_date (struct ipmi_intf * intf) +{ +   struct ipmi_rs *rsp; +   struct ipmi_rq req; +   struct fru_info fru; +   struct fru_header header; +   uint8_t msg_data[4]; +   uint8_t mfg_date[3]; +    +   uint32_t board_sec_len, i; +   uint8_t *fru_data, checksum; + +       +    +    +   memset(msg_data, 0, 4); +   msg_data[0] = 0xb4; +   msg_data[1] = 0x90; +   msg_data[2] = 0x91; +   msg_data[3] = 0x8b; +    +   memset(&req, 0, sizeof(req)); +   req.msg.netfn = 0x3E; +   req.msg.cmd = 0x0E; +   req.msg.data = msg_data; +   req.msg.data_len = 4; +    +   /* Set Lun temporary, necessary for this oem command */ +   req.msg.lun = 0x03; +       +   rsp = intf->sendrecv(intf, &req); +   if (rsp == NULL)  +   { +      printf("Device not present (No Response)\n"); +      return(-1); +   } +    +   if (rsp->ccode > 0)  +   { +      printf("This option is not implemented for this board\n"); +      return(-1); +   } +      +   if(rsp->data_len != 3) +   { +      printf("Invalid response for the Manufacturing date\n"); +      return(-1); +   }   +    +   memset(mfg_date, 0, 3); +   memcpy(mfg_date, rsp->data, 3); + +   memset(msg_data, 0, 4); +   msg_data[0] = 0; +    +   memset(&req, 0, sizeof(req)); +   req.msg.netfn = IPMI_NETFN_STORAGE; +   req.msg.cmd = GET_FRU_INFO; +   req.msg.data = msg_data; +   req.msg.data_len = 1; +    +   rsp = intf->sendrecv(intf, &req); +   if (rsp == NULL) { +      printf(" Device not present (No Response)\n"); +      return(-1); +   } +   if (rsp->ccode > 0) { +      printf(" Device not present (%s)\n", +         val2str(rsp->ccode, completion_code_vals)); +      return(-1); +   } + +   memset(&fru, 0, sizeof(fru)); +   fru.size = (rsp->data[1] << 8) | rsp->data[0]; +   fru.access = rsp->data[2] & 0x1; + +   if (fru.size < 1) { +      printf(" Invalid FRU size %d", fru.size); +      return(-1); +   } +  +   /* +    * retrieve the FRU header +    */ +   msg_data[0] = 0; +   msg_data[1] = 0; +   msg_data[2] = 0; +   msg_data[3] = 8; + +   memset(&req, 0, sizeof(req)); +   req.msg.netfn = IPMI_NETFN_STORAGE; +   req.msg.cmd = GET_FRU_DATA; +   req.msg.data = msg_data; +   req.msg.data_len = 4; + +   rsp = intf->sendrecv(intf, &req); +   if (rsp == NULL)  +   { +      printf(" Device not present (No Response)\n"); +      return(-1); +   } +   if (rsp->ccode > 0)  +   { +      printf(" Device not present (%s)\n", +             val2str(rsp->ccode, completion_code_vals)); +      return(-1); +   } + +   if (verbose > 1) +      printbuf(rsp->data, rsp->data_len, "FRU DATA"); + +   memcpy(&header, rsp->data + 1, 8); + +   if (header.version != 1)  +   { +      printf(" Unknown FRU header version 0x%02x", +         header.version); +      return(-1); +   }  +    +    +   board_sec_len =   (header.offset.product * 8) - (header.offset.board * 8); +    +   fru_data = malloc( fru.size); +    +   if(fru_data == NULL) +   { +      printf("Out of memory!"); +      return(-1); +   } +    +   memset(fru_data, 0, fru.size);  +   if(read_fru_area(intf ,&fru ,0 ,(header.offset.board * 8) ,board_sec_len , fru_data) < 0) +   { +      free(fru_data); +      fru_data = NULL; +      return(-1); +   } +    +   /* Copy the new manufacturing date in the board section saved in memory*/ +   memcpy(fru_data + (header.offset.board * 8) + 3, mfg_date, 3); +    +   checksum = 0; +   /* Calculate Header Checksum */ +   for( i = (header.offset.board * 8); i < (((header.offset.board * 8)+board_sec_len) - 2) ; i ++ ) +   { +      checksum += fru_data[i]; +   } +   checksum = (~checksum) + 1; + +   fru_data[(header.offset.board * 8)+board_sec_len - 1] = checksum; +    +   /* Write the new FRU Board section */ +   if(write_fru_area(intf, &fru, 0, (header.offset.board * 8), (header.offset.board * 8), board_sec_len, fru_data) < 0) +   { +      free(fru_data); +      fru_data = NULL; +      return(-1); +   } + +   free(fru_data); +   fru_data = NULL; +   return(1); +} + + +static char *bootdev[] = {"BIOS", "FDD", "HDD", "CDROM", "network", 0}; + +static void +ipmi_kontron_nextboot_help(void) +{ +   int i; +   printf("nextboot <device>\n" +          "Supported devices:\n"); +   for (i = 0; bootdev[i] != 0; i++) { +       printf("- %s\n", bootdev[i]); +   } +} + +/* ipmi_kontron_next_boot_set - Select the next boot order on CP6012 + * + * @intf:		ipmi interface + * @id:		fru id + * + * returns -1 on error + * returns 1 if successful + */ +static int +ipmi_kontron_nextboot_set(struct ipmi_intf * intf, int argc, char **argv) +{ +   struct ipmi_rs *rsp; +   struct ipmi_rq req; +   uint8_t msg_data[8]; +   int i; +    +   memset(msg_data, 0, sizeof(msg_data)); +   msg_data[0] = 0xb4; +   msg_data[1] = 0x90; +   msg_data[2] = 0x91; +   msg_data[3] = 0x8b; +   msg_data[4] = 0x9d; +   msg_data[5] = 0xFF; +   msg_data[6] = 0xFF; /* any */ + +   for (i = 0; bootdev[i] != 0; i++) { +       if (strcmp(argv[0], bootdev[i]) == 0) { +           msg_data[5] = i; +           break; +       } +   } + +   /* Invalid device selected? */ +   if (msg_data[5] == 0xFF) { +       printf("Unknown boot device: %s\n", argv[0]); +       return -1; +   } +    +   memset(&req, 0, sizeof(req)); +   req.msg.netfn = 0x3E; +   req.msg.cmd = 0x02; +   req.msg.data = msg_data; +   req.msg.data_len = 7; +    +   /* Set Lun temporary, necessary for this oem command */ +   req.msg.lun = 0x03; +       +   rsp = intf->sendrecv(intf, &req); +   if (rsp == NULL)  +   { +      printf("Device not present (No Response)\n"); +      return(-1); +   } +   if (rsp->ccode > 0) { +      printf("Device not present (%s)\n", +         val2str(rsp->ccode, completion_code_vals)); +      return(-1); +   } +   return 0; +} +  | 
