diff options
author | Thomas Klein <tklein@de.ibm.com> | 2010-04-20 19:10:55 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-04-22 01:32:43 -0400 |
commit | ea96ceac80cc82cb1c54a37bb8aaf4e695e87d0a (patch) | |
tree | 1d7225d032cff478b9b01609cd739b3e5ebfa7bf /drivers/net/ehea | |
parent | a1aa8822d577c8714f8d343eea028befbab3da9d (diff) |
ehea: error handling improvement
Reset a port's resources only if they're actually in an error state
Signed-off-by: Thomas Klein <tklein@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ehea')
-rw-r--r-- | drivers/net/ehea/ehea_main.c | 31 | ||||
-rw-r--r-- | drivers/net/ehea/ehea_qmr.c | 43 | ||||
-rw-r--r-- | drivers/net/ehea/ehea_qmr.h | 14 |
3 files changed, 62 insertions, 26 deletions
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 3f445efa9482..c35d1e3631d1 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c | |||
@@ -791,11 +791,17 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) | |||
791 | cqe_counter++; | 791 | cqe_counter++; |
792 | rmb(); | 792 | rmb(); |
793 | if (cqe->status & EHEA_CQE_STAT_ERR_MASK) { | 793 | if (cqe->status & EHEA_CQE_STAT_ERR_MASK) { |
794 | ehea_error("Send Completion Error: Resetting port"); | 794 | ehea_error("Bad send completion status=0x%04X", |
795 | cqe->status); | ||
796 | |||
795 | if (netif_msg_tx_err(pr->port)) | 797 | if (netif_msg_tx_err(pr->port)) |
796 | ehea_dump(cqe, sizeof(*cqe), "Send CQE"); | 798 | ehea_dump(cqe, sizeof(*cqe), "Send CQE"); |
797 | ehea_schedule_port_reset(pr->port); | 799 | |
798 | break; | 800 | if (cqe->status & EHEA_CQE_STAT_RESET_MASK) { |
801 | ehea_error("Resetting port"); | ||
802 | ehea_schedule_port_reset(pr->port); | ||
803 | break; | ||
804 | } | ||
799 | } | 805 | } |
800 | 806 | ||
801 | if (netif_msg_tx_done(pr->port)) | 807 | if (netif_msg_tx_done(pr->port)) |
@@ -901,6 +907,8 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) | |||
901 | struct ehea_eqe *eqe; | 907 | struct ehea_eqe *eqe; |
902 | struct ehea_qp *qp; | 908 | struct ehea_qp *qp; |
903 | u32 qp_token; | 909 | u32 qp_token; |
910 | u64 resource_type, aer, aerr; | ||
911 | int reset_port = 0; | ||
904 | 912 | ||
905 | eqe = ehea_poll_eq(port->qp_eq); | 913 | eqe = ehea_poll_eq(port->qp_eq); |
906 | 914 | ||
@@ -910,11 +918,24 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) | |||
910 | eqe->entry, qp_token); | 918 | eqe->entry, qp_token); |
911 | 919 | ||
912 | qp = port->port_res[qp_token].qp; | 920 | qp = port->port_res[qp_token].qp; |
913 | ehea_error_data(port->adapter, qp->fw_handle); | 921 | |
922 | resource_type = ehea_error_data(port->adapter, qp->fw_handle, | ||
923 | &aer, &aerr); | ||
924 | |||
925 | if (resource_type == EHEA_AER_RESTYPE_QP) { | ||
926 | if ((aer & EHEA_AER_RESET_MASK) || | ||
927 | (aerr & EHEA_AERR_RESET_MASK)) | ||
928 | reset_port = 1; | ||
929 | } else | ||
930 | reset_port = 1; /* Reset in case of CQ or EQ error */ | ||
931 | |||
914 | eqe = ehea_poll_eq(port->qp_eq); | 932 | eqe = ehea_poll_eq(port->qp_eq); |
915 | } | 933 | } |
916 | 934 | ||
917 | ehea_schedule_port_reset(port); | 935 | if (reset_port) { |
936 | ehea_error("Resetting port"); | ||
937 | ehea_schedule_port_reset(port); | ||
938 | } | ||
918 | 939 | ||
919 | return IRQ_HANDLED; | 940 | return IRQ_HANDLED; |
920 | } | 941 | } |
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index a1b4c7e56367..89128b6373e3 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c | |||
@@ -229,14 +229,14 @@ u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force) | |||
229 | 229 | ||
230 | int ehea_destroy_cq(struct ehea_cq *cq) | 230 | int ehea_destroy_cq(struct ehea_cq *cq) |
231 | { | 231 | { |
232 | u64 hret; | 232 | u64 hret, aer, aerr; |
233 | if (!cq) | 233 | if (!cq) |
234 | return 0; | 234 | return 0; |
235 | 235 | ||
236 | hcp_epas_dtor(&cq->epas); | 236 | hcp_epas_dtor(&cq->epas); |
237 | hret = ehea_destroy_cq_res(cq, NORMAL_FREE); | 237 | hret = ehea_destroy_cq_res(cq, NORMAL_FREE); |
238 | if (hret == H_R_STATE) { | 238 | if (hret == H_R_STATE) { |
239 | ehea_error_data(cq->adapter, cq->fw_handle); | 239 | ehea_error_data(cq->adapter, cq->fw_handle, &aer, &aerr); |
240 | hret = ehea_destroy_cq_res(cq, FORCE_FREE); | 240 | hret = ehea_destroy_cq_res(cq, FORCE_FREE); |
241 | } | 241 | } |
242 | 242 | ||
@@ -357,7 +357,7 @@ u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force) | |||
357 | 357 | ||
358 | int ehea_destroy_eq(struct ehea_eq *eq) | 358 | int ehea_destroy_eq(struct ehea_eq *eq) |
359 | { | 359 | { |
360 | u64 hret; | 360 | u64 hret, aer, aerr; |
361 | if (!eq) | 361 | if (!eq) |
362 | return 0; | 362 | return 0; |
363 | 363 | ||
@@ -365,7 +365,7 @@ int ehea_destroy_eq(struct ehea_eq *eq) | |||
365 | 365 | ||
366 | hret = ehea_destroy_eq_res(eq, NORMAL_FREE); | 366 | hret = ehea_destroy_eq_res(eq, NORMAL_FREE); |
367 | if (hret == H_R_STATE) { | 367 | if (hret == H_R_STATE) { |
368 | ehea_error_data(eq->adapter, eq->fw_handle); | 368 | ehea_error_data(eq->adapter, eq->fw_handle, &aer, &aerr); |
369 | hret = ehea_destroy_eq_res(eq, FORCE_FREE); | 369 | hret = ehea_destroy_eq_res(eq, FORCE_FREE); |
370 | } | 370 | } |
371 | 371 | ||
@@ -540,7 +540,7 @@ u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force) | |||
540 | 540 | ||
541 | int ehea_destroy_qp(struct ehea_qp *qp) | 541 | int ehea_destroy_qp(struct ehea_qp *qp) |
542 | { | 542 | { |
543 | u64 hret; | 543 | u64 hret, aer, aerr; |
544 | if (!qp) | 544 | if (!qp) |
545 | return 0; | 545 | return 0; |
546 | 546 | ||
@@ -548,7 +548,7 @@ int ehea_destroy_qp(struct ehea_qp *qp) | |||
548 | 548 | ||
549 | hret = ehea_destroy_qp_res(qp, NORMAL_FREE); | 549 | hret = ehea_destroy_qp_res(qp, NORMAL_FREE); |
550 | if (hret == H_R_STATE) { | 550 | if (hret == H_R_STATE) { |
551 | ehea_error_data(qp->adapter, qp->fw_handle); | 551 | ehea_error_data(qp->adapter, qp->fw_handle, &aer, &aerr); |
552 | hret = ehea_destroy_qp_res(qp, FORCE_FREE); | 552 | hret = ehea_destroy_qp_res(qp, FORCE_FREE); |
553 | } | 553 | } |
554 | 554 | ||
@@ -986,42 +986,45 @@ void print_error_data(u64 *data) | |||
986 | if (length > EHEA_PAGESIZE) | 986 | if (length > EHEA_PAGESIZE) |
987 | length = EHEA_PAGESIZE; | 987 | length = EHEA_PAGESIZE; |
988 | 988 | ||
989 | if (type == 0x8) /* Queue Pair */ | 989 | if (type == EHEA_AER_RESTYPE_QP) |
990 | ehea_error("QP (resource=%llX) state: AER=0x%llX, AERR=0x%llX, " | 990 | ehea_error("QP (resource=%llX) state: AER=0x%llX, AERR=0x%llX, " |
991 | "port=%llX", resource, data[6], data[12], data[22]); | 991 | "port=%llX", resource, data[6], data[12], data[22]); |
992 | 992 | else if (type == EHEA_AER_RESTYPE_CQ) | |
993 | if (type == 0x4) /* Completion Queue */ | ||
994 | ehea_error("CQ (resource=%llX) state: AER=0x%llX", resource, | 993 | ehea_error("CQ (resource=%llX) state: AER=0x%llX", resource, |
995 | data[6]); | 994 | data[6]); |
996 | 995 | else if (type == EHEA_AER_RESTYPE_EQ) | |
997 | if (type == 0x3) /* Event Queue */ | ||
998 | ehea_error("EQ (resource=%llX) state: AER=0x%llX", resource, | 996 | ehea_error("EQ (resource=%llX) state: AER=0x%llX", resource, |
999 | data[6]); | 997 | data[6]); |
1000 | 998 | ||
1001 | ehea_dump(data, length, "error data"); | 999 | ehea_dump(data, length, "error data"); |
1002 | } | 1000 | } |
1003 | 1001 | ||
1004 | void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle) | 1002 | u64 ehea_error_data(struct ehea_adapter *adapter, u64 res_handle, |
1003 | u64 *aer, u64 *aerr) | ||
1005 | { | 1004 | { |
1006 | unsigned long ret; | 1005 | unsigned long ret; |
1007 | u64 *rblock; | 1006 | u64 *rblock; |
1007 | u64 type = 0; | ||
1008 | 1008 | ||
1009 | rblock = (void *)get_zeroed_page(GFP_KERNEL); | 1009 | rblock = (void *)get_zeroed_page(GFP_KERNEL); |
1010 | if (!rblock) { | 1010 | if (!rblock) { |
1011 | ehea_error("Cannot allocate rblock memory."); | 1011 | ehea_error("Cannot allocate rblock memory."); |
1012 | return; | 1012 | goto out; |
1013 | } | 1013 | } |
1014 | 1014 | ||
1015 | ret = ehea_h_error_data(adapter->handle, | 1015 | ret = ehea_h_error_data(adapter->handle, res_handle, rblock); |
1016 | res_handle, | ||
1017 | rblock); | ||
1018 | 1016 | ||
1019 | if (ret == H_R_STATE) | 1017 | if (ret == H_SUCCESS) { |
1020 | ehea_error("No error data is available: %llX.", res_handle); | 1018 | type = EHEA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]); |
1021 | else if (ret == H_SUCCESS) | 1019 | *aer = rblock[6]; |
1020 | *aerr = rblock[12]; | ||
1022 | print_error_data(rblock); | 1021 | print_error_data(rblock); |
1023 | else | 1022 | } else if (ret == H_R_STATE) { |
1023 | ehea_error("No error data available: %llX.", res_handle); | ||
1024 | } else | ||
1024 | ehea_error("Error data could not be fetched: %llX", res_handle); | 1025 | ehea_error("Error data could not be fetched: %llX", res_handle); |
1025 | 1026 | ||
1026 | free_page((unsigned long)rblock); | 1027 | free_page((unsigned long)rblock); |
1028 | out: | ||
1029 | return type; | ||
1027 | } | 1030 | } |
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h index 0817c1e74a19..882c50c9c34f 100644 --- a/drivers/net/ehea/ehea_qmr.h +++ b/drivers/net/ehea/ehea_qmr.h | |||
@@ -154,6 +154,9 @@ struct ehea_rwqe { | |||
154 | #define EHEA_CQE_STAT_ERR_IP 0x2000 | 154 | #define EHEA_CQE_STAT_ERR_IP 0x2000 |
155 | #define EHEA_CQE_STAT_ERR_CRC 0x1000 | 155 | #define EHEA_CQE_STAT_ERR_CRC 0x1000 |
156 | 156 | ||
157 | /* Defines which bad send cqe stati lead to a port reset */ | ||
158 | #define EHEA_CQE_STAT_RESET_MASK 0x0002 | ||
159 | |||
157 | struct ehea_cqe { | 160 | struct ehea_cqe { |
158 | u64 wr_id; /* work request ID from WQE */ | 161 | u64 wr_id; /* work request ID from WQE */ |
159 | u8 type; | 162 | u8 type; |
@@ -187,6 +190,14 @@ struct ehea_cqe { | |||
187 | #define EHEA_EQE_SM_MECH_NUMBER EHEA_BMASK_IBM(48, 55) | 190 | #define EHEA_EQE_SM_MECH_NUMBER EHEA_BMASK_IBM(48, 55) |
188 | #define EHEA_EQE_SM_PORT_NUMBER EHEA_BMASK_IBM(56, 63) | 191 | #define EHEA_EQE_SM_PORT_NUMBER EHEA_BMASK_IBM(56, 63) |
189 | 192 | ||
193 | #define EHEA_AER_RESTYPE_QP 0x8 | ||
194 | #define EHEA_AER_RESTYPE_CQ 0x4 | ||
195 | #define EHEA_AER_RESTYPE_EQ 0x3 | ||
196 | |||
197 | /* Defines which affiliated errors lead to a port reset */ | ||
198 | #define EHEA_AER_RESET_MASK 0xFFFFFFFFFEFFFFFFULL | ||
199 | #define EHEA_AERR_RESET_MASK 0xFFFFFFFFFFFFFFFFULL | ||
200 | |||
190 | struct ehea_eqe { | 201 | struct ehea_eqe { |
191 | u64 entry; | 202 | u64 entry; |
192 | }; | 203 | }; |
@@ -379,7 +390,8 @@ int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr, | |||
379 | 390 | ||
380 | int ehea_rem_mr(struct ehea_mr *mr); | 391 | int ehea_rem_mr(struct ehea_mr *mr); |
381 | 392 | ||
382 | void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle); | 393 | u64 ehea_error_data(struct ehea_adapter *adapter, u64 res_handle, |
394 | u64 *aer, u64 *aerr); | ||
383 | 395 | ||
384 | int ehea_add_sect_bmap(unsigned long pfn, unsigned long nr_pages); | 396 | int ehea_add_sect_bmap(unsigned long pfn, unsigned long nr_pages); |
385 | int ehea_rem_sect_bmap(unsigned long pfn, unsigned long nr_pages); | 397 | int ehea_rem_sect_bmap(unsigned long pfn, unsigned long nr_pages); |