static void return_hosed_msg(struct kcs_info *kcs_info) { struct ipmi_smi_msg *msg = kcs_info->curr_msg; /* Make it a reponse */ msg->rsp[0] = msg->data[0] | 4; msg->rsp[1] = msg->data[1]; msg->rsp[2] = 0xFF; /* Unknown error. */ msg->rsp_size = 3; kcs_info->curr_msg = NULL; deliver_recv_msg(kcs_info, msg); }
static void return_hosed_msg(struct smi_info *smi_info, int cCode) { struct ipmi_smi_msg *msg = smi_info->curr_msg; if (cCode < 0 || cCode > IPMI_ERR_UNSPECIFIED) cCode = IPMI_ERR_UNSPECIFIED; /* else use it as is */ /* Make it a response */ msg->rsp[0] = msg->data[0] | 4; msg->rsp[1] = msg->data[1]; msg->rsp[2] = cCode; msg->rsp_size = 3; smi_info->curr_msg = NULL; deliver_recv_msg(smi_info, msg); }
static void handle_transaction_done(struct smi_info *smi_info) { struct ipmi_smi_msg *msg; debug_timestamp("Done"); switch (smi_info->si_state) { case SI_NORMAL: if (!smi_info->curr_msg) break; smi_info->curr_msg->rsp_size = smi_info->handlers->get_result( smi_info->si_sm, smi_info->curr_msg->rsp, IPMI_MAX_MSG_LENGTH); /* * Do this here becase deliver_recv_msg() releases the * lock, and a new message can be put in during the * time the lock is released. */ msg = smi_info->curr_msg; smi_info->curr_msg = NULL; deliver_recv_msg(smi_info, msg); break; case SI_GETTING_FLAGS: { unsigned char msg[4]; unsigned int len; /* We got the flags from the SMI, now handle them. */ len = smi_info->handlers->get_result(smi_info->si_sm, msg, 4); if (msg[2] != 0) { /* Error fetching flags, just give up for now. */ smi_info->si_state = SI_NORMAL; } else if (len < 4) { /* * Hmm, no flags. That's technically illegal, but * don't use uninitialized data. */ smi_info->si_state = SI_NORMAL; } else { smi_info->msg_flags = msg[3]; handle_flags(smi_info); } break; } case SI_CLEARING_FLAGS: { unsigned char msg[3]; /* We cleared the flags. */ smi_info->handlers->get_result(smi_info->si_sm, msg, 3); if (msg[2] != 0) { /* Error clearing flags */ dev_warn(smi_info->dev, "Error clearing flags: %2.2x\n", msg[2]); } smi_info->si_state = SI_NORMAL; break; } case SI_GETTING_EVENTS: { smi_info->curr_msg->rsp_size = smi_info->handlers->get_result( smi_info->si_sm, smi_info->curr_msg->rsp, IPMI_MAX_MSG_LENGTH); /* * Do this here becase deliver_recv_msg() releases the * lock, and a new message can be put in during the * time the lock is released. */ msg = smi_info->curr_msg; smi_info->curr_msg = NULL; if (msg->rsp[2] != 0) { /* Error getting event, probably done. */ msg->done(msg); /* Take off the event flag. */ smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL; handle_flags(smi_info); } else { smi_inc_stat(smi_info, events); /* * Do this before we deliver the message * because delivering the message releases the * lock and something else can mess with the * state. */ handle_flags(smi_info); deliver_recv_msg(smi_info, msg); } break; } case SI_GETTING_MESSAGES: { smi_info->curr_msg->rsp_size = smi_info->handlers->get_result( smi_info->si_sm, smi_info->curr_msg->rsp, IPMI_MAX_MSG_LENGTH); /* * Do this here becase deliver_recv_msg() releases the * lock, and a new message can be put in during the * time the lock is released. */ msg = smi_info->curr_msg; smi_info->curr_msg = NULL; if (msg->rsp[2] != 0) { /* Error getting event, probably done. */ msg->done(msg); /* Take off the msg flag. */ smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL; handle_flags(smi_info); } else { smi_inc_stat(smi_info, incoming_messages); /* * Do this before we deliver the message * because delivering the message releases the * lock and something else can mess with the * state. */ handle_flags(smi_info); deliver_recv_msg(smi_info, msg); } break; } case SI_CHECKING_ENABLES: { unsigned char msg[4]; u8 enables; bool irq_on; /* We got the flags from the SMI, now handle them. */ smi_info->handlers->get_result(smi_info->si_sm, msg, 4); if (msg[2] != 0) { dev_warn(smi_info->dev, "Couldn't get irq info: %x.\n", msg[2]); dev_warn(smi_info->dev, "Maybe ok, but ipmi might run very slowly.\n"); smi_info->si_state = SI_NORMAL; break; } enables = current_global_enables(smi_info, 0, &irq_on); if (smi_info->si_type == SI_BT) /* BT has its own interrupt enable bit. */ check_bt_irq(smi_info, irq_on); if (enables != (msg[3] & GLOBAL_ENABLES_MASK)) { /* Enables are not correct, fix them. */ msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; msg[2] = enables | (msg[3] & ~GLOBAL_ENABLES_MASK); smi_info->handlers->start_transaction( smi_info->si_sm, msg, 3); smi_info->si_state = SI_SETTING_ENABLES; } else if (smi_info->supports_event_msg_buff) { smi_info->curr_msg = ipmi_alloc_smi_msg(); if (!smi_info->curr_msg) { smi_info->si_state = SI_NORMAL; break; } start_getting_msg_queue(smi_info); } else { smi_info->si_state = SI_NORMAL; } break; } case SI_SETTING_ENABLES: { unsigned char msg[4]; smi_info->handlers->get_result(smi_info->si_sm, msg, 4); if (msg[2] != 0) dev_warn(smi_info->dev, "Could not set the global enables: 0x%x.\n", msg[2]); if (smi_info->supports_event_msg_buff) { smi_info->curr_msg = ipmi_alloc_smi_msg(); if (!smi_info->curr_msg) { smi_info->si_state = SI_NORMAL; break; } start_getting_msg_queue(smi_info); } else { smi_info->si_state = SI_NORMAL; } break; } } }
static void handle_transaction_done(struct kcs_info *kcs_info) { struct ipmi_smi_msg *msg; #ifdef DEBUG_TIMING struct timeval t; do_gettimeofday(&t); printk("**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif switch (kcs_info->kcs_state) { case KCS_NORMAL: if (!kcs_info->curr_msg) break; kcs_info->curr_msg->rsp_size = kcs_get_result(kcs_info->kcs_sm, kcs_info->curr_msg->rsp, IPMI_MAX_MSG_LENGTH); /* Do this here becase deliver_recv_msg() releases the lock, and a new message can be put in during the time the lock is released. */ msg = kcs_info->curr_msg; kcs_info->curr_msg = NULL; deliver_recv_msg(kcs_info, msg); break; case KCS_GETTING_FLAGS: { unsigned char msg[4]; unsigned int len; /* We got the flags from the KCS, now handle them. */ len = kcs_get_result(kcs_info->kcs_sm, msg, 4); if (msg[2] != 0) { /* Error fetching flags, just give up for now. */ kcs_info->kcs_state = KCS_NORMAL; } else if (len < 3) { /* Hmm, no flags. That's technically illegal, but don't use uninitialized data. */ kcs_info->kcs_state = KCS_NORMAL; } else { kcs_info->msg_flags = msg[3]; handle_flags(kcs_info); } break; } case KCS_CLEARING_FLAGS: case KCS_CLEARING_FLAGS_THEN_SET_IRQ: { unsigned char msg[3]; /* We cleared the flags. */ kcs_get_result(kcs_info->kcs_sm, msg, 3); if (msg[2] != 0) { /* Error clearing flags */ printk(KERN_WARNING "ipmi_kcs: Error clearing flags: %2.2x\n", msg[2]); } if (kcs_info->kcs_state == KCS_CLEARING_FLAGS_THEN_SET_IRQ) start_enable_irq(kcs_info); else kcs_info->kcs_state = KCS_NORMAL; break; } case KCS_GETTING_EVENTS: { kcs_info->curr_msg->rsp_size = kcs_get_result(kcs_info->kcs_sm, kcs_info->curr_msg->rsp, IPMI_MAX_MSG_LENGTH); /* Do this here becase deliver_recv_msg() releases the lock, and a new message can be put in during the time the lock is released. */ msg = kcs_info->curr_msg; kcs_info->curr_msg = NULL; if (msg->rsp[2] != 0) { /* Error getting event, probably done. */ msg->done(msg); /* Take off the event flag. */ kcs_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL; } else { deliver_recv_msg(kcs_info, msg); } handle_flags(kcs_info); break; } case KCS_GETTING_MESSAGES: { kcs_info->curr_msg->rsp_size = kcs_get_result(kcs_info->kcs_sm, kcs_info->curr_msg->rsp, IPMI_MAX_MSG_LENGTH); /* Do this here becase deliver_recv_msg() releases the lock, and a new message can be put in during the time the lock is released. */ msg = kcs_info->curr_msg; kcs_info->curr_msg = NULL; if (msg->rsp[2] != 0) { /* Error getting event, probably done. */ msg->done(msg); /* Take off the msg flag. */ kcs_info->msg_flags &= ~RECEIVE_MSG_AVAIL; } else { deliver_recv_msg(kcs_info, msg); } handle_flags(kcs_info); break; } case KCS_ENABLE_INTERRUPTS1: { unsigned char msg[4]; /* We got the flags from the KCS, now handle them. */ kcs_get_result(kcs_info->kcs_sm, msg, 4); if (msg[2] != 0) { printk(KERN_WARNING "ipmi_kcs: Could not enable interrupts" ", failed get, using polled mode.\n"); kcs_info->kcs_state = KCS_NORMAL; } else { msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; msg[2] = msg[3] | 1; /* enable msg queue int */ start_kcs_transaction(kcs_info->kcs_sm, msg,3); kcs_info->kcs_state = KCS_ENABLE_INTERRUPTS2; } break; } case KCS_ENABLE_INTERRUPTS2: { unsigned char msg[4]; /* We got the flags from the KCS, now handle them. */ kcs_get_result(kcs_info->kcs_sm, msg, 4); if (msg[2] != 0) { printk(KERN_WARNING "ipmi_kcs: Could not enable interrupts" ", failed set, using polled mode.\n"); } kcs_info->kcs_state = KCS_NORMAL; break; } } }