patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / arch / ia64 / sn / io / sn2 / module.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved.
7  */
8
9 #include <linux/types.h>
10 #include <linux/slab.h>
11 #include <linux/init.h>
12 #include <linux/string.h>
13 #include <asm/sn/sgi.h>
14 #include <asm/sn/sn_sal.h>
15 #include <asm/sn/io.h>
16 #include <asm/sn/hcl.h>
17 #include <asm/sn/labelcl.h>
18 #include <asm/sn/xtalk/xbow.h>
19 #include <asm/sn/klconfig.h>
20 #include <asm/sn/module.h>
21 #include <asm/sn/pci/pcibr.h>
22 #include <asm/sn/xtalk/xswitch.h>
23 #include <asm/sn/nodepda.h>
24 #include <asm/sn/sn_cpuid.h>
25
26
27 /* #define LDEBUG       1  */
28
29 #ifdef LDEBUG
30 #define DPRINTF         printk
31 #define printf          printk
32 #else
33 #define DPRINTF(x...)
34 #endif
35
36 module_t               *modules[MODULE_MAX];
37 int                     nummodules;
38
39 #define SN00_SERIAL_FUDGE       0x3b1af409d513c2
40 #define SN0_SERIAL_FUDGE        0x6e
41
42
43 static void __init
44 encode_str_serial(const char *src, char *dest)
45 {
46     int i;
47
48     for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) {
49
50         dest[i] = src[MAX_SERIAL_NUM_SIZE/2 +
51                      ((i%2) ? ((i/2 * -1) - 1) : (i/2))] +
52             SN0_SERIAL_FUDGE;
53     }
54 }
55
56 module_t * __init 
57 module_lookup(moduleid_t id)
58 {
59     int                 i;
60
61     for (i = 0; i < nummodules; i++)
62         if (modules[i]->id == id) {
63             DPRINTF("module_lookup: found m=0x%p\n", modules[i]);
64             return modules[i];
65         }
66
67     return NULL;
68 }
69
70 /*
71  * module_add_node
72  *
73  *   The first time a new module number is seen, a module structure is
74  *   inserted into the module list in order sorted by module number
75  *   and the structure is initialized.
76  *
77  *   The node number is added to the list of nodes in the module.
78  */
79 static module_t * __init
80 module_add_node(geoid_t geoid, cnodeid_t cnodeid)
81 {
82     module_t           *m;
83     int                 i;
84     char                buffer[16];
85     moduleid_t          moduleid;
86     slabid_t            slab_number;
87
88     memset(buffer, 0, 16);
89     moduleid = geo_module(geoid);
90     format_module_id(buffer, moduleid, MODULE_FORMAT_BRIEF);
91     DPRINTF("module_add_node: moduleid=%s node=%d\n", buffer, cnodeid);
92
93     if ((m = module_lookup(moduleid)) == 0) {
94         m = kmalloc(sizeof (module_t), GFP_KERNEL);
95         ASSERT_ALWAYS(m);
96         memset(m, 0 , sizeof(module_t));
97
98         for (slab_number = 0; slab_number <= MAX_SLABS; slab_number++) {
99                 m->nodes[slab_number] = -1;
100         }
101
102         m->id = moduleid;
103         spin_lock_init(&m->lock);
104
105         /* Insert in sorted order by module number */
106
107         for (i = nummodules; i > 0 && modules[i - 1]->id > moduleid; i--)
108             modules[i] = modules[i - 1];
109
110         modules[i] = m;
111         nummodules++;
112     }
113
114     /*
115      * Save this information in the correct slab number of the node in the 
116      * module.
117      */
118     slab_number = geo_slab(geoid);
119     DPRINTF("slab number added 0x%x\n", slab_number);
120
121     if (m->nodes[slab_number] != -1) {
122         printk("module_add_node .. slab previously found\n");
123         return NULL;
124     }
125
126     m->nodes[slab_number] = cnodeid;
127     m->geoid[slab_number] = geoid;
128
129     return m;
130 }
131
132 static int __init
133 module_probe_snum(module_t *m, nasid_t host_nasid, nasid_t nasid)
134 {
135     lboard_t           *board;
136     klmod_serial_num_t *comp;
137     char serial_number[16];
138
139     /*
140      * record brick serial number
141      */
142     board = find_lboard_nasid((lboard_t *) KL_CONFIG_INFO(host_nasid), host_nasid, KLTYPE_SNIA);
143
144     if (! board || KL_CONFIG_DUPLICATE_BOARD(board))
145     {
146         return 0;
147     }
148
149     board_serial_number_get( board, serial_number );
150     if( serial_number[0] != '\0' ) {
151         encode_str_serial( serial_number, m->snum.snum_str );
152         m->snum_valid = 1;
153     }
154
155     board = find_lboard_nasid((lboard_t *) KL_CONFIG_INFO(nasid),
156                         nasid, KLTYPE_IOBRICK_XBOW);
157
158     if (! board || KL_CONFIG_DUPLICATE_BOARD(board))
159         return 0;
160
161     comp = GET_SNUM_COMP(board);
162
163     if (comp) {
164             if (comp->snum.snum_str[0] != '\0') {
165                     memcpy(m->sys_snum, comp->snum.snum_str,
166                            MAX_SERIAL_NUM_SIZE);
167                     m->sys_snum_valid = 1;
168             }
169     }
170
171     if (m->sys_snum_valid)
172         return 1;
173     else {
174         DPRINTF("Invalid serial number for module %d, "
175                 "possible missing or invalid NIC.", m->id);
176         return 0;
177     }
178 }
179
180 void __init
181 io_module_init(void)
182 {
183     cnodeid_t           node;
184     lboard_t           *board;
185     nasid_t             nasid;
186     int                 nserial;
187     module_t           *m;
188     extern              int numionodes;
189
190     DPRINTF("*******module_init\n");
191
192     nserial = 0;
193
194     /*
195      * First pass just scan for compute node boards KLTYPE_SNIA.
196      * We do not support memoryless compute nodes.
197      */
198     for (node = 0; node < numnodes; node++) {
199         nasid = cnodeid_to_nasid(node);
200         board = find_lboard_nasid((lboard_t *) KL_CONFIG_INFO(nasid), nasid, KLTYPE_SNIA);
201         ASSERT(board);
202
203         HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, NULL, NULL, "Found Shub lboard 0x%lx nasid 0x%x cnode 0x%x \n", (unsigned long)board, (int)nasid, (int)node);
204
205         m = module_add_node(board->brd_geoid, node);
206         if (! m->snum_valid && module_probe_snum(m, nasid, nasid))
207             nserial++;
208     }
209
210     /*
211      * Second scan, look for headless/memless board hosted by compute nodes.
212      */
213     for (node = numnodes; node < numionodes; node++) {
214         nasid_t         nasid;
215         char            serial_number[16];
216
217         nasid = cnodeid_to_nasid(node);
218         board = find_lboard_nasid((lboard_t *) KL_CONFIG_INFO(nasid), 
219                                 nasid, KLTYPE_SNIA);
220         ASSERT(board);
221
222         HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, NULL, NULL, "Found headless/memless lboard 0x%lx node %d nasid %d cnode %d\n", (unsigned long)board, node, (int)nasid, (int)node);
223
224         m = module_add_node(board->brd_geoid, node);
225
226         /*
227          * Get and initialize the serial number.
228          */
229         board_serial_number_get( board, serial_number );
230         if( serial_number[0] != '\0' ) {
231                 encode_str_serial( serial_number, m->snum.snum_str );
232                 m->snum_valid = 1;
233                 nserial++;
234         }
235     }
236 }