root/lm-sensors/trunk/kernel/chips/bmcsensors.c @ 1615

Revision 1615, 25.2 KB (checked in by mds, 11 years ago)

BMC cleanup

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    bmcsensors.c - Part of lm_sensors, Linux kernel modules
3                for hardware monitoring
4               
5    Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include <linux/version.h>
23#include <linux/module.h>
24#include <linux/slab.h>
25#include <linux/proc_fs.h>
26#include <linux/sysctl.h>
27#include <asm/errno.h>
28#include <asm/io.h>
29#include <linux/types.h>
30#include <linux/i2c.h>
31#include <linux/ipmi.h>
32#include "version.h"
33#include "sensors.h"
34#include <linux/init.h>
35
36static unsigned short normal_i2c[] = { SENSORS_I2C_END };
37static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
38static unsigned int normal_isa[] = { 0, SENSORS_ISA_END };
39static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
40
41SENSORS_INSMOD_1(bmcsensors);
42
43#ifdef MODULE
44extern int init_module(void);
45extern int cleanup_module(void);
46#endif                          /* MODULE */
47
48struct bmcsensors_data {
49        struct semaphore lock;
50        int sysctl_id;
51
52        struct semaphore update_lock;
53        char valid;             /* !=0 if following fields are valid */
54        unsigned long last_updated;     /* In jiffies */
55
56        u8 alarms;
57};
58
59#ifdef MODULE
60static
61#else
62extern
63#endif
64int __init sensors_bmcsensors_init(void);
65static int __init bmcsensors_cleanup(void);
66
67static int bmcsensors_attach_adapter(struct i2c_adapter *adapter);
68static int bmcsensors_detect(struct i2c_adapter *adapter, int address,
69                          unsigned short flags, int kind);
70static int bmcsensors_detach_client(struct i2c_client *client);
71static int bmcsensors_command(struct i2c_client *client, unsigned int cmd,
72                           void *arg);
73static void bmcsensors_inc_use(struct i2c_client *client);
74static void bmcsensors_dec_use(struct i2c_client *client);
75
76static void bmcsensors_update_client(struct i2c_client *client);
77static void bmcsensors_init_client(struct i2c_client *client);
78static int bmcsensors_find(int *address);
79
80
81static void bmcsensors_all(struct i2c_client *client, int operation,
82                        int ctl_name, int *nrels_mag, long *results);
83static void bmcsensors_alarms(struct i2c_client *client, int operation,
84                           int ctl_name, int *nrels_mag, long *results);
85static void bmcsensors_fan_div(struct i2c_client *client, int operation,
86                            int ctl_name, int *nrels_mag, long *results);
87static void bmcsensors_pwm(struct i2c_client *client, int operation,
88                        int ctl_name, int *nrels_mag, long *results);
89void bmcsensors_get_sdr(u16 resid, u16 record, u8 offset);
90void bmcsensors_get_reading(struct i2c_client *client, int i);
91
92static int bmcsensors_id = 0;
93
94static struct i2c_driver bmcsensors_driver = {
95        /* name */ "BMC Sensors driver",
96        /* id */ I2C_DRIVERID_BMCSENSORS,
97        /* flags */ I2C_DF_NOTIFY,
98        /* attach_adapter */ &bmcsensors_attach_adapter,
99        /* detach_client */ &bmcsensors_detach_client,
100        /* command */ &bmcsensors_command,
101        /* inc_use */ &bmcsensors_inc_use,
102        /* dec_use */ &bmcsensors_dec_use
103};
104
105static struct bmcsensors_data bmc_data;
106struct i2c_client bmc_client = {
107        "BMC Sensors",
108        1,                  /* fake should be 0 */
109        0,
110        0,
111        NULL,   /* adapter */
112        &bmcsensors_driver,
113        & bmc_data,
114        0
115};
116
117static bmcsensors_initialized;
118
119
120#define MAX_SDR_ENTRIES 50
121#define SDR_LIMITS 8
122#define SDR_MAX_ID_LENGTH 16
123#define SDR_MAX_UNPACKED_ID_LENGTH ((SDR_MAX_ID_LENGTH * 4 / 3) + 2)
124struct sdrdata {
125        /* reverse lookup from sysctl */
126        int sysctl;
127        /* retrieved from SDR, not expected to change */
128        u8 stype;
129        u8 number;
130        u8 capab;
131        u16 thresh_mask;
132        u8 format;
133        u8 linear;
134        s16 m;
135        s16 b;
136        u8 k;
137        u8 nominal;
138        u8 limits[SDR_LIMITS];
139        int lim1, lim2;
140        u8 lim1_write, lim2_write;
141        u8 string_type;
142        u8 id_length;
143        u8 id[SDR_MAX_ID_LENGTH];
144        /* retrieved from reading */
145        u8 reading;
146        u8 status;
147        u8 thresholds;
148};
149static struct sdrdata sdrd[MAX_SDR_ENTRIES];
150static int sdrd_count;
151
152#define MAX_PROC_ENTRIES (MAX_SDR_ENTRIES + 5)
153#define MAX_PROCNAME_SIZE 8
154static ctl_table *bmcsensors_dir_table;
155static char *bmcsensors_proc_name_pool;
156
157#define IPMI_SDR_SIZE 67
158static int ipmi_sdr_partial_size = IPMI_SDR_SIZE;
159static struct ipmi_msg tx_message;      /* send message */
160static unsigned char tx_msg_data[IPMI_MAX_MSG_LENGTH + 50];
161static unsigned char rx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; /* sloppy */
162int rx_msg_data_offset;
163static long msgid;              /* message ID */
164static u16 resid;
165
166enum states {STATE_INIT, STATE_RESERVE, STATE_SDR, STATE_SDRPARTIAL, STATE_READING, STATE_DONE};
167int state;
168static int receive_counter;
169
170
171/* IPMI Message defs */
172/* Network Function Codes */
173#define IPMI_NETFN_SENSOR       0x04
174#define IPMI_NETFN_STORAGE      0x0A
175/* Commands */
176#define IPMI_RESERVE_SDR                0x22
177#define IPMI_GET_SDR            0x23
178#define IPMI_GET_SENSOR_STATE_READING           0x2D
179
180/* SDR defs */
181#define STYPE_TEMP      0x01
182#define STYPE_VOLT      0x02
183#define STYPE_CURR      0x03
184#define STYPE_FAN       0x04
185
186/* get rid of this ***************/
187#define STYPE_MAX       0x29            /* the last sensor type we are interested in */
188static u8 bmcs_count[STYPE_MAX + 1] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
189static const u8 bmcs_max[STYPE_MAX + 1] = {
1900, 10, 10, 10, 10, 0, 0, 0}; /* more zeros*/
191
192/************************************/
193
194
195/* unpack based on string type, convert to normal, null terminate */
196static void ipmi_sprintf(u8 * to, u8 * from, u8 type, u8 length)
197{
198        static const u8 *bcdplus = "0123456789 -.:,_";
199        int i;
200
201        switch (type) {
202                case 0:         /* unicode */           
203                        for(i = 0; i < length; i++)
204                                *to++ = *from++ & 0x7f;
205                        *to = 0;
206                        break;
207                case 1:         /* BCD Plus */         
208                        for(i = 0; i < length; i++)
209                                *to++ = bcdplus[*from++ & 0x0f];
210                        *to = 0;
211                        break;
212                case 2:         /* packed ascii */ /* if not a mult. of 3 this will run over */     
213                        for(i = 0; i < length; i += 3) {
214                                *to++ = *from & 0x3f;
215                                *to++ = *from++ >> 6 | ((*from & 0xf)  << 2);
216                                *to++ = *from++ >> 4 | ((*from & 0x3)  << 4);
217                                *to++ = (*from++ >> 2) & 0x3f;
218                        }
219                        *to = 0;
220                        break;
221                case 3:         /* normal */           
222                        if(length > 1)
223                                memcpy(to, from, length);
224                        to[length] = 0;
225                        break;
226        }
227}
228
229static const char * threshold_text[] = {
230        "upper non-recoverable threshold",
231        "upper critical threshold",
232        "upper non-critical threshold",
233        "lower non-recoverable threshold",
234        "lower critical threshold",
235        "lower non-critical threshold",
236        "positive-going hysteresis",
237        "negative-going hysteresis"     /* unused */
238};
239
240/* select two out of the 8 possible readable thresholds, and place indexes into the limits
241   array into lim1 and lim2. Set writable flags */
242static void bmcsensors_select_thresholds(int i)
243{
244        u8 capab = sdrd[i].capab;
245        u16 mask = sdrd[i].thresh_mask;
246
247        sdrd[i].lim1 = -1;
248        sdrd[i].lim2 = -1;
249        sdrd[i].lim1_write = 0;
250        sdrd[i].lim2_write = 0;
251
252        if(((capab & 0x0c) == 0x04) ||  /* readable thresholds ? */
253           ((capab & 0x0c) == 0x08)) {
254                /* select upper threshold */
255                if(mask & 0x10) {                       /* upper crit */
256                        sdrd[i].lim1 = 1;
257                        if((capab & 0x0c) == 0x08 && (mask & 0x1000))
258                                sdrd[i].lim1_write = 1;
259                }
260                else if(mask & 0x20) {          /* upper non-recov */
261                        sdrd[i].lim1 = 0;
262                        if((capab & 0x0c) == 0x08 && (mask & 0x2000))
263                                sdrd[i].lim1_write = 1;
264                }
265                else if(mask & 0x08) {          /* upper non-crit */
266                        sdrd[i].lim1 = 2;
267                        if((capab & 0x0c) == 0x08 && (mask & 0x0800))
268                                sdrd[i].lim1_write = 1;
269                }
270
271                /* select lower threshold */
272                if(((capab & 0x30) == 0x10) ||  /* readable hysteresis ? */
273                   ((capab & 0x30) == 0x20))    /* pos hyst */
274                        sdrd[i].lim2 = 6;
275                else if(mask & 0x02) {          /* lower crit */
276                        sdrd[i].lim2 = 4;
277                        if((capab & 0x0c) == 0x08 && (mask & 0x0200))
278                                sdrd[i].lim2_write = 1;
279                }
280                else if(mask & 0x04) {          /* lower non-recov */
281                        sdrd[i].lim2 = 3;
282                        if((capab & 0x0c) == 0x08 && (mask & 0x0400))
283                                sdrd[i].lim2_write = 1;
284                }
285                else if(mask & 0x01) {          /* lower non-crit */
286                        sdrd[i].lim2 = 5;
287                        if((capab & 0x0c) == 0x08 && (mask & 0x0100))
288                                sdrd[i].lim2_write = 1;
289                }
290        }
291
292        if(sdrd[i].lim1 >= 0)
293                printk(KERN_INFO "bmcsensors.o: sensor %d: using %s for upper limit\n",
294                        i, threshold_text[sdrd[i].lim1]);
295/*
296        else
297                printk(KERN_INFO "bmcsensors.o: sensor %d: no readable upper limit\n", i);
298*/
299        if(sdrd[i].lim2 >= 0)
300                printk(KERN_INFO "bmcsensors.o: sensor %d: using %s for lower limit\n",
301                        i, threshold_text[sdrd[i].lim2]);
302/*
303        else
304                printk(KERN_INFO "bmcsensors.o: sensor %d: no readable lower limit\n", i);
305*/
306}
307
308/* After we have received all the SDR entries and picked out the ones
309   we are interested in, build a table of the /proc entries and register.
310*/
311static void bmcsensors_build_proc_table()
312{
313        int i;
314        int temps = 0, volts = 0, currs = 0, fans = 0;
315        u8 id[SDR_MAX_UNPACKED_ID_LENGTH];
316
317        if(!(bmcsensors_dir_table = kmalloc((sdrd_count + 1) * sizeof(struct ctl_table), GFP_KERNEL))) {
318                printk(KERN_ERR "bmcsensors.o: no memory\n");
319                return; /* do more than this */ /* ^^ add 1 or more for alarms, etc. */
320        }
321        if(!(bmcsensors_proc_name_pool = kmalloc((sdrd_count + 0) * MAX_PROCNAME_SIZE, GFP_KERNEL))) {
322                kfree(bmcsensors_dir_table);
323                printk(KERN_ERR "bmcsensors.o: no memory\n");
324                return; /* do more than this */ /* ^^ add 1 or more for alarms, etc. */
325        }
326
327        for(i = 0; i < sdrd_count; i++) {
328                bmcsensors_dir_table[i].procname = bmcsensors_proc_name_pool + (i * MAX_PROCNAME_SIZE);
329                bmcsensors_dir_table[i].data = NULL;
330                bmcsensors_dir_table[i].maxlen = 0;
331                bmcsensors_dir_table[i].child = NULL;
332                bmcsensors_dir_table[i].proc_handler = &i2c_proc_real;
333                bmcsensors_dir_table[i].strategy = &i2c_sysctl_real;
334                bmcsensors_dir_table[i].de = NULL;
335
336                switch(sdrd[i].stype) {
337                        case(STYPE_TEMP) :
338                                bmcsensors_dir_table[i].ctl_name = BMC_SYSCTL_TEMP1 + temps;
339                                sprintf((char *)bmcsensors_dir_table[i].procname, "temp%d", ++temps);
340                                bmcsensors_dir_table[i].extra1 = &bmcsensors_all;
341                                break;
342                        case(STYPE_VOLT) :
343                                bmcsensors_dir_table[i].ctl_name = BMC_SYSCTL_IN1 + volts;
344                                sprintf((char *)bmcsensors_dir_table[i].procname, "in%d", ++volts);
345                                bmcsensors_dir_table[i].extra1 = &bmcsensors_all;
346                                break;
347                        case(STYPE_CURR) :
348                                bmcsensors_dir_table[i].ctl_name = BMC_SYSCTL_CURR1 + currs;
349                                sprintf((char *)bmcsensors_dir_table[i].procname, "curr%d", ++currs);
350                                bmcsensors_dir_table[i].extra1 = &bmcsensors_all;
351                                break;
352                        case(STYPE_FAN) :
353                                bmcsensors_dir_table[i].ctl_name = BMC_SYSCTL_FAN1 + fans;
354                                sprintf((char *)bmcsensors_dir_table[i].procname, "fan%d", ++fans);
355                                bmcsensors_dir_table[i].extra1 = &bmcsensors_all;
356                                break;
357                        default: /* ?? */
358                                printk(KERN_INFO "bmcsensors.o: unk stype\n");
359                                continue;
360                }
361                sdrd[i].sysctl = bmcsensors_dir_table[i].ctl_name;
362                printk(KERN_INFO "bmcsensors.o: registering sensor %d: (type 0x%.2x) "
363                        "(fmt=%d; m=%d; b=%d; k1=%d; k2=%d; cap=0x%.2x; mask=0x%.4x)\n",
364                        i, sdrd[i].stype, sdrd[i].format,
365                        sdrd[i].m, sdrd[i].b,sdrd[i].k & 0xf, sdrd[i].k >> 4,
366                        sdrd[i].capab, sdrd[i].thresh_mask);
367                if(sdrd[i].id_length) {
368                        ipmi_sprintf(id, sdrd[i].id, sdrd[i].string_type, sdrd[i].id_length);
369                        printk(KERN_INFO "bmcsensors.o: sensors.conf: label %s \"%s\"\n",
370                                bmcsensors_dir_table[i].procname, id);
371                }
372                bmcsensors_select_thresholds(i);
373                if(sdrd[i].linear != 0) {
374                        printk(KERN_INFO "bmcsensors.o: sensor %d: nonlinear function 0x%.2x unsupported\n",
375                                i, sdrd[i].linear);
376                }
377                if((sdrd[i].format & 0x03) == 0x02) {
378                        printk(KERN_INFO "bmcsensors.o: sensor %d: 1's complement format unsupported\n",
379                                i);
380                } else if((sdrd[i].format & 0x03) == 0x03) {
381                        printk(KERN_INFO "bmcsensors.o: sensor %d: threshold sensor only, no readings available",
382                                i);
383                }
384                if(sdrd[i].lim1_write || sdrd[i].lim2_write)
385                        bmcsensors_dir_table[i].mode = 0644;
386                else
387                        bmcsensors_dir_table[i].mode = 0444;
388        }
389        bmcsensors_dir_table[sdrd_count].ctl_name = 0;
390
391        if ((i = i2c_register_entry(&bmc_client, "bmc",
392                                        bmcsensors_dir_table,
393                                        THIS_MODULE)) < 0) {
394                printk(KERN_INFO "bmcsensors.o: i2c registration failed.\n");
395                kfree(bmcsensors_dir_table);
396                kfree(bmcsensors_proc_name_pool);
397                return;
398        }
399        bmcsensors_initialized = 3;
400        bmc_data.sysctl_id = i;
401
402        bmcsensors_init_client(&bmc_client);
403        printk(KERN_INFO "bmcsensors.o: registered %d temp, %d volt, %d current, %d fan sensors\n",
404                        temps, volts, currs, fans);
405        bmcsensors_update_client(&bmc_client);
406}
407
408
409/* Process a sensor reading response */
410static int bmcsensors_rcv_reading_msg(struct ipmi_msg *msg)
411{
412        if(receive_counter >= sdrd_count) {
413                /* shouldn't happen */
414                receive_counter = 0;
415                return STATE_DONE;
416        }
417        sdrd[receive_counter].reading = msg->data[1];
418        sdrd[receive_counter].status = msg->data[2];
419        sdrd[receive_counter].thresholds = msg->data[3];
420#ifdef DEBUG
421        printk(KERN_DEBUG "bmcsensors.o: sensor %d (type %d) reading %d\n",
422                receive_counter, sdrd[receive_counter].stype, msg->data[1]);
423#endif
424        if(++receive_counter >= sdrd_count) {
425                receive_counter = 0;
426                return STATE_DONE;
427        }
428        bmcsensors_get_reading(&bmc_client, receive_counter); /* don't really need to pass client */
429        return STATE_READING; 
430}
431
432/* Process a SDR response */
433static int bmcsensors_rcv_sdr_msg(struct ipmi_msg *msg, int state)
434{
435        u16 record, nextrecord;
436        int version, type, length, owner, lun, number, entity, instance, init;
437        int stype, code;
438        int id_length;
439        int i;
440        int rstate = STATE_SDR;
441        struct ipmi_msg txmsg;
442        unsigned char * data;
443
444
445        if(msg->data[0] != 0) {
446                /* cut request in half and try again */
447                ipmi_sdr_partial_size /= 2;
448                if(ipmi_sdr_partial_size < 8) {
449                        printk(KERN_INFO "bmcsensors.o: IPMI buffers too small, giving up\n");
450                        return STATE_DONE;
451                }
452                printk(KERN_INFO "bmcsensors.o: Reducing SDR request size to %d\n", ipmi_sdr_partial_size);
453                bmcsensors_get_sdr(resid, 0, 0);
454                return STATE_SDR;
455        }
456        if(ipmi_sdr_partial_size < IPMI_SDR_SIZE) {
457                if(rx_msg_data_offset == 0) {
458                        memcpy(rx_msg_data, msg->data, ipmi_sdr_partial_size + 3);
459                        rx_msg_data_offset = ipmi_sdr_partial_size + 3;
460                } else {
461                        memcpy(rx_msg_data + rx_msg_data_offset, msg->data + 3, ipmi_sdr_partial_size);
462                        rx_msg_data_offset += ipmi_sdr_partial_size;
463                }
464                if(rx_msg_data_offset > IPMI_SDR_SIZE + 3) {
465                        /* got last chunk */
466                        rx_msg_data_offset =  0;
467                        data = rx_msg_data;
468                } else {
469                        /* get more */
470                        record = (rx_msg_data[4] << 8) | rx_msg_data[3];
471                        bmcsensors_get_sdr(resid, record, rx_msg_data_offset - 3);
472                        return STATE_SDR;
473                }
474        } else {
475                data = msg->data;       /* got it in one chunk */
476        }
477
478        nextrecord = (data[2] << 8) | data[1];
479        version = data[5];
480        type = data[6];
481        if(type == 1 || type == 2) {            /* known SDR type */
482/*
483                owner = data[8];
484                lun = data[9];
485                entity = data[11];
486                init = data[13];
487*/
488                stype = data[15];
489
490                if(stype <= STYPE_MAX) {        /* known sensor type */
491                        if(bmcs_count[stype] >= bmcs_max[stype]) {
492                                if(bmcs_max[stype] > 0) {
493                                        printk(KERN_INFO "bmcsensors.o: Limit of %d exceeded for sensor type 0x%x\n", bmcs_max[stype], stype);
494#ifdef DEBUG
495                                } else {
496                                        printk(KERN_INFO "bmcsensors.o: Ignoring unsupported sensor type 0x%x\n", stype);
497#endif
498                                }
499                        } else {
500                                if(sdrd_count >= MAX_SDR_ENTRIES) {
501                                        printk(KERN_INFO "bmcsensors.o: Limit of %d exceeded for total sensors\n", MAX_SDR_ENTRIES);
502                                } else {
503                                        /* add SDR database entry */
504                                        sdrd[sdrd_count].stype = stype;
505                                        sdrd[sdrd_count].number = data[10];
506                                        sdrd[sdrd_count].capab = data[14];
507                                        sdrd[sdrd_count].thresh_mask = (data[22] << 8) | data[21];
508                                        if(type == 1) {
509                                                sdrd[sdrd_count].format = data[24] >> 6;
510                                                sdrd[sdrd_count].linear = data[26] & 0x7f;
511                                                sdrd[sdrd_count].m = data[27];
512                                                sdrd[sdrd_count].m |= ((u16) (data[28] & 0xc0)) << 2;
513                                                if(sdrd[sdrd_count].m & 0x0200)
514                                                        sdrd[sdrd_count].m |= 0xfc00;   /* sign extend */
515                                                sdrd[sdrd_count].b = data[29];
516                                                sdrd[sdrd_count].b |= ((u16) (data[30] & 0xc0)) << 2;
517                                                if(sdrd[sdrd_count].b & 0x0200)
518                                                        sdrd[sdrd_count].b |= 0xfc00;   /* sign extend */
519                                                sdrd[sdrd_count].k = data[32];
520                                                sdrd[sdrd_count].nominal = data[34];
521                                                for(i = 0; i < SDR_LIMITS; i++)         /* assume readable */
522                                                        sdrd[sdrd_count].limits[i] = data[39 + i];
523                                                sdrd[sdrd_count].string_type = data[50] >> 6;
524                                                id_length = data[50] & 0x1f;
525                                                if(id_length > 0)
526                                                        memcpy(sdrd[sdrd_count].id, &data[51], id_length);
527                                                sdrd[sdrd_count].id_length = id_length;
528                                        } else {
529                                                sdrd[sdrd_count].m = 1;
530                                                sdrd[sdrd_count].b = 0;
531                                                sdrd[sdrd_count].k = 0;
532                                                sdrd[sdrd_count].string_type = data[34] >> 6;
533                                                id_length = data[34] & 0x1f;
534                                                if(id_length > 0)
535                                                        memcpy(sdrd[sdrd_count].id, &data[35], id_length);
536                                                sdrd[sdrd_count].id_length = id_length;
537                                                /* limits?? */
538                                        }
539                                        bmcs_count[stype]++;
540                                        sdrd_count++;
541                                }
542                        }
543                }
544        }
545                       
546        if(nextrecord == 0xFFFF) {
547                rstate = STATE_READING;
548                if(sdrd_count == 0) {
549                        printk(KERN_INFO "bmcsensors.o: No recognized sensors found.\n");
550                } else {
551                        printk(KERN_INFO "bmcsensors.o: found %d temp, %d volt, %d current, %d fan sensors\n",
552bmcs_count[1], bmcs_count[2], bmcs_count[3], bmcs_count[4]);
553                        bmcsensors_build_proc_table();
554                }
555        } else {
556                bmcsensors_get_sdr(resid, nextrecord, 0);
557        }
558        return rstate;
559}
560
561/* Process incoming messages based on internal state */
562static void bmcsensors_rcv_msg(struct ipmi_msg *msg)
563{
564
565        switch(state) {
566                case STATE_INIT:
567                case STATE_RESERVE:
568                        resid = (msg->data[2] << 8) || msg->data[1];
569                        bmcsensors_get_sdr(resid, 0, 0);
570                        state = STATE_SDR;
571                        break;
572
573                case STATE_SDR:
574                case STATE_SDRPARTIAL:
575                        state = bmcsensors_rcv_sdr_msg(msg, state);
576                        break;
577
578                case STATE_READING:
579                        state = bmcsensors_rcv_reading_msg(msg);
580                        break;
581
582                case STATE_DONE:
583                        break;
584
585                default:
586                        state = STATE_INIT;
587        }
588}
589
590
591/* Incoming message handler */
592static void bmcsensors_msg_handler(struct ipmi_recv_msg *msg,
593                                   void * handler_data)
594{
595        if (msg->msg.data[0] != 0 && msg->msg.data[0] != 0xca) {
596                printk(KERN_ERR "BMCsensors response: Error %x on cmd %x; state = %d; probably fatal.\n",
597                       msg->msg.data[0], msg->msg.cmd, state);
598        } else {
599                bmcsensors_rcv_msg(&(msg->msg));
600        }       
601        ipmi_free_recv_msg(msg);
602}
603
604/************** Message Sending **************/
605
606/* Send an IPMI message */
607static void bmcsensors_send_message(struct ipmi_msg * msg)
608{
609#ifdef DEBUG
610        printk(KERN_INFO "bmcsensors.o: Send BMC msg, cmd: 0x%x\n",
611                       msg->cmd);
612#endif
613/*
614        bmcclient_i2c_send_message(&bmc_client, msgid++, msg);
615*/
616        bmc_client.adapter->algo->slave_send((struct i2c_adapter *) &bmc_client,
617                                             (char *) msg, msgid++);
618
619}
620
621/* Compose and send a "reserve SDR" message */
622void bmcsensors_reserve_sdr(void)
623{
624        tx_message.netfn = IPMI_NETFN_STORAGE;
625        tx_message.cmd = IPMI_RESERVE_SDR;
626        tx_message.data_len = 0;
627        tx_message.data = NULL;
628        bmcsensors_send_message(&tx_message);
629}
630
631/* Componse and send a "get SDR" message */
632void bmcsensors_get_sdr(u16 resid, u16 record, u8 offset)
633{
634        tx_message.netfn = IPMI_NETFN_STORAGE;
635        tx_message.cmd = IPMI_GET_SDR;
636        tx_message.data_len = 6;
637        tx_message.data = tx_msg_data;
638        tx_msg_data[0] = resid & 0xff;
639        tx_msg_data[1] = resid >> 8;
640        tx_msg_data[2] = record & 0xff;
641        tx_msg_data[3] = record >> 8;
642        tx_msg_data[4] = offset;
643        tx_msg_data[5] = ipmi_sdr_partial_size;
644        bmcsensors_send_message(&tx_message);
645}
646
647/* Compose and send a "get sensor reading" message */
648void bmcsensors_get_reading(struct i2c_client *client, int i)
649{
650        tx_message.netfn = IPMI_NETFN_SENSOR;
651        tx_message.cmd = IPMI_GET_SENSOR_STATE_READING;
652        tx_message.data_len = 1;
653        tx_message.data = tx_msg_data;
654        tx_msg_data[0] = sdrd[i].number;
655        bmcsensors_send_message(&tx_message);
656}
657
658/**************** Initialization ****************/
659
660int bmcsensors_attach_adapter(struct i2c_adapter *adapter)
661{
662        if(adapter->algo->id != I2C_ALGO_IPMI)
663                return 0;
664
665        if(bmcsensors_initialized >= 2) {
666                printk(KERN_INFO "bmcsensors.o: Additional IPMI adapter not supported\n");
667                return 0;
668        }
669
670        return bmcsensors_detect(adapter, 0, 0, 0);
671}
672
673int bmcsensors_detect(struct i2c_adapter *adapter, int address,
674                   unsigned short flags, int kind)
675{
676        int err, i;
677
678        bmc_client.id = 0;
679        bmc_client.adapter = adapter;
680        bmc_data.valid = 0;
681
682        if ((err = i2c_attach_client(&bmc_client))) {
683                printk(KERN_ERR "attach client error in bmcsensors_detect()\n");
684                return err;
685        }
686        bmcsensors_initialized = 2;
687
688        state = STATE_INIT;
689        sdrd_count = 0;
690        receive_counter = 0;
691        rx_msg_data_offset = 0;
692        ipmi_sdr_partial_size = IPMI_SDR_SIZE;
693        for(i = 0; i <= STYPE_MAX; i++)
694                bmcs_count[i] = 0;
695
696        /* send our first message, which kicks things off */
697        bmcsensors_reserve_sdr();
698        /* don't call i2c_register_entry until we scan the SDR's */
699        return 0;
700}
701
702int bmcsensors_detach_client(struct i2c_client *client)
703{
704        int err;
705
706        if(bmcsensors_initialized >= 3) {
707                kfree(bmcsensors_dir_table);
708                kfree(bmcsensors_proc_name_pool);
709                i2c_deregister_entry(((struct bmcsensors_data *) (client->data))->
710                                 sysctl_id);
711        }
712
713        if ((err = i2c_detach_client(client))) {
714/*
715                printk
716                    ("bmcsensors.o: Client deregistration failed, client not detached.\n");
717*/
718                return err;
719        }
720
721        return 0;
722}
723
724int bmcsensors_command(struct i2c_client *client, unsigned int cmd, void *arg)
725{
726        bmcsensors_msg_handler((struct ipmi_recv_msg *) arg, NULL);
727        return 0;
728}
729
730void bmcsensors_inc_use(struct i2c_client *client)
731{
732#ifdef MODULE
733        MOD_INC_USE_COUNT;
734#endif
735}
736
737void bmcsensors_dec_use(struct i2c_client *client)
738{
739#ifdef MODULE
740        MOD_DEC_USE_COUNT;
741#endif
742}
743
744void bmcsensors_init_client(struct i2c_client *client)
745{
746/*******************************************/
747
748
749
750}
751
752void bmcsensors_update_client(struct i2c_client *client)
753{
754        struct bmcsensors_data *data = client->data;
755        int i;
756
757/*
758        down(&data->update_lock);
759*/
760
761        if ((jiffies - data->last_updated > 3 * HZ) ||
762            (jiffies < data->last_updated) || !data->valid) {
763                /* don't start an update cycle if one already in progress */
764                if(state != STATE_READING) {
765                        state = STATE_READING;
766                        bmcsensors_get_reading(client, 0);
767                }
768        }
769
770/*
771        up(&data->update_lock);
772*/
773}
774
775
776/************* /proc callback helper functions *********/
777
778/* need better way to map from sysctl to sdrd record number */
779int find_sdrd(int sysctl)
780{
781        int i;
782
783        for(i = 0; i < sdrd_count; i++)
784                if(sdrd[i].sysctl == sysctl)
785                        return i;
786        return -1;
787}
788
789/* IPMI V1.5 Section 30 */
790static const int exps[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000};
791
792static int decplaces(int i)
793{
794        u8 k2;
795
796        k2 = sdrd[i].k >> 4;
797        if(k2 < 8)
798                return 0;
799        else
800                return 16 - k2;
801}
802
803static long convert_value(u8 value, int i)
804{
805        u8 k1, k2;
806        long r;
807
808/* fixme signed/unsigned */
809        r = value * sdrd[i].m;
810
811        k1 = sdrd[i].k & 0x0f;
812        k2 = sdrd[i].k >> 4;
813        if(k1 < 8)
814                r += sdrd[i].b * exps[k1];
815        else
816                r += sdrd[i].b / exps[16 - k1];
817        if(k2 < 8)
818                r *= exps[k2];
819/*
820        taken care of by nrels_mag
821        else
822                r /= exps[16 - k2];
823*/
824        return r;
825}
826
827
828/************** /proc callbacks *****************/
829
830void bmcsensors_all(struct i2c_client *client, int operation, int ctl_name,
831                 int *nrels_mag, long *results)
832{
833        int i;
834        struct bmcsensors_data *data = client->data;
835        int nr = ctl_name - BMC_SYSCTL_TEMP1 + 1;
836
837        if((i = find_sdrd(ctl_name)) < 0) {
838                *nrels_mag = 0;
839                return;         
840        }
841        if (operation == SENSORS_PROC_REAL_INFO)
842                *nrels_mag = decplaces(i);
843        else if (operation == SENSORS_PROC_REAL_READ) {
844                bmcsensors_update_client(client);
845                if(sdrd[i].stype == STYPE_FAN) { /* lower limit only */
846                        if(sdrd[i].lim2 >= 0)
847                                results[0] = convert_value(sdrd[i].limits[sdrd[i].lim2], i);
848                        else
849                                results[0] = 0;
850                        results[1] = convert_value(sdrd[i].reading, i);
851                        *nrels_mag = 2;
852                } else {
853                        if(sdrd[i].lim1 >= 0)
854                                results[0] = convert_value(sdrd[i].limits[sdrd[i].lim1], i);
855                        else
856                                results[0] = 0;
857                        results[2] = convert_value(sdrd[i].reading, i);
858                        if(sdrd[i].lim2 >= 0) {
859                                results[1] = convert_value(sdrd[i].limits[sdrd[i].lim2], i);
860                                if(sdrd[i].lim2 == 6) /* pos. threshold */
861                                        results[1] = results[2] - results[1];
862                        } else
863                                results[1] = 0;
864                        *nrels_mag = 3;
865                }
866        } else if (operation == SENSORS_PROC_REAL_WRITE) {
867                if (*nrels_mag >= 1) {
868                }
869        }
870}
871
872void bmcsensors_alarms(struct i2c_client *client, int operation, int ctl_name,
873                    int *nrels_mag, long *results)
874{
875        struct bmcsensors_data *data = client->data;
876#if 0
877        if (operation == SENSORS_PROC_REAL_INFO)
878                *nrels_mag = 0;
879        else if (operation == SENSORS_PROC_REAL_READ) {
880                bmcsensors_update_client(client);
881                results[0] = data->alarms;
882                *nrels_mag = 1;
883        }
884#endif
885}
886
887int __init sensors_bmcsensors_init(void)
888{
889        int res, addr;
890
891        printk(KERN_INFO "bmcsensors.o version %s (%s)\n", LM_VERSION, LM_DATE);
892        bmcsensors_initialized = 0;
893
894        if ((res = i2c_add_driver(&bmcsensors_driver))) {
895                printk(KERN_ERR
896                   "bmcsensors.o: Driver registration failed, module not inserted.\n");
897                bmcsensors_cleanup();
898                return res;
899        }
900        bmcsensors_initialized = 1;
901        return 0;
902}
903
904int __init bmcsensors_cleanup(void)
905{
906        int res;
907
908        if (bmcsensors_initialized >= 1) {
909                if ((res = i2c_del_driver(&bmcsensors_driver))) {
910                        printk(KERN_WARNING
911                            "bmcsensors.o: Driver deregistration failed, module not removed.\n");
912                        return res;
913                }
914                bmcsensors_initialized--;
915        }
916        return 0;
917}
918
919EXPORT_NO_SYMBOLS;
920
921#ifdef MODULE
922
923MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
924MODULE_DESCRIPTION("IPMI BMC sensors");
925#ifdef MODULE_LICENSE
926MODULE_LICENSE("GPL");
927#endif
928
929int init_module(void)
930{
931        return sensors_bmcsensors_init();
932}
933
934int cleanup_module(void)
935{
936        return bmcsensors_cleanup();
937}
938
939#endif                          /* MODULE */
Note: See TracBrowser for help on using the browser.