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

Revision 1626, 27.2 KB (checked in by mds, 11 years ago)

cleanup, handle reservation cancellation,

skip non-threshold sensors

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