This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / arch / ia64 / sn / kernel / bte_error.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
7  */
8
9 #include <linux/types.h>
10 #include <asm/sn/sn_sal.h>
11 #include "ioerror.h"
12 #include <asm/sn/addrs.h>
13 #include "shubio.h"
14 #include <asm/sn/geo.h>
15 #include "xtalk/xwidgetdev.h"
16 #include "xtalk/hubdev.h"
17 #include <asm/sn/bte.h>
18
19 /*
20  * Bte error handling is done in two parts.  The first captures
21  * any crb related errors.  Since there can be multiple crbs per
22  * interface and multiple interfaces active, we need to wait until
23  * all active crbs are completed.  This is the first job of the
24  * second part error handler.  When all bte related CRBs are cleanly
25  * completed, it resets the interfaces and gets them ready for new
26  * transfers to be queued.
27  */
28
29 void bte_error_handler(unsigned long);
30
31 /*
32  * Wait until all BTE related CRBs are completed
33  * and then reset the interfaces.
34  */
35 void bte_error_handler(unsigned long _nodepda)
36 {
37         struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda;
38         spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock;
39         struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer;
40         nasid_t nasid;
41         int i;
42         int valid_crbs;
43         unsigned long irq_flags;
44         volatile u64 *notify;
45         bte_result_t bh_error;
46         ii_imem_u_t imem;       /* II IMEM Register */
47         ii_icrb0_d_u_t icrbd;   /* II CRB Register D */
48         ii_ibcr_u_t ibcr;
49         ii_icmr_u_t icmr;
50
51         BTE_PRINTK(("bte_error_handler(%p) - %d\n", err_nodepda,
52                     smp_processor_id()));
53
54         spin_lock_irqsave(recovery_lock, irq_flags);
55
56         if ((err_nodepda->bte_if[0].bh_error == BTE_SUCCESS) &&
57             (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) {
58                 BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda,
59                             smp_processor_id()));
60                 spin_unlock_irqrestore(recovery_lock, irq_flags);
61                 return;
62         }
63         /*
64          * Lock all interfaces on this node to prevent new transfers
65          * from being queued.
66          */
67         for (i = 0; i < BTES_PER_NODE; i++) {
68                 if (err_nodepda->bte_if[i].cleanup_active) {
69                         continue;
70                 }
71                 spin_lock(&err_nodepda->bte_if[i].spinlock);
72                 BTE_PRINTK(("eh:%p:%d locked %d\n", err_nodepda,
73                             smp_processor_id(), i));
74                 err_nodepda->bte_if[i].cleanup_active = 1;
75         }
76
77         /* Determine information about our hub */
78         nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode);
79
80         /*
81          * A BTE transfer can use multiple CRBs.  We need to make sure
82          * that all the BTE CRBs are complete (or timed out) before
83          * attempting to clean up the error.  Resetting the BTE while
84          * there are still BTE CRBs active will hang the BTE.
85          * We should look at all the CRBs to see if they are allocated
86          * to the BTE and see if they are still active.  When none
87          * are active, we can continue with the cleanup.
88          *
89          * We also want to make sure that the local NI port is up.
90          * When a router resets the NI port can go down, while it
91          * goes through the LLP handshake, but then comes back up.
92          */
93         icmr.ii_icmr_regval = REMOTE_HUB_L(nasid, IIO_ICMR);
94         if (icmr.ii_icmr_fld_s.i_crb_mark != 0) {
95                 /*
96                  * There are errors which still need to be cleaned up by
97                  * hubiio_crb_error_handler
98                  */
99                 mod_timer(recovery_timer, HZ * 5);
100                 BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda,
101                             smp_processor_id()));
102                 spin_unlock_irqrestore(recovery_lock, irq_flags);
103                 return;
104         }
105         if (icmr.ii_icmr_fld_s.i_crb_vld != 0) {
106
107                 valid_crbs = icmr.ii_icmr_fld_s.i_crb_vld;
108
109                 for (i = 0; i < IIO_NUM_CRBS; i++) {
110                         if (!((1 << i) & valid_crbs)) {
111                                 /* This crb was not marked as valid, ignore */
112                                 continue;
113                         }
114                         icrbd.ii_icrb0_d_regval =
115                             REMOTE_HUB_L(nasid, IIO_ICRB_D(i));
116                         if (icrbd.d_bteop) {
117                                 mod_timer(recovery_timer, HZ * 5);
118                                 BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n",
119                                             err_nodepda, smp_processor_id(),
120                                             i));
121                                 spin_unlock_irqrestore(recovery_lock,
122                                                        irq_flags);
123                                 return;
124                         }
125                 }
126         }
127
128         BTE_PRINTK(("eh:%p:%d Cleaning up\n", err_nodepda, smp_processor_id()));
129         /* Reenable both bte interfaces */
130         imem.ii_imem_regval = REMOTE_HUB_L(nasid, IIO_IMEM);
131         imem.ii_imem_fld_s.i_b0_esd = imem.ii_imem_fld_s.i_b1_esd = 1;
132         REMOTE_HUB_S(nasid, IIO_IMEM, imem.ii_imem_regval);
133
134         /* Reinitialize both BTE state machines. */
135         ibcr.ii_ibcr_regval = REMOTE_HUB_L(nasid, IIO_IBCR);
136         ibcr.ii_ibcr_fld_s.i_soft_reset = 1;
137         REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval);
138
139         for (i = 0; i < BTES_PER_NODE; i++) {
140                 bh_error = err_nodepda->bte_if[i].bh_error;
141                 if (bh_error != BTE_SUCCESS) {
142                         /* There is an error which needs to be notified */
143                         notify = err_nodepda->bte_if[i].most_rcnt_na;
144                         BTE_PRINTK(("cnode %d bte %d error=0x%lx\n",
145                                     err_nodepda->bte_if[i].bte_cnode,
146                                     err_nodepda->bte_if[i].bte_num,
147                                     IBLS_ERROR | (u64) bh_error));
148                         *notify = IBLS_ERROR | bh_error;
149                         err_nodepda->bte_if[i].bh_error = BTE_SUCCESS;
150                 }
151
152                 err_nodepda->bte_if[i].cleanup_active = 0;
153                 BTE_PRINTK(("eh:%p:%d Unlocked %d\n", err_nodepda,
154                             smp_processor_id(), i));
155                 spin_unlock(&pda->cpu_bte_if[i]->spinlock);
156         }
157
158         del_timer(recovery_timer);
159
160         spin_unlock_irqrestore(recovery_lock, irq_flags);
161 }
162
163 /*
164  * First part error handler.  This is called whenever any error CRB interrupt
165  * is generated by the II.
166  */
167 void
168 bte_crb_error_handler(cnodeid_t cnode, int btenum,
169                       int crbnum, ioerror_t * ioe, int bteop)
170 {
171         struct bteinfo_s *bte;
172
173
174         bte = &(NODEPDA(cnode)->bte_if[btenum]);
175
176         /*
177          * The caller has already figured out the error type, we save that
178          * in the bte handle structure for the thread excercising the
179          * interface to consume.
180          */
181         bte->bh_error = ioe->ie_errortype + BTEFAIL_OFFSET;
182         bte->bte_error_count++;
183
184         BTE_PRINTK(("Got an error on cnode %d bte %d: HW error type 0x%x\n",
185                 bte->bte_cnode, bte->bte_num, ioe->ie_errortype));
186         bte_error_handler((unsigned long) NODEPDA(cnode));
187 }
188