diff options
Diffstat (limited to 'drivers/infiniband/hw/nes/nes_hw.c')
-rw-r--r-- | drivers/infiniband/hw/nes/nes_hw.c | 767 |
1 files changed, 547 insertions, 220 deletions
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 4a84d02ece06..63a1a8e1e8a3 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c | |||
@@ -74,6 +74,8 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
74 | static void process_critical_error(struct nes_device *nesdev); | 74 | static void process_critical_error(struct nes_device *nesdev); |
75 | static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number); | 75 | static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number); |
76 | static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode); | 76 | static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode); |
77 | static void nes_terminate_timeout(unsigned long context); | ||
78 | static void nes_terminate_start_timer(struct nes_qp *nesqp); | ||
77 | 79 | ||
78 | #ifdef CONFIG_INFINIBAND_NES_DEBUG | 80 | #ifdef CONFIG_INFINIBAND_NES_DEBUG |
79 | static unsigned char *nes_iwarp_state_str[] = { | 81 | static unsigned char *nes_iwarp_state_str[] = { |
@@ -2903,6 +2905,417 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) | |||
2903 | } | 2905 | } |
2904 | 2906 | ||
2905 | 2907 | ||
2908 | static u8 *locate_mpa(u8 *pkt, u32 aeq_info) | ||
2909 | { | ||
2910 | u16 pkt_len; | ||
2911 | |||
2912 | if (aeq_info & NES_AEQE_Q2_DATA_ETHERNET) { | ||
2913 | /* skip over ethernet header */ | ||
2914 | pkt_len = be16_to_cpu(*(u16 *)(pkt + ETH_HLEN - 2)); | ||
2915 | pkt += ETH_HLEN; | ||
2916 | |||
2917 | /* Skip over IP and TCP headers */ | ||
2918 | pkt += 4 * (pkt[0] & 0x0f); | ||
2919 | pkt += 4 * ((pkt[12] >> 4) & 0x0f); | ||
2920 | } | ||
2921 | return pkt; | ||
2922 | } | ||
2923 | |||
2924 | /* Determine if incoming error pkt is rdma layer */ | ||
2925 | static u32 iwarp_opcode(struct nes_qp *nesqp, u32 aeq_info) | ||
2926 | { | ||
2927 | u8 *pkt; | ||
2928 | u16 *mpa; | ||
2929 | u32 opcode = 0xffffffff; | ||
2930 | |||
2931 | if (aeq_info & NES_AEQE_Q2_DATA_WRITTEN) { | ||
2932 | pkt = nesqp->hwqp.q2_vbase + BAD_FRAME_OFFSET; | ||
2933 | mpa = (u16 *)locate_mpa(pkt, aeq_info); | ||
2934 | opcode = be16_to_cpu(mpa[1]) & 0xf; | ||
2935 | } | ||
2936 | |||
2937 | return opcode; | ||
2938 | } | ||
2939 | |||
2940 | /* Build iWARP terminate header */ | ||
2941 | static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 aeq_info) | ||
2942 | { | ||
2943 | u8 *pkt = nesqp->hwqp.q2_vbase + BAD_FRAME_OFFSET; | ||
2944 | u16 ddp_seg_len; | ||
2945 | int copy_len = 0; | ||
2946 | u8 is_tagged = 0; | ||
2947 | u8 flush_code = 0; | ||
2948 | struct nes_terminate_hdr *termhdr; | ||
2949 | |||
2950 | termhdr = (struct nes_terminate_hdr *)nesqp->hwqp.q2_vbase; | ||
2951 | memset(termhdr, 0, 64); | ||
2952 | |||
2953 | if (aeq_info & NES_AEQE_Q2_DATA_WRITTEN) { | ||
2954 | |||
2955 | /* Use data from offending packet to fill in ddp & rdma hdrs */ | ||
2956 | pkt = locate_mpa(pkt, aeq_info); | ||
2957 | ddp_seg_len = be16_to_cpu(*(u16 *)pkt); | ||
2958 | if (ddp_seg_len) { | ||
2959 | copy_len = 2; | ||
2960 | termhdr->hdrct = DDP_LEN_FLAG; | ||
2961 | if (pkt[2] & 0x80) { | ||
2962 | is_tagged = 1; | ||
2963 | if (ddp_seg_len >= TERM_DDP_LEN_TAGGED) { | ||
2964 | copy_len += TERM_DDP_LEN_TAGGED; | ||
2965 | termhdr->hdrct |= DDP_HDR_FLAG; | ||
2966 | } | ||
2967 | } else { | ||
2968 | if (ddp_seg_len >= TERM_DDP_LEN_UNTAGGED) { | ||
2969 | copy_len += TERM_DDP_LEN_UNTAGGED; | ||
2970 | termhdr->hdrct |= DDP_HDR_FLAG; | ||
2971 | } | ||
2972 | |||
2973 | if (ddp_seg_len >= (TERM_DDP_LEN_UNTAGGED + TERM_RDMA_LEN)) { | ||
2974 | if ((pkt[3] & RDMA_OPCODE_MASK) == RDMA_READ_REQ_OPCODE) { | ||
2975 | copy_len += TERM_RDMA_LEN; | ||
2976 | termhdr->hdrct |= RDMA_HDR_FLAG; | ||
2977 | } | ||
2978 | } | ||
2979 | } | ||
2980 | } | ||
2981 | } | ||
2982 | |||
2983 | switch (async_event_id) { | ||
2984 | case NES_AEQE_AEID_AMP_UNALLOCATED_STAG: | ||
2985 | switch (iwarp_opcode(nesqp, aeq_info)) { | ||
2986 | case IWARP_OPCODE_WRITE: | ||
2987 | flush_code = IB_WC_LOC_PROT_ERR; | ||
2988 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; | ||
2989 | termhdr->error_code = DDP_TAGGED_INV_STAG; | ||
2990 | break; | ||
2991 | default: | ||
2992 | flush_code = IB_WC_REM_ACCESS_ERR; | ||
2993 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
2994 | termhdr->error_code = RDMAP_INV_STAG; | ||
2995 | } | ||
2996 | break; | ||
2997 | case NES_AEQE_AEID_AMP_INVALID_STAG: | ||
2998 | flush_code = IB_WC_REM_ACCESS_ERR; | ||
2999 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
3000 | termhdr->error_code = RDMAP_INV_STAG; | ||
3001 | break; | ||
3002 | case NES_AEQE_AEID_AMP_BAD_QP: | ||
3003 | flush_code = IB_WC_LOC_QP_OP_ERR; | ||
3004 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; | ||
3005 | termhdr->error_code = DDP_UNTAGGED_INV_QN; | ||
3006 | break; | ||
3007 | case NES_AEQE_AEID_AMP_BAD_STAG_KEY: | ||
3008 | case NES_AEQE_AEID_AMP_BAD_STAG_INDEX: | ||
3009 | switch (iwarp_opcode(nesqp, aeq_info)) { | ||
3010 | case IWARP_OPCODE_SEND_INV: | ||
3011 | case IWARP_OPCODE_SEND_SE_INV: | ||
3012 | flush_code = IB_WC_REM_OP_ERR; | ||
3013 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; | ||
3014 | termhdr->error_code = RDMAP_CANT_INV_STAG; | ||
3015 | break; | ||
3016 | default: | ||
3017 | flush_code = IB_WC_REM_ACCESS_ERR; | ||
3018 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
3019 | termhdr->error_code = RDMAP_INV_STAG; | ||
3020 | } | ||
3021 | break; | ||
3022 | case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: | ||
3023 | if (aeq_info & (NES_AEQE_Q2_DATA_ETHERNET | NES_AEQE_Q2_DATA_MPA)) { | ||
3024 | flush_code = IB_WC_LOC_PROT_ERR; | ||
3025 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; | ||
3026 | termhdr->error_code = DDP_TAGGED_BOUNDS; | ||
3027 | } else { | ||
3028 | flush_code = IB_WC_REM_ACCESS_ERR; | ||
3029 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
3030 | termhdr->error_code = RDMAP_INV_BOUNDS; | ||
3031 | } | ||
3032 | break; | ||
3033 | case NES_AEQE_AEID_AMP_RIGHTS_VIOLATION: | ||
3034 | case NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS: | ||
3035 | case NES_AEQE_AEID_PRIV_OPERATION_DENIED: | ||
3036 | flush_code = IB_WC_REM_ACCESS_ERR; | ||
3037 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
3038 | termhdr->error_code = RDMAP_ACCESS; | ||
3039 | break; | ||
3040 | case NES_AEQE_AEID_AMP_TO_WRAP: | ||
3041 | flush_code = IB_WC_REM_ACCESS_ERR; | ||
3042 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
3043 | termhdr->error_code = RDMAP_TO_WRAP; | ||
3044 | break; | ||
3045 | case NES_AEQE_AEID_AMP_BAD_PD: | ||
3046 | switch (iwarp_opcode(nesqp, aeq_info)) { | ||
3047 | case IWARP_OPCODE_WRITE: | ||
3048 | flush_code = IB_WC_LOC_PROT_ERR; | ||
3049 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; | ||
3050 | termhdr->error_code = DDP_TAGGED_UNASSOC_STAG; | ||
3051 | break; | ||
3052 | case IWARP_OPCODE_SEND_INV: | ||
3053 | case IWARP_OPCODE_SEND_SE_INV: | ||
3054 | flush_code = IB_WC_REM_ACCESS_ERR; | ||
3055 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
3056 | termhdr->error_code = RDMAP_CANT_INV_STAG; | ||
3057 | break; | ||
3058 | default: | ||
3059 | flush_code = IB_WC_REM_ACCESS_ERR; | ||
3060 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
3061 | termhdr->error_code = RDMAP_UNASSOC_STAG; | ||
3062 | } | ||
3063 | break; | ||
3064 | case NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH: | ||
3065 | flush_code = IB_WC_LOC_LEN_ERR; | ||
3066 | termhdr->layer_etype = (LAYER_MPA << 4) | DDP_LLP; | ||
3067 | termhdr->error_code = MPA_MARKER; | ||
3068 | break; | ||
3069 | case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: | ||
3070 | flush_code = IB_WC_GENERAL_ERR; | ||
3071 | termhdr->layer_etype = (LAYER_MPA << 4) | DDP_LLP; | ||
3072 | termhdr->error_code = MPA_CRC; | ||
3073 | break; | ||
3074 | case NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE: | ||
3075 | case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL: | ||
3076 | flush_code = IB_WC_LOC_LEN_ERR; | ||
3077 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_CATASTROPHIC; | ||
3078 | termhdr->error_code = DDP_CATASTROPHIC_LOCAL; | ||
3079 | break; | ||
3080 | case NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC: | ||
3081 | case NES_AEQE_AEID_DDP_NO_L_BIT: | ||
3082 | flush_code = IB_WC_FATAL_ERR; | ||
3083 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_CATASTROPHIC; | ||
3084 | termhdr->error_code = DDP_CATASTROPHIC_LOCAL; | ||
3085 | break; | ||
3086 | case NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN: | ||
3087 | case NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID: | ||
3088 | flush_code = IB_WC_GENERAL_ERR; | ||
3089 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; | ||
3090 | termhdr->error_code = DDP_UNTAGGED_INV_MSN_RANGE; | ||
3091 | break; | ||
3092 | case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: | ||
3093 | flush_code = IB_WC_LOC_LEN_ERR; | ||
3094 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; | ||
3095 | termhdr->error_code = DDP_UNTAGGED_INV_TOO_LONG; | ||
3096 | break; | ||
3097 | case NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION: | ||
3098 | flush_code = IB_WC_GENERAL_ERR; | ||
3099 | if (is_tagged) { | ||
3100 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; | ||
3101 | termhdr->error_code = DDP_TAGGED_INV_DDP_VER; | ||
3102 | } else { | ||
3103 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; | ||
3104 | termhdr->error_code = DDP_UNTAGGED_INV_DDP_VER; | ||
3105 | } | ||
3106 | break; | ||
3107 | case NES_AEQE_AEID_DDP_UBE_INVALID_MO: | ||
3108 | flush_code = IB_WC_GENERAL_ERR; | ||
3109 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; | ||
3110 | termhdr->error_code = DDP_UNTAGGED_INV_MO; | ||
3111 | break; | ||
3112 | case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: | ||
3113 | flush_code = IB_WC_REM_OP_ERR; | ||
3114 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; | ||
3115 | termhdr->error_code = DDP_UNTAGGED_INV_MSN_NO_BUF; | ||
3116 | break; | ||
3117 | case NES_AEQE_AEID_DDP_UBE_INVALID_QN: | ||
3118 | flush_code = IB_WC_GENERAL_ERR; | ||
3119 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; | ||
3120 | termhdr->error_code = DDP_UNTAGGED_INV_QN; | ||
3121 | break; | ||
3122 | case NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION: | ||
3123 | flush_code = IB_WC_GENERAL_ERR; | ||
3124 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; | ||
3125 | termhdr->error_code = RDMAP_INV_RDMAP_VER; | ||
3126 | break; | ||
3127 | case NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE: | ||
3128 | flush_code = IB_WC_LOC_QP_OP_ERR; | ||
3129 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; | ||
3130 | termhdr->error_code = RDMAP_UNEXPECTED_OP; | ||
3131 | break; | ||
3132 | default: | ||
3133 | flush_code = IB_WC_FATAL_ERR; | ||
3134 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; | ||
3135 | termhdr->error_code = RDMAP_UNSPECIFIED; | ||
3136 | break; | ||
3137 | } | ||
3138 | |||
3139 | if (copy_len) | ||
3140 | memcpy(termhdr + 1, pkt, copy_len); | ||
3141 | |||
3142 | if ((flush_code) && ((NES_AEQE_INBOUND_RDMA & aeq_info) == 0)) { | ||
3143 | if (aeq_info & NES_AEQE_SQ) | ||
3144 | nesqp->term_sq_flush_code = flush_code; | ||
3145 | else | ||
3146 | nesqp->term_rq_flush_code = flush_code; | ||
3147 | } | ||
3148 | |||
3149 | return sizeof(struct nes_terminate_hdr) + copy_len; | ||
3150 | } | ||
3151 | |||
3152 | static void nes_terminate_connection(struct nes_device *nesdev, struct nes_qp *nesqp, | ||
3153 | struct nes_hw_aeqe *aeqe, enum ib_event_type eventtype) | ||
3154 | { | ||
3155 | u64 context; | ||
3156 | unsigned long flags; | ||
3157 | u32 aeq_info; | ||
3158 | u16 async_event_id; | ||
3159 | u8 tcp_state; | ||
3160 | u8 iwarp_state; | ||
3161 | u32 termlen = 0; | ||
3162 | u32 mod_qp_flags = NES_CQP_QP_IWARP_STATE_TERMINATE | | ||
3163 | NES_CQP_QP_TERM_DONT_SEND_FIN; | ||
3164 | struct nes_adapter *nesadapter = nesdev->nesadapter; | ||
3165 | |||
3166 | if (nesqp->term_flags & NES_TERM_SENT) | ||
3167 | return; /* Sanity check */ | ||
3168 | |||
3169 | aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); | ||
3170 | tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT; | ||
3171 | iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT; | ||
3172 | async_event_id = (u16)aeq_info; | ||
3173 | |||
3174 | context = (unsigned long)nesadapter->qp_table[le32_to_cpu( | ||
3175 | aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN]; | ||
3176 | if (!context) { | ||
3177 | WARN_ON(!context); | ||
3178 | return; | ||
3179 | } | ||
3180 | |||
3181 | nesqp = (struct nes_qp *)(unsigned long)context; | ||
3182 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3183 | nesqp->hw_iwarp_state = iwarp_state; | ||
3184 | nesqp->hw_tcp_state = tcp_state; | ||
3185 | nesqp->last_aeq = async_event_id; | ||
3186 | nesqp->terminate_eventtype = eventtype; | ||
3187 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3188 | |||
3189 | if (nesadapter->send_term_ok) | ||
3190 | termlen = nes_bld_terminate_hdr(nesqp, async_event_id, aeq_info); | ||
3191 | else | ||
3192 | mod_qp_flags |= NES_CQP_QP_TERM_DONT_SEND_TERM_MSG; | ||
3193 | |||
3194 | nes_terminate_start_timer(nesqp); | ||
3195 | nesqp->term_flags |= NES_TERM_SENT; | ||
3196 | nes_hw_modify_qp(nesdev, nesqp, mod_qp_flags, termlen, 0); | ||
3197 | } | ||
3198 | |||
3199 | static void nes_terminate_send_fin(struct nes_device *nesdev, | ||
3200 | struct nes_qp *nesqp, struct nes_hw_aeqe *aeqe) | ||
3201 | { | ||
3202 | u32 aeq_info; | ||
3203 | u16 async_event_id; | ||
3204 | u8 tcp_state; | ||
3205 | u8 iwarp_state; | ||
3206 | unsigned long flags; | ||
3207 | |||
3208 | aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); | ||
3209 | tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT; | ||
3210 | iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT; | ||
3211 | async_event_id = (u16)aeq_info; | ||
3212 | |||
3213 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3214 | nesqp->hw_iwarp_state = iwarp_state; | ||
3215 | nesqp->hw_tcp_state = tcp_state; | ||
3216 | nesqp->last_aeq = async_event_id; | ||
3217 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3218 | |||
3219 | /* Send the fin only */ | ||
3220 | nes_hw_modify_qp(nesdev, nesqp, NES_CQP_QP_IWARP_STATE_TERMINATE | | ||
3221 | NES_CQP_QP_TERM_DONT_SEND_TERM_MSG, 0, 0); | ||
3222 | } | ||
3223 | |||
3224 | /* Cleanup after a terminate sent or received */ | ||
3225 | static void nes_terminate_done(struct nes_qp *nesqp, int timeout_occurred) | ||
3226 | { | ||
3227 | u32 next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR; | ||
3228 | unsigned long flags; | ||
3229 | struct nes_vnic *nesvnic = to_nesvnic(nesqp->ibqp.device); | ||
3230 | struct nes_device *nesdev = nesvnic->nesdev; | ||
3231 | u8 first_time = 0; | ||
3232 | |||
3233 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3234 | if (nesqp->hte_added) { | ||
3235 | nesqp->hte_added = 0; | ||
3236 | next_iwarp_state |= NES_CQP_QP_DEL_HTE; | ||
3237 | } | ||
3238 | |||
3239 | first_time = (nesqp->term_flags & NES_TERM_DONE) == 0; | ||
3240 | nesqp->term_flags |= NES_TERM_DONE; | ||
3241 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3242 | |||
3243 | /* Make sure we go through this only once */ | ||
3244 | if (first_time) { | ||
3245 | if (timeout_occurred == 0) | ||
3246 | del_timer(&nesqp->terminate_timer); | ||
3247 | else | ||
3248 | next_iwarp_state |= NES_CQP_QP_RESET; | ||
3249 | |||
3250 | nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0); | ||
3251 | nes_cm_disconn(nesqp); | ||
3252 | } | ||
3253 | } | ||
3254 | |||
3255 | static void nes_terminate_received(struct nes_device *nesdev, | ||
3256 | struct nes_qp *nesqp, struct nes_hw_aeqe *aeqe) | ||
3257 | { | ||
3258 | u32 aeq_info; | ||
3259 | u8 *pkt; | ||
3260 | u32 *mpa; | ||
3261 | u8 ddp_ctl; | ||
3262 | u8 rdma_ctl; | ||
3263 | u16 aeq_id = 0; | ||
3264 | |||
3265 | aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); | ||
3266 | if (aeq_info & NES_AEQE_Q2_DATA_WRITTEN) { | ||
3267 | /* Terminate is not a performance path so the silicon */ | ||
3268 | /* did not validate the frame - do it now */ | ||
3269 | pkt = nesqp->hwqp.q2_vbase + BAD_FRAME_OFFSET; | ||
3270 | mpa = (u32 *)locate_mpa(pkt, aeq_info); | ||
3271 | ddp_ctl = (be32_to_cpu(mpa[0]) >> 8) & 0xff; | ||
3272 | rdma_ctl = be32_to_cpu(mpa[0]) & 0xff; | ||
3273 | if ((ddp_ctl & 0xc0) != 0x40) | ||
3274 | aeq_id = NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC; | ||
3275 | else if ((ddp_ctl & 0x03) != 1) | ||
3276 | aeq_id = NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION; | ||
3277 | else if (be32_to_cpu(mpa[2]) != 2) | ||
3278 | aeq_id = NES_AEQE_AEID_DDP_UBE_INVALID_QN; | ||
3279 | else if (be32_to_cpu(mpa[3]) != 1) | ||
3280 | aeq_id = NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN; | ||
3281 | else if (be32_to_cpu(mpa[4]) != 0) | ||
3282 | aeq_id = NES_AEQE_AEID_DDP_UBE_INVALID_MO; | ||
3283 | else if ((rdma_ctl & 0xc0) != 0x40) | ||
3284 | aeq_id = NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION; | ||
3285 | |||
3286 | if (aeq_id) { | ||
3287 | /* Bad terminate recvd - send back a terminate */ | ||
3288 | aeq_info = (aeq_info & 0xffff0000) | aeq_id; | ||
3289 | aeqe->aeqe_words[NES_AEQE_MISC_IDX] = cpu_to_le32(aeq_info); | ||
3290 | nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); | ||
3291 | return; | ||
3292 | } | ||
3293 | } | ||
3294 | |||
3295 | nesqp->term_flags |= NES_TERM_RCVD; | ||
3296 | nesqp->terminate_eventtype = IB_EVENT_QP_FATAL; | ||
3297 | nes_terminate_start_timer(nesqp); | ||
3298 | nes_terminate_send_fin(nesdev, nesqp, aeqe); | ||
3299 | } | ||
3300 | |||
3301 | /* Timeout routine in case terminate fails to complete */ | ||
3302 | static void nes_terminate_timeout(unsigned long context) | ||
3303 | { | ||
3304 | struct nes_qp *nesqp = (struct nes_qp *)(unsigned long)context; | ||
3305 | |||
3306 | nes_terminate_done(nesqp, 1); | ||
3307 | } | ||
3308 | |||
3309 | /* Set a timer in case hw cannot complete the terminate sequence */ | ||
3310 | static void nes_terminate_start_timer(struct nes_qp *nesqp) | ||
3311 | { | ||
3312 | init_timer(&nesqp->terminate_timer); | ||
3313 | nesqp->terminate_timer.function = nes_terminate_timeout; | ||
3314 | nesqp->terminate_timer.expires = jiffies + HZ; | ||
3315 | nesqp->terminate_timer.data = (unsigned long)nesqp; | ||
3316 | add_timer(&nesqp->terminate_timer); | ||
3317 | } | ||
3318 | |||
2906 | /** | 3319 | /** |
2907 | * nes_process_iwarp_aeqe | 3320 | * nes_process_iwarp_aeqe |
2908 | */ | 3321 | */ |
@@ -2910,28 +3323,27 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
2910 | struct nes_hw_aeqe *aeqe) | 3323 | struct nes_hw_aeqe *aeqe) |
2911 | { | 3324 | { |
2912 | u64 context; | 3325 | u64 context; |
2913 | u64 aeqe_context = 0; | ||
2914 | unsigned long flags; | 3326 | unsigned long flags; |
2915 | struct nes_qp *nesqp; | 3327 | struct nes_qp *nesqp; |
3328 | struct nes_hw_cq *hw_cq; | ||
3329 | struct nes_cq *nescq; | ||
2916 | int resource_allocated; | 3330 | int resource_allocated; |
2917 | /* struct iw_cm_id *cm_id; */ | ||
2918 | struct nes_adapter *nesadapter = nesdev->nesadapter; | 3331 | struct nes_adapter *nesadapter = nesdev->nesadapter; |
2919 | struct ib_event ibevent; | ||
2920 | /* struct iw_cm_event cm_event; */ | ||
2921 | u32 aeq_info; | 3332 | u32 aeq_info; |
2922 | u32 next_iwarp_state = 0; | 3333 | u32 next_iwarp_state = 0; |
2923 | u16 async_event_id; | 3334 | u16 async_event_id; |
2924 | u8 tcp_state; | 3335 | u8 tcp_state; |
2925 | u8 iwarp_state; | 3336 | u8 iwarp_state; |
3337 | int must_disconn = 1; | ||
3338 | int must_terminate = 0; | ||
3339 | struct ib_event ibevent; | ||
2926 | 3340 | ||
2927 | nes_debug(NES_DBG_AEQ, "\n"); | 3341 | nes_debug(NES_DBG_AEQ, "\n"); |
2928 | aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); | 3342 | aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); |
2929 | if ((NES_AEQE_INBOUND_RDMA&aeq_info) || (!(NES_AEQE_QP&aeq_info))) { | 3343 | if ((NES_AEQE_INBOUND_RDMA & aeq_info) || (!(NES_AEQE_QP & aeq_info))) { |
2930 | context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); | 3344 | context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); |
2931 | context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; | 3345 | context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; |
2932 | } else { | 3346 | } else { |
2933 | aeqe_context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); | ||
2934 | aeqe_context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; | ||
2935 | context = (unsigned long)nesadapter->qp_table[le32_to_cpu( | 3347 | context = (unsigned long)nesadapter->qp_table[le32_to_cpu( |
2936 | aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN]; | 3348 | aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN]; |
2937 | BUG_ON(!context); | 3349 | BUG_ON(!context); |
@@ -2948,7 +3360,11 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
2948 | 3360 | ||
2949 | switch (async_event_id) { | 3361 | switch (async_event_id) { |
2950 | case NES_AEQE_AEID_LLP_FIN_RECEIVED: | 3362 | case NES_AEQE_AEID_LLP_FIN_RECEIVED: |
2951 | nesqp = *((struct nes_qp **)&context); | 3363 | nesqp = (struct nes_qp *)(unsigned long)context; |
3364 | |||
3365 | if (nesqp->term_flags) | ||
3366 | return; /* Ignore it, wait for close complete */ | ||
3367 | |||
2952 | if (atomic_inc_return(&nesqp->close_timer_started) == 1) { | 3368 | if (atomic_inc_return(&nesqp->close_timer_started) == 1) { |
2953 | nesqp->cm_id->add_ref(nesqp->cm_id); | 3369 | nesqp->cm_id->add_ref(nesqp->cm_id); |
2954 | schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp, | 3370 | schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp, |
@@ -2959,18 +3375,24 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
2959 | nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), | 3375 | nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), |
2960 | async_event_id, nesqp->last_aeq, tcp_state); | 3376 | async_event_id, nesqp->last_aeq, tcp_state); |
2961 | } | 3377 | } |
3378 | |||
2962 | if ((tcp_state != NES_AEQE_TCP_STATE_CLOSE_WAIT) || | 3379 | if ((tcp_state != NES_AEQE_TCP_STATE_CLOSE_WAIT) || |
2963 | (nesqp->ibqp_state != IB_QPS_RTS)) { | 3380 | (nesqp->ibqp_state != IB_QPS_RTS)) { |
2964 | /* FIN Received but tcp state or IB state moved on, | 3381 | /* FIN Received but tcp state or IB state moved on, |
2965 | should expect a close complete */ | 3382 | should expect a close complete */ |
2966 | return; | 3383 | return; |
2967 | } | 3384 | } |
3385 | |||
2968 | case NES_AEQE_AEID_LLP_CLOSE_COMPLETE: | 3386 | case NES_AEQE_AEID_LLP_CLOSE_COMPLETE: |
3387 | nesqp = (struct nes_qp *)(unsigned long)context; | ||
3388 | if (nesqp->term_flags) { | ||
3389 | nes_terminate_done(nesqp, 0); | ||
3390 | return; | ||
3391 | } | ||
3392 | |||
2969 | case NES_AEQE_AEID_LLP_CONNECTION_RESET: | 3393 | case NES_AEQE_AEID_LLP_CONNECTION_RESET: |
2970 | case NES_AEQE_AEID_TERMINATE_SENT: | ||
2971 | case NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE: | ||
2972 | case NES_AEQE_AEID_RESET_SENT: | 3394 | case NES_AEQE_AEID_RESET_SENT: |
2973 | nesqp = *((struct nes_qp **)&context); | 3395 | nesqp = (struct nes_qp *)(unsigned long)context; |
2974 | if (async_event_id == NES_AEQE_AEID_RESET_SENT) { | 3396 | if (async_event_id == NES_AEQE_AEID_RESET_SENT) { |
2975 | tcp_state = NES_AEQE_TCP_STATE_CLOSED; | 3397 | tcp_state = NES_AEQE_TCP_STATE_CLOSED; |
2976 | } | 3398 | } |
@@ -2982,12 +3404,7 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
2982 | if ((tcp_state == NES_AEQE_TCP_STATE_CLOSED) || | 3404 | if ((tcp_state == NES_AEQE_TCP_STATE_CLOSED) || |
2983 | (tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT)) { | 3405 | (tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT)) { |
2984 | nesqp->hte_added = 0; | 3406 | nesqp->hte_added = 0; |
2985 | spin_unlock_irqrestore(&nesqp->lock, flags); | 3407 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE; |
2986 | nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u to remove hte\n", | ||
2987 | nesqp->hwqp.qp_id); | ||
2988 | nes_hw_modify_qp(nesdev, nesqp, | ||
2989 | NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE, 0); | ||
2990 | spin_lock_irqsave(&nesqp->lock, flags); | ||
2991 | } | 3408 | } |
2992 | 3409 | ||
2993 | if ((nesqp->ibqp_state == IB_QPS_RTS) && | 3410 | if ((nesqp->ibqp_state == IB_QPS_RTS) && |
@@ -2999,151 +3416,106 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
2999 | nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING; | 3416 | nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING; |
3000 | break; | 3417 | break; |
3001 | case NES_AEQE_IWARP_STATE_TERMINATE: | 3418 | case NES_AEQE_IWARP_STATE_TERMINATE: |
3002 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE; | 3419 | must_disconn = 0; /* terminate path takes care of disconn */ |
3003 | nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_TERMINATE; | 3420 | if (nesqp->term_flags == 0) |
3004 | if (async_event_id == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) { | 3421 | must_terminate = 1; |
3005 | next_iwarp_state |= 0x02000000; | ||
3006 | nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; | ||
3007 | } | ||
3008 | break; | 3422 | break; |
3009 | default: | ||
3010 | next_iwarp_state = 0; | ||
3011 | } | ||
3012 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3013 | if (next_iwarp_state) { | ||
3014 | nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X," | ||
3015 | " also added another reference\n", | ||
3016 | nesqp->hwqp.qp_id, next_iwarp_state); | ||
3017 | nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0); | ||
3018 | } | 3423 | } |
3019 | nes_cm_disconn(nesqp); | ||
3020 | } else { | 3424 | } else { |
3021 | if (async_event_id == NES_AEQE_AEID_LLP_FIN_RECEIVED) { | 3425 | if (async_event_id == NES_AEQE_AEID_LLP_FIN_RECEIVED) { |
3022 | /* FIN Received but ib state not RTS, | 3426 | /* FIN Received but ib state not RTS, |
3023 | close complete will be on its way */ | 3427 | close complete will be on its way */ |
3024 | spin_unlock_irqrestore(&nesqp->lock, flags); | 3428 | must_disconn = 0; |
3025 | return; | ||
3026 | } | ||
3027 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3028 | if (async_event_id == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) { | ||
3029 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000; | ||
3030 | nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; | ||
3031 | nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X," | ||
3032 | " also added another reference\n", | ||
3033 | nesqp->hwqp.qp_id, next_iwarp_state); | ||
3034 | nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0); | ||
3035 | } | 3429 | } |
3036 | nes_cm_disconn(nesqp); | ||
3037 | } | 3430 | } |
3038 | break; | ||
3039 | case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED: | ||
3040 | nesqp = *((struct nes_qp **)&context); | ||
3041 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3042 | nesqp->hw_iwarp_state = iwarp_state; | ||
3043 | nesqp->hw_tcp_state = tcp_state; | ||
3044 | nesqp->last_aeq = async_event_id; | ||
3045 | spin_unlock_irqrestore(&nesqp->lock, flags); | 3431 | spin_unlock_irqrestore(&nesqp->lock, flags); |
3046 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TERMINATE_RECEIVED" | 3432 | |
3047 | " event on QP%u \n Q2 Data:\n", | 3433 | if (must_terminate) |
3048 | nesqp->hwqp.qp_id); | 3434 | nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); |
3049 | if (nesqp->ibqp.event_handler) { | 3435 | else if (must_disconn) { |
3050 | ibevent.device = nesqp->ibqp.device; | 3436 | if (next_iwarp_state) { |
3051 | ibevent.element.qp = &nesqp->ibqp; | 3437 | nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X\n", |
3052 | ibevent.event = IB_EVENT_QP_FATAL; | 3438 | nesqp->hwqp.qp_id, next_iwarp_state); |
3053 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | 3439 | nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0); |
3054 | } | 3440 | } |
3055 | if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) || | ||
3056 | ((nesqp->ibqp_state == IB_QPS_RTS)&& | ||
3057 | (async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { | ||
3058 | nes_cm_disconn(nesqp); | 3441 | nes_cm_disconn(nesqp); |
3059 | } else { | ||
3060 | nesqp->in_disconnect = 0; | ||
3061 | wake_up(&nesqp->kick_waitq); | ||
3062 | } | 3442 | } |
3063 | break; | 3443 | break; |
3064 | case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES: | 3444 | |
3065 | nesqp = *((struct nes_qp **)&context); | 3445 | case NES_AEQE_AEID_TERMINATE_SENT: |
3066 | spin_lock_irqsave(&nesqp->lock, flags); | 3446 | nesqp = (struct nes_qp *)(unsigned long)context; |
3067 | nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR; | 3447 | nes_terminate_send_fin(nesdev, nesqp, aeqe); |
3068 | nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; | ||
3069 | nesqp->last_aeq = async_event_id; | ||
3070 | if (nesqp->cm_id) { | ||
3071 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TOO_MANY_RETRIES" | ||
3072 | " event on QP%u, remote IP = 0x%08X \n", | ||
3073 | nesqp->hwqp.qp_id, | ||
3074 | ntohl(nesqp->cm_id->remote_addr.sin_addr.s_addr)); | ||
3075 | } else { | ||
3076 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TOO_MANY_RETRIES" | ||
3077 | " event on QP%u \n", | ||
3078 | nesqp->hwqp.qp_id); | ||
3079 | } | ||
3080 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3081 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_RESET; | ||
3082 | nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0); | ||
3083 | if (nesqp->ibqp.event_handler) { | ||
3084 | ibevent.device = nesqp->ibqp.device; | ||
3085 | ibevent.element.qp = &nesqp->ibqp; | ||
3086 | ibevent.event = IB_EVENT_QP_FATAL; | ||
3087 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | ||
3088 | } | ||
3089 | break; | 3448 | break; |
3090 | case NES_AEQE_AEID_AMP_BAD_STAG_INDEX: | 3449 | |
3091 | if (NES_AEQE_INBOUND_RDMA&aeq_info) { | 3450 | case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED: |
3092 | nesqp = nesadapter->qp_table[le32_to_cpu( | 3451 | nesqp = (struct nes_qp *)(unsigned long)context; |
3093 | aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN]; | 3452 | nes_terminate_received(nesdev, nesqp, aeqe); |
3094 | } else { | ||
3095 | /* TODO: get the actual WQE and mask off wqe index */ | ||
3096 | context &= ~((u64)511); | ||
3097 | nesqp = *((struct nes_qp **)&context); | ||
3098 | } | ||
3099 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3100 | nesqp->hw_iwarp_state = iwarp_state; | ||
3101 | nesqp->hw_tcp_state = tcp_state; | ||
3102 | nesqp->last_aeq = async_event_id; | ||
3103 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3104 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_AMP_BAD_STAG_INDEX event on QP%u\n", | ||
3105 | nesqp->hwqp.qp_id); | ||
3106 | if (nesqp->ibqp.event_handler) { | ||
3107 | ibevent.device = nesqp->ibqp.device; | ||
3108 | ibevent.element.qp = &nesqp->ibqp; | ||
3109 | ibevent.event = IB_EVENT_QP_ACCESS_ERR; | ||
3110 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | ||
3111 | } | ||
3112 | break; | 3453 | break; |
3454 | |||
3455 | case NES_AEQE_AEID_AMP_BAD_STAG_KEY: | ||
3456 | case NES_AEQE_AEID_AMP_BAD_STAG_INDEX: | ||
3113 | case NES_AEQE_AEID_AMP_UNALLOCATED_STAG: | 3457 | case NES_AEQE_AEID_AMP_UNALLOCATED_STAG: |
3114 | nesqp = *((struct nes_qp **)&context); | 3458 | case NES_AEQE_AEID_AMP_INVALID_STAG: |
3115 | spin_lock_irqsave(&nesqp->lock, flags); | 3459 | case NES_AEQE_AEID_AMP_RIGHTS_VIOLATION: |
3116 | nesqp->hw_iwarp_state = iwarp_state; | 3460 | case NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS: |
3117 | nesqp->hw_tcp_state = tcp_state; | ||
3118 | nesqp->last_aeq = async_event_id; | ||
3119 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3120 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_AMP_UNALLOCATED_STAG event on QP%u\n", | ||
3121 | nesqp->hwqp.qp_id); | ||
3122 | if (nesqp->ibqp.event_handler) { | ||
3123 | ibevent.device = nesqp->ibqp.device; | ||
3124 | ibevent.element.qp = &nesqp->ibqp; | ||
3125 | ibevent.event = IB_EVENT_QP_ACCESS_ERR; | ||
3126 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | ||
3127 | } | ||
3128 | break; | ||
3129 | case NES_AEQE_AEID_PRIV_OPERATION_DENIED: | 3461 | case NES_AEQE_AEID_PRIV_OPERATION_DENIED: |
3130 | nesqp = nesadapter->qp_table[le32_to_cpu(aeqe->aeqe_words | 3462 | case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: |
3131 | [NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN]; | 3463 | case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: |
3132 | spin_lock_irqsave(&nesqp->lock, flags); | 3464 | case NES_AEQE_AEID_AMP_TO_WRAP: |
3133 | nesqp->hw_iwarp_state = iwarp_state; | 3465 | nesqp = (struct nes_qp *)(unsigned long)context; |
3134 | nesqp->hw_tcp_state = tcp_state; | 3466 | nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_ACCESS_ERR); |
3135 | nesqp->last_aeq = async_event_id; | 3467 | break; |
3136 | spin_unlock_irqrestore(&nesqp->lock, flags); | 3468 | |
3137 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_PRIV_OPERATION_DENIED event on QP%u," | 3469 | case NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE: |
3138 | " nesqp = %p, AE reported %p\n", | 3470 | case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL: |
3139 | nesqp->hwqp.qp_id, nesqp, *((struct nes_qp **)&context)); | 3471 | case NES_AEQE_AEID_DDP_UBE_INVALID_MO: |
3140 | if (nesqp->ibqp.event_handler) { | 3472 | case NES_AEQE_AEID_DDP_UBE_INVALID_QN: |
3141 | ibevent.device = nesqp->ibqp.device; | 3473 | nesqp = (struct nes_qp *)(unsigned long)context; |
3142 | ibevent.element.qp = &nesqp->ibqp; | 3474 | if (iwarp_opcode(nesqp, aeq_info) > IWARP_OPCODE_TERM) { |
3143 | ibevent.event = IB_EVENT_QP_ACCESS_ERR; | 3475 | aeq_info &= 0xffff0000; |
3144 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | 3476 | aeq_info |= NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE; |
3477 | aeqe->aeqe_words[NES_AEQE_MISC_IDX] = cpu_to_le32(aeq_info); | ||
3145 | } | 3478 | } |
3479 | |||
3480 | case NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE: | ||
3481 | case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES: | ||
3482 | case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: | ||
3483 | case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: | ||
3484 | case NES_AEQE_AEID_AMP_BAD_QP: | ||
3485 | case NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH: | ||
3486 | case NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC: | ||
3487 | case NES_AEQE_AEID_DDP_NO_L_BIT: | ||
3488 | case NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN: | ||
3489 | case NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID: | ||
3490 | case NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION: | ||
3491 | case NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION: | ||
3492 | case NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE: | ||
3493 | case NES_AEQE_AEID_AMP_BAD_PD: | ||
3494 | case NES_AEQE_AEID_AMP_FASTREG_SHARED: | ||
3495 | case NES_AEQE_AEID_AMP_FASTREG_VALID_STAG: | ||
3496 | case NES_AEQE_AEID_AMP_FASTREG_MW_STAG: | ||
3497 | case NES_AEQE_AEID_AMP_FASTREG_INVALID_RIGHTS: | ||
3498 | case NES_AEQE_AEID_AMP_FASTREG_PBL_TABLE_OVERFLOW: | ||
3499 | case NES_AEQE_AEID_AMP_FASTREG_INVALID_LENGTH: | ||
3500 | case NES_AEQE_AEID_AMP_INVALIDATE_SHARED: | ||
3501 | case NES_AEQE_AEID_AMP_INVALIDATE_MR_WITH_BOUND_WINDOWS: | ||
3502 | case NES_AEQE_AEID_AMP_MWBIND_VALID_STAG: | ||
3503 | case NES_AEQE_AEID_AMP_MWBIND_OF_MR_STAG: | ||
3504 | case NES_AEQE_AEID_AMP_MWBIND_TO_ZERO_BASED_STAG: | ||
3505 | case NES_AEQE_AEID_AMP_MWBIND_TO_MW_STAG: | ||
3506 | case NES_AEQE_AEID_AMP_MWBIND_INVALID_RIGHTS: | ||
3507 | case NES_AEQE_AEID_AMP_MWBIND_INVALID_BOUNDS: | ||
3508 | case NES_AEQE_AEID_AMP_MWBIND_TO_INVALID_PARENT: | ||
3509 | case NES_AEQE_AEID_AMP_MWBIND_BIND_DISABLED: | ||
3510 | case NES_AEQE_AEID_BAD_CLOSE: | ||
3511 | case NES_AEQE_AEID_RDMA_READ_WHILE_ORD_ZERO: | ||
3512 | case NES_AEQE_AEID_STAG_ZERO_INVALID: | ||
3513 | case NES_AEQE_AEID_ROE_INVALID_RDMA_READ_REQUEST: | ||
3514 | case NES_AEQE_AEID_ROE_INVALID_RDMA_WRITE_OR_READ_RESP: | ||
3515 | nesqp = (struct nes_qp *)(unsigned long)context; | ||
3516 | nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); | ||
3146 | break; | 3517 | break; |
3518 | |||
3147 | case NES_AEQE_AEID_CQ_OPERATION_ERROR: | 3519 | case NES_AEQE_AEID_CQ_OPERATION_ERROR: |
3148 | context <<= 1; | 3520 | context <<= 1; |
3149 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u, %p\n", | 3521 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u, %p\n", |
@@ -3153,83 +3525,19 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
3153 | if (resource_allocated) { | 3525 | if (resource_allocated) { |
3154 | printk(KERN_ERR PFX "%s: Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u\n", | 3526 | printk(KERN_ERR PFX "%s: Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u\n", |
3155 | __func__, le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])); | 3527 | __func__, le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])); |
3528 | hw_cq = (struct nes_hw_cq *)(unsigned long)context; | ||
3529 | if (hw_cq) { | ||
3530 | nescq = container_of(hw_cq, struct nes_cq, hw_cq); | ||
3531 | if (nescq->ibcq.event_handler) { | ||
3532 | ibevent.device = nescq->ibcq.device; | ||
3533 | ibevent.event = IB_EVENT_CQ_ERR; | ||
3534 | ibevent.element.cq = &nescq->ibcq; | ||
3535 | nescq->ibcq.event_handler(&ibevent, nescq->ibcq.cq_context); | ||
3536 | } | ||
3537 | } | ||
3156 | } | 3538 | } |
3157 | break; | 3539 | break; |
3158 | case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: | 3540 | |
3159 | nesqp = nesadapter->qp_table[le32_to_cpu( | ||
3160 | aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN]; | ||
3161 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3162 | nesqp->hw_iwarp_state = iwarp_state; | ||
3163 | nesqp->hw_tcp_state = tcp_state; | ||
3164 | nesqp->last_aeq = async_event_id; | ||
3165 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3166 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG" | ||
3167 | "_FOR_AVAILABLE_BUFFER event on QP%u\n", | ||
3168 | nesqp->hwqp.qp_id); | ||
3169 | if (nesqp->ibqp.event_handler) { | ||
3170 | ibevent.device = nesqp->ibqp.device; | ||
3171 | ibevent.element.qp = &nesqp->ibqp; | ||
3172 | ibevent.event = IB_EVENT_QP_ACCESS_ERR; | ||
3173 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | ||
3174 | } | ||
3175 | /* tell cm to disconnect, cm will queue work to thread */ | ||
3176 | nes_cm_disconn(nesqp); | ||
3177 | break; | ||
3178 | case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: | ||
3179 | nesqp = *((struct nes_qp **)&context); | ||
3180 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3181 | nesqp->hw_iwarp_state = iwarp_state; | ||
3182 | nesqp->hw_tcp_state = tcp_state; | ||
3183 | nesqp->last_aeq = async_event_id; | ||
3184 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3185 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_DDP_UBE_INVALID_MSN" | ||
3186 | "_NO_BUFFER_AVAILABLE event on QP%u\n", | ||
3187 | nesqp->hwqp.qp_id); | ||
3188 | if (nesqp->ibqp.event_handler) { | ||
3189 | ibevent.device = nesqp->ibqp.device; | ||
3190 | ibevent.element.qp = &nesqp->ibqp; | ||
3191 | ibevent.event = IB_EVENT_QP_FATAL; | ||
3192 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | ||
3193 | } | ||
3194 | /* tell cm to disconnect, cm will queue work to thread */ | ||
3195 | nes_cm_disconn(nesqp); | ||
3196 | break; | ||
3197 | case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: | ||
3198 | nesqp = *((struct nes_qp **)&context); | ||
3199 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3200 | nesqp->hw_iwarp_state = iwarp_state; | ||
3201 | nesqp->hw_tcp_state = tcp_state; | ||
3202 | nesqp->last_aeq = async_event_id; | ||
3203 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3204 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR" | ||
3205 | " event on QP%u \n Q2 Data:\n", | ||
3206 | nesqp->hwqp.qp_id); | ||
3207 | if (nesqp->ibqp.event_handler) { | ||
3208 | ibevent.device = nesqp->ibqp.device; | ||
3209 | ibevent.element.qp = &nesqp->ibqp; | ||
3210 | ibevent.event = IB_EVENT_QP_FATAL; | ||
3211 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | ||
3212 | } | ||
3213 | /* tell cm to disconnect, cm will queue work to thread */ | ||
3214 | nes_cm_disconn(nesqp); | ||
3215 | break; | ||
3216 | /* TODO: additional AEs need to be here */ | ||
3217 | case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: | ||
3218 | nesqp = *((struct nes_qp **)&context); | ||
3219 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3220 | nesqp->hw_iwarp_state = iwarp_state; | ||
3221 | nesqp->hw_tcp_state = tcp_state; | ||
3222 | nesqp->last_aeq = async_event_id; | ||
3223 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3224 | if (nesqp->ibqp.event_handler) { | ||
3225 | ibevent.device = nesqp->ibqp.device; | ||
3226 | ibevent.element.qp = &nesqp->ibqp; | ||
3227 | ibevent.event = IB_EVENT_QP_ACCESS_ERR; | ||
3228 | nesqp->ibqp.event_handler(&ibevent, | ||
3229 | nesqp->ibqp.qp_context); | ||
3230 | } | ||
3231 | nes_cm_disconn(nesqp); | ||
3232 | break; | ||
3233 | default: | 3541 | default: |
3234 | nes_debug(NES_DBG_AEQ, "Processing an iWARP related AE for QP, misc = 0x%04X\n", | 3542 | nes_debug(NES_DBG_AEQ, "Processing an iWARP related AE for QP, misc = 0x%04X\n", |
3235 | async_event_id); | 3543 | async_event_id); |
@@ -3238,7 +3546,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
3238 | 3546 | ||
3239 | } | 3547 | } |
3240 | 3548 | ||
3241 | |||
3242 | /** | 3549 | /** |
3243 | * nes_iwarp_ce_handler | 3550 | * nes_iwarp_ce_handler |
3244 | */ | 3551 | */ |
@@ -3373,6 +3680,8 @@ void flush_wqes(struct nes_device *nesdev, struct nes_qp *nesqp, | |||
3373 | { | 3680 | { |
3374 | struct nes_cqp_request *cqp_request; | 3681 | struct nes_cqp_request *cqp_request; |
3375 | struct nes_hw_cqp_wqe *cqp_wqe; | 3682 | struct nes_hw_cqp_wqe *cqp_wqe; |
3683 | u32 sq_code = (NES_IWARP_CQE_MAJOR_FLUSH << 16) | NES_IWARP_CQE_MINOR_FLUSH; | ||
3684 | u32 rq_code = (NES_IWARP_CQE_MAJOR_FLUSH << 16) | NES_IWARP_CQE_MINOR_FLUSH; | ||
3376 | int ret; | 3685 | int ret; |
3377 | 3686 | ||
3378 | cqp_request = nes_get_cqp_request(nesdev); | 3687 | cqp_request = nes_get_cqp_request(nesdev); |
@@ -3389,6 +3698,24 @@ void flush_wqes(struct nes_device *nesdev, struct nes_qp *nesqp, | |||
3389 | cqp_wqe = &cqp_request->cqp_wqe; | 3698 | cqp_wqe = &cqp_request->cqp_wqe; |
3390 | nes_fill_init_cqp_wqe(cqp_wqe, nesdev); | 3699 | nes_fill_init_cqp_wqe(cqp_wqe, nesdev); |
3391 | 3700 | ||
3701 | /* If wqe in error was identified, set code to be put into cqe */ | ||
3702 | if ((nesqp->term_sq_flush_code) && (which_wq & NES_CQP_FLUSH_SQ)) { | ||
3703 | which_wq |= NES_CQP_FLUSH_MAJ_MIN; | ||
3704 | sq_code = (CQE_MAJOR_DRV << 16) | nesqp->term_sq_flush_code; | ||
3705 | nesqp->term_sq_flush_code = 0; | ||
3706 | } | ||
3707 | |||
3708 | if ((nesqp->term_rq_flush_code) && (which_wq & NES_CQP_FLUSH_RQ)) { | ||
3709 | which_wq |= NES_CQP_FLUSH_MAJ_MIN; | ||
3710 | rq_code = (CQE_MAJOR_DRV << 16) | nesqp->term_rq_flush_code; | ||
3711 | nesqp->term_rq_flush_code = 0; | ||
3712 | } | ||
3713 | |||
3714 | if (which_wq & NES_CQP_FLUSH_MAJ_MIN) { | ||
3715 | cqp_wqe->wqe_words[NES_CQP_QP_WQE_FLUSH_SQ_CODE] = cpu_to_le32(sq_code); | ||
3716 | cqp_wqe->wqe_words[NES_CQP_QP_WQE_FLUSH_RQ_CODE] = cpu_to_le32(rq_code); | ||
3717 | } | ||
3718 | |||
3392 | cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = | 3719 | cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = |
3393 | cpu_to_le32(NES_CQP_FLUSH_WQES | which_wq); | 3720 | cpu_to_le32(NES_CQP_FLUSH_WQES | which_wq); |
3394 | cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesqp->hwqp.qp_id); | 3721 | cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesqp->hwqp.qp_id); |