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