1c18ec02fSPetter Reinholdtsen /* 2c18ec02fSPetter Reinholdtsen * Redistribution and use in source and binary forms, with or without 3c18ec02fSPetter Reinholdtsen * modification, are permitted provided that the following conditions 4c18ec02fSPetter Reinholdtsen * are met: 5c18ec02fSPetter Reinholdtsen * 6c18ec02fSPetter Reinholdtsen * Redistribution of source code must retain the above copyright 7c18ec02fSPetter Reinholdtsen * notice, this list of conditions and the following disclaimer. 8c18ec02fSPetter Reinholdtsen * 9c18ec02fSPetter Reinholdtsen * Redistribution in binary form must reproduce the above copyright 10c18ec02fSPetter Reinholdtsen * notice, this list of conditions and the following disclaimer in the 11c18ec02fSPetter Reinholdtsen * documentation and/or other materials provided with the distribution. 12c18ec02fSPetter Reinholdtsen * 13c18ec02fSPetter Reinholdtsen * Neither the name of Sun Microsystems, Inc. or the names of 14c18ec02fSPetter Reinholdtsen * contributors may be used to endorse or promote products derived 15c18ec02fSPetter Reinholdtsen * from this software without specific prior written permission. 16c18ec02fSPetter Reinholdtsen * 17c18ec02fSPetter Reinholdtsen * This software is provided "AS IS," without a warranty of any kind. 18c18ec02fSPetter Reinholdtsen * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, 19c18ec02fSPetter Reinholdtsen * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 20c18ec02fSPetter Reinholdtsen * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. 21c18ec02fSPetter Reinholdtsen * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE 22c18ec02fSPetter Reinholdtsen * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING 23c18ec02fSPetter Reinholdtsen * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL 24c18ec02fSPetter Reinholdtsen * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, 25c18ec02fSPetter Reinholdtsen * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR 26c18ec02fSPetter Reinholdtsen * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF 27c18ec02fSPetter Reinholdtsen * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 28c18ec02fSPetter Reinholdtsen * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 29c18ec02fSPetter Reinholdtsen */ 30c18ec02fSPetter Reinholdtsen 31c18ec02fSPetter Reinholdtsen /* 32c18ec02fSPetter Reinholdtsen * Functions to program the SDR repository, from built-in sensors or 33c18ec02fSPetter Reinholdtsen * from sensors dumped in a binary file. 34c18ec02fSPetter Reinholdtsen */ 35c18ec02fSPetter Reinholdtsen 36c18ec02fSPetter Reinholdtsen #include <stdlib.h> 37c18ec02fSPetter Reinholdtsen #include <string.h> 38c18ec02fSPetter Reinholdtsen #include <stdio.h> 39c18ec02fSPetter Reinholdtsen #include <time.h> 40c18ec02fSPetter Reinholdtsen #include <fcntl.h> 41c18ec02fSPetter Reinholdtsen 42c18ec02fSPetter Reinholdtsen #include <ipmitool/helper.h> 43c18ec02fSPetter Reinholdtsen #include <ipmitool/log.h> 44c18ec02fSPetter Reinholdtsen #include <ipmitool/bswap.h> 45c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi.h> 46c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_intf.h> 47c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_mc.h> 48c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_strings.h> 49c18ec02fSPetter Reinholdtsen 50c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_sdr.h> 51c18ec02fSPetter Reinholdtsen 52c18ec02fSPetter Reinholdtsen 53c18ec02fSPetter Reinholdtsen #define ADD_PARTIAL_SDR 0x25 54c18ec02fSPetter Reinholdtsen 55c18ec02fSPetter Reinholdtsen #ifdef HAVE_PRAGMA_PACK 56c18ec02fSPetter Reinholdtsen #pragma pack(1) 57c18ec02fSPetter Reinholdtsen #endif 58c18ec02fSPetter Reinholdtsen struct sdr_add_rq { 59c18ec02fSPetter Reinholdtsen uint16_t reserve_id; /* reservation ID */ 60c18ec02fSPetter Reinholdtsen uint16_t id; /* record ID */ 61c18ec02fSPetter Reinholdtsen uint8_t offset; /* offset into SDR */ 62c18ec02fSPetter Reinholdtsen uint8_t in_progress; /* 0=partial, 1=last */ 63c18ec02fSPetter Reinholdtsen #define PARTIAL_ADD (0) 64c18ec02fSPetter Reinholdtsen #define LAST_RECORD (1) 65c18ec02fSPetter Reinholdtsen uint8_t data[1]; /* SDR record data */ 66c18ec02fSPetter Reinholdtsen } ATTRIBUTE_PACKING; 67c18ec02fSPetter Reinholdtsen #ifdef HAVE_PRAGMA_PACK 68c18ec02fSPetter Reinholdtsen #pragma pack(0) 69c18ec02fSPetter Reinholdtsen #endif 70c18ec02fSPetter Reinholdtsen 71c18ec02fSPetter Reinholdtsen /* This was formerly initialized to 24, reduced this to 19 so the overall 72c18ec02fSPetter Reinholdtsen message fits into the recommended 32-byte limit */ 73c18ec02fSPetter Reinholdtsen static int sdr_max_write_len = 19; 74c18ec02fSPetter Reinholdtsen int ipmi_parse_range_list(const char *rangeList, unsigned char *pHexList); 75c18ec02fSPetter Reinholdtsen int ipmi_hex_to_dec( char * rangeList, unsigned char * pDecValue); 76c18ec02fSPetter Reinholdtsen 77c18ec02fSPetter Reinholdtsen static int 78c18ec02fSPetter Reinholdtsen partial_send(struct ipmi_intf *intf, struct ipmi_rq *req, uint16_t *id) 79c18ec02fSPetter Reinholdtsen { 80c18ec02fSPetter Reinholdtsen struct ipmi_rs *rsp; 81c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, req); 82c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 83c18ec02fSPetter Reinholdtsen return -1; 84c18ec02fSPetter Reinholdtsen } 85c18ec02fSPetter Reinholdtsen 86c18ec02fSPetter Reinholdtsen if (rsp->ccode || rsp->data_len < 2) { 87c18ec02fSPetter Reinholdtsen return -1; 88c18ec02fSPetter Reinholdtsen } 89c18ec02fSPetter Reinholdtsen 90c18ec02fSPetter Reinholdtsen *id = rsp->data[0] + (rsp->data[1] << 8); 91c18ec02fSPetter Reinholdtsen return 0; 92c18ec02fSPetter Reinholdtsen } 93c18ec02fSPetter Reinholdtsen 94c18ec02fSPetter Reinholdtsen int 95c18ec02fSPetter Reinholdtsen ipmi_sdr_add_record(struct ipmi_intf *intf, struct sdr_record_list *sdrr) 96c18ec02fSPetter Reinholdtsen { 97c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 98c18ec02fSPetter Reinholdtsen struct sdr_add_rq *sdr_rq; 99c18ec02fSPetter Reinholdtsen uint16_t reserve_id; 100c18ec02fSPetter Reinholdtsen uint16_t id; 101c18ec02fSPetter Reinholdtsen int i; 102c18ec02fSPetter Reinholdtsen int len = sdrr->length; 103c18ec02fSPetter Reinholdtsen int rc = 0; 104c18ec02fSPetter Reinholdtsen 105c18ec02fSPetter Reinholdtsen /* actually no SDR to program */ 106c18ec02fSPetter Reinholdtsen if (len < 1 || !sdrr->raw) { 107c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: bad record , skipped"); 108c18ec02fSPetter Reinholdtsen return 0; 109c18ec02fSPetter Reinholdtsen } 110c18ec02fSPetter Reinholdtsen 111c18ec02fSPetter Reinholdtsen if (ipmi_sdr_get_reservation(intf, 0, &reserve_id)) { 112c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: reservation failed"); 113c18ec02fSPetter Reinholdtsen return -1; 114c18ec02fSPetter Reinholdtsen } 115c18ec02fSPetter Reinholdtsen 116c18ec02fSPetter Reinholdtsen sdr_rq = (struct sdr_add_rq *)malloc(sizeof(*sdr_rq) + sdr_max_write_len); 117c18ec02fSPetter Reinholdtsen if (sdr_rq == NULL) { 118c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: malloc failure"); 119c18ec02fSPetter Reinholdtsen return -1; 120c18ec02fSPetter Reinholdtsen } 121c18ec02fSPetter Reinholdtsen sdr_rq->reserve_id = reserve_id; 122c18ec02fSPetter Reinholdtsen sdr_rq->in_progress = PARTIAL_ADD; 123c18ec02fSPetter Reinholdtsen 124c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 125c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 126c18ec02fSPetter Reinholdtsen req.msg.cmd = ADD_PARTIAL_SDR; 127c18ec02fSPetter Reinholdtsen req.msg.data = (uint8_t *) sdr_rq; 128c18ec02fSPetter Reinholdtsen 129c18ec02fSPetter Reinholdtsen /* header first */ 130c18ec02fSPetter Reinholdtsen sdr_rq->id = 0; 131c18ec02fSPetter Reinholdtsen sdr_rq->offset = 0; 132c18ec02fSPetter Reinholdtsen sdr_rq->data[0] = sdrr->id & 0xFF; 133c18ec02fSPetter Reinholdtsen sdr_rq->data[1] = (sdrr->id >> 8) & 0xFF; 134c18ec02fSPetter Reinholdtsen sdr_rq->data[2] = sdrr->version; 135c18ec02fSPetter Reinholdtsen sdr_rq->data[3] = sdrr->type; 136c18ec02fSPetter Reinholdtsen sdr_rq->data[4] = sdrr->length; 137c18ec02fSPetter Reinholdtsen req.msg.data_len = 5 + sizeof(*sdr_rq) - 1; 138c18ec02fSPetter Reinholdtsen 139c18ec02fSPetter Reinholdtsen if (partial_send(intf, &req, &id)) { 140c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: partial send error"); 141c18ec02fSPetter Reinholdtsen free(sdr_rq); 142c18ec02fSPetter Reinholdtsen sdr_rq = NULL; 143c18ec02fSPetter Reinholdtsen return -1; 144c18ec02fSPetter Reinholdtsen } 145c18ec02fSPetter Reinholdtsen 146c18ec02fSPetter Reinholdtsen i = 0; 147c18ec02fSPetter Reinholdtsen 148c18ec02fSPetter Reinholdtsen /* sdr entry */ 149c18ec02fSPetter Reinholdtsen while (i < len) { 150c18ec02fSPetter Reinholdtsen int data_len = 0; 151c18ec02fSPetter Reinholdtsen if ( (len - i) <= sdr_max_write_len) { 152c18ec02fSPetter Reinholdtsen /* last crunch */ 153c18ec02fSPetter Reinholdtsen data_len = len - i; 154c18ec02fSPetter Reinholdtsen sdr_rq->in_progress = LAST_RECORD; 155c18ec02fSPetter Reinholdtsen } else { 156c18ec02fSPetter Reinholdtsen data_len = sdr_max_write_len; 157c18ec02fSPetter Reinholdtsen } 158c18ec02fSPetter Reinholdtsen 159c18ec02fSPetter Reinholdtsen sdr_rq->id = id; 160c18ec02fSPetter Reinholdtsen sdr_rq->offset = i + 5; 161c18ec02fSPetter Reinholdtsen memcpy(sdr_rq->data, sdrr->raw + i, data_len); 162c18ec02fSPetter Reinholdtsen req.msg.data_len = data_len + sizeof(*sdr_rq) - 1; 163c18ec02fSPetter Reinholdtsen 164c18ec02fSPetter Reinholdtsen if ((rc = partial_send(intf, &req, &id)) != 0) { 165c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: partial add failed"); 166c18ec02fSPetter Reinholdtsen break; 167c18ec02fSPetter Reinholdtsen } 168c18ec02fSPetter Reinholdtsen 169c18ec02fSPetter Reinholdtsen i += data_len; 170c18ec02fSPetter Reinholdtsen } 171c18ec02fSPetter Reinholdtsen 172c18ec02fSPetter Reinholdtsen free(sdr_rq); 173c18ec02fSPetter Reinholdtsen sdr_rq = NULL; 174c18ec02fSPetter Reinholdtsen return rc; 175c18ec02fSPetter Reinholdtsen } 176c18ec02fSPetter Reinholdtsen 177c18ec02fSPetter Reinholdtsen static int 178c18ec02fSPetter Reinholdtsen ipmi_sdr_repo_clear(struct ipmi_intf *intf) 179c18ec02fSPetter Reinholdtsen { 180c18ec02fSPetter Reinholdtsen struct ipmi_rs * rsp; 181c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 182c18ec02fSPetter Reinholdtsen uint8_t msg_data[8]; 183c18ec02fSPetter Reinholdtsen uint16_t reserve_id; 184c18ec02fSPetter Reinholdtsen int try; 185c18ec02fSPetter Reinholdtsen 186c18ec02fSPetter Reinholdtsen if (ipmi_sdr_get_reservation(intf, 0, &reserve_id)) 187c18ec02fSPetter Reinholdtsen return -1; 188c18ec02fSPetter Reinholdtsen 189c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 190c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 191c18ec02fSPetter Reinholdtsen req.msg.cmd = 0x27; // FIXME 192c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 193c18ec02fSPetter Reinholdtsen req.msg.data_len = 6; 194c18ec02fSPetter Reinholdtsen 195c18ec02fSPetter Reinholdtsen msg_data[0] = reserve_id & 0xFF; 196c18ec02fSPetter Reinholdtsen msg_data[1] = reserve_id >> 8; 197c18ec02fSPetter Reinholdtsen msg_data[2] = 'C'; 198c18ec02fSPetter Reinholdtsen msg_data[3] = 'L'; 199c18ec02fSPetter Reinholdtsen msg_data[4] = 'R'; 200c18ec02fSPetter Reinholdtsen msg_data[5] = 0xAA; 201c18ec02fSPetter Reinholdtsen 202c18ec02fSPetter Reinholdtsen for (try = 0; try < 5; try++) { 203c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 204c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 205c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Unable to clear SDRR"); 206c18ec02fSPetter Reinholdtsen return -1; 207c18ec02fSPetter Reinholdtsen } 208c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 209c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Unable to clear SDRR: %s", 210c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 211c18ec02fSPetter Reinholdtsen return -1; 212c18ec02fSPetter Reinholdtsen } 213c18ec02fSPetter Reinholdtsen if ((rsp->data[0] & 1) == 1) { 214c18ec02fSPetter Reinholdtsen printf("SDRR successfully erased\n"); 215c18ec02fSPetter Reinholdtsen return 0; 216c18ec02fSPetter Reinholdtsen } 217c18ec02fSPetter Reinholdtsen printf("Wait for SDRR erasure completed...\n"); 218c18ec02fSPetter Reinholdtsen msg_data[5] = 0; 219c18ec02fSPetter Reinholdtsen sleep(1); 220c18ec02fSPetter Reinholdtsen } 221c18ec02fSPetter Reinholdtsen 222c18ec02fSPetter Reinholdtsen /* if we are here we fed up trying erase */ 223c18ec02fSPetter Reinholdtsen return -1; 224c18ec02fSPetter Reinholdtsen } 225c18ec02fSPetter Reinholdtsen 226c18ec02fSPetter Reinholdtsen 227c18ec02fSPetter Reinholdtsen struct sdrr_queue { 228c18ec02fSPetter Reinholdtsen struct sdr_record_list *head; 229c18ec02fSPetter Reinholdtsen struct sdr_record_list *tail; 230c18ec02fSPetter Reinholdtsen }; 231c18ec02fSPetter Reinholdtsen 232c18ec02fSPetter Reinholdtsen 233c18ec02fSPetter Reinholdtsen /* 234c18ec02fSPetter Reinholdtsen * Fill the SDR repository from built-in sensors 235c18ec02fSPetter Reinholdtsen * 236c18ec02fSPetter Reinholdtsen */ 237c18ec02fSPetter Reinholdtsen 238c18ec02fSPetter Reinholdtsen /* 239c18ec02fSPetter Reinholdtsen * Get all the SDR records stored in <queue> 240c18ec02fSPetter Reinholdtsen */ 241c18ec02fSPetter Reinholdtsen static int 242c18ec02fSPetter Reinholdtsen sdrr_get_records(struct ipmi_intf *intf, struct ipmi_sdr_iterator *itr, 243c18ec02fSPetter Reinholdtsen struct sdrr_queue *queue) 244c18ec02fSPetter Reinholdtsen { 245c18ec02fSPetter Reinholdtsen struct sdr_get_rs *header; 246c18ec02fSPetter Reinholdtsen 247c18ec02fSPetter Reinholdtsen queue->head = NULL; 248c18ec02fSPetter Reinholdtsen queue->tail = NULL; 249c18ec02fSPetter Reinholdtsen 250c18ec02fSPetter Reinholdtsen while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) { 251c18ec02fSPetter Reinholdtsen struct sdr_record_list *sdrr; 252c18ec02fSPetter Reinholdtsen 253c18ec02fSPetter Reinholdtsen sdrr = malloc(sizeof (struct sdr_record_list)); 254c18ec02fSPetter Reinholdtsen if (sdrr == NULL) { 255c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: malloc failure"); 256c18ec02fSPetter Reinholdtsen return -1; 257c18ec02fSPetter Reinholdtsen } 258c18ec02fSPetter Reinholdtsen memset(sdrr, 0, sizeof (struct sdr_record_list)); 259c18ec02fSPetter Reinholdtsen 260c18ec02fSPetter Reinholdtsen sdrr->id = header->id; 261c18ec02fSPetter Reinholdtsen sdrr->version = header->version; 262c18ec02fSPetter Reinholdtsen sdrr->type = header->type; 263c18ec02fSPetter Reinholdtsen sdrr->length = header->length; 264c18ec02fSPetter Reinholdtsen sdrr->raw = ipmi_sdr_get_record(intf, header, itr); 265c18ec02fSPetter Reinholdtsen (void)ipmi_sdr_print_name_from_rawentry(intf, sdrr->id, sdrr->type,sdrr->raw); 266c18ec02fSPetter Reinholdtsen 267c18ec02fSPetter Reinholdtsen /* put in the record queue */ 268c18ec02fSPetter Reinholdtsen if (queue->head == NULL) 269c18ec02fSPetter Reinholdtsen queue->head = sdrr; 270c18ec02fSPetter Reinholdtsen else 271c18ec02fSPetter Reinholdtsen queue->tail->next = sdrr; 272c18ec02fSPetter Reinholdtsen queue->tail = sdrr; 273c18ec02fSPetter Reinholdtsen } 274c18ec02fSPetter Reinholdtsen return 0; 275c18ec02fSPetter Reinholdtsen } 276c18ec02fSPetter Reinholdtsen 277c18ec02fSPetter Reinholdtsen static int 278c18ec02fSPetter Reinholdtsen sdr_copy_to_sdrr(struct ipmi_intf *intf, int use_builtin, 279c18ec02fSPetter Reinholdtsen int from_addr, int to_addr) 280c18ec02fSPetter Reinholdtsen { 281c18ec02fSPetter Reinholdtsen int rc; 282c18ec02fSPetter Reinholdtsen struct sdrr_queue sdrr_queue; 283c18ec02fSPetter Reinholdtsen struct ipmi_sdr_iterator *itr; 284c18ec02fSPetter Reinholdtsen struct sdr_record_list *sdrr; 285c18ec02fSPetter Reinholdtsen struct sdr_record_list *sdrr_next; 286c18ec02fSPetter Reinholdtsen 287c18ec02fSPetter Reinholdtsen /* generate list of records for this target */ 288c18ec02fSPetter Reinholdtsen intf->target_addr = from_addr; 289c18ec02fSPetter Reinholdtsen 290c18ec02fSPetter Reinholdtsen /* initialize iterator */ 291c18ec02fSPetter Reinholdtsen itr = ipmi_sdr_start(intf, use_builtin); 292c18ec02fSPetter Reinholdtsen if (itr == 0) 293c18ec02fSPetter Reinholdtsen return 0; 294c18ec02fSPetter Reinholdtsen 295c18ec02fSPetter Reinholdtsen printf("Load SDRs from 0x%x\n", from_addr); 296c18ec02fSPetter Reinholdtsen rc = sdrr_get_records(intf, itr, &sdrr_queue); 297c18ec02fSPetter Reinholdtsen ipmi_sdr_end(intf, itr); 298c18ec02fSPetter Reinholdtsen /* ... */ 299c18ec02fSPetter Reinholdtsen 300c18ec02fSPetter Reinholdtsen /* write the SDRs to the destination SDR Repository */ 301c18ec02fSPetter Reinholdtsen intf->target_addr = to_addr; 302c18ec02fSPetter Reinholdtsen for (sdrr = sdrr_queue.head; sdrr != NULL; sdrr = sdrr_next) { 303c18ec02fSPetter Reinholdtsen sdrr_next = sdrr->next; 304c18ec02fSPetter Reinholdtsen rc = ipmi_sdr_add_record(intf, sdrr); 305c18ec02fSPetter Reinholdtsen if(rc < 0){ 306c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Cannot add SDR ID 0x%04x to repository...", sdrr->id); 307c18ec02fSPetter Reinholdtsen } 308c18ec02fSPetter Reinholdtsen free(sdrr); 309c18ec02fSPetter Reinholdtsen sdrr = NULL; 310c18ec02fSPetter Reinholdtsen } 311c18ec02fSPetter Reinholdtsen return rc; 312c18ec02fSPetter Reinholdtsen } 313c18ec02fSPetter Reinholdtsen 314c18ec02fSPetter Reinholdtsen int 315c18ec02fSPetter Reinholdtsen ipmi_sdr_add_from_sensors(struct ipmi_intf *intf, int maxslot) 316c18ec02fSPetter Reinholdtsen { 317c18ec02fSPetter Reinholdtsen int i; 318c18ec02fSPetter Reinholdtsen int rc = 0; 319c18ec02fSPetter Reinholdtsen int slave_addr; 320c18ec02fSPetter Reinholdtsen int myaddr = intf->target_addr; 321c18ec02fSPetter Reinholdtsen 322c18ec02fSPetter Reinholdtsen if (ipmi_sdr_repo_clear(intf)) { 323c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Cannot erase SDRR. Give up."); 324c18ec02fSPetter Reinholdtsen return -1; 325c18ec02fSPetter Reinholdtsen } 326c18ec02fSPetter Reinholdtsen 327c18ec02fSPetter Reinholdtsen /* First fill the SDRR from local built-in sensors */ 328c18ec02fSPetter Reinholdtsen rc = sdr_copy_to_sdrr(intf, 1, myaddr, myaddr); 329c18ec02fSPetter Reinholdtsen 330c18ec02fSPetter Reinholdtsen /* Now fill the SDRR with remote sensors */ 331c18ec02fSPetter Reinholdtsen if( maxslot != 0 ) { 332c18ec02fSPetter Reinholdtsen for (i = 0, slave_addr = 0xB0; i < maxslot; i++, slave_addr += 2) { 333c18ec02fSPetter Reinholdtsen /* Hole in the PICMG 2.9 mapping */ 334c18ec02fSPetter Reinholdtsen if (slave_addr == 0xC2) slave_addr += 2; 335c18ec02fSPetter Reinholdtsen if(sdr_copy_to_sdrr(intf, 0, slave_addr, myaddr) < 0) 336c18ec02fSPetter Reinholdtsen { 337c18ec02fSPetter Reinholdtsen rc = -1; 338c18ec02fSPetter Reinholdtsen } 339c18ec02fSPetter Reinholdtsen } 340c18ec02fSPetter Reinholdtsen } 341c18ec02fSPetter Reinholdtsen return rc; 342c18ec02fSPetter Reinholdtsen } 343c18ec02fSPetter Reinholdtsen 344c18ec02fSPetter Reinholdtsen int ipmi_hex_to_dec( char * strchar, unsigned char * pDecValue) 345c18ec02fSPetter Reinholdtsen { 346c18ec02fSPetter Reinholdtsen int rc = -1; 347c18ec02fSPetter Reinholdtsen unsigned char retValue = 0; 348c18ec02fSPetter Reinholdtsen 349c18ec02fSPetter Reinholdtsen if( 350c18ec02fSPetter Reinholdtsen (strlen(strchar) == 4) 351c18ec02fSPetter Reinholdtsen && 352c18ec02fSPetter Reinholdtsen (strchar[0] == '0') 353c18ec02fSPetter Reinholdtsen && 354c18ec02fSPetter Reinholdtsen (strchar[1] == 'x') 355c18ec02fSPetter Reinholdtsen ) 356c18ec02fSPetter Reinholdtsen { 357c18ec02fSPetter Reinholdtsen rc = 0; 358c18ec02fSPetter Reinholdtsen 359c18ec02fSPetter Reinholdtsen if((strchar[2] >= '0') && (strchar[2] <= '9')) 360c18ec02fSPetter Reinholdtsen { 361c18ec02fSPetter Reinholdtsen retValue += ((strchar[2]-'0') * 16); 362c18ec02fSPetter Reinholdtsen } 363c18ec02fSPetter Reinholdtsen else if((strchar[2] >= 'a') && (strchar[2] <= 'f')) 364c18ec02fSPetter Reinholdtsen { 365c18ec02fSPetter Reinholdtsen retValue += (((strchar[2]-'a') + 10) * 16); 366c18ec02fSPetter Reinholdtsen } 367c18ec02fSPetter Reinholdtsen else if((strchar[2] >= 'A') && (strchar[2] <= 'F')) 368c18ec02fSPetter Reinholdtsen { 369c18ec02fSPetter Reinholdtsen retValue += (((strchar[2]-'A') + 10) * 16); 370c18ec02fSPetter Reinholdtsen } 371c18ec02fSPetter Reinholdtsen else 372c18ec02fSPetter Reinholdtsen { 373c18ec02fSPetter Reinholdtsen rc = -1; 374c18ec02fSPetter Reinholdtsen } 375c18ec02fSPetter Reinholdtsen 376c18ec02fSPetter Reinholdtsen if((strchar[3] >= '0') && (strchar[3] <= '9')) 377c18ec02fSPetter Reinholdtsen { 378c18ec02fSPetter Reinholdtsen retValue += ((strchar[3]-'0')); 379c18ec02fSPetter Reinholdtsen } 380c18ec02fSPetter Reinholdtsen else if((strchar[3] >= 'a') && (strchar[3] <= 'f')) 381c18ec02fSPetter Reinholdtsen { 382c18ec02fSPetter Reinholdtsen retValue += (((strchar[3]-'a') + 10)); 383c18ec02fSPetter Reinholdtsen } 384c18ec02fSPetter Reinholdtsen else if((strchar[3] >= 'A') && (strchar[3] <= 'F')) 385c18ec02fSPetter Reinholdtsen { 386c18ec02fSPetter Reinholdtsen retValue += (((strchar[3]-'A') + 10)); 387c18ec02fSPetter Reinholdtsen } 388c18ec02fSPetter Reinholdtsen else 389c18ec02fSPetter Reinholdtsen { 390c18ec02fSPetter Reinholdtsen rc = -1; 391c18ec02fSPetter Reinholdtsen } 392c18ec02fSPetter Reinholdtsen } 393c18ec02fSPetter Reinholdtsen 394c18ec02fSPetter Reinholdtsen if(rc == 0) 395c18ec02fSPetter Reinholdtsen { 396c18ec02fSPetter Reinholdtsen * pDecValue = retValue; 397c18ec02fSPetter Reinholdtsen } 398c18ec02fSPetter Reinholdtsen else 399c18ec02fSPetter Reinholdtsen { 400c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Must be Hex value of 4 characters (Ex.: 0x24)"); 401c18ec02fSPetter Reinholdtsen } 402c18ec02fSPetter Reinholdtsen 403c18ec02fSPetter Reinholdtsen return rc; 404c18ec02fSPetter Reinholdtsen } 405c18ec02fSPetter Reinholdtsen 406c18ec02fSPetter Reinholdtsen 407c18ec02fSPetter Reinholdtsen 408c18ec02fSPetter Reinholdtsen #define MAX_NUM_SLOT 128 409c18ec02fSPetter Reinholdtsen int ipmi_parse_range_list(const char *rangeList, unsigned char * pHexList) 410c18ec02fSPetter Reinholdtsen { 411c18ec02fSPetter Reinholdtsen int rc = -1; 412c18ec02fSPetter Reinholdtsen 413c18ec02fSPetter Reinholdtsen unsigned char listOffset = 0; 414c18ec02fSPetter Reinholdtsen char * nextString; 415c18ec02fSPetter Reinholdtsen char * rangeString; 416c18ec02fSPetter Reinholdtsen char * inProcessString = (char *) rangeList; 417c18ec02fSPetter Reinholdtsen 418c18ec02fSPetter Reinholdtsen /* Discard empty string */ 419c18ec02fSPetter Reinholdtsen if(strlen(rangeList) == 0) 420c18ec02fSPetter Reinholdtsen { 421c18ec02fSPetter Reinholdtsen return rc; 422c18ec02fSPetter Reinholdtsen } 423c18ec02fSPetter Reinholdtsen 424c18ec02fSPetter Reinholdtsen /* First, cut to comma separated string */ 425c18ec02fSPetter Reinholdtsen nextString = strstr( rangeList, "," ); 426c18ec02fSPetter Reinholdtsen 427c18ec02fSPetter Reinholdtsen if(nextString != rangeList) 428c18ec02fSPetter Reinholdtsen { 429c18ec02fSPetter Reinholdtsen unsigned char isLast; 430c18ec02fSPetter Reinholdtsen /* We get a valid string so far */ 431c18ec02fSPetter Reinholdtsen rc = 0; 432c18ec02fSPetter Reinholdtsen 433c18ec02fSPetter Reinholdtsen do 434c18ec02fSPetter Reinholdtsen { 435c18ec02fSPetter Reinholdtsen if(nextString != NULL) 436c18ec02fSPetter Reinholdtsen { 437c18ec02fSPetter Reinholdtsen (*nextString)= 0; 438c18ec02fSPetter Reinholdtsen nextString ++; 439c18ec02fSPetter Reinholdtsen isLast = 0; 440c18ec02fSPetter Reinholdtsen } 441c18ec02fSPetter Reinholdtsen else 442c18ec02fSPetter Reinholdtsen { 443c18ec02fSPetter Reinholdtsen isLast = 1; 444c18ec02fSPetter Reinholdtsen } 445c18ec02fSPetter Reinholdtsen 446c18ec02fSPetter Reinholdtsen /* At this point, it is a single entry or a range */ 447c18ec02fSPetter Reinholdtsen rangeString = strstr( inProcessString, "-" ); 448c18ec02fSPetter Reinholdtsen if(rangeString == NULL) 449c18ec02fSPetter Reinholdtsen { 450c18ec02fSPetter Reinholdtsen unsigned char decValue = 0; 451c18ec02fSPetter Reinholdtsen 452c18ec02fSPetter Reinholdtsen /* Single entry */ 453c18ec02fSPetter Reinholdtsen rc = ipmi_hex_to_dec( inProcessString, &decValue); 454c18ec02fSPetter Reinholdtsen 455c18ec02fSPetter Reinholdtsen if(rc == 0) 456c18ec02fSPetter Reinholdtsen { 457c18ec02fSPetter Reinholdtsen if((decValue % 2) == 0) 458c18ec02fSPetter Reinholdtsen { 459c18ec02fSPetter Reinholdtsen pHexList[listOffset++] = decValue; 460c18ec02fSPetter Reinholdtsen } 461c18ec02fSPetter Reinholdtsen else 462c18ec02fSPetter Reinholdtsen { 463c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "I2C address provided value must be even."); 464c18ec02fSPetter Reinholdtsen } 465c18ec02fSPetter Reinholdtsen } 466c18ec02fSPetter Reinholdtsen } 467c18ec02fSPetter Reinholdtsen else 468c18ec02fSPetter Reinholdtsen { 469c18ec02fSPetter Reinholdtsen unsigned char startValue = 0; 470c18ec02fSPetter Reinholdtsen unsigned char endValue = 0; 471c18ec02fSPetter Reinholdtsen 472c18ec02fSPetter Reinholdtsen 473c18ec02fSPetter Reinholdtsen (*rangeString)= 0; /* Cut string*/ 474c18ec02fSPetter Reinholdtsen rangeString ++; 475c18ec02fSPetter Reinholdtsen 476c18ec02fSPetter Reinholdtsen /* Range */ 477c18ec02fSPetter Reinholdtsen rc = ipmi_hex_to_dec( inProcessString, &startValue); 478c18ec02fSPetter Reinholdtsen if(rc == 0) 479c18ec02fSPetter Reinholdtsen rc = ipmi_hex_to_dec( rangeString, &endValue); 480c18ec02fSPetter Reinholdtsen 481c18ec02fSPetter Reinholdtsen if(rc == 0) 482c18ec02fSPetter Reinholdtsen { 483c18ec02fSPetter Reinholdtsen if(((startValue % 2) == 0) && ((endValue % 2) == 0)) 484c18ec02fSPetter Reinholdtsen { 485c18ec02fSPetter Reinholdtsen do 486c18ec02fSPetter Reinholdtsen { 487c18ec02fSPetter Reinholdtsen pHexList[listOffset++] = startValue; 488c18ec02fSPetter Reinholdtsen startValue += 2; 489c18ec02fSPetter Reinholdtsen } 490c18ec02fSPetter Reinholdtsen while(startValue != endValue); 491c18ec02fSPetter Reinholdtsen pHexList[listOffset++] = endValue; 492c18ec02fSPetter Reinholdtsen } 493c18ec02fSPetter Reinholdtsen else 494c18ec02fSPetter Reinholdtsen { 495c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "I2C address provided value must be even."); 496c18ec02fSPetter Reinholdtsen } 497c18ec02fSPetter Reinholdtsen } 498c18ec02fSPetter Reinholdtsen } 499c18ec02fSPetter Reinholdtsen 500c18ec02fSPetter Reinholdtsen if(isLast == 0) 501c18ec02fSPetter Reinholdtsen { 502c18ec02fSPetter Reinholdtsen /* Setup for next string */ 503c18ec02fSPetter Reinholdtsen inProcessString = nextString; 504c18ec02fSPetter Reinholdtsen nextString = strstr( rangeList, "," ); 505c18ec02fSPetter Reinholdtsen } 506c18ec02fSPetter Reinholdtsen }while ((isLast == 0) && (rc == 0)); 507c18ec02fSPetter Reinholdtsen } 508c18ec02fSPetter Reinholdtsen 509c18ec02fSPetter Reinholdtsen return rc; 510c18ec02fSPetter Reinholdtsen } 511c18ec02fSPetter Reinholdtsen 512c18ec02fSPetter Reinholdtsen int 513c18ec02fSPetter Reinholdtsen ipmi_sdr_add_from_list(struct ipmi_intf *intf, const char *rangeList) 514c18ec02fSPetter Reinholdtsen { 515c18ec02fSPetter Reinholdtsen int i; 516c18ec02fSPetter Reinholdtsen int rc = 0; 517c18ec02fSPetter Reinholdtsen int slave_addr; 518c18ec02fSPetter Reinholdtsen int myaddr = intf->target_addr; 519c18ec02fSPetter Reinholdtsen unsigned char listValue[MAX_NUM_SLOT]; 520c18ec02fSPetter Reinholdtsen 521c18ec02fSPetter Reinholdtsen memset( listValue, 0, MAX_NUM_SLOT ); 522c18ec02fSPetter Reinholdtsen 523c18ec02fSPetter Reinholdtsen /* Build list from string */ 524c18ec02fSPetter Reinholdtsen if(ipmi_parse_range_list(rangeList, listValue) != 0) 525c18ec02fSPetter Reinholdtsen { 526c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Range - List invalid, cannot be parsed."); 527c18ec02fSPetter Reinholdtsen return -1; 528c18ec02fSPetter Reinholdtsen } 529c18ec02fSPetter Reinholdtsen 530c18ec02fSPetter Reinholdtsen { 531c18ec02fSPetter Reinholdtsen unsigned char counter = 0; 532c18ec02fSPetter Reinholdtsen printf("List to scan: (Built-in) "); 533c18ec02fSPetter Reinholdtsen while(listValue[counter] != 0) 534c18ec02fSPetter Reinholdtsen { 535c18ec02fSPetter Reinholdtsen printf("%02x ", listValue[counter]); 536c18ec02fSPetter Reinholdtsen counter++; 537c18ec02fSPetter Reinholdtsen } 538c18ec02fSPetter Reinholdtsen printf("\n"); 539c18ec02fSPetter Reinholdtsen } 540c18ec02fSPetter Reinholdtsen 541c18ec02fSPetter Reinholdtsen printf("Clearing SDR Repository\n"); 542c18ec02fSPetter Reinholdtsen if (ipmi_sdr_repo_clear(intf)) { 543c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Cannot erase SDRR. Give up."); 544c18ec02fSPetter Reinholdtsen return -1; 545c18ec02fSPetter Reinholdtsen } 546c18ec02fSPetter Reinholdtsen 547c18ec02fSPetter Reinholdtsen /* First fill the SDRR from local built-in sensors */ 548c18ec02fSPetter Reinholdtsen printf("Sanning built-in sensors..\n"); 549c18ec02fSPetter Reinholdtsen rc = sdr_copy_to_sdrr(intf, 1, myaddr, myaddr); 550c18ec02fSPetter Reinholdtsen 551c18ec02fSPetter Reinholdtsen /* Now fill the SDRR with provided sensors list */ 552c18ec02fSPetter Reinholdtsen { 553c18ec02fSPetter Reinholdtsen unsigned char counter = 0; 554c18ec02fSPetter Reinholdtsen while((rc == 0) && (listValue[counter] != 0)) 555c18ec02fSPetter Reinholdtsen { 556c18ec02fSPetter Reinholdtsen slave_addr = listValue[counter]; 557c18ec02fSPetter Reinholdtsen printf("Scanning %02Xh..\n", slave_addr); 558c18ec02fSPetter Reinholdtsen if(sdr_copy_to_sdrr(intf, 0, slave_addr, myaddr) < 0) 559c18ec02fSPetter Reinholdtsen { 560c18ec02fSPetter Reinholdtsen rc = -1; 561c18ec02fSPetter Reinholdtsen } 562c18ec02fSPetter Reinholdtsen counter++; 563c18ec02fSPetter Reinholdtsen } 564c18ec02fSPetter Reinholdtsen } 565c18ec02fSPetter Reinholdtsen 566c18ec02fSPetter Reinholdtsen return rc; 567c18ec02fSPetter Reinholdtsen } 568c18ec02fSPetter Reinholdtsen 569c18ec02fSPetter Reinholdtsen 570c18ec02fSPetter Reinholdtsen /* 571c18ec02fSPetter Reinholdtsen * Fill the SDR repository from records stored in a binary file 572c18ec02fSPetter Reinholdtsen * 573c18ec02fSPetter Reinholdtsen */ 574c18ec02fSPetter Reinholdtsen 575c18ec02fSPetter Reinholdtsen static int 576c18ec02fSPetter Reinholdtsen ipmi_sdr_read_records(const char *filename, struct sdrr_queue *queue) 577c18ec02fSPetter Reinholdtsen { 578c18ec02fSPetter Reinholdtsen struct sdr_get_rs header; 579c18ec02fSPetter Reinholdtsen int rc = 0; 580c18ec02fSPetter Reinholdtsen int fd; 581c18ec02fSPetter Reinholdtsen uint8_t binHdr[5]; 582c18ec02fSPetter Reinholdtsen 583c18ec02fSPetter Reinholdtsen queue->head = NULL; 584c18ec02fSPetter Reinholdtsen queue->tail = NULL; 585c18ec02fSPetter Reinholdtsen 586c18ec02fSPetter Reinholdtsen if ((fd = open(filename, O_RDONLY)) < 0) { 587c18ec02fSPetter Reinholdtsen return -1; 588c18ec02fSPetter Reinholdtsen } 589c18ec02fSPetter Reinholdtsen 590c18ec02fSPetter Reinholdtsen while (read(fd, binHdr, 5) == 5) { 591c18ec02fSPetter Reinholdtsen 592c18ec02fSPetter Reinholdtsen struct sdr_record_list *sdrr; 593c18ec02fSPetter Reinholdtsen 594c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "binHdr[0] (id[MSB]) = 0x%02x", binHdr[0]); 595c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "binHdr[1] (id[LSB]) = 0x%02x", binHdr[1]); 596c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "binHdr[2] (version) = 0x%02x", binHdr[2]); 597c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "binHdr[3] (type) = 0x%02x", binHdr[3]); 598c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "binHdr[4] (length) = 0x%02x", binHdr[4]); 599c18ec02fSPetter Reinholdtsen 600c18ec02fSPetter Reinholdtsen sdrr = malloc(sizeof(*sdrr)); 601c18ec02fSPetter Reinholdtsen if (sdrr == NULL) { 602c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: malloc failure"); 603c18ec02fSPetter Reinholdtsen rc = -1; 604c18ec02fSPetter Reinholdtsen break; 605c18ec02fSPetter Reinholdtsen } 606c18ec02fSPetter Reinholdtsen sdrr->id = (binHdr[1] << 8) | binHdr[0]; // LS Byte first 607c18ec02fSPetter Reinholdtsen sdrr->version = binHdr[2]; 608c18ec02fSPetter Reinholdtsen sdrr->type = binHdr[3]; 609c18ec02fSPetter Reinholdtsen sdrr->length = binHdr[4]; 610c18ec02fSPetter Reinholdtsen 611c18ec02fSPetter Reinholdtsen if ((sdrr->raw = malloc(sdrr->length)) == NULL) { 612c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: malloc failure"); 613c18ec02fSPetter Reinholdtsen free(sdrr); 614c18ec02fSPetter Reinholdtsen sdrr = NULL; 615c18ec02fSPetter Reinholdtsen rc = -1; 616c18ec02fSPetter Reinholdtsen break; 617c18ec02fSPetter Reinholdtsen } 618c18ec02fSPetter Reinholdtsen 619c18ec02fSPetter Reinholdtsen if (read(fd, sdrr->raw, sdrr->length) != sdrr->length) { 620c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "SDR from '%s' truncated", filename); 621c18ec02fSPetter Reinholdtsen free(sdrr->raw); 622c18ec02fSPetter Reinholdtsen sdrr->raw = NULL; 623c18ec02fSPetter Reinholdtsen free(sdrr); 624c18ec02fSPetter Reinholdtsen sdrr = NULL; 625c18ec02fSPetter Reinholdtsen rc = -1; 626c18ec02fSPetter Reinholdtsen break; 627c18ec02fSPetter Reinholdtsen } 628c18ec02fSPetter Reinholdtsen 629c18ec02fSPetter Reinholdtsen /* put in the record queue */ 630c18ec02fSPetter Reinholdtsen if (queue->head == NULL) 631c18ec02fSPetter Reinholdtsen queue->head = sdrr; 632c18ec02fSPetter Reinholdtsen else 633c18ec02fSPetter Reinholdtsen queue->tail->next = sdrr; 634c18ec02fSPetter Reinholdtsen queue->tail = sdrr; 635c18ec02fSPetter Reinholdtsen } 636*e9c3de03SZdenek Styblik close(fd); 637c18ec02fSPetter Reinholdtsen return rc; 638c18ec02fSPetter Reinholdtsen } 639c18ec02fSPetter Reinholdtsen 640c18ec02fSPetter Reinholdtsen int 641c18ec02fSPetter Reinholdtsen ipmi_sdr_add_from_file(struct ipmi_intf *intf, const char *ifile) 642c18ec02fSPetter Reinholdtsen { 643c18ec02fSPetter Reinholdtsen int rc; 644c18ec02fSPetter Reinholdtsen struct sdrr_queue sdrr_queue; 645c18ec02fSPetter Reinholdtsen struct sdr_record_list *sdrr; 646c18ec02fSPetter Reinholdtsen struct sdr_record_list *sdrr_next; 647c18ec02fSPetter Reinholdtsen 648c18ec02fSPetter Reinholdtsen /* read the SDR records from file */ 649c18ec02fSPetter Reinholdtsen rc = ipmi_sdr_read_records(ifile, &sdrr_queue); 650c18ec02fSPetter Reinholdtsen 651c18ec02fSPetter Reinholdtsen if (ipmi_sdr_repo_clear(intf)) { 652c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Cannot erase SDRR. Giving up."); 653c18ec02fSPetter Reinholdtsen /* FIXME: free sdr list */ 654c18ec02fSPetter Reinholdtsen return -1; 655c18ec02fSPetter Reinholdtsen } 656c18ec02fSPetter Reinholdtsen 657c18ec02fSPetter Reinholdtsen /* write the SDRs to the SDR Repository */ 658c18ec02fSPetter Reinholdtsen for (sdrr = sdrr_queue.head; sdrr != NULL; sdrr = sdrr_next) { 659c18ec02fSPetter Reinholdtsen sdrr_next = sdrr->next; 660c18ec02fSPetter Reinholdtsen rc = ipmi_sdr_add_record(intf, sdrr); 661c18ec02fSPetter Reinholdtsen if(rc < 0){ 662c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Cannot add SDR ID 0x%04x to repository...", sdrr->id); 663c18ec02fSPetter Reinholdtsen } 664c18ec02fSPetter Reinholdtsen free(sdrr); 665c18ec02fSPetter Reinholdtsen sdrr = NULL; 666c18ec02fSPetter Reinholdtsen } 667c18ec02fSPetter Reinholdtsen return rc; 668c18ec02fSPetter Reinholdtsen } 669c18ec02fSPetter Reinholdtsen 670