staticint bmcaddr = 0x20;
module_param(bmcaddr, int, 0644);
MODULE_PARM_DESC(bmcaddr, "Address to use for BMC.");
staticunsignedint retry_time_ms = 250;
module_param(retry_time_ms, uint, 0644);
MODULE_PARM_DESC(retry_time_ms, "Timeout time between retries, in milliseconds.");
staticunsignedint max_retries = 1;
module_param(max_retries, uint, 0644);
MODULE_PARM_DESC(max_retries, "Max resends of a command before timing out.");
/* Add room for the two slave addresses, two checksums, and rqSeq. */ #define IPMB_MAX_MSG_LEN (IPMI_MAX_MSG_LENGTH + 5)
/* Minimum message size. */ if (iidev->rcvlen < 7) returnfalse;
/* Is it a response? */
netfn = msg[1] >> 2; if (netfn & 1) { /* Response messages have an added completion code. */ if (iidev->rcvlen < 8) returnfalse;
}
if (ipmb_checksum(msg, 3) != 0) returnfalse; if (ipmb_checksum(msg + 3, iidev->rcvlen - 3) != 0) returnfalse;
if (iidev->rcvlen == 0) return; if (!valid_ipmb(iidev)) goto done;
is_cmd = ((msg[1] >> 2) & 1) == 0;
if (is_cmd) { /* Ignore commands until we are up. */ if (!iidev->ready) goto done;
/* It's a command, allocate a message for it. */
imsg = ipmi_alloc_smi_msg(); if (!imsg) goto done;
imsg->type = IPMI_SMI_MSG_TYPE_IPMB_DIRECT;
imsg->data_size = 0;
} else {
spin_lock_irqsave(&iidev->lock, flags); if (iidev->working_msg) {
u8 seq = msg[4] >> 2; bool xmit_rsp = (iidev->working_msg->data[0] >> 2) & 1;
/* * Responses should carry the sequence we sent * them with. If it's a transmitted response, * ignore it. And if the message hasn't been * transmitted, ignore it.
*/ if (!xmit_rsp && seq == iidev->curr_seq) {
iidev->curr_seq = (iidev->curr_seq + 1) & 0x3f;
/* * The IPMB protocol only supports i2c writes so there is no need to * support I2C_SLAVE_READ* events, except to know if the other end has * issued a read without going to stop mode.
*/ staticint ipmi_ipmb_slave_cb(struct i2c_client *client, enum i2c_slave_event event, u8 *val)
{ struct ipmi_ipmb_dev *iidev = i2c_get_clientdata(client);
switch (event) { case I2C_SLAVE_WRITE_REQUESTED:
ipmi_ipmb_check_msg_done(iidev); /* * First byte is the slave address, to ease the checksum * calculation.
*/
iidev->rcvmsg[0] = client->addr << 1;
iidev->rcvlen = 1; break;
case I2C_SLAVE_WRITE_RECEIVED: if (iidev->rcvlen >= sizeof(iidev->rcvmsg))
iidev->overrun = true; else
iidev->rcvmsg[iidev->rcvlen++] = *val; break;
case I2C_SLAVE_READ_REQUESTED: case I2C_SLAVE_STOP:
ipmi_ipmb_check_msg_done(iidev); break;
case I2C_SLAVE_READ_PROCESSED: break;
}
return 0;
}
staticvoid ipmi_ipmb_send_response(struct ipmi_ipmb_dev *iidev, struct ipmi_smi_msg *msg, u8 cc)
{ if ((msg->data[0] >> 2) & 1) { /* * It's a response being sent, we need to return a * response to the response. Fake a send msg command * response with channel 0. This will always be ipmb * direct.
*/
msg->data[0] = (IPMI_NETFN_APP_REQUEST | 1) << 2;
msg->data[3] = IPMI_SEND_MSG_CMD;
msg->data[4] = cc;
msg->data_size = 5;
}
msg->rsp[0] = msg->data[0] | (1 << 2); if (msg->type == IPMI_SMI_MSG_TYPE_IPMB_DIRECT) {
msg->rsp[1] = msg->data[1];
msg->rsp[2] = msg->data[2];
msg->rsp[3] = msg->data[3];
msg->rsp[4] = cc;
msg->rsp_size = 5;
} else {
msg->rsp[1] = msg->data[1];
msg->rsp[2] = cc;
msg->rsp_size = 3;
}
ipmi_smi_msg_received(iidev->intf, msg);
}
/* A command was sent, wait for its response. */
ret = down_timeout(&iidev->got_rsp,
msecs_to_jiffies(iidev->retry_time_ms));
/* * Grab the message if we can. If the handler hasn't * already handled it, the message will still be there.
*/
spin_lock_irqsave(&iidev->lock, flags);
msg = iidev->working_msg;
iidev->working_msg = NULL;
spin_unlock_irqrestore(&iidev->lock, flags);
if (!msg && ret) { /* * If working_msg is not set and we timed out, * that means the message grabbed by * check_msg_done before we could grab it * here. Wait again for check_msg_done to up * the semaphore.
*/
down(&iidev->got_rsp);
} elseif (msg && ++retries <= iidev->max_retries) {
spin_lock_irqsave(&iidev->lock, flags);
iidev->working_msg = msg;
spin_unlock_irqrestore(&iidev->lock, flags); goto retry;
}
if (msg)
ipmi_ipmb_send_response(iidev, msg, IPMI_TIMEOUT_ERR);
}
if (iidev->next_msg) /* Return an unspecified error. */
ipmi_ipmb_send_response(iidev, iidev->next_msg, 0xff);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.