1c18ec02fSPetter Reinholdtsen /* 2c18ec02fSPetter Reinholdtsen * Copyright (c) 2004 Kontron Canada, Inc. All Rights Reserved. 3c18ec02fSPetter Reinholdtsen * 4c18ec02fSPetter Reinholdtsen * Base on code from 5c18ec02fSPetter Reinholdtsen * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. 6c18ec02fSPetter Reinholdtsen * 7c18ec02fSPetter Reinholdtsen * Redistribution and use in source and binary forms, with or without 8c18ec02fSPetter Reinholdtsen * modification, are permitted provided that the following conditions 9c18ec02fSPetter Reinholdtsen * are met: 10c18ec02fSPetter Reinholdtsen * 11c18ec02fSPetter Reinholdtsen * Redistribution of source code must retain the above copyright 12c18ec02fSPetter Reinholdtsen * notice, this list of conditions and the following disclaimer. 13c18ec02fSPetter Reinholdtsen * 14c18ec02fSPetter Reinholdtsen * Redistribution in binary form must reproduce the above copyright 15c18ec02fSPetter Reinholdtsen * notice, this list of conditions and the following disclaimer in the 16c18ec02fSPetter Reinholdtsen * documentation and/or other materials provided with the distribution. 17c18ec02fSPetter Reinholdtsen * 18c18ec02fSPetter Reinholdtsen * Neither the name of Sun Microsystems, Inc. or the names of 19c18ec02fSPetter Reinholdtsen * contributors may be used to endorse or promote products derived 20c18ec02fSPetter Reinholdtsen * from this software without specific prior written permission. 21c18ec02fSPetter Reinholdtsen * 22c18ec02fSPetter Reinholdtsen * This software is provided "AS IS," without a warranty of any kind. 23c18ec02fSPetter Reinholdtsen * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, 24c18ec02fSPetter Reinholdtsen * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 25c18ec02fSPetter Reinholdtsen * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. 26c18ec02fSPetter Reinholdtsen * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE 27c18ec02fSPetter Reinholdtsen * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING 28c18ec02fSPetter Reinholdtsen * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL 29c18ec02fSPetter Reinholdtsen * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, 30c18ec02fSPetter Reinholdtsen * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR 31c18ec02fSPetter Reinholdtsen * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF 32c18ec02fSPetter Reinholdtsen * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 33c18ec02fSPetter Reinholdtsen * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 34c18ec02fSPetter Reinholdtsen */ 35c18ec02fSPetter Reinholdtsen 36c18ec02fSPetter Reinholdtsen /* 37c18ec02fSPetter Reinholdtsen * Tue Mar 7 14:36:12 2006 38c18ec02fSPetter Reinholdtsen * <stephane.filion@ca.kontron.com> 39c18ec02fSPetter Reinholdtsen * 40c18ec02fSPetter Reinholdtsen * This code implements an Kontron OEM proprietary commands. 41c18ec02fSPetter Reinholdtsen */ 42c18ec02fSPetter Reinholdtsen #include <string.h> 43c18ec02fSPetter Reinholdtsen #include <ipmitool/helper.h> 44*58837647SZdenek Styblik #include <ipmitool/log.h> 45c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi.h> 46c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_intf.h> 47c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_fru.h> 48c18ec02fSPetter Reinholdtsen 49c18ec02fSPetter Reinholdtsen extern int verbose; 50c18ec02fSPetter Reinholdtsen extern int read_fru_area(struct ipmi_intf *intf, struct fru_info *fru, 51c18ec02fSPetter Reinholdtsen uint8_t id, uint32_t offset, uint32_t length, 52c18ec02fSPetter Reinholdtsen uint8_t *frubuf); 53c18ec02fSPetter Reinholdtsen extern int write_fru_area(struct ipmi_intf * intf, struct fru_info *fru, 547560d4f2SZdenek Styblik uint8_t id, uint16_t soffset, 557560d4f2SZdenek Styblik uint16_t doffset, uint16_t length, 567560d4f2SZdenek Styblik uint8_t *pFrubuf); 57c18ec02fSPetter Reinholdtsen extern char *get_fru_area_str(uint8_t *data, uint32_t *offset); 58c18ec02fSPetter Reinholdtsen 59c18ec02fSPetter Reinholdtsen static void ipmi_kontron_help(void); 60c18ec02fSPetter Reinholdtsen static int ipmi_kontron_set_serial_number(struct ipmi_intf *intf); 61c18ec02fSPetter Reinholdtsen static int ipmi_kontron_set_mfg_date (struct ipmi_intf *intf); 62c18ec02fSPetter Reinholdtsen static void ipmi_kontron_nextboot_help(void); 63*58837647SZdenek Styblik static int ipmi_kontron_nextboot_set(struct ipmi_intf *intf, int argc, 64*58837647SZdenek Styblik char **argv); 65c18ec02fSPetter Reinholdtsen static int ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf *intf, 66*58837647SZdenek Styblik unsigned char channel, unsigned char size); 67*58837647SZdenek Styblik 68*58837647SZdenek Styblik static char *bootdev[] = {"BIOS", "FDD", "HDD", "CDROM", "network", 0}; 69c18ec02fSPetter Reinholdtsen 70c18ec02fSPetter Reinholdtsen int 71c18ec02fSPetter Reinholdtsen ipmi_kontronoem_main(struct ipmi_intf *intf, int argc, char **argv) 72c18ec02fSPetter Reinholdtsen { 73c18ec02fSPetter Reinholdtsen int rc = 0; 74*58837647SZdenek Styblik if (argc == 0) { 75*58837647SZdenek Styblik lprintf(LOG_ERR, "Not enough parameters given."); 76c18ec02fSPetter Reinholdtsen ipmi_kontron_help(); 77*58837647SZdenek Styblik return (-1); 78*58837647SZdenek Styblik } 79*58837647SZdenek Styblik if (strncmp(argv[0], "help", 4) == 0) { 80c18ec02fSPetter Reinholdtsen ipmi_kontron_help(); 81*58837647SZdenek Styblik rc = 0; 82*58837647SZdenek Styblik } else if (!strncmp(argv[0], "setsn", 5)) { 83*58837647SZdenek Styblik if (argc < 1) { 84c18ec02fSPetter Reinholdtsen printf("fru setsn\n"); 85*58837647SZdenek Styblik return (-1); 86c18ec02fSPetter Reinholdtsen } 87*58837647SZdenek Styblik if (ipmi_kontron_set_serial_number(intf) > 0) { 88*58837647SZdenek Styblik printf("FRU serial number setted successfully\n"); 89*58837647SZdenek Styblik } else { 90*58837647SZdenek Styblik printf("FRU serial number set failed\n"); 91*58837647SZdenek Styblik rc = (-1); 92c18ec02fSPetter Reinholdtsen } 93*58837647SZdenek Styblik } else if (!strncmp(argv[0], "setmfgdate", 10)) { 94*58837647SZdenek Styblik if (argc < 1) { 95c18ec02fSPetter Reinholdtsen printf("fru setmfgdate\n"); 96*58837647SZdenek Styblik return (-1); 97c18ec02fSPetter Reinholdtsen } 98*58837647SZdenek Styblik if (ipmi_kontron_set_mfg_date(intf) > 0) { 99*58837647SZdenek Styblik printf("FRU manufacturing date setted successfully\n"); 100*58837647SZdenek Styblik } else { 101*58837647SZdenek Styblik printf("FRU manufacturing date set failed\n"); 102*58837647SZdenek Styblik rc = (-1); 103c18ec02fSPetter Reinholdtsen } 104*58837647SZdenek Styblik } else if (!strncmp(argv[0], "nextboot", 8)) { 105*58837647SZdenek Styblik if (argc < 2) { 106*58837647SZdenek Styblik lprintf(LOG_ERR, "Not enough parameters given."); 107c18ec02fSPetter Reinholdtsen ipmi_kontron_nextboot_help(); 108*58837647SZdenek Styblik rc = (-1); 109c18ec02fSPetter Reinholdtsen } 110*58837647SZdenek Styblik rc = ipmi_kontron_nextboot_set(intf, (argc - 1), (argv + 1)); 111*58837647SZdenek Styblik if (rc == 0) { 112*58837647SZdenek Styblik printf("Nextboot set successfully\n"); 113*58837647SZdenek Styblik } else { 114*58837647SZdenek Styblik printf("Nextboot set failed\n"); 115*58837647SZdenek Styblik rc = (-1); 116c18ec02fSPetter Reinholdtsen } 117*58837647SZdenek Styblik } else { 118*58837647SZdenek Styblik lprintf(LOG_ERR, "Invalid Kontron command: %s", argv[0]); 119c18ec02fSPetter Reinholdtsen ipmi_kontron_help(); 120*58837647SZdenek Styblik rc = (-1); 121c18ec02fSPetter Reinholdtsen } 122c18ec02fSPetter Reinholdtsen return rc; 123c18ec02fSPetter Reinholdtsen } 124c18ec02fSPetter Reinholdtsen 125*58837647SZdenek Styblik static void 126*58837647SZdenek Styblik ipmi_kontron_help(void) 127c18ec02fSPetter Reinholdtsen { 128c18ec02fSPetter Reinholdtsen printf("Kontron Commands: setsn setmfgdate nextboot\n"); 129c18ec02fSPetter Reinholdtsen } 130c18ec02fSPetter Reinholdtsen 131*58837647SZdenek Styblik int 132*58837647SZdenek Styblik ipmi_kontronoem_set_large_buffer(struct ipmi_intf *intf, unsigned char size) 133c18ec02fSPetter Reinholdtsen { 134c18ec02fSPetter Reinholdtsen uint8_t error_occurs = 0; 135c18ec02fSPetter Reinholdtsen uint32_t prev_target_addr = intf->target_addr ; 136*58837647SZdenek Styblik if (intf->target_addr > 0 && (intf->target_addr != intf->my_addr)) { 137c18ec02fSPetter Reinholdtsen intf->target_addr = intf->my_addr; 138c18ec02fSPetter Reinholdtsen printf("Set local big buffer\n"); 139*58837647SZdenek Styblik if (ipmi_kontronoem_send_set_large_buffer(intf, 0x0e, size) == 0) { 140c18ec02fSPetter Reinholdtsen printf("Set local big buffer:success\n"); 141*58837647SZdenek Styblik } else { 142c18ec02fSPetter Reinholdtsen error_occurs = 1; 143c18ec02fSPetter Reinholdtsen } 144*58837647SZdenek Styblik if (error_occurs == 0) { 145*58837647SZdenek Styblik if (ipmi_kontronoem_send_set_large_buffer(intf, 0x00, size) == 0) { 146c18ec02fSPetter Reinholdtsen printf("IPMB was set\n"); 147*58837647SZdenek Styblik } else { 148c18ec02fSPetter Reinholdtsen /* Revert back the previous set large buffer */ 149c18ec02fSPetter Reinholdtsen error_occurs = 1; 150c18ec02fSPetter Reinholdtsen ipmi_kontronoem_send_set_large_buffer( intf, 0x0e, 0 ); 151c18ec02fSPetter Reinholdtsen } 152c18ec02fSPetter Reinholdtsen } 153c18ec02fSPetter Reinholdtsen /* Restore target address */ 154c18ec02fSPetter Reinholdtsen intf->target_addr = prev_target_addr; 155c18ec02fSPetter Reinholdtsen } 156*58837647SZdenek Styblik if (error_occurs == 0) { 157*58837647SZdenek Styblik if(ipmi_kontronoem_send_set_large_buffer(intf, 0x0e, size) == 0) { 158*58837647SZdenek Styblik /* printf("Set remote big buffer\n"); */ 159*58837647SZdenek Styblik } else { 160*58837647SZdenek Styblik if (intf->target_addr > 0 && (intf->target_addr != intf->my_addr)) { 161c18ec02fSPetter Reinholdtsen /* Error occurs revert back the previous set large buffer */ 162c18ec02fSPetter Reinholdtsen intf->target_addr = intf->my_addr; 163*58837647SZdenek Styblik /* ipmi_kontronoem_send_set_large_buffer(intf, 0x00, 0); */ 164c18ec02fSPetter Reinholdtsen ipmi_kontronoem_send_set_large_buffer(intf, 0x0e, 0); 165c18ec02fSPetter Reinholdtsen intf->target_addr = prev_target_addr; 166c18ec02fSPetter Reinholdtsen } 167c18ec02fSPetter Reinholdtsen } 168c18ec02fSPetter Reinholdtsen } 169c18ec02fSPetter Reinholdtsen return error_occurs; 170c18ec02fSPetter Reinholdtsen } 171c18ec02fSPetter Reinholdtsen 172*58837647SZdenek Styblik int 173*58837647SZdenek Styblik ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf *intf, 174*58837647SZdenek Styblik unsigned char channel, unsigned char size) 175c18ec02fSPetter Reinholdtsen { 176c18ec02fSPetter Reinholdtsen struct ipmi_rs *rsp; 177c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 178c18ec02fSPetter Reinholdtsen uint8_t msg_data[2]; 179c18ec02fSPetter Reinholdtsen int i; 180c18ec02fSPetter Reinholdtsen memset(msg_data, 0, sizeof(msg_data)); 181*58837647SZdenek Styblik /* channel =~ 0x0e => Currently running interface */ 182*58837647SZdenek Styblik msg_data[0] = channel; 183c18ec02fSPetter Reinholdtsen msg_data[1] = size; 184c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 185*58837647SZdenek Styblik req.msg.netfn = 0x3E; 186*58837647SZdenek Styblik /* Set Channel Buffer Length - OEM */ 187*58837647SZdenek Styblik req.msg.cmd = 0x82; 188c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 189c18ec02fSPetter Reinholdtsen req.msg.data_len = 2; 190c18ec02fSPetter Reinholdtsen req.msg.lun = 0x00; 191c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 192*58837647SZdenek Styblik if (rsp == NULL) { 193c18ec02fSPetter Reinholdtsen printf("Cannot send large buffer command\n"); 194c18ec02fSPetter Reinholdtsen return(-1); 195*58837647SZdenek Styblik } else if (rsp->ccode > 0) { 196c18ec02fSPetter Reinholdtsen printf("Invalid length for the selected interface (%s) %d\n", 197c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals), rsp->ccode); 198c18ec02fSPetter Reinholdtsen return(-1); 199c18ec02fSPetter Reinholdtsen } 200c18ec02fSPetter Reinholdtsen return 0; 201c18ec02fSPetter Reinholdtsen } 202c18ec02fSPetter Reinholdtsen 203c18ec02fSPetter Reinholdtsen /* ipmi_fru_set_serial_number - Set the Serial Number in FRU 204c18ec02fSPetter Reinholdtsen * 205c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 206c18ec02fSPetter Reinholdtsen * @id: fru id 207c18ec02fSPetter Reinholdtsen * 208c18ec02fSPetter Reinholdtsen * returns -1 on error 209c18ec02fSPetter Reinholdtsen * returns 1 if successful 210c18ec02fSPetter Reinholdtsen */ 211c18ec02fSPetter Reinholdtsen static int 212c18ec02fSPetter Reinholdtsen ipmi_kontron_set_serial_number(struct ipmi_intf *intf) 213c18ec02fSPetter Reinholdtsen { 214*58837647SZdenek Styblik struct fru_header header; 215*58837647SZdenek Styblik struct fru_info fru; 216c18ec02fSPetter Reinholdtsen struct ipmi_rs *rsp; 217c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 218c18ec02fSPetter Reinholdtsen char *sn; 219c18ec02fSPetter Reinholdtsen char *fru_area; 220*58837647SZdenek Styblik uint8_t checksum; 221*58837647SZdenek Styblik uint8_t *fru_data; 222*58837647SZdenek Styblik uint8_t msg_data[4]; 223*58837647SZdenek Styblik uint8_t sn_size; 224*58837647SZdenek Styblik uint32_t board_sec_len; 225*58837647SZdenek Styblik uint32_t fru_data_offset; 226*58837647SZdenek Styblik uint32_t fru_data_offset_tmp; 227*58837647SZdenek Styblik uint32_t i; 228*58837647SZdenek Styblik uint32_t prod_sec_len; 229c18ec02fSPetter Reinholdtsen 230c18ec02fSPetter Reinholdtsen sn = NULL; 231c18ec02fSPetter Reinholdtsen fru_data = NULL; 232c18ec02fSPetter Reinholdtsen 233c18ec02fSPetter Reinholdtsen memset(msg_data, 0, 4); 234c18ec02fSPetter Reinholdtsen msg_data[0] = 0xb4; 235c18ec02fSPetter Reinholdtsen msg_data[1] = 0x90; 236c18ec02fSPetter Reinholdtsen msg_data[2] = 0x91; 237c18ec02fSPetter Reinholdtsen msg_data[3] = 0x8b; 238c18ec02fSPetter Reinholdtsen 239c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 240c18ec02fSPetter Reinholdtsen req.msg.netfn = 0x3E; 241c18ec02fSPetter Reinholdtsen req.msg.cmd = 0x0C; 242c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 243c18ec02fSPetter Reinholdtsen req.msg.data_len = 4; 244c18ec02fSPetter Reinholdtsen /* Set Lun, necessary for this oem command */ 245c18ec02fSPetter Reinholdtsen req.msg.lun = 0x03; 246c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 247*58837647SZdenek Styblik if (rsp == NULL) { 248c18ec02fSPetter Reinholdtsen printf(" Device not present (No Response)\n"); 249*58837647SZdenek Styblik return (-1); 250*58837647SZdenek Styblik } else if (rsp->ccode > 0) { 251c18ec02fSPetter Reinholdtsen printf(" This option is not implemented for this board\n"); 252*58837647SZdenek Styblik return (-1); 253c18ec02fSPetter Reinholdtsen } 254c18ec02fSPetter Reinholdtsen sn_size = rsp->data_len; 255c18ec02fSPetter Reinholdtsen sn = malloc(sn_size + 1); 256*58837647SZdenek Styblik if (sn == NULL) { 257*58837647SZdenek Styblik lprintf(LOG_ERR, "ipmitool: malloc failure"); 258*58837647SZdenek Styblik return (-1); 259c18ec02fSPetter Reinholdtsen } 260c18ec02fSPetter Reinholdtsen memset(sn, 0, sn_size + 1); 261c18ec02fSPetter Reinholdtsen memcpy(sn, rsp->data, sn_size); 262*58837647SZdenek Styblik if (verbose >= 1) { 263c18ec02fSPetter Reinholdtsen printf("Original serial number is : [%s]\n", sn); 264c18ec02fSPetter Reinholdtsen } 265c18ec02fSPetter Reinholdtsen memset(msg_data, 0, 4); 266c18ec02fSPetter Reinholdtsen msg_data[0] = 0; 267c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 268c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 269c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_INFO; 270c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 271c18ec02fSPetter Reinholdtsen req.msg.data_len = 1; 272c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 273c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 274c18ec02fSPetter Reinholdtsen printf(" Device not present (No Response)\n"); 275c18ec02fSPetter Reinholdtsen free(sn); 276c18ec02fSPetter Reinholdtsen sn = NULL; 277*58837647SZdenek Styblik return (-1); 278*58837647SZdenek Styblik } else if (rsp->ccode > 0) { 279c18ec02fSPetter Reinholdtsen printf(" Device not present (%s)\n", 280c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 281c18ec02fSPetter Reinholdtsen free(sn); 282c18ec02fSPetter Reinholdtsen sn = NULL; 283c18ec02fSPetter Reinholdtsen return (-1); 284c18ec02fSPetter Reinholdtsen } 285c18ec02fSPetter Reinholdtsen memset(&fru, 0, sizeof(fru)); 286c18ec02fSPetter Reinholdtsen fru.size = (rsp->data[1] << 8) | rsp->data[0]; 287c18ec02fSPetter Reinholdtsen fru.access = rsp->data[2] & 0x1; 288c18ec02fSPetter Reinholdtsen if (fru.size < 1) { 289c18ec02fSPetter Reinholdtsen printf(" Invalid FRU size %d", fru.size); 290c18ec02fSPetter Reinholdtsen free(sn); 291c18ec02fSPetter Reinholdtsen sn = NULL; 292*58837647SZdenek Styblik return (-1); 293c18ec02fSPetter Reinholdtsen } 294*58837647SZdenek Styblik /* retrieve the FRU header */ 295c18ec02fSPetter Reinholdtsen msg_data[0] = 0; 296c18ec02fSPetter Reinholdtsen msg_data[1] = 0; 297c18ec02fSPetter Reinholdtsen msg_data[2] = 0; 298c18ec02fSPetter Reinholdtsen msg_data[3] = 8; 299c18ec02fSPetter Reinholdtsen 300c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 301c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 302c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_DATA; 303c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 304c18ec02fSPetter Reinholdtsen req.msg.data_len = 4; 305c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 306*58837647SZdenek Styblik if (rsp == NULL) { 307c18ec02fSPetter Reinholdtsen printf(" Device not present (No Response)\n"); 308c18ec02fSPetter Reinholdtsen free(sn); 309c18ec02fSPetter Reinholdtsen sn = NULL; 310c18ec02fSPetter Reinholdtsen return (-1); 311*58837647SZdenek Styblik } else if (rsp->ccode > 0) { 312c18ec02fSPetter Reinholdtsen printf(" Device not present (%s)\n", 313c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 314c18ec02fSPetter Reinholdtsen free(sn); 315c18ec02fSPetter Reinholdtsen sn = NULL; 316c18ec02fSPetter Reinholdtsen return (-1); 317c18ec02fSPetter Reinholdtsen } 318*58837647SZdenek Styblik if (verbose > 1) { 319c18ec02fSPetter Reinholdtsen printbuf(rsp->data, rsp->data_len, "FRU DATA"); 320*58837647SZdenek Styblik } 321c18ec02fSPetter Reinholdtsen memcpy(&header, rsp->data + 1, 8); 322*58837647SZdenek Styblik if (header.version != 1) { 323c18ec02fSPetter Reinholdtsen printf(" Unknown FRU header version 0x%02x", 324c18ec02fSPetter Reinholdtsen header.version); 325c18ec02fSPetter Reinholdtsen free(sn); 326c18ec02fSPetter Reinholdtsen sn = NULL; 327c18ec02fSPetter Reinholdtsen return(-1); 328c18ec02fSPetter Reinholdtsen } 329c18ec02fSPetter Reinholdtsen /* Set the Board Section */ 330c18ec02fSPetter Reinholdtsen board_sec_len = (header.offset.product * 8) - (header.offset.board * 8); 331c18ec02fSPetter Reinholdtsen fru_data = malloc(fru.size); 332*58837647SZdenek Styblik if (fru_data == NULL) { 333*58837647SZdenek Styblik lprintf(LOG_ERR, "ipmitool: malloc failure"); 334c18ec02fSPetter Reinholdtsen free(sn); 335c18ec02fSPetter Reinholdtsen sn = NULL; 336c18ec02fSPetter Reinholdtsen return (-1); 337c18ec02fSPetter Reinholdtsen } 338c18ec02fSPetter Reinholdtsen memset(fru_data, 0, fru.size); 339*58837647SZdenek Styblik if (read_fru_area(intf, &fru, 0, (header.offset.board * 8), 340*58837647SZdenek Styblik board_sec_len, fru_data) < 0) { 341c18ec02fSPetter Reinholdtsen free(sn); 342c18ec02fSPetter Reinholdtsen sn = NULL; 343c18ec02fSPetter Reinholdtsen free(fru_data); 344c18ec02fSPetter Reinholdtsen fru_data = NULL; 345c18ec02fSPetter Reinholdtsen return (-1); 346c18ec02fSPetter Reinholdtsen } 347c18ec02fSPetter Reinholdtsen /* Position at Board Manufacturer */ 348c18ec02fSPetter Reinholdtsen fru_data_offset = (header.offset.board * 8) + 6; 349c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &fru_data_offset); 350c18ec02fSPetter Reinholdtsen /* Position at Board Product Name */ 351c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &fru_data_offset); 352c18ec02fSPetter Reinholdtsen fru_data_offset_tmp = fru_data_offset; 353c18ec02fSPetter Reinholdtsen /* Position at Serial Number */ 354c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp); 355c18ec02fSPetter Reinholdtsen fru_data_offset++; 356*58837647SZdenek Styblik if (strlen(fru_area) != sn_size) { 357c18ec02fSPetter Reinholdtsen printf("The length of the serial number in the FRU Board Area is wrong.\n"); 358c18ec02fSPetter Reinholdtsen free(sn); 359c18ec02fSPetter Reinholdtsen sn = NULL; 360c18ec02fSPetter Reinholdtsen free(fru_data); 361c18ec02fSPetter Reinholdtsen fru_data = NULL; 362c18ec02fSPetter Reinholdtsen return(-1); 363c18ec02fSPetter Reinholdtsen } 364c18ec02fSPetter Reinholdtsen /* Copy the new serial number in the board section saved in memory*/ 365c18ec02fSPetter Reinholdtsen memcpy(fru_data + fru_data_offset, sn, sn_size); 366c18ec02fSPetter Reinholdtsen checksum = 0; 367c18ec02fSPetter Reinholdtsen /* Calculate Header Checksum */ 368*58837647SZdenek Styblik for(i = (header.offset.board * 8); 369*58837647SZdenek Styblik i < (((header.offset.board * 8) + board_sec_len) - 2); 370*58837647SZdenek Styblik i++) { 371c18ec02fSPetter Reinholdtsen checksum += fru_data[i]; 372c18ec02fSPetter Reinholdtsen } 373c18ec02fSPetter Reinholdtsen checksum = (~checksum) + 1; 374c18ec02fSPetter Reinholdtsen fru_data[(header.offset.board * 8) + board_sec_len - 1] = checksum; 375c18ec02fSPetter Reinholdtsen /* Write the new FRU Board section */ 376*58837647SZdenek Styblik if (write_fru_area(intf, &fru, 0, (header.offset.board * 8), 377*58837647SZdenek Styblik (header.offset.board * 8), 378*58837647SZdenek Styblik board_sec_len, fru_data) < 0) { 379c18ec02fSPetter Reinholdtsen free(sn); 380c18ec02fSPetter Reinholdtsen sn = NULL; 381c18ec02fSPetter Reinholdtsen free(fru_data); 382c18ec02fSPetter Reinholdtsen fru_data = NULL; 383c18ec02fSPetter Reinholdtsen return(-1); 384c18ec02fSPetter Reinholdtsen } 385c18ec02fSPetter Reinholdtsen /* Set the Product Section */ 386c18ec02fSPetter Reinholdtsen prod_sec_len = (header.offset.multi * 8) - (header.offset.product * 8); 387*58837647SZdenek Styblik if (read_fru_area(intf, &fru, 0, (header.offset.product * 8), 388*58837647SZdenek Styblik prod_sec_len, fru_data) < 0) { 389c18ec02fSPetter Reinholdtsen free(sn); 390c18ec02fSPetter Reinholdtsen sn = NULL; 391c18ec02fSPetter Reinholdtsen free(fru_data); 392c18ec02fSPetter Reinholdtsen fru_data = NULL; 393c18ec02fSPetter Reinholdtsen return(-1); 394c18ec02fSPetter Reinholdtsen } 395c18ec02fSPetter Reinholdtsen /* Position at Product Manufacturer */ 396c18ec02fSPetter Reinholdtsen fru_data_offset = (header.offset.product * 8) + 3; 397c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &fru_data_offset); 398c18ec02fSPetter Reinholdtsen /* Position at Product Name */ 399c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &fru_data_offset); 400c18ec02fSPetter Reinholdtsen /* Position at Product Part */ 401c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &fru_data_offset); 402c18ec02fSPetter Reinholdtsen /* Position at Product Version */ 403c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &fru_data_offset); 404c18ec02fSPetter Reinholdtsen fru_data_offset_tmp = fru_data_offset; 405c18ec02fSPetter Reinholdtsen /* Position at Serial Number */ 406c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp); 407c18ec02fSPetter Reinholdtsen fru_data_offset ++; 408*58837647SZdenek Styblik if (strlen(fru_area) != sn_size) { 409c18ec02fSPetter Reinholdtsen free(sn); 410c18ec02fSPetter Reinholdtsen sn = NULL; 411c18ec02fSPetter Reinholdtsen free(fru_data); 412c18ec02fSPetter Reinholdtsen fru_data = NULL; 413c18ec02fSPetter Reinholdtsen printf("The length of the serial number in the FRU Product Area is wrong.\n"); 414c18ec02fSPetter Reinholdtsen return(-1); 415c18ec02fSPetter Reinholdtsen } 416c18ec02fSPetter Reinholdtsen /* Copy the new serial number in the product section saved in memory*/ 417c18ec02fSPetter Reinholdtsen memcpy(fru_data + fru_data_offset, sn, sn_size); 418c18ec02fSPetter Reinholdtsen checksum = 0; 419c18ec02fSPetter Reinholdtsen /* Calculate Header Checksum */ 420*58837647SZdenek Styblik for (i = (header.offset.product * 8); 421*58837647SZdenek Styblik i < (((header.offset.product * 8) + prod_sec_len) - 2); 422*58837647SZdenek Styblik i ++) { 423c18ec02fSPetter Reinholdtsen checksum += fru_data[i]; 424c18ec02fSPetter Reinholdtsen } 425c18ec02fSPetter Reinholdtsen checksum = (~checksum) + 1; 426c18ec02fSPetter Reinholdtsen fru_data[(header.offset.product * 8)+prod_sec_len - 1] = checksum; 427c18ec02fSPetter Reinholdtsen /* Write the new FRU Board section */ 428*58837647SZdenek Styblik if (write_fru_area(intf, &fru, 0, (header.offset.product * 8), 429*58837647SZdenek Styblik (header.offset.product * 8), 430*58837647SZdenek Styblik prod_sec_len, fru_data) < 0) { 431c18ec02fSPetter Reinholdtsen free(sn); 432c18ec02fSPetter Reinholdtsen sn = NULL; 433c18ec02fSPetter Reinholdtsen free(fru_data); 434c18ec02fSPetter Reinholdtsen fru_data = NULL; 435c18ec02fSPetter Reinholdtsen return -1; 436c18ec02fSPetter Reinholdtsen } 437c18ec02fSPetter Reinholdtsen free(sn); 438c18ec02fSPetter Reinholdtsen sn = NULL; 439c18ec02fSPetter Reinholdtsen free(fru_data); 440c18ec02fSPetter Reinholdtsen fru_data = NULL; 441c18ec02fSPetter Reinholdtsen return(1); 442c18ec02fSPetter Reinholdtsen } 443c18ec02fSPetter Reinholdtsen 444c18ec02fSPetter Reinholdtsen /* ipmi_fru_set_mfg_date - Set the Manufacturing Date in FRU 445c18ec02fSPetter Reinholdtsen * 446c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 447c18ec02fSPetter Reinholdtsen * @id: fru id 448c18ec02fSPetter Reinholdtsen * 449c18ec02fSPetter Reinholdtsen * returns -1 on error 450c18ec02fSPetter Reinholdtsen * returns 1 if successful 451c18ec02fSPetter Reinholdtsen */ 452c18ec02fSPetter Reinholdtsen static int 453c18ec02fSPetter Reinholdtsen ipmi_kontron_set_mfg_date (struct ipmi_intf *intf) 454c18ec02fSPetter Reinholdtsen { 455*58837647SZdenek Styblik struct fru_header header; 456*58837647SZdenek Styblik struct fru_info fru; 457c18ec02fSPetter Reinholdtsen struct ipmi_rs *rsp; 458c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 459*58837647SZdenek Styblik uint8_t *fru_data; 460*58837647SZdenek Styblik uint8_t checksum; 461c18ec02fSPetter Reinholdtsen uint8_t msg_data[4]; 462c18ec02fSPetter Reinholdtsen uint8_t mfg_date[3]; 463*58837647SZdenek Styblik uint32_t board_sec_len; 464*58837647SZdenek Styblik uint32_t i; 465c18ec02fSPetter Reinholdtsen 466c18ec02fSPetter Reinholdtsen memset(msg_data, 0, 4); 467c18ec02fSPetter Reinholdtsen msg_data[0] = 0xb4; 468c18ec02fSPetter Reinholdtsen msg_data[1] = 0x90; 469c18ec02fSPetter Reinholdtsen msg_data[2] = 0x91; 470c18ec02fSPetter Reinholdtsen msg_data[3] = 0x8b; 471c18ec02fSPetter Reinholdtsen 472c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 473c18ec02fSPetter Reinholdtsen req.msg.netfn = 0x3E; 474c18ec02fSPetter Reinholdtsen req.msg.cmd = 0x0E; 475c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 476c18ec02fSPetter Reinholdtsen req.msg.data_len = 4; 477c18ec02fSPetter Reinholdtsen /* Set Lun temporary, necessary for this oem command */ 478c18ec02fSPetter Reinholdtsen req.msg.lun = 0x03; 479c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 480*58837647SZdenek Styblik if (rsp == NULL) { 481c18ec02fSPetter Reinholdtsen printf("Device not present (No Response)\n"); 482c18ec02fSPetter Reinholdtsen return(-1); 483*58837647SZdenek Styblik } else if (rsp->ccode > 0) { 484c18ec02fSPetter Reinholdtsen printf("This option is not implemented for this board\n"); 485c18ec02fSPetter Reinholdtsen return(-1); 486c18ec02fSPetter Reinholdtsen } 487*58837647SZdenek Styblik if (rsp->data_len != 3) { 488c18ec02fSPetter Reinholdtsen printf("Invalid response for the Manufacturing date\n"); 489c18ec02fSPetter Reinholdtsen return(-1); 490c18ec02fSPetter Reinholdtsen } 491c18ec02fSPetter Reinholdtsen memset(mfg_date, 0, 3); 492c18ec02fSPetter Reinholdtsen memcpy(mfg_date, rsp->data, 3); 493c18ec02fSPetter Reinholdtsen memset(msg_data, 0, 4); 494c18ec02fSPetter Reinholdtsen msg_data[0] = 0; 495c18ec02fSPetter Reinholdtsen 496c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 497c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 498c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_INFO; 499c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 500c18ec02fSPetter Reinholdtsen req.msg.data_len = 1; 501c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 502c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 503c18ec02fSPetter Reinholdtsen printf(" Device not present (No Response)\n"); 504c18ec02fSPetter Reinholdtsen return(-1); 505*58837647SZdenek Styblik } else if (rsp->ccode > 0) { 506c18ec02fSPetter Reinholdtsen printf(" Device not present (%s)\n", 507c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 508c18ec02fSPetter Reinholdtsen return(-1); 509c18ec02fSPetter Reinholdtsen } 510c18ec02fSPetter Reinholdtsen 511c18ec02fSPetter Reinholdtsen memset(&fru, 0, sizeof(fru)); 512c18ec02fSPetter Reinholdtsen fru.size = (rsp->data[1] << 8) | rsp->data[0]; 513c18ec02fSPetter Reinholdtsen fru.access = rsp->data[2] & 0x1; 514c18ec02fSPetter Reinholdtsen if (fru.size < 1) { 515c18ec02fSPetter Reinholdtsen printf(" Invalid FRU size %d", fru.size); 516c18ec02fSPetter Reinholdtsen return(-1); 517c18ec02fSPetter Reinholdtsen } 518*58837647SZdenek Styblik /* retrieve the FRU header */ 519c18ec02fSPetter Reinholdtsen msg_data[0] = 0; 520c18ec02fSPetter Reinholdtsen msg_data[1] = 0; 521c18ec02fSPetter Reinholdtsen msg_data[2] = 0; 522c18ec02fSPetter Reinholdtsen msg_data[3] = 8; 523c18ec02fSPetter Reinholdtsen 524c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 525c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 526c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_DATA; 527c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 528c18ec02fSPetter Reinholdtsen req.msg.data_len = 4; 529c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 530*58837647SZdenek Styblik if (rsp == NULL) { 531c18ec02fSPetter Reinholdtsen printf(" Device not present (No Response)\n"); 532c18ec02fSPetter Reinholdtsen return (-1); 533*58837647SZdenek Styblik } else if (rsp->ccode > 0) { 534c18ec02fSPetter Reinholdtsen printf(" Device not present (%s)\n", 535c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 536c18ec02fSPetter Reinholdtsen return (-1); 537c18ec02fSPetter Reinholdtsen } 538*58837647SZdenek Styblik if (verbose > 1) { 539c18ec02fSPetter Reinholdtsen printbuf(rsp->data, rsp->data_len, "FRU DATA"); 540*58837647SZdenek Styblik } 541c18ec02fSPetter Reinholdtsen memcpy(&header, rsp->data + 1, 8); 542*58837647SZdenek Styblik if (header.version != 1) { 543c18ec02fSPetter Reinholdtsen printf(" Unknown FRU header version 0x%02x", 544c18ec02fSPetter Reinholdtsen header.version); 545c18ec02fSPetter Reinholdtsen return(-1); 546c18ec02fSPetter Reinholdtsen } 547c18ec02fSPetter Reinholdtsen board_sec_len = (header.offset.product * 8) - (header.offset.board * 8); 548c18ec02fSPetter Reinholdtsen fru_data = malloc(fru.size); 549*58837647SZdenek Styblik if(fru_data == NULL) { 550*58837647SZdenek Styblik lprintf(LOG_ERR, "ipmitool: malloc failure"); 551c18ec02fSPetter Reinholdtsen return(-1); 552c18ec02fSPetter Reinholdtsen } 553c18ec02fSPetter Reinholdtsen memset(fru_data, 0, fru.size); 554*58837647SZdenek Styblik if (read_fru_area(intf ,&fru ,0 ,(header.offset.board * 8), 555*58837647SZdenek Styblik board_sec_len ,fru_data) < 0) { 556c18ec02fSPetter Reinholdtsen free(fru_data); 557c18ec02fSPetter Reinholdtsen fru_data = NULL; 558c18ec02fSPetter Reinholdtsen return(-1); 559c18ec02fSPetter Reinholdtsen } 560c18ec02fSPetter Reinholdtsen /* Copy the new manufacturing date in the board section saved in memory*/ 561c18ec02fSPetter Reinholdtsen memcpy(fru_data + (header.offset.board * 8) + 3, mfg_date, 3); 562c18ec02fSPetter Reinholdtsen checksum = 0; 563c18ec02fSPetter Reinholdtsen /* Calculate Header Checksum */ 564*58837647SZdenek Styblik for (i = (header.offset.board * 8); 565*58837647SZdenek Styblik i < (((header.offset.board * 8) + board_sec_len) - 2); 566*58837647SZdenek Styblik i ++ ) { 567c18ec02fSPetter Reinholdtsen checksum += fru_data[i]; 568c18ec02fSPetter Reinholdtsen } 569c18ec02fSPetter Reinholdtsen checksum = (~checksum) + 1; 570c18ec02fSPetter Reinholdtsen fru_data[(header.offset.board * 8)+board_sec_len - 1] = checksum; 571c18ec02fSPetter Reinholdtsen /* Write the new FRU Board section */ 572*58837647SZdenek Styblik if (write_fru_area(intf, &fru, 0, (header.offset.board * 8), 573*58837647SZdenek Styblik (header.offset.board * 8), 574*58837647SZdenek Styblik board_sec_len, fru_data) < 0) { 575c18ec02fSPetter Reinholdtsen free(fru_data); 576c18ec02fSPetter Reinholdtsen fru_data = NULL; 577c18ec02fSPetter Reinholdtsen return (-1); 578c18ec02fSPetter Reinholdtsen } 579c18ec02fSPetter Reinholdtsen free(fru_data); 580c18ec02fSPetter Reinholdtsen fru_data = NULL; 581c18ec02fSPetter Reinholdtsen return (1); 582c18ec02fSPetter Reinholdtsen } 583c18ec02fSPetter Reinholdtsen 584c18ec02fSPetter Reinholdtsen static void 585c18ec02fSPetter Reinholdtsen ipmi_kontron_nextboot_help(void) 586c18ec02fSPetter Reinholdtsen { 587c18ec02fSPetter Reinholdtsen int i; 588c18ec02fSPetter Reinholdtsen printf("nextboot <device>\n" 589c18ec02fSPetter Reinholdtsen "Supported devices:\n"); 590c18ec02fSPetter Reinholdtsen for (i = 0; bootdev[i] != 0; i++) { 591c18ec02fSPetter Reinholdtsen printf("- %s\n", bootdev[i]); 592c18ec02fSPetter Reinholdtsen } 593c18ec02fSPetter Reinholdtsen } 594c18ec02fSPetter Reinholdtsen 595c18ec02fSPetter Reinholdtsen /* ipmi_kontron_next_boot_set - Select the next boot order on CP6012 596c18ec02fSPetter Reinholdtsen * 597c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 598c18ec02fSPetter Reinholdtsen * @id: fru id 599c18ec02fSPetter Reinholdtsen * 600c18ec02fSPetter Reinholdtsen * returns -1 on error 601c18ec02fSPetter Reinholdtsen * returns 1 if successful 602c18ec02fSPetter Reinholdtsen */ 603c18ec02fSPetter Reinholdtsen static int 604c18ec02fSPetter Reinholdtsen ipmi_kontron_nextboot_set(struct ipmi_intf *intf, int argc, char **argv) 605c18ec02fSPetter Reinholdtsen { 606c18ec02fSPetter Reinholdtsen struct ipmi_rs *rsp; 607c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 608c18ec02fSPetter Reinholdtsen uint8_t msg_data[8]; 609c18ec02fSPetter Reinholdtsen int i; 610c18ec02fSPetter Reinholdtsen 611c18ec02fSPetter Reinholdtsen memset(msg_data, 0, sizeof(msg_data)); 612c18ec02fSPetter Reinholdtsen msg_data[0] = 0xb4; 613c18ec02fSPetter Reinholdtsen msg_data[1] = 0x90; 614c18ec02fSPetter Reinholdtsen msg_data[2] = 0x91; 615c18ec02fSPetter Reinholdtsen msg_data[3] = 0x8b; 616c18ec02fSPetter Reinholdtsen msg_data[4] = 0x9d; 617c18ec02fSPetter Reinholdtsen msg_data[5] = 0xFF; 618c18ec02fSPetter Reinholdtsen msg_data[6] = 0xFF; /* any */ 619c18ec02fSPetter Reinholdtsen for (i = 0; bootdev[i] != 0; i++) { 620c18ec02fSPetter Reinholdtsen if (strcmp(argv[0], bootdev[i]) == 0) { 621c18ec02fSPetter Reinholdtsen msg_data[5] = i; 622c18ec02fSPetter Reinholdtsen break; 623c18ec02fSPetter Reinholdtsen } 624c18ec02fSPetter Reinholdtsen } 625c18ec02fSPetter Reinholdtsen /* Invalid device selected? */ 626c18ec02fSPetter Reinholdtsen if (msg_data[5] == 0xFF) { 627c18ec02fSPetter Reinholdtsen printf("Unknown boot device: %s\n", argv[0]); 628*58837647SZdenek Styblik return (-1); 629c18ec02fSPetter Reinholdtsen } 630c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 631c18ec02fSPetter Reinholdtsen req.msg.netfn = 0x3E; 632c18ec02fSPetter Reinholdtsen req.msg.cmd = 0x02; 633c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 634c18ec02fSPetter Reinholdtsen req.msg.data_len = 7; 635c18ec02fSPetter Reinholdtsen /* Set Lun temporary, necessary for this oem command */ 636c18ec02fSPetter Reinholdtsen req.msg.lun = 0x03; 637c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 638*58837647SZdenek Styblik if (rsp == NULL) { 639c18ec02fSPetter Reinholdtsen printf("Device not present (No Response)\n"); 640c18ec02fSPetter Reinholdtsen return(-1); 641*58837647SZdenek Styblik } else if (rsp->ccode > 0) { 642c18ec02fSPetter Reinholdtsen printf("Device not present (%s)\n", 643c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 644c18ec02fSPetter Reinholdtsen return (-1); 645c18ec02fSPetter Reinholdtsen } 646c18ec02fSPetter Reinholdtsen return 0; 647c18ec02fSPetter Reinholdtsen } 648