Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0+ */
0002 /*
0003  * ipmi_smi.h
0004  *
0005  * MontaVista IPMI system management interface
0006  *
0007  * Author: MontaVista Software, Inc.
0008  *         Corey Minyard <minyard@mvista.com>
0009  *         source@mvista.com
0010  *
0011  * Copyright 2002 MontaVista Software Inc.
0012  *
0013  */
0014 
0015 #ifndef __LINUX_IPMI_SMI_H
0016 #define __LINUX_IPMI_SMI_H
0017 
0018 #include <linux/ipmi_msgdefs.h>
0019 #include <linux/proc_fs.h>
0020 #include <linux/platform_device.h>
0021 #include <linux/ipmi.h>
0022 
0023 struct device;
0024 
0025 /*
0026  * This files describes the interface for IPMI system management interface
0027  * drivers to bind into the IPMI message handler.
0028  */
0029 
0030 /* Structure for the low-level drivers. */
0031 struct ipmi_smi;
0032 
0033 /*
0034  * Flags for set_check_watch() below.  Tells if the SMI should be
0035  * waiting for watchdog timeouts, commands and/or messages.
0036  */
0037 #define IPMI_WATCH_MASK_CHECK_MESSAGES  (1 << 0)
0038 #define IPMI_WATCH_MASK_CHECK_WATCHDOG  (1 << 1)
0039 #define IPMI_WATCH_MASK_CHECK_COMMANDS  (1 << 2)
0040 
0041 /*
0042  * SMI messages
0043  *
0044  * When communicating with an SMI, messages come in two formats:
0045  *
0046  * * Normal (to a BMC over a BMC interface)
0047  *
0048  * * IPMB (over a IPMB to another MC)
0049  *
0050  * When normal, commands are sent using the format defined by a
0051  * standard message over KCS (NetFn must be even):
0052  *
0053  *   +-----------+-----+------+
0054  *   | NetFn/LUN | Cmd | Data |
0055  *   +-----------+-----+------+
0056  *
0057  * And responses, similarly, with an completion code added (NetFn must
0058  * be odd):
0059  *
0060  *   +-----------+-----+------+------+
0061  *   | NetFn/LUN | Cmd | CC   | Data |
0062  *   +-----------+-----+------+------+
0063  *
0064  * With normal messages, only commands are sent and only responses are
0065  * received.
0066  *
0067  * In IPMB mode, we are acting as an IPMB device. Commands will be in
0068  * the following format (NetFn must be even):
0069  *
0070  *   +-------------+------+-------------+-----+------+
0071  *   | NetFn/rsLUN | Addr | rqSeq/rqLUN | Cmd | Data |
0072  *   +-------------+------+-------------+-----+------+
0073  *
0074  * Responses will using the following format:
0075  *
0076  *   +-------------+------+-------------+-----+------+------+
0077  *   | NetFn/rqLUN | Addr | rqSeq/rsLUN | Cmd | CC   | Data |
0078  *   +-------------+------+-------------+-----+------+------+
0079  *
0080  * This is similar to the format defined in the IPMB manual section
0081  * 2.11.1 with the checksums and the first address removed.  Also, the
0082  * address is always the remote address.
0083  *
0084  * IPMB messages can be commands and responses in both directions.
0085  * Received commands are handled as received commands from the message
0086  * queue.
0087  */
0088 
0089 enum ipmi_smi_msg_type {
0090     IPMI_SMI_MSG_TYPE_NORMAL = 0,
0091     IPMI_SMI_MSG_TYPE_IPMB_DIRECT
0092 };
0093 
0094 /*
0095  * Messages to/from the lower layer.  The smi interface will take one
0096  * of these to send. After the send has occurred and a response has
0097  * been received, it will report this same data structure back up to
0098  * the upper layer.  If an error occurs, it should fill in the
0099  * response with an error code in the completion code location. When
0100  * asynchronous data is received, one of these is allocated, the
0101  * data_size is set to zero and the response holds the data from the
0102  * get message or get event command that the interface initiated.
0103  * Note that it is the interfaces responsibility to detect
0104  * asynchronous data and messages and request them from the
0105  * interface.
0106  */
0107 struct ipmi_smi_msg {
0108     struct list_head link;
0109 
0110     enum ipmi_smi_msg_type type;
0111 
0112     long    msgid;
0113     void    *user_data;
0114 
0115     int           data_size;
0116     unsigned char data[IPMI_MAX_MSG_LENGTH];
0117 
0118     int           rsp_size;
0119     unsigned char rsp[IPMI_MAX_MSG_LENGTH];
0120 
0121     /*
0122      * Will be called when the system is done with the message
0123      * (presumably to free it).
0124      */
0125     void (*done)(struct ipmi_smi_msg *msg);
0126 };
0127 
0128 #define INIT_IPMI_SMI_MSG(done_handler) \
0129 {                       \
0130     .done = done_handler,           \
0131     .type = IPMI_SMI_MSG_TYPE_NORMAL    \
0132 }
0133 
0134 struct ipmi_smi_handlers {
0135     struct module *owner;
0136 
0137     /* Capabilities of the SMI. */
0138 #define IPMI_SMI_CAN_HANDLE_IPMB_DIRECT     (1 << 0)
0139     unsigned int flags;
0140 
0141     /*
0142      * The low-level interface cannot start sending messages to
0143      * the upper layer until this function is called.  This may
0144      * not be NULL, the lower layer must take the interface from
0145      * this call.
0146      */
0147     int (*start_processing)(void            *send_info,
0148                 struct ipmi_smi *new_intf);
0149 
0150     /*
0151      * When called, the low-level interface should disable all
0152      * processing, it should be complete shut down when it returns.
0153      */
0154     void (*shutdown)(void *send_info);
0155 
0156     /*
0157      * Get the detailed private info of the low level interface and store
0158      * it into the structure of ipmi_smi_data. For example: the
0159      * ACPI device handle will be returned for the pnp_acpi IPMI device.
0160      */
0161     int (*get_smi_info)(void *send_info, struct ipmi_smi_info *data);
0162 
0163     /*
0164      * Called to enqueue an SMI message to be sent.  This
0165      * operation is not allowed to fail.  If an error occurs, it
0166      * should report back the error in a received message.  It may
0167      * do this in the current call context, since no write locks
0168      * are held when this is run.  Message are delivered one at
0169      * a time by the message handler, a new message will not be
0170      * delivered until the previous message is returned.
0171      */
0172     void (*sender)(void                *send_info,
0173                struct ipmi_smi_msg *msg);
0174 
0175     /*
0176      * Called by the upper layer to request that we try to get
0177      * events from the BMC we are attached to.
0178      */
0179     void (*request_events)(void *send_info);
0180 
0181     /*
0182      * Called by the upper layer when some user requires that the
0183      * interface watch for received messages and watchdog
0184      * pretimeouts (basically do a "Get Flags", or not.  Used by
0185      * the SMI to know if it should watch for these.  This may be
0186      * NULL if the SMI does not implement it.  watch_mask is from
0187      * IPMI_WATCH_MASK_xxx above.  The interface should run slower
0188      * timeouts for just watchdog checking or faster timeouts when
0189      * waiting for the message queue.
0190      */
0191     void (*set_need_watch)(void *send_info, unsigned int watch_mask);
0192 
0193     /*
0194      * Called when flushing all pending messages.
0195      */
0196     void (*flush_messages)(void *send_info);
0197 
0198     /*
0199      * Called when the interface should go into "run to
0200      * completion" mode.  If this call sets the value to true, the
0201      * interface should make sure that all messages are flushed
0202      * out and that none are pending, and any new requests are run
0203      * to completion immediately.
0204      */
0205     void (*set_run_to_completion)(void *send_info, bool run_to_completion);
0206 
0207     /*
0208      * Called to poll for work to do.  This is so upper layers can
0209      * poll for operations during things like crash dumps.
0210      */
0211     void (*poll)(void *send_info);
0212 
0213     /*
0214      * Enable/disable firmware maintenance mode.  Note that this
0215      * is *not* the modes defined, this is simply an on/off
0216      * setting.  The message handler does the mode handling.  Note
0217      * that this is called from interrupt context, so it cannot
0218      * block.
0219      */
0220     void (*set_maintenance_mode)(void *send_info, bool enable);
0221 };
0222 
0223 struct ipmi_device_id {
0224     unsigned char device_id;
0225     unsigned char device_revision;
0226     unsigned char firmware_revision_1;
0227     unsigned char firmware_revision_2;
0228     unsigned char ipmi_version;
0229     unsigned char additional_device_support;
0230     unsigned int  manufacturer_id;
0231     unsigned int  product_id;
0232     unsigned char aux_firmware_revision[4];
0233     unsigned int  aux_firmware_revision_set : 1;
0234 };
0235 
0236 #define ipmi_version_major(v) ((v)->ipmi_version & 0xf)
0237 #define ipmi_version_minor(v) ((v)->ipmi_version >> 4)
0238 
0239 /*
0240  * Take a pointer to an IPMI response and extract device id information from
0241  * it. @netfn is in the IPMI_NETFN_ format, so may need to be shifted from
0242  * a SI response.
0243  */
0244 static inline int ipmi_demangle_device_id(uint8_t netfn, uint8_t cmd,
0245                       const unsigned char *data,
0246                       unsigned int data_len,
0247                       struct ipmi_device_id *id)
0248 {
0249     if (data_len < 7)
0250         return -EINVAL;
0251     if (netfn != IPMI_NETFN_APP_RESPONSE || cmd != IPMI_GET_DEVICE_ID_CMD)
0252         /* Strange, didn't get the response we expected. */
0253         return -EINVAL;
0254     if (data[0] != 0)
0255         /* That's odd, it shouldn't be able to fail. */
0256         return -EINVAL;
0257 
0258     data++;
0259     data_len--;
0260 
0261     id->device_id = data[0];
0262     id->device_revision = data[1];
0263     id->firmware_revision_1 = data[2];
0264     id->firmware_revision_2 = data[3];
0265     id->ipmi_version = data[4];
0266     id->additional_device_support = data[5];
0267     if (data_len >= 11) {
0268         id->manufacturer_id = (data[6] | (data[7] << 8) |
0269                        (data[8] << 16));
0270         id->product_id = data[9] | (data[10] << 8);
0271     } else {
0272         id->manufacturer_id = 0;
0273         id->product_id = 0;
0274     }
0275     if (data_len >= 15) {
0276         memcpy(id->aux_firmware_revision, data+11, 4);
0277         id->aux_firmware_revision_set = 1;
0278     } else
0279         id->aux_firmware_revision_set = 0;
0280 
0281     return 0;
0282 }
0283 
0284 /*
0285  * Add a low-level interface to the IPMI driver.  Note that if the
0286  * interface doesn't know its slave address, it should pass in zero.
0287  * The low-level interface should not deliver any messages to the
0288  * upper layer until the start_processing() function in the handlers
0289  * is called, and the lower layer must get the interface from that
0290  * call.
0291  */
0292 int ipmi_add_smi(struct module            *owner,
0293          const struct ipmi_smi_handlers *handlers,
0294          void                     *send_info,
0295          struct device            *dev,
0296          unsigned char            slave_addr);
0297 
0298 #define ipmi_register_smi(handlers, send_info, dev, slave_addr) \
0299     ipmi_add_smi(THIS_MODULE, handlers, send_info, dev, slave_addr)
0300 
0301 /*
0302  * Remove a low-level interface from the IPMI driver.  This will
0303  * return an error if the interface is still in use by a user.
0304  */
0305 void ipmi_unregister_smi(struct ipmi_smi *intf);
0306 
0307 /*
0308  * The lower layer reports received messages through this interface.
0309  * The data_size should be zero if this is an asynchronous message.  If
0310  * the lower layer gets an error sending a message, it should format
0311  * an error response in the message response.
0312  */
0313 void ipmi_smi_msg_received(struct ipmi_smi     *intf,
0314                struct ipmi_smi_msg *msg);
0315 
0316 /* The lower layer received a watchdog pre-timeout on interface. */
0317 void ipmi_smi_watchdog_pretimeout(struct ipmi_smi *intf);
0318 
0319 struct ipmi_smi_msg *ipmi_alloc_smi_msg(void);
0320 static inline void ipmi_free_smi_msg(struct ipmi_smi_msg *msg)
0321 {
0322     msg->done(msg);
0323 }
0324 
0325 #endif /* __LINUX_IPMI_SMI_H */