aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorey Minyard <cminyard@mvista.com>2015-04-29 18:59:21 -0400
committerCorey Minyard <cminyard@mvista.com>2015-05-05 20:37:22 -0400
commit3d69d43baa2749c3d187ce70940d7aebe609e149 (patch)
treee7e7825d758c3c3e5e932865bcf0b1b02e235939
parent9162052173d2381e2bbabc224c3c1457acb4c54c (diff)
ipmi: Fix multi-part message handling
Lots of little fixes for multi-part messages: The values was not being re-initialized, if something went wrong handling a multi-part message and it got left in a bad state, it might be an issue. The commands were not correct when issuing multi-part reads, the code was not passing in the proper value for commands. Also clean up some minor formatting issues. Get the block number from the right location, limit the maximum send message size to 63 bytes and explain why, and fix some minor sylistic issues. Signed-off-by: Corey Minyard <cminyard@mvista.com>
-rw-r--r--drivers/char/ipmi/ipmi_ssif.c51
1 files changed, 38 insertions, 13 deletions
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index 5b82d9947ec5..207689c444a8 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -489,13 +489,13 @@ static int ipmi_ssif_thread(void *data)
489 489
490 if (ssif_info->i2c_read_write == I2C_SMBUS_WRITE) { 490 if (ssif_info->i2c_read_write == I2C_SMBUS_WRITE) {
491 result = i2c_smbus_write_block_data( 491 result = i2c_smbus_write_block_data(
492 ssif_info->client, SSIF_IPMI_REQUEST, 492 ssif_info->client, ssif_info->i2c_command,
493 ssif_info->i2c_data[0], 493 ssif_info->i2c_data[0],
494 ssif_info->i2c_data + 1); 494 ssif_info->i2c_data + 1);
495 ssif_info->done_handler(ssif_info, result, NULL, 0); 495 ssif_info->done_handler(ssif_info, result, NULL, 0);
496 } else { 496 } else {
497 result = i2c_smbus_read_block_data( 497 result = i2c_smbus_read_block_data(
498 ssif_info->client, SSIF_IPMI_RESPONSE, 498 ssif_info->client, ssif_info->i2c_command,
499 ssif_info->i2c_data); 499 ssif_info->i2c_data);
500 if (result < 0) 500 if (result < 0)
501 ssif_info->done_handler(ssif_info, result, 501 ssif_info->done_handler(ssif_info, result,
@@ -534,6 +534,7 @@ static void start_get(struct ssif_info *ssif_info)
534 int rv; 534 int rv;
535 535
536 ssif_info->rtc_us_timer = 0; 536 ssif_info->rtc_us_timer = 0;
537 ssif_info->multi_pos = 0;
537 538
538 rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ, 539 rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ,
539 SSIF_IPMI_RESPONSE, 540 SSIF_IPMI_RESPONSE,
@@ -631,9 +632,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
631 ssif_inc_stat(ssif_info, received_message_parts); 632 ssif_inc_stat(ssif_info, received_message_parts);
632 633
633 /* Remove the multi-part read marker. */ 634 /* Remove the multi-part read marker. */
634 for (i = 0; i < (len-2); i++)
635 ssif_info->data[i] = data[i+2];
636 len -= 2; 635 len -= 2;
636 for (i = 0; i < len; i++)
637 ssif_info->data[i] = data[i+2];
637 ssif_info->multi_len = len; 638 ssif_info->multi_len = len;
638 ssif_info->multi_pos = 1; 639 ssif_info->multi_pos = 1;
639 640
@@ -660,9 +661,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
660 goto continue_op; 661 goto continue_op;
661 } 662 }
662 663
663 blocknum = data[ssif_info->multi_len]; 664 blocknum = data[0];
664 665
665 if (ssif_info->multi_len+len-1 > IPMI_MAX_MSG_LENGTH) { 666 if (ssif_info->multi_len + len - 1 > IPMI_MAX_MSG_LENGTH) {
666 /* Received message too big, abort the operation. */ 667 /* Received message too big, abort the operation. */
667 result = -E2BIG; 668 result = -E2BIG;
668 if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) 669 if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
@@ -672,15 +673,15 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
672 } 673 }
673 674
674 /* Remove the blocknum from the data. */ 675 /* Remove the blocknum from the data. */
675 for (i = 0; i < (len-1); i++)
676 ssif_info->data[i+ssif_info->multi_len] = data[i+1];
677 len--; 676 len--;
677 for (i = 0; i < len; i++)
678 ssif_info->data[i + ssif_info->multi_len] = data[i + 1];
678 ssif_info->multi_len += len; 679 ssif_info->multi_len += len;
679 if (blocknum == 0xff) { 680 if (blocknum == 0xff) {
680 /* End of read */ 681 /* End of read */
681 len = ssif_info->multi_len; 682 len = ssif_info->multi_len;
682 data = ssif_info->data; 683 data = ssif_info->data;
683 } else if ((blocknum+1) != ssif_info->multi_pos) { 684 } else if (blocknum + 1 != ssif_info->multi_pos) {
684 /* 685 /*
685 * Out of sequence block, just abort. Block 686 * Out of sequence block, just abort. Block
686 * numbers start at zero for the second block, 687 * numbers start at zero for the second block,
@@ -880,7 +881,11 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
880 } 881 }
881 882
882 if (ssif_info->multi_data) { 883 if (ssif_info->multi_data) {
883 /* In the middle of a multi-data write. */ 884 /*
885 * In the middle of a multi-data write. See the comment
886 * in the SSIF_MULTI_n_PART case in the probe function
887 * for details on the intricacies of this.
888 */
884 int left; 889 int left;
885 890
886 ssif_inc_stat(ssif_info, sent_messages_parts); 891 ssif_inc_stat(ssif_info, sent_messages_parts);
@@ -984,7 +989,7 @@ static int start_send(struct ssif_info *ssif_info,
984 return -E2BIG; 989 return -E2BIG;
985 990
986 ssif_info->retries_left = SSIF_SEND_RETRIES; 991 ssif_info->retries_left = SSIF_SEND_RETRIES;
987 memcpy(ssif_info->data+1, data, len); 992 memcpy(ssif_info->data + 1, data, len);
988 ssif_info->data_len = len; 993 ssif_info->data_len = len;
989 return start_resend(ssif_info); 994 return start_resend(ssif_info);
990} 995}
@@ -1487,13 +1492,33 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
1487 break; 1492 break;
1488 1493
1489 case SSIF_MULTI_2_PART: 1494 case SSIF_MULTI_2_PART:
1490 if (ssif_info->max_xmit_msg_size > 64) 1495 if (ssif_info->max_xmit_msg_size > 63)
1491 ssif_info->max_xmit_msg_size = 64; 1496 ssif_info->max_xmit_msg_size = 63;
1492 if (ssif_info->max_recv_msg_size > 62) 1497 if (ssif_info->max_recv_msg_size > 62)
1493 ssif_info->max_recv_msg_size = 62; 1498 ssif_info->max_recv_msg_size = 62;
1494 break; 1499 break;
1495 1500
1496 case SSIF_MULTI_n_PART: 1501 case SSIF_MULTI_n_PART:
1502 /*
1503 * The specification is rather confusing at
1504 * this point, but I think I understand what
1505 * is meant. At least I have a workable
1506 * solution. With multi-part messages, you
1507 * cannot send a message that is a multiple of
1508 * 32-bytes in length, because the start and
1509 * middle messages are 32-bytes and the end
1510 * message must be at least one byte. You
1511 * can't fudge on an extra byte, that would
1512 * screw up things like fru data writes. So
1513 * we limit the length to 63 bytes. That way
1514 * a 32-byte message gets sent as a single
1515 * part. A larger message will be a 32-byte
1516 * start and the next message is always going
1517 * to be 1-31 bytes in length. Not ideal, but
1518 * it should work.
1519 */
1520 if (ssif_info->max_xmit_msg_size > 63)
1521 ssif_info->max_xmit_msg_size = 63;
1497 break; 1522 break;
1498 1523
1499 default: 1524 default: