Path: blob/master/drivers/char/ipmi/ipmi_smic_sm.c
15111 views
/*1* ipmi_smic_sm.c2*3* The state-machine driver for an IPMI SMIC driver4*5* It started as a copy of Corey Minyard's driver for the KSC interface6* and the kernel patch "mmcdev-patch-245" by HP7*8* modified by: Hannes Schulz <[email protected]>9* [email protected]10*11*12* Corey Minyard's driver for the KSC interface has the following13* copyright notice:14* Copyright 2002 MontaVista Software Inc.15*16* the kernel patch "mmcdev-patch-245" by HP has the following17* copyright notice:18* (c) Copyright 2001 Grant Grundler (c) Copyright19* 2001 Hewlett-Packard Company20*21*22* This program is free software; you can redistribute it and/or modify it23* under the terms of the GNU General Public License as published by the24* Free Software Foundation; either version 2 of the License, or (at your25* option) any later version.26*27*28* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED29* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF30* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.31* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,32* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,33* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS34* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND35* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR36* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE37* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.38*39* You should have received a copy of the GNU General Public License along40* with this program; if not, write to the Free Software Foundation, Inc.,41* 675 Mass Ave, Cambridge, MA 02139, USA. */4243#include <linux/kernel.h> /* For printk. */44#include <linux/string.h>45#include <linux/module.h>46#include <linux/moduleparam.h>47#include <linux/ipmi_msgdefs.h> /* for completion codes */48#include "ipmi_si_sm.h"4950/* smic_debug is a bit-field51* SMIC_DEBUG_ENABLE - turned on for now52* SMIC_DEBUG_MSG - commands and their responses53* SMIC_DEBUG_STATES - state machine54*/55#define SMIC_DEBUG_STATES 456#define SMIC_DEBUG_MSG 257#define SMIC_DEBUG_ENABLE 15859static int smic_debug = 1;60module_param(smic_debug, int, 0644);61MODULE_PARM_DESC(smic_debug, "debug bitmask, 1=enable, 2=messages, 4=states");6263enum smic_states {64SMIC_IDLE,65SMIC_START_OP,66SMIC_OP_OK,67SMIC_WRITE_START,68SMIC_WRITE_NEXT,69SMIC_WRITE_END,70SMIC_WRITE2READ,71SMIC_READ_START,72SMIC_READ_NEXT,73SMIC_READ_END,74SMIC_HOSED75};7677#define MAX_SMIC_READ_SIZE 8078#define MAX_SMIC_WRITE_SIZE 8079#define SMIC_MAX_ERROR_RETRIES 38081/* Timeouts in microseconds. */82#define SMIC_RETRY_TIMEOUT 20000008384/* SMIC Flags Register Bits */85#define SMIC_RX_DATA_READY 0x8086#define SMIC_TX_DATA_READY 0x408788/*89* SMIC_SMI and SMIC_EVM_DATA_AVAIL are only used by90* a few systems, and then only by Systems Management91* Interrupts, not by the OS. Always ignore these bits.92*93*/94#define SMIC_SMI 0x1095#define SMIC_EVM_DATA_AVAIL 0x0896#define SMIC_SMS_DATA_AVAIL 0x0497#define SMIC_FLAG_BSY 0x019899/* SMIC Error Codes */100#define EC_NO_ERROR 0x00101#define EC_ABORTED 0x01102#define EC_ILLEGAL_CONTROL 0x02103#define EC_NO_RESPONSE 0x03104#define EC_ILLEGAL_COMMAND 0x04105#define EC_BUFFER_FULL 0x05106107struct si_sm_data {108enum smic_states state;109struct si_sm_io *io;110unsigned char write_data[MAX_SMIC_WRITE_SIZE];111int write_pos;112int write_count;113int orig_write_count;114unsigned char read_data[MAX_SMIC_READ_SIZE];115int read_pos;116int truncated;117unsigned int error_retries;118long smic_timeout;119};120121static unsigned int init_smic_data(struct si_sm_data *smic,122struct si_sm_io *io)123{124smic->state = SMIC_IDLE;125smic->io = io;126smic->write_pos = 0;127smic->write_count = 0;128smic->orig_write_count = 0;129smic->read_pos = 0;130smic->error_retries = 0;131smic->truncated = 0;132smic->smic_timeout = SMIC_RETRY_TIMEOUT;133134/* We use 3 bytes of I/O. */135return 3;136}137138static int start_smic_transaction(struct si_sm_data *smic,139unsigned char *data, unsigned int size)140{141unsigned int i;142143if (size < 2)144return IPMI_REQ_LEN_INVALID_ERR;145if (size > MAX_SMIC_WRITE_SIZE)146return IPMI_REQ_LEN_EXCEEDED_ERR;147148if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED))149return IPMI_NOT_IN_MY_STATE_ERR;150151if (smic_debug & SMIC_DEBUG_MSG) {152printk(KERN_DEBUG "start_smic_transaction -");153for (i = 0; i < size; i++)154printk(" %02x", (unsigned char) data[i]);155printk("\n");156}157smic->error_retries = 0;158memcpy(smic->write_data, data, size);159smic->write_count = size;160smic->orig_write_count = size;161smic->write_pos = 0;162smic->read_pos = 0;163smic->state = SMIC_START_OP;164smic->smic_timeout = SMIC_RETRY_TIMEOUT;165return 0;166}167168static int smic_get_result(struct si_sm_data *smic,169unsigned char *data, unsigned int length)170{171int i;172173if (smic_debug & SMIC_DEBUG_MSG) {174printk(KERN_DEBUG "smic_get result -");175for (i = 0; i < smic->read_pos; i++)176printk(" %02x", smic->read_data[i]);177printk("\n");178}179if (length < smic->read_pos) {180smic->read_pos = length;181smic->truncated = 1;182}183memcpy(data, smic->read_data, smic->read_pos);184185if ((length >= 3) && (smic->read_pos < 3)) {186data[2] = IPMI_ERR_UNSPECIFIED;187smic->read_pos = 3;188}189if (smic->truncated) {190data[2] = IPMI_ERR_MSG_TRUNCATED;191smic->truncated = 0;192}193return smic->read_pos;194}195196static inline unsigned char read_smic_flags(struct si_sm_data *smic)197{198return smic->io->inputb(smic->io, 2);199}200201static inline unsigned char read_smic_status(struct si_sm_data *smic)202{203return smic->io->inputb(smic->io, 1);204}205206static inline unsigned char read_smic_data(struct si_sm_data *smic)207{208return smic->io->inputb(smic->io, 0);209}210211static inline void write_smic_flags(struct si_sm_data *smic,212unsigned char flags)213{214smic->io->outputb(smic->io, 2, flags);215}216217static inline void write_smic_control(struct si_sm_data *smic,218unsigned char control)219{220smic->io->outputb(smic->io, 1, control);221}222223static inline void write_si_sm_data(struct si_sm_data *smic,224unsigned char data)225{226smic->io->outputb(smic->io, 0, data);227}228229static inline void start_error_recovery(struct si_sm_data *smic, char *reason)230{231(smic->error_retries)++;232if (smic->error_retries > SMIC_MAX_ERROR_RETRIES) {233if (smic_debug & SMIC_DEBUG_ENABLE)234printk(KERN_WARNING235"ipmi_smic_drv: smic hosed: %s\n", reason);236smic->state = SMIC_HOSED;237} else {238smic->write_count = smic->orig_write_count;239smic->write_pos = 0;240smic->read_pos = 0;241smic->state = SMIC_START_OP;242smic->smic_timeout = SMIC_RETRY_TIMEOUT;243}244}245246static inline void write_next_byte(struct si_sm_data *smic)247{248write_si_sm_data(smic, smic->write_data[smic->write_pos]);249(smic->write_pos)++;250(smic->write_count)--;251}252253static inline void read_next_byte(struct si_sm_data *smic)254{255if (smic->read_pos >= MAX_SMIC_READ_SIZE) {256read_smic_data(smic);257smic->truncated = 1;258} else {259smic->read_data[smic->read_pos] = read_smic_data(smic);260smic->read_pos++;261}262}263264/* SMIC Control/Status Code Components */265#define SMIC_GET_STATUS 0x00 /* Control form's name */266#define SMIC_READY 0x00 /* Status form's name */267#define SMIC_WR_START 0x01 /* Unified Control/Status names... */268#define SMIC_WR_NEXT 0x02269#define SMIC_WR_END 0x03270#define SMIC_RD_START 0x04271#define SMIC_RD_NEXT 0x05272#define SMIC_RD_END 0x06273#define SMIC_CODE_MASK 0x0f274275#define SMIC_CONTROL 0x00276#define SMIC_STATUS 0x80277#define SMIC_CS_MASK 0x80278279#define SMIC_SMS 0x40280#define SMIC_SMM 0x60281#define SMIC_STREAM_MASK 0x60282283/* SMIC Control Codes */284#define SMIC_CC_SMS_GET_STATUS (SMIC_CONTROL|SMIC_SMS|SMIC_GET_STATUS)285#define SMIC_CC_SMS_WR_START (SMIC_CONTROL|SMIC_SMS|SMIC_WR_START)286#define SMIC_CC_SMS_WR_NEXT (SMIC_CONTROL|SMIC_SMS|SMIC_WR_NEXT)287#define SMIC_CC_SMS_WR_END (SMIC_CONTROL|SMIC_SMS|SMIC_WR_END)288#define SMIC_CC_SMS_RD_START (SMIC_CONTROL|SMIC_SMS|SMIC_RD_START)289#define SMIC_CC_SMS_RD_NEXT (SMIC_CONTROL|SMIC_SMS|SMIC_RD_NEXT)290#define SMIC_CC_SMS_RD_END (SMIC_CONTROL|SMIC_SMS|SMIC_RD_END)291292#define SMIC_CC_SMM_GET_STATUS (SMIC_CONTROL|SMIC_SMM|SMIC_GET_STATUS)293#define SMIC_CC_SMM_WR_START (SMIC_CONTROL|SMIC_SMM|SMIC_WR_START)294#define SMIC_CC_SMM_WR_NEXT (SMIC_CONTROL|SMIC_SMM|SMIC_WR_NEXT)295#define SMIC_CC_SMM_WR_END (SMIC_CONTROL|SMIC_SMM|SMIC_WR_END)296#define SMIC_CC_SMM_RD_START (SMIC_CONTROL|SMIC_SMM|SMIC_RD_START)297#define SMIC_CC_SMM_RD_NEXT (SMIC_CONTROL|SMIC_SMM|SMIC_RD_NEXT)298#define SMIC_CC_SMM_RD_END (SMIC_CONTROL|SMIC_SMM|SMIC_RD_END)299300/* SMIC Status Codes */301#define SMIC_SC_SMS_READY (SMIC_STATUS|SMIC_SMS|SMIC_READY)302#define SMIC_SC_SMS_WR_START (SMIC_STATUS|SMIC_SMS|SMIC_WR_START)303#define SMIC_SC_SMS_WR_NEXT (SMIC_STATUS|SMIC_SMS|SMIC_WR_NEXT)304#define SMIC_SC_SMS_WR_END (SMIC_STATUS|SMIC_SMS|SMIC_WR_END)305#define SMIC_SC_SMS_RD_START (SMIC_STATUS|SMIC_SMS|SMIC_RD_START)306#define SMIC_SC_SMS_RD_NEXT (SMIC_STATUS|SMIC_SMS|SMIC_RD_NEXT)307#define SMIC_SC_SMS_RD_END (SMIC_STATUS|SMIC_SMS|SMIC_RD_END)308309#define SMIC_SC_SMM_READY (SMIC_STATUS|SMIC_SMM|SMIC_READY)310#define SMIC_SC_SMM_WR_START (SMIC_STATUS|SMIC_SMM|SMIC_WR_START)311#define SMIC_SC_SMM_WR_NEXT (SMIC_STATUS|SMIC_SMM|SMIC_WR_NEXT)312#define SMIC_SC_SMM_WR_END (SMIC_STATUS|SMIC_SMM|SMIC_WR_END)313#define SMIC_SC_SMM_RD_START (SMIC_STATUS|SMIC_SMM|SMIC_RD_START)314#define SMIC_SC_SMM_RD_NEXT (SMIC_STATUS|SMIC_SMM|SMIC_RD_NEXT)315#define SMIC_SC_SMM_RD_END (SMIC_STATUS|SMIC_SMM|SMIC_RD_END)316317/* these are the control/status codes we actually use318SMIC_CC_SMS_GET_STATUS 0x40319SMIC_CC_SMS_WR_START 0x41320SMIC_CC_SMS_WR_NEXT 0x42321SMIC_CC_SMS_WR_END 0x43322SMIC_CC_SMS_RD_START 0x44323SMIC_CC_SMS_RD_NEXT 0x45324SMIC_CC_SMS_RD_END 0x46325326SMIC_SC_SMS_READY 0xC0327SMIC_SC_SMS_WR_START 0xC1328SMIC_SC_SMS_WR_NEXT 0xC2329SMIC_SC_SMS_WR_END 0xC3330SMIC_SC_SMS_RD_START 0xC4331SMIC_SC_SMS_RD_NEXT 0xC5332SMIC_SC_SMS_RD_END 0xC6333*/334335static enum si_sm_result smic_event(struct si_sm_data *smic, long time)336{337unsigned char status;338unsigned char flags;339unsigned char data;340341if (smic->state == SMIC_HOSED) {342init_smic_data(smic, smic->io);343return SI_SM_HOSED;344}345if (smic->state != SMIC_IDLE) {346if (smic_debug & SMIC_DEBUG_STATES)347printk(KERN_DEBUG348"smic_event - smic->smic_timeout = %ld,"349" time = %ld\n",350smic->smic_timeout, time);351/*352* FIXME: smic_event is sometimes called with time >353* SMIC_RETRY_TIMEOUT354*/355if (time < SMIC_RETRY_TIMEOUT) {356smic->smic_timeout -= time;357if (smic->smic_timeout < 0) {358start_error_recovery(smic, "smic timed out.");359return SI_SM_CALL_WITH_DELAY;360}361}362}363flags = read_smic_flags(smic);364if (flags & SMIC_FLAG_BSY)365return SI_SM_CALL_WITH_DELAY;366367status = read_smic_status(smic);368if (smic_debug & SMIC_DEBUG_STATES)369printk(KERN_DEBUG370"smic_event - state = %d, flags = 0x%02x,"371" status = 0x%02x\n",372smic->state, flags, status);373374switch (smic->state) {375case SMIC_IDLE:376/* in IDLE we check for available messages */377if (flags & SMIC_SMS_DATA_AVAIL)378return SI_SM_ATTN;379return SI_SM_IDLE;380381case SMIC_START_OP:382/* sanity check whether smic is really idle */383write_smic_control(smic, SMIC_CC_SMS_GET_STATUS);384write_smic_flags(smic, flags | SMIC_FLAG_BSY);385smic->state = SMIC_OP_OK;386break;387388case SMIC_OP_OK:389if (status != SMIC_SC_SMS_READY) {390/* this should not happen */391start_error_recovery(smic,392"state = SMIC_OP_OK,"393" status != SMIC_SC_SMS_READY");394return SI_SM_CALL_WITH_DELAY;395}396/* OK so far; smic is idle let us start ... */397write_smic_control(smic, SMIC_CC_SMS_WR_START);398write_next_byte(smic);399write_smic_flags(smic, flags | SMIC_FLAG_BSY);400smic->state = SMIC_WRITE_START;401break;402403case SMIC_WRITE_START:404if (status != SMIC_SC_SMS_WR_START) {405start_error_recovery(smic,406"state = SMIC_WRITE_START, "407"status != SMIC_SC_SMS_WR_START");408return SI_SM_CALL_WITH_DELAY;409}410/*411* we must not issue WR_(NEXT|END) unless412* TX_DATA_READY is set413* */414if (flags & SMIC_TX_DATA_READY) {415if (smic->write_count == 1) {416/* last byte */417write_smic_control(smic, SMIC_CC_SMS_WR_END);418smic->state = SMIC_WRITE_END;419} else {420write_smic_control(smic, SMIC_CC_SMS_WR_NEXT);421smic->state = SMIC_WRITE_NEXT;422}423write_next_byte(smic);424write_smic_flags(smic, flags | SMIC_FLAG_BSY);425} else426return SI_SM_CALL_WITH_DELAY;427break;428429case SMIC_WRITE_NEXT:430if (status != SMIC_SC_SMS_WR_NEXT) {431start_error_recovery(smic,432"state = SMIC_WRITE_NEXT, "433"status != SMIC_SC_SMS_WR_NEXT");434return SI_SM_CALL_WITH_DELAY;435}436/* this is the same code as in SMIC_WRITE_START */437if (flags & SMIC_TX_DATA_READY) {438if (smic->write_count == 1) {439write_smic_control(smic, SMIC_CC_SMS_WR_END);440smic->state = SMIC_WRITE_END;441} else {442write_smic_control(smic, SMIC_CC_SMS_WR_NEXT);443smic->state = SMIC_WRITE_NEXT;444}445write_next_byte(smic);446write_smic_flags(smic, flags | SMIC_FLAG_BSY);447} else448return SI_SM_CALL_WITH_DELAY;449break;450451case SMIC_WRITE_END:452if (status != SMIC_SC_SMS_WR_END) {453start_error_recovery(smic,454"state = SMIC_WRITE_END, "455"status != SMIC_SC_SMS_WR_END");456return SI_SM_CALL_WITH_DELAY;457}458/* data register holds an error code */459data = read_smic_data(smic);460if (data != 0) {461if (smic_debug & SMIC_DEBUG_ENABLE)462printk(KERN_DEBUG463"SMIC_WRITE_END: data = %02x\n", data);464start_error_recovery(smic,465"state = SMIC_WRITE_END, "466"data != SUCCESS");467return SI_SM_CALL_WITH_DELAY;468} else469smic->state = SMIC_WRITE2READ;470break;471472case SMIC_WRITE2READ:473/*474* we must wait for RX_DATA_READY to be set before we475* can continue476*/477if (flags & SMIC_RX_DATA_READY) {478write_smic_control(smic, SMIC_CC_SMS_RD_START);479write_smic_flags(smic, flags | SMIC_FLAG_BSY);480smic->state = SMIC_READ_START;481} else482return SI_SM_CALL_WITH_DELAY;483break;484485case SMIC_READ_START:486if (status != SMIC_SC_SMS_RD_START) {487start_error_recovery(smic,488"state = SMIC_READ_START, "489"status != SMIC_SC_SMS_RD_START");490return SI_SM_CALL_WITH_DELAY;491}492if (flags & SMIC_RX_DATA_READY) {493read_next_byte(smic);494write_smic_control(smic, SMIC_CC_SMS_RD_NEXT);495write_smic_flags(smic, flags | SMIC_FLAG_BSY);496smic->state = SMIC_READ_NEXT;497} else498return SI_SM_CALL_WITH_DELAY;499break;500501case SMIC_READ_NEXT:502switch (status) {503/*504* smic tells us that this is the last byte to be read505* --> clean up506*/507case SMIC_SC_SMS_RD_END:508read_next_byte(smic);509write_smic_control(smic, SMIC_CC_SMS_RD_END);510write_smic_flags(smic, flags | SMIC_FLAG_BSY);511smic->state = SMIC_READ_END;512break;513case SMIC_SC_SMS_RD_NEXT:514if (flags & SMIC_RX_DATA_READY) {515read_next_byte(smic);516write_smic_control(smic, SMIC_CC_SMS_RD_NEXT);517write_smic_flags(smic, flags | SMIC_FLAG_BSY);518smic->state = SMIC_READ_NEXT;519} else520return SI_SM_CALL_WITH_DELAY;521break;522default:523start_error_recovery(524smic,525"state = SMIC_READ_NEXT, "526"status != SMIC_SC_SMS_RD_(NEXT|END)");527return SI_SM_CALL_WITH_DELAY;528}529break;530531case SMIC_READ_END:532if (status != SMIC_SC_SMS_READY) {533start_error_recovery(smic,534"state = SMIC_READ_END, "535"status != SMIC_SC_SMS_READY");536return SI_SM_CALL_WITH_DELAY;537}538data = read_smic_data(smic);539/* data register holds an error code */540if (data != 0) {541if (smic_debug & SMIC_DEBUG_ENABLE)542printk(KERN_DEBUG543"SMIC_READ_END: data = %02x\n", data);544start_error_recovery(smic,545"state = SMIC_READ_END, "546"data != SUCCESS");547return SI_SM_CALL_WITH_DELAY;548} else {549smic->state = SMIC_IDLE;550return SI_SM_TRANSACTION_COMPLETE;551}552553case SMIC_HOSED:554init_smic_data(smic, smic->io);555return SI_SM_HOSED;556557default:558if (smic_debug & SMIC_DEBUG_ENABLE) {559printk(KERN_DEBUG "smic->state = %d\n", smic->state);560start_error_recovery(smic, "state = UNKNOWN");561return SI_SM_CALL_WITH_DELAY;562}563}564smic->smic_timeout = SMIC_RETRY_TIMEOUT;565return SI_SM_CALL_WITHOUT_DELAY;566}567568static int smic_detect(struct si_sm_data *smic)569{570/*571* It's impossible for the SMIC fnags register to be all 1's,572* (assuming a properly functioning, self-initialized BMC)573* but that's what you get from reading a bogus address, so we574* test that first.575*/576if (read_smic_flags(smic) == 0xff)577return 1;578579return 0;580}581582static void smic_cleanup(struct si_sm_data *kcs)583{584}585586static int smic_size(void)587{588return sizeof(struct si_sm_data);589}590591struct si_sm_handlers smic_smi_handlers = {592.init_data = init_smic_data,593.start_transaction = start_smic_transaction,594.get_result = smic_get_result,595.event = smic_event,596.detect = smic_detect,597.cleanup = smic_cleanup,598.size = smic_size,599};600601602