Skip to content

Commit 62cd145

Browse files
committed
ipmi:msghandler: Handle error returns from the SMI sender
It used to be, until recently, that the sender operation on the low level interfaces would not fail. That's not the case any more with recent changes. So check the return value from the sender operation, and propagate it back up from there and handle the errors in all places. Reported-by: Rafael J. Wysocki <rafael@kernel.org> Fixes: bc3a9d2 ("ipmi:si: Gracefully handle if the BMC is non-functional") Cc: stable@vger.kernel.org # 4.18 Signed-off-by: Corey Minyard <corey@minyard.net> Reviewed-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>
1 parent f895e5d commit 62cd145

1 file changed

Lines changed: 68 additions & 32 deletions

File tree

drivers/char/ipmi/ipmi_msghandler.c

Lines changed: 68 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1887,19 +1887,32 @@ static struct ipmi_smi_msg *smi_add_send_msg(struct ipmi_smi *intf,
18871887
return smi_msg;
18881888
}
18891889

1890-
static void smi_send(struct ipmi_smi *intf,
1890+
static int smi_send(struct ipmi_smi *intf,
18911891
const struct ipmi_smi_handlers *handlers,
18921892
struct ipmi_smi_msg *smi_msg, int priority)
18931893
{
18941894
int run_to_completion = READ_ONCE(intf->run_to_completion);
18951895
unsigned long flags = 0;
1896+
int rv = 0;
18961897

18971898
ipmi_lock_xmit_msgs(intf, run_to_completion, &flags);
18981899
smi_msg = smi_add_send_msg(intf, smi_msg, priority);
18991900
ipmi_unlock_xmit_msgs(intf, run_to_completion, &flags);
19001901

1901-
if (smi_msg)
1902-
handlers->sender(intf->send_info, smi_msg);
1902+
if (smi_msg) {
1903+
rv = handlers->sender(intf->send_info, smi_msg);
1904+
if (rv) {
1905+
ipmi_lock_xmit_msgs(intf, run_to_completion, &flags);
1906+
intf->curr_msg = NULL;
1907+
ipmi_unlock_xmit_msgs(intf, run_to_completion, &flags);
1908+
/*
1909+
* Something may have been added to the transmit
1910+
* queue, so schedule a check for that.
1911+
*/
1912+
queue_work(system_wq, &intf->smi_work);
1913+
}
1914+
}
1915+
return rv;
19031916
}
19041917

19051918
static bool is_maintenance_mode_cmd(struct kernel_ipmi_msg *msg)
@@ -2312,6 +2325,7 @@ static int i_ipmi_request(struct ipmi_user *user,
23122325
struct ipmi_recv_msg *recv_msg;
23132326
int run_to_completion = READ_ONCE(intf->run_to_completion);
23142327
int rv = 0;
2328+
bool in_seq_table = false;
23152329

23162330
if (supplied_recv) {
23172331
recv_msg = supplied_recv;
@@ -2365,33 +2379,50 @@ static int i_ipmi_request(struct ipmi_user *user,
23652379
rv = i_ipmi_req_ipmb(intf, addr, msgid, msg, smi_msg, recv_msg,
23662380
source_address, source_lun,
23672381
retries, retry_time_ms);
2382+
in_seq_table = true;
23682383
} else if (is_ipmb_direct_addr(addr)) {
23692384
rv = i_ipmi_req_ipmb_direct(intf, addr, msgid, msg, smi_msg,
23702385
recv_msg, source_lun);
23712386
} else if (is_lan_addr(addr)) {
23722387
rv = i_ipmi_req_lan(intf, addr, msgid, msg, smi_msg, recv_msg,
23732388
source_lun, retries, retry_time_ms);
2389+
in_seq_table = true;
23742390
} else {
2375-
/* Unknown address type. */
2391+
/* Unknown address type. */
23762392
ipmi_inc_stat(intf, sent_invalid_commands);
23772393
rv = -EINVAL;
23782394
}
23792395

2380-
if (rv) {
2381-
out_err:
2382-
if (!supplied_smi)
2383-
ipmi_free_smi_msg(smi_msg);
2384-
if (!supplied_recv)
2385-
ipmi_free_recv_msg(recv_msg);
2386-
} else {
2396+
if (!rv) {
23872397
dev_dbg(intf->si_dev, "Send: %*ph\n",
23882398
smi_msg->data_size, smi_msg->data);
23892399

2390-
smi_send(intf, intf->handlers, smi_msg, priority);
2400+
rv = smi_send(intf, intf->handlers, smi_msg, priority);
2401+
if (rv != IPMI_CC_NO_ERROR)
2402+
/* smi_send() returns an IPMI err, return a Linux one. */
2403+
rv = -EIO;
2404+
if (rv && in_seq_table) {
2405+
/*
2406+
* If it's in the sequence table, it will be
2407+
* retried later, so ignore errors.
2408+
*/
2409+
rv = 0;
2410+
/* But we need to fix the timeout. */
2411+
intf_start_seq_timer(intf, smi_msg->msgid);
2412+
ipmi_free_smi_msg(smi_msg);
2413+
smi_msg = NULL;
2414+
}
23912415
}
2416+
out_err:
23922417
if (!run_to_completion)
23932418
mutex_unlock(&intf->users_mutex);
23942419

2420+
if (rv) {
2421+
if (!supplied_smi)
2422+
ipmi_free_smi_msg(smi_msg);
2423+
if (!supplied_recv)
2424+
ipmi_free_recv_msg(recv_msg);
2425+
}
23952426
return rv;
23962427
}
23972428

@@ -3965,12 +3996,12 @@ static int handle_ipmb_get_msg_cmd(struct ipmi_smi *intf,
39653996
dev_dbg(intf->si_dev, "Invalid command: %*ph\n",
39663997
msg->data_size, msg->data);
39673998

3968-
smi_send(intf, intf->handlers, msg, 0);
3969-
/*
3970-
* We used the message, so return the value that
3971-
* causes it to not be freed or queued.
3972-
*/
3973-
rv = -1;
3999+
if (smi_send(intf, intf->handlers, msg, 0) == IPMI_CC_NO_ERROR)
4000+
/*
4001+
* We used the message, so return the value that
4002+
* causes it to not be freed or queued.
4003+
*/
4004+
rv = -1;
39744005
} else if (!IS_ERR(recv_msg)) {
39754006
/* Extract the source address from the data. */
39764007
ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
@@ -4044,12 +4075,12 @@ static int handle_ipmb_direct_rcv_cmd(struct ipmi_smi *intf,
40444075
msg->data[4] = IPMI_INVALID_CMD_COMPLETION_CODE;
40454076
msg->data_size = 5;
40464077

4047-
smi_send(intf, intf->handlers, msg, 0);
4048-
/*
4049-
* We used the message, so return the value that
4050-
* causes it to not be freed or queued.
4051-
*/
4052-
rv = -1;
4078+
if (smi_send(intf, intf->handlers, msg, 0) == IPMI_CC_NO_ERROR)
4079+
/*
4080+
* We used the message, so return the value that
4081+
* causes it to not be freed or queued.
4082+
*/
4083+
rv = -1;
40534084
} else if (!IS_ERR(recv_msg)) {
40544085
/* Extract the source address from the data. */
40554086
daddr = (struct ipmi_ipmb_direct_addr *)&recv_msg->addr;
@@ -4189,7 +4220,7 @@ static int handle_lan_get_msg_cmd(struct ipmi_smi *intf,
41894220
struct ipmi_smi_msg *msg)
41904221
{
41914222
struct cmd_rcvr *rcvr;
4192-
int rv = 0;
4223+
int rv = 0; /* Free by default */
41934224
unsigned char netfn;
41944225
unsigned char cmd;
41954226
unsigned char chan;
@@ -4242,12 +4273,12 @@ static int handle_lan_get_msg_cmd(struct ipmi_smi *intf,
42424273
dev_dbg(intf->si_dev, "Invalid command: %*ph\n",
42434274
msg->data_size, msg->data);
42444275

4245-
smi_send(intf, intf->handlers, msg, 0);
4246-
/*
4247-
* We used the message, so return the value that
4248-
* causes it to not be freed or queued.
4249-
*/
4250-
rv = -1;
4276+
if (smi_send(intf, intf->handlers, msg, 0) == IPMI_CC_NO_ERROR)
4277+
/*
4278+
* We used the message, so return the value that
4279+
* causes it to not be freed or queued.
4280+
*/
4281+
rv = -1;
42514282
} else if (!IS_ERR(recv_msg)) {
42524283
/* Extract the source address from the data. */
42534284
lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
@@ -5056,7 +5087,12 @@ static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent,
50565087
ipmi_inc_stat(intf,
50575088
retransmitted_ipmb_commands);
50585089

5059-
smi_send(intf, intf->handlers, smi_msg, 0);
5090+
/* If this fails we'll retry later or timeout. */
5091+
if (smi_send(intf, intf->handlers, smi_msg, 0) != IPMI_CC_NO_ERROR) {
5092+
/* But fix the timeout. */
5093+
intf_start_seq_timer(intf, smi_msg->msgid);
5094+
ipmi_free_smi_msg(smi_msg);
5095+
}
50605096
} else
50615097
ipmi_free_smi_msg(smi_msg);
50625098

0 commit comments

Comments
 (0)