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

Revision 3024, 31.7 KB (checked in by khali, 9 years ago)

Strip useless whitespace before new line at end of string.
Backport from a Linux 2.6 patch from Denis Vlasenko.

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