Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds
[linux-2.6] / arch / x86 / mach-voyager / voyager_cat.c
1 /* -*- mode: c; c-basic-offset: 8 -*- */
2
3 /* Copyright (C) 1999,2001
4  *
5  * Author: J.E.J.Bottomley@HansenPartnership.com
6  *
7  * linux/arch/i386/kernel/voyager_cat.c
8  *
9  * This file contains all the logic for manipulating the CAT bus
10  * in a level 5 machine.
11  *
12  * The CAT bus is a serial configuration and test bus.  Its primary
13  * uses are to probe the initial configuration of the system and to
14  * diagnose error conditions when a system interrupt occurs.  The low
15  * level interface is fairly primitive, so most of this file consists
16  * of bit shift manipulations to send and receive packets on the
17  * serial bus */
18
19 #include <linux/types.h>
20 #include <linux/completion.h>
21 #include <linux/sched.h>
22 #include <asm/voyager.h>
23 #include <asm/vic.h>
24 #include <linux/ioport.h>
25 #include <linux/init.h>
26 #include <linux/slab.h>
27 #include <linux/delay.h>
28 #include <asm/io.h>
29
30 #ifdef VOYAGER_CAT_DEBUG
31 #define CDEBUG(x)       printk x
32 #else
33 #define CDEBUG(x)
34 #endif
35
36 /* the CAT command port */
37 #define CAT_CMD         (sspb + 0xe)
38 /* the CAT data port */
39 #define CAT_DATA        (sspb + 0xd)
40
41 /* the internal cat functions */
42 static void cat_pack(__u8 *msg, __u16 start_bit, __u8 *data, 
43                      __u16 num_bits);
44 static void cat_unpack(__u8 *msg, __u16 start_bit, __u8 *data,
45                        __u16 num_bits);
46 static void cat_build_header(__u8 *header, const __u16 len, 
47                              const __u16 smallest_reg_bits,
48                              const __u16 longest_reg_bits);
49 static int cat_sendinst(voyager_module_t *modp, voyager_asic_t *asicp,
50                         __u8 reg, __u8 op);
51 static int cat_getdata(voyager_module_t *modp, voyager_asic_t *asicp,
52                        __u8 reg, __u8 *value);
53 static int cat_shiftout(__u8 *data, __u16 data_bytes, __u16 header_bytes,
54                         __u8 pad_bits);
55 static int cat_write(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg,
56                      __u8 value);
57 static int cat_read(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg,
58                     __u8 *value);
59 static int cat_subread(voyager_module_t *modp, voyager_asic_t *asicp,
60                        __u16 offset, __u16 len, void *buf);
61 static int cat_senddata(voyager_module_t *modp, voyager_asic_t *asicp,
62                         __u8 reg, __u8 value);
63 static int cat_disconnect(voyager_module_t *modp, voyager_asic_t *asicp);
64 static int cat_connect(voyager_module_t *modp, voyager_asic_t *asicp);
65
66 static inline const char *
67 cat_module_name(int module_id)
68 {
69         switch(module_id) {
70         case 0x10:
71                 return "Processor Slot 0";
72         case 0x11:
73                 return "Processor Slot 1";
74         case 0x12:
75                 return "Processor Slot 2";
76         case 0x13:
77                 return "Processor Slot 4";
78         case 0x14:
79                 return "Memory Slot 0";
80         case 0x15:
81                 return "Memory Slot 1";
82         case 0x18:
83                 return "Primary Microchannel";
84         case 0x19:
85                 return "Secondary Microchannel";
86         case 0x1a:
87                 return "Power Supply Interface";
88         case 0x1c:
89                 return "Processor Slot 5";
90         case 0x1d:
91                 return "Processor Slot 6";
92         case 0x1e:
93                 return "Processor Slot 7";
94         case 0x1f:
95                 return "Processor Slot 8";
96         default:
97                 return "Unknown Module";
98         }
99 }
100
101 static int sspb = 0;            /* stores the super port location */
102 int voyager_8slot = 0;          /* set to true if a 51xx monster */
103
104 voyager_module_t *voyager_cat_list;
105
106 /* the I/O port assignments for the VIC and QIC */
107 static struct resource vic_res = {
108         .name   = "Voyager Interrupt Controller",
109         .start  = 0xFC00,
110         .end    = 0xFC6F
111 };
112 static struct resource qic_res = {
113         .name   = "Quad Interrupt Controller",
114         .start  = 0xFC70,
115         .end    = 0xFCFF
116 };
117
118 /* This function is used to pack a data bit stream inside a message.
119  * It writes num_bits of the data buffer in msg starting at start_bit.
120  * Note: This function assumes that any unused bit in the data stream
121  * is set to zero so that the ors will work correctly */
122 static void
123 cat_pack(__u8 *msg, const __u16 start_bit, __u8 *data, const __u16 num_bits)
124 {
125         /* compute initial shift needed */
126         const __u16 offset = start_bit % BITS_PER_BYTE;
127         __u16 len = num_bits / BITS_PER_BYTE;
128         __u16 byte = start_bit / BITS_PER_BYTE;
129         __u16 residue = (num_bits % BITS_PER_BYTE) + offset;
130         int i;
131
132         /* adjust if we have more than a byte of residue */
133         if(residue >= BITS_PER_BYTE) {
134                 residue -= BITS_PER_BYTE;
135                 len++;
136         }
137
138         /* clear out the bits.  We assume here that if len==0 then
139          * residue >= offset.  This is always true for the catbus
140          * operations */
141         msg[byte] &= 0xff << (BITS_PER_BYTE - offset); 
142         msg[byte++] |= data[0] >> offset;
143         if(len == 0)
144                 return;
145         for(i = 1; i < len; i++)
146                 msg[byte++] = (data[i-1] << (BITS_PER_BYTE - offset))
147                         | (data[i] >> offset);
148         if(residue != 0) {
149                 __u8 mask = 0xff >> residue;
150                 __u8 last_byte = data[i-1] << (BITS_PER_BYTE - offset)
151                         | (data[i] >> offset);
152                 
153                 last_byte &= ~mask;
154                 msg[byte] &= mask;
155                 msg[byte] |= last_byte;
156         }
157         return;
158 }
159 /* unpack the data again (same arguments as cat_pack()). data buffer
160  * must be zero populated.
161  *
162  * Function: given a message string move to start_bit and copy num_bits into
163  * data (starting at bit 0 in data).
164  */
165 static void
166 cat_unpack(__u8 *msg, const __u16 start_bit, __u8 *data, const __u16 num_bits)
167 {
168         /* compute initial shift needed */
169         const __u16 offset = start_bit % BITS_PER_BYTE;
170         __u16 len = num_bits / BITS_PER_BYTE;
171         const __u8 last_bits = num_bits % BITS_PER_BYTE;
172         __u16 byte = start_bit / BITS_PER_BYTE;
173         int i;
174
175         if(last_bits != 0)
176                 len++;
177
178         /* special case: want < 8 bits from msg and we can get it from
179          * a single byte of the msg */
180         if(len == 0 && BITS_PER_BYTE - offset >= num_bits) {
181                 data[0] = msg[byte] << offset;
182                 data[0] &= 0xff >> (BITS_PER_BYTE - num_bits);
183                 return;
184         }
185         for(i = 0; i < len; i++) {
186                 /* this annoying if has to be done just in case a read of
187                  * msg one beyond the array causes a panic */
188                 if(offset != 0) {
189                         data[i] = msg[byte++] << offset;
190                         data[i] |= msg[byte] >> (BITS_PER_BYTE - offset);
191                 }
192                 else {
193                         data[i] = msg[byte++];
194                 }
195         }
196         /* do we need to truncate the final byte */
197         if(last_bits != 0) {
198                 data[i-1] &= 0xff << (BITS_PER_BYTE - last_bits);
199         }
200         return;
201 }
202
203 static void
204 cat_build_header(__u8 *header, const __u16 len, const __u16 smallest_reg_bits,
205                  const __u16 longest_reg_bits)
206 {
207         int i;
208         __u16 start_bit = (smallest_reg_bits - 1) % BITS_PER_BYTE;
209         __u8 *last_byte = &header[len - 1];
210
211         if(start_bit == 0)
212                 start_bit = 1;  /* must have at least one bit in the hdr */
213         
214         for(i=0; i < len; i++)
215                 header[i] = 0;
216
217         for(i = start_bit; i > 0; i--)
218                 *last_byte = ((*last_byte) << 1) + 1;
219
220 }
221
222 static int
223 cat_sendinst(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg, __u8 op)
224 {
225         __u8 parity, inst, inst_buf[4] = { 0 };
226         __u8 iseq[VOYAGER_MAX_SCAN_PATH], hseq[VOYAGER_MAX_REG_SIZE];
227         __u16 ibytes, hbytes, padbits;
228         int i;
229         
230         /* 
231          * Parity is the parity of the register number + 1 (READ_REGISTER
232          * and WRITE_REGISTER always add '1' to the number of bits == 1)
233          */
234         parity = (__u8)(1 + (reg & 0x01) +
235                  ((__u8)(reg & 0x02) >> 1) +
236                  ((__u8)(reg & 0x04) >> 2) +
237                  ((__u8)(reg & 0x08) >> 3)) % 2;
238
239         inst = ((parity << 7) | (reg << 2) | op);
240
241         outb(VOYAGER_CAT_IRCYC, CAT_CMD);
242         if(!modp->scan_path_connected) {
243                 if(asicp->asic_id != VOYAGER_CAT_ID) {
244                         printk("**WARNING***: cat_sendinst has disconnected scan path not to CAT asic\n");
245                         return 1;
246                 }
247                 outb(VOYAGER_CAT_HEADER, CAT_DATA);
248                 outb(inst, CAT_DATA);
249                 if(inb(CAT_DATA) != VOYAGER_CAT_HEADER) {
250                         CDEBUG(("VOYAGER CAT: cat_sendinst failed to get CAT_HEADER\n"));
251                         return 1;
252                 }
253                 return 0;
254         }
255         ibytes = modp->inst_bits / BITS_PER_BYTE;
256         if((padbits = modp->inst_bits % BITS_PER_BYTE) != 0) {
257                 padbits = BITS_PER_BYTE - padbits;
258                 ibytes++;
259         }
260         hbytes = modp->largest_reg / BITS_PER_BYTE;
261         if(modp->largest_reg % BITS_PER_BYTE)
262                 hbytes++;
263         CDEBUG(("cat_sendinst: ibytes=%d, hbytes=%d\n", ibytes, hbytes));
264         /* initialise the instruction sequence to 0xff */
265         for(i=0; i < ibytes + hbytes; i++)
266                 iseq[i] = 0xff;
267         cat_build_header(hseq, hbytes, modp->smallest_reg, modp->largest_reg);
268         cat_pack(iseq, modp->inst_bits, hseq, hbytes * BITS_PER_BYTE);
269         inst_buf[0] = inst;
270         inst_buf[1] = 0xFF >> (modp->largest_reg % BITS_PER_BYTE);
271         cat_pack(iseq, asicp->bit_location, inst_buf, asicp->ireg_length);
272 #ifdef VOYAGER_CAT_DEBUG
273         printk("ins = 0x%x, iseq: ", inst);
274         for(i=0; i< ibytes + hbytes; i++)
275                 printk("0x%x ", iseq[i]);
276         printk("\n");
277 #endif
278         if(cat_shiftout(iseq, ibytes, hbytes, padbits)) {
279                 CDEBUG(("VOYAGER CAT: cat_sendinst: cat_shiftout failed\n"));
280                 return 1;
281         }
282         CDEBUG(("CAT SHIFTOUT DONE\n"));
283         return 0;
284 }
285
286 static int
287 cat_getdata(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg, 
288             __u8 *value)
289 {
290         if(!modp->scan_path_connected) {
291                 if(asicp->asic_id != VOYAGER_CAT_ID) {
292                         CDEBUG(("VOYAGER CAT: ERROR: cat_getdata to CAT asic with scan path connected\n"));
293                         return 1;
294                 }
295                 if(reg > VOYAGER_SUBADDRHI) 
296                         outb(VOYAGER_CAT_RUN, CAT_CMD);
297                 outb(VOYAGER_CAT_DRCYC, CAT_CMD);
298                 outb(VOYAGER_CAT_HEADER, CAT_DATA);
299                 *value = inb(CAT_DATA);
300                 outb(0xAA, CAT_DATA);
301                 if(inb(CAT_DATA) != VOYAGER_CAT_HEADER) {
302                         CDEBUG(("cat_getdata: failed to get VOYAGER_CAT_HEADER\n"));
303                         return 1;
304                 }
305                 return 0;
306         }
307         else {
308                 __u16 sbits = modp->num_asics -1 + asicp->ireg_length;
309                 __u16 sbytes = sbits / BITS_PER_BYTE;
310                 __u16 tbytes;
311                 __u8 string[VOYAGER_MAX_SCAN_PATH], trailer[VOYAGER_MAX_REG_SIZE];
312                 __u8 padbits;
313                 int i;
314                 
315                 outb(VOYAGER_CAT_DRCYC, CAT_CMD);
316
317                 if((padbits = sbits % BITS_PER_BYTE) != 0) {
318                         padbits = BITS_PER_BYTE - padbits;
319                         sbytes++;
320                 }
321                 tbytes = asicp->ireg_length / BITS_PER_BYTE;
322                 if(asicp->ireg_length % BITS_PER_BYTE)
323                         tbytes++;
324                 CDEBUG(("cat_getdata: tbytes = %d, sbytes = %d, padbits = %d\n",
325                         tbytes, sbytes, padbits));
326                 cat_build_header(trailer, tbytes, 1, asicp->ireg_length);
327
328                 
329                 for(i = tbytes - 1; i >= 0; i--) {
330                         outb(trailer[i], CAT_DATA);
331                         string[sbytes + i] = inb(CAT_DATA);
332                 }
333
334                 for(i = sbytes - 1; i >= 0; i--) {
335                         outb(0xaa, CAT_DATA);
336                         string[i] = inb(CAT_DATA);
337                 }
338                 *value = 0;
339                 cat_unpack(string, padbits + (tbytes * BITS_PER_BYTE) + asicp->asic_location, value, asicp->ireg_length);
340 #ifdef VOYAGER_CAT_DEBUG
341                 printk("value=0x%x, string: ", *value);
342                 for(i=0; i< tbytes+sbytes; i++)
343                         printk("0x%x ", string[i]);
344                 printk("\n");
345 #endif
346                 
347                 /* sanity check the rest of the return */
348                 for(i=0; i < tbytes; i++) {
349                         __u8 input = 0;
350
351                         cat_unpack(string, padbits + (i * BITS_PER_BYTE), &input, BITS_PER_BYTE);
352                         if(trailer[i] != input) {
353                                 CDEBUG(("cat_getdata: failed to sanity check rest of ret(%d) 0x%x != 0x%x\n", i, input, trailer[i]));
354                                 return 1;
355                         }
356                 }
357                 CDEBUG(("cat_getdata DONE\n"));
358                 return 0;
359         }
360 }
361
362 static int
363 cat_shiftout(__u8 *data, __u16 data_bytes, __u16 header_bytes, __u8 pad_bits)
364 {
365         int i;
366         
367         for(i = data_bytes + header_bytes - 1; i >= header_bytes; i--)
368                 outb(data[i], CAT_DATA);
369
370         for(i = header_bytes - 1; i >= 0; i--) {
371                 __u8 header = 0;
372                 __u8 input;
373
374                 outb(data[i], CAT_DATA);
375                 input = inb(CAT_DATA);
376                 CDEBUG(("cat_shiftout: returned 0x%x\n", input));
377                 cat_unpack(data, ((data_bytes + i) * BITS_PER_BYTE) - pad_bits,
378                            &header, BITS_PER_BYTE);
379                 if(input != header) {
380                         CDEBUG(("VOYAGER CAT: cat_shiftout failed to return header 0x%x != 0x%x\n", input, header));
381                         return 1;
382                 }
383         }
384         return 0;
385 }
386
387 static int
388 cat_senddata(voyager_module_t *modp, voyager_asic_t *asicp, 
389              __u8 reg, __u8 value)
390 {
391         outb(VOYAGER_CAT_DRCYC, CAT_CMD);
392         if(!modp->scan_path_connected) {
393                 if(asicp->asic_id != VOYAGER_CAT_ID) {
394                         CDEBUG(("VOYAGER CAT: ERROR: scan path disconnected when asic != CAT\n"));
395                         return 1;
396                 }
397                 outb(VOYAGER_CAT_HEADER, CAT_DATA);
398                 outb(value, CAT_DATA);
399                 if(inb(CAT_DATA) != VOYAGER_CAT_HEADER) {
400                         CDEBUG(("cat_senddata: failed to get correct header response to sent data\n"));
401                         return 1;
402                 }
403                 if(reg > VOYAGER_SUBADDRHI) {
404                         outb(VOYAGER_CAT_RUN, CAT_CMD);
405                         outb(VOYAGER_CAT_END, CAT_CMD);
406                         outb(VOYAGER_CAT_RUN, CAT_CMD);
407                 }
408                 
409                 return 0;
410         }
411         else {
412                 __u16 hbytes = asicp->ireg_length / BITS_PER_BYTE;
413                 __u16 dbytes = (modp->num_asics - 1 + asicp->ireg_length)/BITS_PER_BYTE;
414                 __u8 padbits, dseq[VOYAGER_MAX_SCAN_PATH], 
415                         hseq[VOYAGER_MAX_REG_SIZE];
416                 int i;
417
418                 if((padbits = (modp->num_asics - 1 
419                                + asicp->ireg_length) % BITS_PER_BYTE) != 0) {
420                         padbits = BITS_PER_BYTE - padbits;
421                         dbytes++;
422                 }
423                 if(asicp->ireg_length % BITS_PER_BYTE)
424                         hbytes++;
425                 
426                 cat_build_header(hseq, hbytes, 1, asicp->ireg_length);
427                 
428                 for(i = 0; i < dbytes + hbytes; i++)
429                         dseq[i] = 0xff;
430                 CDEBUG(("cat_senddata: dbytes=%d, hbytes=%d, padbits=%d\n",
431                         dbytes, hbytes, padbits));
432                 cat_pack(dseq, modp->num_asics - 1 + asicp->ireg_length,
433                          hseq, hbytes * BITS_PER_BYTE);
434                 cat_pack(dseq, asicp->asic_location, &value, 
435                          asicp->ireg_length);
436 #ifdef VOYAGER_CAT_DEBUG
437                 printk("dseq ");
438                 for(i=0; i<hbytes+dbytes; i++) {
439                         printk("0x%x ", dseq[i]);
440                 }
441                 printk("\n");
442 #endif
443                 return cat_shiftout(dseq, dbytes, hbytes, padbits);
444         }
445 }
446
447 static int
448 cat_write(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg,
449          __u8 value)
450 {
451         if(cat_sendinst(modp, asicp, reg, VOYAGER_WRITE_CONFIG))
452                 return 1;
453         return cat_senddata(modp, asicp, reg, value);
454 }
455
456 static int
457 cat_read(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg,
458          __u8 *value)
459 {
460         if(cat_sendinst(modp, asicp, reg, VOYAGER_READ_CONFIG))
461                 return 1;
462         return cat_getdata(modp, asicp, reg, value);
463 }
464
465 static int
466 cat_subaddrsetup(voyager_module_t *modp, voyager_asic_t *asicp, __u16 offset,
467                  __u16 len)
468 {
469         __u8 val;
470
471         if(len > 1) {
472                 /* set auto increment */
473                 __u8 newval;
474                 
475                 if(cat_read(modp, asicp, VOYAGER_AUTO_INC_REG, &val)) {
476                         CDEBUG(("cat_subaddrsetup: read of VOYAGER_AUTO_INC_REG failed\n"));
477                         return 1;
478                 }
479                 CDEBUG(("cat_subaddrsetup: VOYAGER_AUTO_INC_REG = 0x%x\n", val));
480                 newval = val | VOYAGER_AUTO_INC;
481                 if(newval != val) {
482                         if(cat_write(modp, asicp, VOYAGER_AUTO_INC_REG, val)) {
483                                 CDEBUG(("cat_subaddrsetup: write to VOYAGER_AUTO_INC_REG failed\n"));
484                                 return 1;
485                         }
486                 }
487         }
488         if(cat_write(modp, asicp, VOYAGER_SUBADDRLO, (__u8)(offset &0xff))) {
489                 CDEBUG(("cat_subaddrsetup: write to SUBADDRLO failed\n"));
490                 return 1;
491         }
492         if(asicp->subaddr > VOYAGER_SUBADDR_LO) {
493                 if(cat_write(modp, asicp, VOYAGER_SUBADDRHI, (__u8)(offset >> 8))) {
494                         CDEBUG(("cat_subaddrsetup: write to SUBADDRHI failed\n"));
495                         return 1;
496                 }
497                 cat_read(modp, asicp, VOYAGER_SUBADDRHI, &val);
498                 CDEBUG(("cat_subaddrsetup: offset = %d, hi = %d\n", offset, val));
499         }
500         cat_read(modp, asicp, VOYAGER_SUBADDRLO, &val);
501         CDEBUG(("cat_subaddrsetup: offset = %d, lo = %d\n", offset, val));
502         return 0;
503 }
504                 
505 static int
506 cat_subwrite(voyager_module_t *modp, voyager_asic_t *asicp, __u16 offset,
507             __u16 len, void *buf)
508 {
509         int i, retval;
510
511         /* FIXME: need special actions for VOYAGER_CAT_ID here */
512         if(asicp->asic_id == VOYAGER_CAT_ID) {
513                 CDEBUG(("cat_subwrite: ATTEMPT TO WRITE TO CAT ASIC\n"));
514                 /* FIXME -- This is supposed to be handled better
515                  * There is a problem writing to the cat asic in the
516                  * PSI.  The 30us delay seems to work, though */
517                 udelay(30);
518         }
519                 
520         if((retval = cat_subaddrsetup(modp, asicp, offset, len)) != 0) {
521                 printk("cat_subwrite: cat_subaddrsetup FAILED\n");
522                 return retval;
523         }
524         
525         if(cat_sendinst(modp, asicp, VOYAGER_SUBADDRDATA, VOYAGER_WRITE_CONFIG)) {
526                 printk("cat_subwrite: cat_sendinst FAILED\n");
527                 return 1;
528         }
529         for(i = 0; i < len; i++) {
530                 if(cat_senddata(modp, asicp, 0xFF, ((__u8 *)buf)[i])) {
531                         printk("cat_subwrite: cat_sendata element at %d FAILED\n", i);
532                         return 1;
533                 }
534         }
535         return 0;
536 }
537 static int
538 cat_subread(voyager_module_t *modp, voyager_asic_t *asicp, __u16 offset,
539             __u16 len, void *buf)
540 {
541         int i, retval;
542
543         if((retval = cat_subaddrsetup(modp, asicp, offset, len)) != 0) {
544                 CDEBUG(("cat_subread: cat_subaddrsetup FAILED\n"));
545                 return retval;
546         }
547
548         if(cat_sendinst(modp, asicp, VOYAGER_SUBADDRDATA, VOYAGER_READ_CONFIG)) {
549                 CDEBUG(("cat_subread: cat_sendinst failed\n"));
550                 return 1;
551         }
552         for(i = 0; i < len; i++) {
553                 if(cat_getdata(modp, asicp, 0xFF,
554                                &((__u8 *)buf)[i])) {
555                         CDEBUG(("cat_subread: cat_getdata element %d failed\n", i));
556                         return 1;
557                 }
558         }
559         return 0;
560 }
561
562
563 /* buffer for storing EPROM data read in during initialisation */
564 static __initdata __u8 eprom_buf[0xFFFF];
565 static voyager_module_t *voyager_initial_module;
566
567 /* Initialise the cat bus components.  We assume this is called by the
568  * boot cpu *after* all memory initialisation has been done (so we can
569  * use kmalloc) but before smp initialisation, so we can probe the SMP
570  * configuration and pick up necessary information.  */
571 void
572 voyager_cat_init(void)
573 {
574         voyager_module_t **modpp = &voyager_initial_module;
575         voyager_asic_t **asicpp;
576         voyager_asic_t *qabc_asic = NULL;
577         int i, j;
578         unsigned long qic_addr = 0;
579         __u8 qabc_data[0x20];
580         __u8 num_submodules, val;
581         voyager_eprom_hdr_t *eprom_hdr = (voyager_eprom_hdr_t *)&eprom_buf[0];
582         
583         __u8 cmos[4];
584         unsigned long addr;
585         
586         /* initiallise the SUS mailbox */
587         for(i=0; i<sizeof(cmos); i++)
588                 cmos[i] = voyager_extended_cmos_read(VOYAGER_DUMP_LOCATION + i);
589         addr = *(unsigned long *)cmos;
590         if((addr & 0xff000000) != 0xff000000) {
591                 printk(KERN_ERR "Voyager failed to get SUS mailbox (addr = 0x%lx\n", addr);
592         } else {
593                 static struct resource res;
594                 
595                 res.name = "voyager SUS";
596                 res.start = addr;
597                 res.end = addr+0x3ff;
598                 
599                 request_resource(&iomem_resource, &res);
600                 voyager_SUS = (struct voyager_SUS *)
601                         ioremap(addr, 0x400);
602                 printk(KERN_NOTICE "Voyager SUS mailbox version 0x%x\n",
603                        voyager_SUS->SUS_version);
604                 voyager_SUS->kernel_version = VOYAGER_MAILBOX_VERSION;
605                 voyager_SUS->kernel_flags = VOYAGER_OS_HAS_SYSINT;
606         }
607
608         /* clear the processor counts */
609         voyager_extended_vic_processors = 0;
610         voyager_quad_processors = 0;
611
612
613
614         printk("VOYAGER: beginning CAT bus probe\n");
615         /* set up the SuperSet Port Block which tells us where the
616          * CAT communication port is */
617         sspb = inb(VOYAGER_SSPB_RELOCATION_PORT) * 0x100;
618         VDEBUG(("VOYAGER DEBUG: sspb = 0x%x\n", sspb));
619
620         /* now find out if were 8 slot or normal */
621         if((inb(VIC_PROC_WHO_AM_I) & EIGHT_SLOT_IDENTIFIER)
622            == EIGHT_SLOT_IDENTIFIER) {
623                 voyager_8slot = 1;
624                 printk(KERN_NOTICE "Voyager: Eight slot 51xx configuration detected\n");
625         }
626
627         for(i = VOYAGER_MIN_MODULE;
628             i <= VOYAGER_MAX_MODULE; i++) {
629                 __u8 input;
630                 int asic;
631                 __u16 eprom_size;
632                 __u16 sp_offset;
633
634                 outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
635                 outb(i, VOYAGER_CAT_CONFIG_PORT);
636
637                 /* check the presence of the module */
638                 outb(VOYAGER_CAT_RUN, CAT_CMD);
639                 outb(VOYAGER_CAT_IRCYC, CAT_CMD);
640                 outb(VOYAGER_CAT_HEADER, CAT_DATA);
641                 /* stream series of alternating 1's and 0's to stimulate
642                  * response */
643                 outb(0xAA, CAT_DATA);
644                 input = inb(CAT_DATA);
645                 outb(VOYAGER_CAT_END, CAT_CMD);
646                 if(input != VOYAGER_CAT_HEADER) {
647                         continue;
648                 }
649                 CDEBUG(("VOYAGER DEBUG: found module id 0x%x, %s\n", i,
650                         cat_module_name(i)));
651                 *modpp = kmalloc(sizeof(voyager_module_t), GFP_KERNEL); /*&voyager_module_storage[cat_count++];*/
652                 if(*modpp == NULL) {
653                         printk("**WARNING** kmalloc failure in cat_init\n");
654                         continue;
655                 }
656                 memset(*modpp, 0, sizeof(voyager_module_t));
657                 /* need temporary asic for cat_subread.  It will be
658                  * filled in correctly later */
659                 (*modpp)->asic = kmalloc(sizeof(voyager_asic_t), GFP_KERNEL); /*&voyager_asic_storage[asic_count];*/
660                 if((*modpp)->asic == NULL) {
661                         printk("**WARNING** kmalloc failure in cat_init\n");
662                         continue;
663                 }
664                 memset((*modpp)->asic, 0, sizeof(voyager_asic_t));
665                 (*modpp)->asic->asic_id = VOYAGER_CAT_ID;
666                 (*modpp)->asic->subaddr = VOYAGER_SUBADDR_HI;
667                 (*modpp)->module_addr = i;
668                 (*modpp)->scan_path_connected = 0;
669                 if(i == VOYAGER_PSI) {
670                         /* Exception leg for modules with no EEPROM */
671                         printk("Module \"%s\"\n", cat_module_name(i));
672                         continue;
673                 }
674                                
675                 CDEBUG(("cat_init: Reading eeprom for module 0x%x at offset %d\n", i, VOYAGER_XSUM_END_OFFSET));
676                 outb(VOYAGER_CAT_RUN, CAT_CMD);
677                 cat_disconnect(*modpp, (*modpp)->asic);
678                 if(cat_subread(*modpp, (*modpp)->asic,
679                                VOYAGER_XSUM_END_OFFSET, sizeof(eprom_size),
680                                &eprom_size)) {
681                         printk("**WARNING**: Voyager couldn't read EPROM size for module 0x%x\n", i);
682                         outb(VOYAGER_CAT_END, CAT_CMD);
683                         continue;
684                 }
685                 if(eprom_size > sizeof(eprom_buf)) {
686                         printk("**WARNING**: Voyager insufficient size to read EPROM data, module 0x%x.  Need %d\n", i, eprom_size);
687                         outb(VOYAGER_CAT_END, CAT_CMD);
688                         continue;
689                 }
690                 outb(VOYAGER_CAT_END, CAT_CMD);
691                 outb(VOYAGER_CAT_RUN, CAT_CMD);
692                 CDEBUG(("cat_init: module 0x%x, eeprom_size %d\n", i, eprom_size));
693                 if(cat_subread(*modpp, (*modpp)->asic, 0, 
694                                eprom_size, eprom_buf)) {
695                         outb(VOYAGER_CAT_END, CAT_CMD);
696                         continue;
697                 }
698                 outb(VOYAGER_CAT_END, CAT_CMD);
699                 printk("Module \"%s\", version 0x%x, tracer 0x%x, asics %d\n",
700                        cat_module_name(i), eprom_hdr->version_id,
701                        *((__u32 *)eprom_hdr->tracer),  eprom_hdr->num_asics);
702                 (*modpp)->ee_size = eprom_hdr->ee_size;
703                 (*modpp)->num_asics = eprom_hdr->num_asics;
704                 asicpp = &((*modpp)->asic);
705                 sp_offset = eprom_hdr->scan_path_offset;
706                 /* All we really care about are the Quad cards.  We
707                  * identify them because they are in a processor slot
708                  * and have only four asics */
709                 if((i < 0x10 || (i>=0x14 && i < 0x1c) || i>0x1f)) {
710                         modpp = &((*modpp)->next);
711                         continue;
712                 }
713                 /* Now we know it's in a processor slot, does it have
714                  * a quad baseboard submodule */
715                 outb(VOYAGER_CAT_RUN, CAT_CMD);
716                 cat_read(*modpp, (*modpp)->asic, VOYAGER_SUBMODPRESENT,
717                          &num_submodules);
718                 /* lowest two bits, active low */
719                 num_submodules = ~(0xfc | num_submodules);
720                 CDEBUG(("VOYAGER CAT: %d submodules present\n", num_submodules));
721                 if(num_submodules == 0) {
722                         /* fill in the dyadic extended processors */
723                         __u8 cpu = i & 0x07;
724
725                         printk("Module \"%s\": Dyadic Processor Card\n",
726                                cat_module_name(i));
727                         voyager_extended_vic_processors |= (1<<cpu);
728                         cpu += 4;
729                         voyager_extended_vic_processors |= (1<<cpu);
730                         outb(VOYAGER_CAT_END, CAT_CMD);
731                         continue;
732                 }
733
734                 /* now we want to read the asics on the first submodule,
735                  * which should be the quad base board */
736
737                 cat_read(*modpp, (*modpp)->asic, VOYAGER_SUBMODSELECT, &val);
738                 CDEBUG(("cat_init: SUBMODSELECT value = 0x%x\n", val));
739                 val = (val & 0x7c) | VOYAGER_QUAD_BASEBOARD;
740                 cat_write(*modpp, (*modpp)->asic, VOYAGER_SUBMODSELECT, val);
741
742                 outb(VOYAGER_CAT_END, CAT_CMD);
743                          
744
745                 CDEBUG(("cat_init: Reading eeprom for module 0x%x at offset %d\n", i, VOYAGER_XSUM_END_OFFSET));
746                 outb(VOYAGER_CAT_RUN, CAT_CMD);
747                 cat_disconnect(*modpp, (*modpp)->asic);
748                 if(cat_subread(*modpp, (*modpp)->asic,
749                                VOYAGER_XSUM_END_OFFSET, sizeof(eprom_size),
750                                &eprom_size)) {
751                         printk("**WARNING**: Voyager couldn't read EPROM size for module 0x%x\n", i);
752                         outb(VOYAGER_CAT_END, CAT_CMD);
753                         continue;
754                 }
755                 if(eprom_size > sizeof(eprom_buf)) {
756                         printk("**WARNING**: Voyager insufficient size to read EPROM data, module 0x%x.  Need %d\n", i, eprom_size);
757                         outb(VOYAGER_CAT_END, CAT_CMD);
758                         continue;
759                 }
760                 outb(VOYAGER_CAT_END, CAT_CMD);
761                 outb(VOYAGER_CAT_RUN, CAT_CMD);
762                 CDEBUG(("cat_init: module 0x%x, eeprom_size %d\n", i, eprom_size));
763                 if(cat_subread(*modpp, (*modpp)->asic, 0, 
764                                eprom_size, eprom_buf)) {
765                         outb(VOYAGER_CAT_END, CAT_CMD);
766                         continue;
767                 }
768                 outb(VOYAGER_CAT_END, CAT_CMD);
769                 /* Now do everything for the QBB submodule 1 */
770                 (*modpp)->ee_size = eprom_hdr->ee_size;
771                 (*modpp)->num_asics = eprom_hdr->num_asics;
772                 asicpp = &((*modpp)->asic);
773                 sp_offset = eprom_hdr->scan_path_offset;
774                 /* get rid of the dummy CAT asic and read the real one */
775                 kfree((*modpp)->asic);
776                 for(asic=0; asic < (*modpp)->num_asics; asic++) {
777                         int j;
778                         voyager_asic_t *asicp = *asicpp 
779                                 = kzalloc(sizeof(voyager_asic_t), GFP_KERNEL); /*&voyager_asic_storage[asic_count++];*/
780                         voyager_sp_table_t *sp_table;
781                         voyager_at_t *asic_table;
782                         voyager_jtt_t *jtag_table;
783
784                         if(asicp == NULL) {
785                                 printk("**WARNING** kmalloc failure in cat_init\n");
786                                 continue;
787                         }
788                         asicpp = &(asicp->next);
789                         asicp->asic_location = asic;
790                         sp_table = (voyager_sp_table_t *)(eprom_buf + sp_offset);
791                         asicp->asic_id = sp_table->asic_id;
792                         asic_table = (voyager_at_t *)(eprom_buf + sp_table->asic_data_offset);
793                         for(j=0; j<4; j++)
794                                 asicp->jtag_id[j] = asic_table->jtag_id[j];
795                         jtag_table = (voyager_jtt_t *)(eprom_buf + asic_table->jtag_offset);
796                         asicp->ireg_length = jtag_table->ireg_len;
797                         asicp->bit_location = (*modpp)->inst_bits;
798                         (*modpp)->inst_bits += asicp->ireg_length;
799                         if(asicp->ireg_length > (*modpp)->largest_reg)
800                                 (*modpp)->largest_reg = asicp->ireg_length;
801                         if (asicp->ireg_length < (*modpp)->smallest_reg ||
802                             (*modpp)->smallest_reg == 0)
803                                 (*modpp)->smallest_reg = asicp->ireg_length;
804                         CDEBUG(("asic 0x%x, ireg_length=%d, bit_location=%d\n",
805                                 asicp->asic_id, asicp->ireg_length,
806                                 asicp->bit_location));
807                         if(asicp->asic_id == VOYAGER_QUAD_QABC) {
808                                 CDEBUG(("VOYAGER CAT: QABC ASIC found\n"));
809                                 qabc_asic = asicp;
810                         }
811                         sp_offset += sizeof(voyager_sp_table_t);
812                 }
813                 CDEBUG(("Module inst_bits = %d, largest_reg = %d, smallest_reg=%d\n",
814                         (*modpp)->inst_bits, (*modpp)->largest_reg,
815                         (*modpp)->smallest_reg));
816                 /* OK, now we have the QUAD ASICs set up, use them.
817                  * we need to:
818                  *
819                  * 1. Find the Memory area for the Quad CPIs.
820                  * 2. Find the Extended VIC processor
821                  * 3. Configure a second extended VIC processor (This
822                  *    cannot be done for the 51xx.
823                  * */
824                 outb(VOYAGER_CAT_RUN, CAT_CMD);
825                 cat_connect(*modpp, (*modpp)->asic);
826                 CDEBUG(("CAT CONNECTED!!\n"));
827                 cat_subread(*modpp, qabc_asic, 0, sizeof(qabc_data), qabc_data);
828                 qic_addr = qabc_data[5] << 8;
829                 qic_addr = (qic_addr | qabc_data[6]) << 8;
830                 qic_addr = (qic_addr | qabc_data[7]) << 8;
831                 printk("Module \"%s\": Quad Processor Card; CPI 0x%lx, SET=0x%x\n",
832                        cat_module_name(i), qic_addr, qabc_data[8]);
833 #if 0                           /* plumbing fails---FIXME */
834                 if((qabc_data[8] & 0xf0) == 0) {
835                         /* FIXME: 32 way 8 CPU slot monster cannot be
836                          * plumbed this way---need to check for it */
837
838                         printk("Plumbing second Extended Quad Processor\n");
839                         /* second VIC line hardwired to Quad CPU 1 */
840                         qabc_data[8] |= 0x20;
841                         cat_subwrite(*modpp, qabc_asic, 8, 1, &qabc_data[8]);
842 #ifdef VOYAGER_CAT_DEBUG
843                         /* verify plumbing */
844                         cat_subread(*modpp, qabc_asic, 8, 1, &qabc_data[8]);
845                         if((qabc_data[8] & 0xf0) == 0) {
846                                 CDEBUG(("PLUMBING FAILED: 0x%x\n", qabc_data[8]));
847                         }
848 #endif
849                 }
850 #endif
851
852                 {
853                         struct resource *res = kzalloc(sizeof(struct resource),GFP_KERNEL);
854                         res->name = kmalloc(128, GFP_KERNEL);
855                         sprintf((char *)res->name, "Voyager %s Quad CPI", cat_module_name(i));
856                         res->start = qic_addr;
857                         res->end = qic_addr + 0x3ff;
858                         request_resource(&iomem_resource, res);
859                 }
860
861                 qic_addr = (unsigned long)ioremap(qic_addr, 0x400);
862                                 
863                 for(j = 0; j < 4; j++) {
864                         __u8 cpu;
865
866                         if(voyager_8slot) {
867                                 /* 8 slot has a different mapping,
868                                  * each slot has only one vic line, so
869                                  * 1 cpu in each slot must be < 8 */
870                                 cpu = (i & 0x07) + j*8;
871                         } else {
872                                 cpu = (i & 0x03) + j*4;
873                         }
874                         if( (qabc_data[8] & (1<<j))) {
875                                 voyager_extended_vic_processors |= (1<<cpu);
876                         }
877                         if(qabc_data[8] & (1<<(j+4)) ) {
878                                 /* Second SET register plumbed: Quad
879                                  * card has two VIC connected CPUs.
880                                  * Secondary cannot be booted as a VIC
881                                  * CPU */
882                                 voyager_extended_vic_processors |= (1<<cpu);
883                                 voyager_allowed_boot_processors &= (~(1<<cpu));
884                         }
885
886                         voyager_quad_processors |= (1<<cpu);
887                         voyager_quad_cpi_addr[cpu] = (struct voyager_qic_cpi *)
888                                 (qic_addr+(j<<8));
889                         CDEBUG(("CPU%d: CPI address 0x%lx\n", cpu,
890                                 (unsigned long)voyager_quad_cpi_addr[cpu]));
891                 }
892                 outb(VOYAGER_CAT_END, CAT_CMD);
893
894                 
895                 
896                 *asicpp = NULL;
897                 modpp = &((*modpp)->next);
898         }
899         *modpp = NULL;
900         printk("CAT Bus Initialisation finished: extended procs 0x%x, quad procs 0x%x, allowed vic boot = 0x%x\n", voyager_extended_vic_processors, voyager_quad_processors, voyager_allowed_boot_processors);
901         request_resource(&ioport_resource, &vic_res);
902         if(voyager_quad_processors)
903                 request_resource(&ioport_resource, &qic_res);
904         /* set up the front power switch */
905 }
906
907 int
908 voyager_cat_readb(__u8 module, __u8 asic, int reg)
909 {
910         return 0;
911 }
912
913 static int
914 cat_disconnect(voyager_module_t *modp, voyager_asic_t *asicp) 
915 {
916         __u8 val;
917         int err = 0;
918
919         if(!modp->scan_path_connected)
920                 return 0;
921         if(asicp->asic_id != VOYAGER_CAT_ID) {
922                 CDEBUG(("cat_disconnect: ASIC is not CAT\n"));
923                 return 1;
924         }
925         err = cat_read(modp, asicp, VOYAGER_SCANPATH, &val);
926         if(err) {
927                 CDEBUG(("cat_disconnect: failed to read SCANPATH\n"));
928                 return err;
929         }
930         val &= VOYAGER_DISCONNECT_ASIC;
931         err = cat_write(modp, asicp, VOYAGER_SCANPATH, val);
932         if(err) {
933                 CDEBUG(("cat_disconnect: failed to write SCANPATH\n"));
934                 return err;
935         }
936         outb(VOYAGER_CAT_END, CAT_CMD);
937         outb(VOYAGER_CAT_RUN, CAT_CMD);
938         modp->scan_path_connected = 0;
939
940         return 0;
941 }
942
943 static int
944 cat_connect(voyager_module_t *modp, voyager_asic_t *asicp) 
945 {
946         __u8 val;
947         int err = 0;
948
949         if(modp->scan_path_connected)
950                 return 0;
951         if(asicp->asic_id != VOYAGER_CAT_ID) {
952                 CDEBUG(("cat_connect: ASIC is not CAT\n"));
953                 return 1;
954         }
955
956         err = cat_read(modp, asicp, VOYAGER_SCANPATH, &val);
957         if(err) {
958                 CDEBUG(("cat_connect: failed to read SCANPATH\n"));
959                 return err;
960         }
961         val |= VOYAGER_CONNECT_ASIC;
962         err = cat_write(modp, asicp, VOYAGER_SCANPATH, val);
963         if(err) {
964                 CDEBUG(("cat_connect: failed to write SCANPATH\n"));
965                 return err;
966         }
967         outb(VOYAGER_CAT_END, CAT_CMD);
968         outb(VOYAGER_CAT_RUN, CAT_CMD);
969         modp->scan_path_connected = 1;
970
971         return 0;
972 }
973
974 void
975 voyager_cat_power_off(void)
976 {
977         /* Power the machine off by writing to the PSI over the CAT
978          * bus */
979         __u8 data;
980         voyager_module_t psi = { 0 };
981         voyager_asic_t psi_asic = { 0 };
982
983         psi.asic = &psi_asic;
984         psi.asic->asic_id = VOYAGER_CAT_ID;
985         psi.asic->subaddr = VOYAGER_SUBADDR_HI;
986         psi.module_addr = VOYAGER_PSI;
987         psi.scan_path_connected = 0;
988
989         outb(VOYAGER_CAT_END, CAT_CMD);
990         /* Connect the PSI to the CAT Bus */
991         outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
992         outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT);
993         outb(VOYAGER_CAT_RUN, CAT_CMD);
994         cat_disconnect(&psi, &psi_asic);
995         /* Read the status */
996         cat_subread(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data);
997         outb(VOYAGER_CAT_END, CAT_CMD);
998         CDEBUG(("PSI STATUS 0x%x\n", data));
999         /* These two writes are power off prep and perform */
1000         data = PSI_CLEAR;
1001         outb(VOYAGER_CAT_RUN, CAT_CMD);
1002         cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data);
1003         outb(VOYAGER_CAT_END, CAT_CMD);
1004         data = PSI_POWER_DOWN;
1005         outb(VOYAGER_CAT_RUN, CAT_CMD);
1006         cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data);
1007         outb(VOYAGER_CAT_END, CAT_CMD);
1008 }
1009
1010 struct voyager_status voyager_status = { 0 };
1011
1012 void
1013 voyager_cat_psi(__u8 cmd, __u16 reg, __u8 *data)
1014 {
1015         voyager_module_t psi = { 0 };
1016         voyager_asic_t psi_asic = { 0 };
1017
1018         psi.asic = &psi_asic;
1019         psi.asic->asic_id = VOYAGER_CAT_ID;
1020         psi.asic->subaddr = VOYAGER_SUBADDR_HI;
1021         psi.module_addr = VOYAGER_PSI;
1022         psi.scan_path_connected = 0;
1023
1024         outb(VOYAGER_CAT_END, CAT_CMD);
1025         /* Connect the PSI to the CAT Bus */
1026         outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
1027         outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT);
1028         outb(VOYAGER_CAT_RUN, CAT_CMD);
1029         cat_disconnect(&psi, &psi_asic);
1030         switch(cmd) {
1031         case VOYAGER_PSI_READ:
1032                 cat_read(&psi, &psi_asic, reg, data);
1033                 break;
1034         case VOYAGER_PSI_WRITE:
1035                 cat_write(&psi, &psi_asic, reg, *data);
1036                 break;
1037         case VOYAGER_PSI_SUBREAD:
1038                 cat_subread(&psi, &psi_asic, reg, 1, data);
1039                 break;
1040         case VOYAGER_PSI_SUBWRITE:
1041                 cat_subwrite(&psi, &psi_asic, reg, 1, data);
1042                 break;
1043         default:
1044                 printk(KERN_ERR "Voyager PSI, unrecognised command %d\n", cmd);
1045                 break;
1046         }
1047         outb(VOYAGER_CAT_END, CAT_CMD);
1048 }
1049
1050 void
1051 voyager_cat_do_common_interrupt(void)
1052 {
1053         /* This is caused either by a memory parity error or something
1054          * in the PSI */
1055         __u8 data;
1056         voyager_module_t psi = { 0 };
1057         voyager_asic_t psi_asic = { 0 };
1058         struct voyager_psi psi_reg;
1059         int i;
1060  re_read:
1061         psi.asic = &psi_asic;
1062         psi.asic->asic_id = VOYAGER_CAT_ID;
1063         psi.asic->subaddr = VOYAGER_SUBADDR_HI;
1064         psi.module_addr = VOYAGER_PSI;
1065         psi.scan_path_connected = 0;
1066
1067         outb(VOYAGER_CAT_END, CAT_CMD);
1068         /* Connect the PSI to the CAT Bus */
1069         outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
1070         outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT);
1071         outb(VOYAGER_CAT_RUN, CAT_CMD);
1072         cat_disconnect(&psi, &psi_asic);
1073         /* Read the status.  NOTE: Need to read *all* the PSI regs here
1074          * otherwise the cmn int will be reasserted */
1075         for(i = 0; i < sizeof(psi_reg.regs); i++) {
1076                 cat_read(&psi, &psi_asic, i, &((__u8 *)&psi_reg.regs)[i]);
1077         }
1078         outb(VOYAGER_CAT_END, CAT_CMD);
1079         if((psi_reg.regs.checkbit & 0x02) == 0) {
1080                 psi_reg.regs.checkbit |= 0x02;
1081                 cat_write(&psi, &psi_asic, 5, psi_reg.regs.checkbit);
1082                 printk("VOYAGER RE-READ PSI\n");
1083                 goto re_read;
1084         }
1085         outb(VOYAGER_CAT_RUN, CAT_CMD);
1086         for(i = 0; i < sizeof(psi_reg.subregs); i++) {
1087                 /* This looks strange, but the PSI doesn't do auto increment
1088                  * correctly */
1089                 cat_subread(&psi, &psi_asic, VOYAGER_PSI_SUPPLY_REG + i, 
1090                             1, &((__u8 *)&psi_reg.subregs)[i]); 
1091         }
1092         outb(VOYAGER_CAT_END, CAT_CMD);
1093 #ifdef VOYAGER_CAT_DEBUG
1094         printk("VOYAGER PSI: ");
1095         for(i=0; i<sizeof(psi_reg.regs); i++)
1096                 printk("%02x ", ((__u8 *)&psi_reg.regs)[i]);
1097         printk("\n           ");
1098         for(i=0; i<sizeof(psi_reg.subregs); i++)
1099                 printk("%02x ", ((__u8 *)&psi_reg.subregs)[i]);
1100         printk("\n");
1101 #endif
1102         if(psi_reg.regs.intstatus & PSI_MON) {
1103                 /* switch off or power fail */
1104
1105                 if(psi_reg.subregs.supply & PSI_SWITCH_OFF) {
1106                         if(voyager_status.switch_off) {
1107                                 printk(KERN_ERR "Voyager front panel switch turned off again---Immediate power off!\n");
1108                                 voyager_cat_power_off();
1109                                 /* not reached */
1110                         } else {
1111                                 printk(KERN_ERR "Voyager front panel switch turned off\n");
1112                                 voyager_status.switch_off = 1;
1113                                 voyager_status.request_from_kernel = 1;
1114                                 wake_up_process(voyager_thread);
1115                         }
1116                         /* Tell the hardware we're taking care of the
1117                          * shutdown, otherwise it will power the box off
1118                          * within 3 seconds of the switch being pressed and,
1119                          * which is much more important to us, continue to 
1120                          * assert the common interrupt */
1121                         data = PSI_CLR_SWITCH_OFF;
1122                         outb(VOYAGER_CAT_RUN, CAT_CMD);
1123                         cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_SUPPLY_REG,
1124                                      1, &data);
1125                         outb(VOYAGER_CAT_END, CAT_CMD);
1126                 } else {
1127
1128                         VDEBUG(("Voyager ac fail reg 0x%x\n",
1129                                 psi_reg.subregs.ACfail));
1130                         if((psi_reg.subregs.ACfail & AC_FAIL_STAT_CHANGE) == 0) {
1131                                 /* No further update */
1132                                 return;
1133                         }
1134 #if 0
1135                         /* Don't bother trying to find out who failed.
1136                          * FIXME: This probably makes the code incorrect on
1137                          * anything other than a 345x */
1138                         for(i=0; i< 5; i++) {
1139                                 if( psi_reg.subregs.ACfail &(1<<i)) {
1140                                         break;
1141                                 }
1142                         }
1143                         printk(KERN_NOTICE "AC FAIL IN SUPPLY %d\n", i);
1144 #endif
1145                         /* DON'T do this: it shuts down the AC PSI 
1146                         outb(VOYAGER_CAT_RUN, CAT_CMD);
1147                         data = PSI_MASK_MASK | i;
1148                         cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_MASK,
1149                                      1, &data);
1150                         outb(VOYAGER_CAT_END, CAT_CMD);
1151                         */
1152                         printk(KERN_ERR "Voyager AC power failure\n");
1153                         outb(VOYAGER_CAT_RUN, CAT_CMD);
1154                         data = PSI_COLD_START;
1155                         cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG,
1156                                      1, &data);
1157                         outb(VOYAGER_CAT_END, CAT_CMD);
1158                         voyager_status.power_fail = 1;
1159                         voyager_status.request_from_kernel = 1;
1160                         wake_up_process(voyager_thread);
1161                 }
1162                 
1163                 
1164         } else if(psi_reg.regs.intstatus & PSI_FAULT) {
1165                 /* Major fault! */
1166                 printk(KERN_ERR "Voyager PSI Detected major fault, immediate power off!\n");
1167                 voyager_cat_power_off();
1168                 /* not reached */
1169         } else if(psi_reg.regs.intstatus & (PSI_DC_FAIL | PSI_ALARM
1170                                             | PSI_CURRENT | PSI_DVM
1171                                             | PSI_PSCFAULT | PSI_STAT_CHG)) {
1172                 /* other psi fault */
1173
1174                 printk(KERN_WARNING "Voyager PSI status 0x%x\n", data);
1175                 /* clear the PSI fault */
1176                 outb(VOYAGER_CAT_RUN, CAT_CMD);
1177                 cat_write(&psi, &psi_asic, VOYAGER_PSI_STATUS_REG, 0);
1178                 outb(VOYAGER_CAT_END, CAT_CMD);
1179         }
1180 }