Skip to content

Commit 3d69d43

Browse files
committed
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>
1 parent 9162052 commit 3d69d43

File tree

1 file changed

+38
-13
lines changed

1 file changed

+38
-13
lines changed

drivers/char/ipmi/ipmi_ssif.c

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -489,13 +489,13 @@ static int ipmi_ssif_thread(void *data)
489489

490490
if (ssif_info->i2c_read_write == I2C_SMBUS_WRITE) {
491491
result = i2c_smbus_write_block_data(
492-
ssif_info->client, SSIF_IPMI_REQUEST,
492+
ssif_info->client, ssif_info->i2c_command,
493493
ssif_info->i2c_data[0],
494494
ssif_info->i2c_data + 1);
495495
ssif_info->done_handler(ssif_info, result, NULL, 0);
496496
} else {
497497
result = i2c_smbus_read_block_data(
498-
ssif_info->client, SSIF_IPMI_RESPONSE,
498+
ssif_info->client, ssif_info->i2c_command,
499499
ssif_info->i2c_data);
500500
if (result < 0)
501501
ssif_info->done_handler(ssif_info, result,
@@ -534,6 +534,7 @@ static void start_get(struct ssif_info *ssif_info)
534534
int rv;
535535

536536
ssif_info->rtc_us_timer = 0;
537+
ssif_info->multi_pos = 0;
537538

538539
rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ,
539540
SSIF_IPMI_RESPONSE,
@@ -631,9 +632,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
631632
ssif_inc_stat(ssif_info, received_message_parts);
632633

633634
/* Remove the multi-part read marker. */
634-
for (i = 0; i < (len-2); i++)
635-
ssif_info->data[i] = data[i+2];
636635
len -= 2;
636+
for (i = 0; i < len; i++)
637+
ssif_info->data[i] = data[i+2];
637638
ssif_info->multi_len = len;
638639
ssif_info->multi_pos = 1;
639640

@@ -660,9 +661,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
660661
goto continue_op;
661662
}
662663

663-
blocknum = data[ssif_info->multi_len];
664+
blocknum = data[0];
664665

665-
if (ssif_info->multi_len+len-1 > IPMI_MAX_MSG_LENGTH) {
666+
if (ssif_info->multi_len + len - 1 > IPMI_MAX_MSG_LENGTH) {
666667
/* Received message too big, abort the operation. */
667668
result = -E2BIG;
668669
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
@@ -672,15 +673,15 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
672673
}
673674

674675
/* 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];
677676
len--;
677+
for (i = 0; i < len; i++)
678+
ssif_info->data[i + ssif_info->multi_len] = data[i + 1];
678679
ssif_info->multi_len += len;
679680
if (blocknum == 0xff) {
680681
/* End of read */
681682
len = ssif_info->multi_len;
682683
data = ssif_info->data;
683-
} else if ((blocknum+1) != ssif_info->multi_pos) {
684+
} else if (blocknum + 1 != ssif_info->multi_pos) {
684685
/*
685686
* Out of sequence block, just abort. Block
686687
* numbers start at zero for the second block,
@@ -880,7 +881,11 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
880881
}
881882

882883
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+
*/
884889
int left;
885890

886891
ssif_inc_stat(ssif_info, sent_messages_parts);
@@ -984,7 +989,7 @@ static int start_send(struct ssif_info *ssif_info,
984989
return -E2BIG;
985990

986991
ssif_info->retries_left = SSIF_SEND_RETRIES;
987-
memcpy(ssif_info->data+1, data, len);
992+
memcpy(ssif_info->data + 1, data, len);
988993
ssif_info->data_len = len;
989994
return start_resend(ssif_info);
990995
}
@@ -1487,13 +1492,33 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
14871492
break;
14881493

14891494
case SSIF_MULTI_2_PART:
1490-
if (ssif_info->max_xmit_msg_size > 64)
1491-
ssif_info->max_xmit_msg_size = 64;
1495+
if (ssif_info->max_xmit_msg_size > 63)
1496+
ssif_info->max_xmit_msg_size = 63;
14921497
if (ssif_info->max_recv_msg_size > 62)
14931498
ssif_info->max_recv_msg_size = 62;
14941499
break;
14951500

14961501
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;
14971522
break;
14981523

14991524
default:

0 commit comments

Comments
 (0)