diff options
author | Don Wood <donald.e.wood@intel.com> | 2009-09-05 23:36:38 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2009-09-05 23:36:38 -0400 |
commit | 8b1c9dc4ba713985d33aba87c761bf71d5a96491 (patch) | |
tree | 54578c370a52c89a626e6fbbdfc2e12579f47494 /drivers/infiniband/hw | |
parent | 3c28b4457a4cf95e982ca13578a5613a11009394 (diff) |
RDMA/nes: Implement Terminate Packet
Implement the sending and receiving of Terminate packets.
Signed-off-by: Don Wood <donald.e.wood@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw')
-rw-r--r-- | drivers/infiniband/hw/nes/nes.h | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_cm.h | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_hw.c | 701 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_hw.h | 91 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_utils.c | 3 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_verbs.c | 26 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_verbs.h | 7 |
7 files changed, 607 insertions, 225 deletions
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index bf1720f7f35f..bcc6abc4faff 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h | |||
@@ -523,7 +523,7 @@ int nes_cm_disconn(struct nes_qp *); | |||
523 | void nes_cm_disconn_worker(void *); | 523 | void nes_cm_disconn_worker(void *); |
524 | 524 | ||
525 | /* nes_verbs.c */ | 525 | /* nes_verbs.c */ |
526 | int nes_hw_modify_qp(struct nes_device *, struct nes_qp *, u32, u32); | 526 | int nes_hw_modify_qp(struct nes_device *, struct nes_qp *, u32, u32, u32); |
527 | int nes_modify_qp(struct ib_qp *, struct ib_qp_attr *, int, struct ib_udata *); | 527 | int nes_modify_qp(struct ib_qp *, struct ib_qp_attr *, int, struct ib_udata *); |
528 | struct nes_ib_device *nes_init_ofa_device(struct net_device *); | 528 | struct nes_ib_device *nes_init_ofa_device(struct net_device *); |
529 | void nes_destroy_ofa_device(struct nes_ib_device *); | 529 | void nes_destroy_ofa_device(struct nes_ib_device *); |
diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h index 8b7e7c0e496e..90e8e4d8a5ce 100644 --- a/drivers/infiniband/hw/nes/nes_cm.h +++ b/drivers/infiniband/hw/nes/nes_cm.h | |||
@@ -410,8 +410,6 @@ struct nes_cm_ops { | |||
410 | int schedule_nes_timer(struct nes_cm_node *, struct sk_buff *, | 410 | int schedule_nes_timer(struct nes_cm_node *, struct sk_buff *, |
411 | enum nes_timer_type, int, int); | 411 | enum nes_timer_type, int, int); |
412 | 412 | ||
413 | int nes_cm_disconn(struct nes_qp *); | ||
414 | |||
415 | int nes_accept(struct iw_cm_id *, struct iw_cm_conn_param *); | 413 | int nes_accept(struct iw_cm_id *, struct iw_cm_conn_param *); |
416 | int nes_reject(struct iw_cm_id *, const void *, u8); | 414 | int nes_reject(struct iw_cm_id *, const void *, u8); |
417 | int nes_connect(struct iw_cm_id *, struct iw_cm_conn_param *); | 415 | int nes_connect(struct iw_cm_id *, struct iw_cm_conn_param *); |
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 2a0c5a18e139..297026f0c138 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,383 @@ 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 | struct nes_terminate_hdr *termhdr; | ||
2948 | |||
2949 | termhdr = (struct nes_terminate_hdr *)nesqp->hwqp.q2_vbase; | ||
2950 | memset(termhdr, 0, 64); | ||
2951 | |||
2952 | if (aeq_info & NES_AEQE_Q2_DATA_WRITTEN) { | ||
2953 | |||
2954 | /* Use data from offending packet to fill in ddp & rdma hdrs */ | ||
2955 | pkt = locate_mpa(pkt, aeq_info); | ||
2956 | ddp_seg_len = be16_to_cpu(*(u16 *)pkt); | ||
2957 | if (ddp_seg_len) { | ||
2958 | copy_len = 2; | ||
2959 | termhdr->hdrct = DDP_LEN_FLAG; | ||
2960 | if (pkt[2] & 0x80) { | ||
2961 | is_tagged = 1; | ||
2962 | if (ddp_seg_len >= TERM_DDP_LEN_TAGGED) { | ||
2963 | copy_len += TERM_DDP_LEN_TAGGED; | ||
2964 | termhdr->hdrct |= DDP_HDR_FLAG; | ||
2965 | } | ||
2966 | } else { | ||
2967 | if (ddp_seg_len >= TERM_DDP_LEN_UNTAGGED) { | ||
2968 | copy_len += TERM_DDP_LEN_UNTAGGED; | ||
2969 | termhdr->hdrct |= DDP_HDR_FLAG; | ||
2970 | } | ||
2971 | |||
2972 | if (ddp_seg_len >= (TERM_DDP_LEN_UNTAGGED + TERM_RDMA_LEN)) { | ||
2973 | if ((pkt[3] & RDMA_OPCODE_MASK) == RDMA_READ_REQ_OPCODE) { | ||
2974 | copy_len += TERM_RDMA_LEN; | ||
2975 | termhdr->hdrct |= RDMA_HDR_FLAG; | ||
2976 | } | ||
2977 | } | ||
2978 | } | ||
2979 | } | ||
2980 | } | ||
2981 | |||
2982 | switch (async_event_id) { | ||
2983 | case NES_AEQE_AEID_AMP_UNALLOCATED_STAG: | ||
2984 | switch (iwarp_opcode(nesqp, aeq_info)) { | ||
2985 | case IWARP_OPCODE_WRITE: | ||
2986 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; | ||
2987 | termhdr->error_code = DDP_TAGGED_INV_STAG; | ||
2988 | break; | ||
2989 | default: | ||
2990 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
2991 | termhdr->error_code = RDMAP_INV_STAG; | ||
2992 | } | ||
2993 | break; | ||
2994 | case NES_AEQE_AEID_AMP_INVALID_STAG: | ||
2995 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
2996 | termhdr->error_code = RDMAP_INV_STAG; | ||
2997 | break; | ||
2998 | case NES_AEQE_AEID_AMP_BAD_QP: | ||
2999 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; | ||
3000 | termhdr->error_code = DDP_UNTAGGED_INV_QN; | ||
3001 | break; | ||
3002 | case NES_AEQE_AEID_AMP_BAD_STAG_KEY: | ||
3003 | case NES_AEQE_AEID_AMP_BAD_STAG_INDEX: | ||
3004 | switch (iwarp_opcode(nesqp, aeq_info)) { | ||
3005 | case IWARP_OPCODE_SEND_INV: | ||
3006 | case IWARP_OPCODE_SEND_SE_INV: | ||
3007 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; | ||
3008 | termhdr->error_code = RDMAP_CANT_INV_STAG; | ||
3009 | break; | ||
3010 | default: | ||
3011 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
3012 | termhdr->error_code = RDMAP_INV_STAG; | ||
3013 | } | ||
3014 | break; | ||
3015 | case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: | ||
3016 | if (aeq_info & (NES_AEQE_Q2_DATA_ETHERNET | NES_AEQE_Q2_DATA_MPA)) { | ||
3017 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; | ||
3018 | termhdr->error_code = DDP_TAGGED_BOUNDS; | ||
3019 | } else { | ||
3020 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
3021 | termhdr->error_code = RDMAP_INV_BOUNDS; | ||
3022 | } | ||
3023 | break; | ||
3024 | case NES_AEQE_AEID_AMP_RIGHTS_VIOLATION: | ||
3025 | case NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS: | ||
3026 | case NES_AEQE_AEID_PRIV_OPERATION_DENIED: | ||
3027 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
3028 | termhdr->error_code = RDMAP_ACCESS; | ||
3029 | break; | ||
3030 | case NES_AEQE_AEID_AMP_TO_WRAP: | ||
3031 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
3032 | termhdr->error_code = RDMAP_TO_WRAP; | ||
3033 | break; | ||
3034 | case NES_AEQE_AEID_AMP_BAD_PD: | ||
3035 | switch (iwarp_opcode(nesqp, aeq_info)) { | ||
3036 | case IWARP_OPCODE_WRITE: | ||
3037 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; | ||
3038 | termhdr->error_code = DDP_TAGGED_UNASSOC_STAG; | ||
3039 | break; | ||
3040 | case IWARP_OPCODE_SEND_INV: | ||
3041 | case IWARP_OPCODE_SEND_SE_INV: | ||
3042 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
3043 | termhdr->error_code = RDMAP_CANT_INV_STAG; | ||
3044 | break; | ||
3045 | default: | ||
3046 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; | ||
3047 | termhdr->error_code = RDMAP_UNASSOC_STAG; | ||
3048 | } | ||
3049 | break; | ||
3050 | case NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH: | ||
3051 | termhdr->layer_etype = (LAYER_MPA << 4) | DDP_LLP; | ||
3052 | termhdr->error_code = MPA_MARKER; | ||
3053 | break; | ||
3054 | case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: | ||
3055 | termhdr->layer_etype = (LAYER_MPA << 4) | DDP_LLP; | ||
3056 | termhdr->error_code = MPA_CRC; | ||
3057 | break; | ||
3058 | case NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE: | ||
3059 | case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL: | ||
3060 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_CATASTROPHIC; | ||
3061 | termhdr->error_code = DDP_CATASTROPHIC_LOCAL; | ||
3062 | break; | ||
3063 | case NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC: | ||
3064 | case NES_AEQE_AEID_DDP_NO_L_BIT: | ||
3065 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_CATASTROPHIC; | ||
3066 | termhdr->error_code = DDP_CATASTROPHIC_LOCAL; | ||
3067 | break; | ||
3068 | case NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN: | ||
3069 | case NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID: | ||
3070 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; | ||
3071 | termhdr->error_code = DDP_UNTAGGED_INV_MSN_RANGE; | ||
3072 | break; | ||
3073 | case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: | ||
3074 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; | ||
3075 | termhdr->error_code = DDP_UNTAGGED_INV_TOO_LONG; | ||
3076 | break; | ||
3077 | case NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION: | ||
3078 | if (is_tagged) { | ||
3079 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; | ||
3080 | termhdr->error_code = DDP_TAGGED_INV_DDP_VER; | ||
3081 | } else { | ||
3082 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; | ||
3083 | termhdr->error_code = DDP_UNTAGGED_INV_DDP_VER; | ||
3084 | } | ||
3085 | break; | ||
3086 | case NES_AEQE_AEID_DDP_UBE_INVALID_MO: | ||
3087 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; | ||
3088 | termhdr->error_code = DDP_UNTAGGED_INV_MO; | ||
3089 | break; | ||
3090 | case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: | ||
3091 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; | ||
3092 | termhdr->error_code = DDP_UNTAGGED_INV_MSN_NO_BUF; | ||
3093 | break; | ||
3094 | case NES_AEQE_AEID_DDP_UBE_INVALID_QN: | ||
3095 | termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; | ||
3096 | termhdr->error_code = DDP_UNTAGGED_INV_QN; | ||
3097 | break; | ||
3098 | case NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION: | ||
3099 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; | ||
3100 | termhdr->error_code = RDMAP_INV_RDMAP_VER; | ||
3101 | break; | ||
3102 | case NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE: | ||
3103 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; | ||
3104 | termhdr->error_code = RDMAP_UNEXPECTED_OP; | ||
3105 | break; | ||
3106 | default: | ||
3107 | termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; | ||
3108 | termhdr->error_code = RDMAP_UNSPECIFIED; | ||
3109 | break; | ||
3110 | } | ||
3111 | |||
3112 | if (copy_len) | ||
3113 | memcpy(termhdr + 1, pkt, copy_len); | ||
3114 | |||
3115 | return sizeof(struct nes_terminate_hdr) + copy_len; | ||
3116 | } | ||
3117 | |||
3118 | static void nes_terminate_connection(struct nes_device *nesdev, struct nes_qp *nesqp, | ||
3119 | struct nes_hw_aeqe *aeqe, enum ib_event_type eventtype) | ||
3120 | { | ||
3121 | u64 context; | ||
3122 | unsigned long flags; | ||
3123 | u32 aeq_info; | ||
3124 | u16 async_event_id; | ||
3125 | u8 tcp_state; | ||
3126 | u8 iwarp_state; | ||
3127 | u32 termlen = 0; | ||
3128 | u32 mod_qp_flags = NES_CQP_QP_IWARP_STATE_TERMINATE | | ||
3129 | NES_CQP_QP_TERM_DONT_SEND_FIN; | ||
3130 | struct nes_adapter *nesadapter = nesdev->nesadapter; | ||
3131 | |||
3132 | if (nesqp->term_flags & NES_TERM_SENT) | ||
3133 | return; /* Sanity check */ | ||
3134 | |||
3135 | aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); | ||
3136 | tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT; | ||
3137 | iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT; | ||
3138 | async_event_id = (u16)aeq_info; | ||
3139 | |||
3140 | context = (unsigned long)nesadapter->qp_table[le32_to_cpu( | ||
3141 | aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN]; | ||
3142 | if (!context) { | ||
3143 | WARN_ON(!context); | ||
3144 | return; | ||
3145 | } | ||
3146 | |||
3147 | nesqp = (struct nes_qp *)(unsigned long)context; | ||
3148 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3149 | nesqp->hw_iwarp_state = iwarp_state; | ||
3150 | nesqp->hw_tcp_state = tcp_state; | ||
3151 | nesqp->last_aeq = async_event_id; | ||
3152 | nesqp->terminate_eventtype = eventtype; | ||
3153 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3154 | |||
3155 | if (nesadapter->send_term_ok) | ||
3156 | termlen = nes_bld_terminate_hdr(nesqp, async_event_id, aeq_info); | ||
3157 | else | ||
3158 | mod_qp_flags |= NES_CQP_QP_TERM_DONT_SEND_TERM_MSG; | ||
3159 | |||
3160 | nes_terminate_start_timer(nesqp); | ||
3161 | nesqp->term_flags |= NES_TERM_SENT; | ||
3162 | nes_hw_modify_qp(nesdev, nesqp, mod_qp_flags, termlen, 0); | ||
3163 | } | ||
3164 | |||
3165 | static void nes_terminate_send_fin(struct nes_device *nesdev, | ||
3166 | struct nes_qp *nesqp, struct nes_hw_aeqe *aeqe) | ||
3167 | { | ||
3168 | u32 aeq_info; | ||
3169 | u16 async_event_id; | ||
3170 | u8 tcp_state; | ||
3171 | u8 iwarp_state; | ||
3172 | unsigned long flags; | ||
3173 | |||
3174 | aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); | ||
3175 | tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT; | ||
3176 | iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT; | ||
3177 | async_event_id = (u16)aeq_info; | ||
3178 | |||
3179 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3180 | nesqp->hw_iwarp_state = iwarp_state; | ||
3181 | nesqp->hw_tcp_state = tcp_state; | ||
3182 | nesqp->last_aeq = async_event_id; | ||
3183 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3184 | |||
3185 | /* Send the fin only */ | ||
3186 | nes_hw_modify_qp(nesdev, nesqp, NES_CQP_QP_IWARP_STATE_TERMINATE | | ||
3187 | NES_CQP_QP_TERM_DONT_SEND_TERM_MSG, 0, 0); | ||
3188 | } | ||
3189 | |||
3190 | /* Cleanup after a terminate sent or received */ | ||
3191 | static void nes_terminate_done(struct nes_qp *nesqp, int timeout_occurred) | ||
3192 | { | ||
3193 | u32 next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR; | ||
3194 | unsigned long flags; | ||
3195 | struct nes_vnic *nesvnic = to_nesvnic(nesqp->ibqp.device); | ||
3196 | struct nes_device *nesdev = nesvnic->nesdev; | ||
3197 | u8 first_time = 0; | ||
3198 | |||
3199 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3200 | if (nesqp->hte_added) { | ||
3201 | nesqp->hte_added = 0; | ||
3202 | next_iwarp_state |= NES_CQP_QP_DEL_HTE; | ||
3203 | } | ||
3204 | |||
3205 | first_time = (nesqp->term_flags & NES_TERM_DONE) == 0; | ||
3206 | nesqp->term_flags |= NES_TERM_DONE; | ||
3207 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3208 | |||
3209 | /* Make sure we go through this only once */ | ||
3210 | if (first_time) { | ||
3211 | if (timeout_occurred == 0) | ||
3212 | del_timer(&nesqp->terminate_timer); | ||
3213 | else | ||
3214 | next_iwarp_state |= NES_CQP_QP_RESET; | ||
3215 | |||
3216 | nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0); | ||
3217 | nes_cm_disconn(nesqp); | ||
3218 | } | ||
3219 | } | ||
3220 | |||
3221 | static void nes_terminate_received(struct nes_device *nesdev, | ||
3222 | struct nes_qp *nesqp, struct nes_hw_aeqe *aeqe) | ||
3223 | { | ||
3224 | u32 aeq_info; | ||
3225 | u8 *pkt; | ||
3226 | u32 *mpa; | ||
3227 | u8 ddp_ctl; | ||
3228 | u8 rdma_ctl; | ||
3229 | u16 aeq_id = 0; | ||
3230 | |||
3231 | aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); | ||
3232 | if (aeq_info & NES_AEQE_Q2_DATA_WRITTEN) { | ||
3233 | /* Terminate is not a performance path so the silicon */ | ||
3234 | /* did not validate the frame - do it now */ | ||
3235 | pkt = nesqp->hwqp.q2_vbase + BAD_FRAME_OFFSET; | ||
3236 | mpa = (u32 *)locate_mpa(pkt, aeq_info); | ||
3237 | ddp_ctl = (be32_to_cpu(mpa[0]) >> 8) & 0xff; | ||
3238 | rdma_ctl = be32_to_cpu(mpa[0]) & 0xff; | ||
3239 | if ((ddp_ctl & 0xc0) != 0x40) | ||
3240 | aeq_id = NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC; | ||
3241 | else if ((ddp_ctl & 0x03) != 1) | ||
3242 | aeq_id = NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION; | ||
3243 | else if (be32_to_cpu(mpa[2]) != 2) | ||
3244 | aeq_id = NES_AEQE_AEID_DDP_UBE_INVALID_QN; | ||
3245 | else if (be32_to_cpu(mpa[3]) != 1) | ||
3246 | aeq_id = NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN; | ||
3247 | else if (be32_to_cpu(mpa[4]) != 0) | ||
3248 | aeq_id = NES_AEQE_AEID_DDP_UBE_INVALID_MO; | ||
3249 | else if ((rdma_ctl & 0xc0) != 0x40) | ||
3250 | aeq_id = NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION; | ||
3251 | |||
3252 | if (aeq_id) { | ||
3253 | /* Bad terminate recvd - send back a terminate */ | ||
3254 | aeq_info = (aeq_info & 0xffff0000) | aeq_id; | ||
3255 | aeqe->aeqe_words[NES_AEQE_MISC_IDX] = cpu_to_le32(aeq_info); | ||
3256 | nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); | ||
3257 | return; | ||
3258 | } | ||
3259 | } | ||
3260 | |||
3261 | nesqp->term_flags |= NES_TERM_RCVD; | ||
3262 | nesqp->terminate_eventtype = IB_EVENT_QP_FATAL; | ||
3263 | nes_terminate_start_timer(nesqp); | ||
3264 | nes_terminate_send_fin(nesdev, nesqp, aeqe); | ||
3265 | } | ||
3266 | |||
3267 | /* Timeout routine in case terminate fails to complete */ | ||
3268 | static void nes_terminate_timeout(unsigned long context) | ||
3269 | { | ||
3270 | struct nes_qp *nesqp = (struct nes_qp *)(unsigned long)context; | ||
3271 | |||
3272 | nes_terminate_done(nesqp, 1); | ||
3273 | } | ||
3274 | |||
3275 | /* Set a timer in case hw cannot complete the terminate sequence */ | ||
3276 | static void nes_terminate_start_timer(struct nes_qp *nesqp) | ||
3277 | { | ||
3278 | init_timer(&nesqp->terminate_timer); | ||
3279 | nesqp->terminate_timer.function = nes_terminate_timeout; | ||
3280 | nesqp->terminate_timer.expires = jiffies + HZ; | ||
3281 | nesqp->terminate_timer.data = (unsigned long)nesqp; | ||
3282 | add_timer(&nesqp->terminate_timer); | ||
3283 | } | ||
3284 | |||
2906 | /** | 3285 | /** |
2907 | * nes_process_iwarp_aeqe | 3286 | * nes_process_iwarp_aeqe |
2908 | */ | 3287 | */ |
@@ -2910,30 +3289,27 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
2910 | struct nes_hw_aeqe *aeqe) | 3289 | struct nes_hw_aeqe *aeqe) |
2911 | { | 3290 | { |
2912 | u64 context; | 3291 | u64 context; |
2913 | u64 aeqe_context = 0; | ||
2914 | unsigned long flags; | 3292 | unsigned long flags; |
2915 | struct nes_qp *nesqp; | 3293 | struct nes_qp *nesqp; |
2916 | struct nes_hw_cq *hw_cq; | 3294 | struct nes_hw_cq *hw_cq; |
2917 | struct nes_cq *nescq; | 3295 | struct nes_cq *nescq; |
2918 | int resource_allocated; | 3296 | int resource_allocated; |
2919 | /* struct iw_cm_id *cm_id; */ | ||
2920 | struct nes_adapter *nesadapter = nesdev->nesadapter; | 3297 | struct nes_adapter *nesadapter = nesdev->nesadapter; |
2921 | struct ib_event ibevent; | ||
2922 | /* struct iw_cm_event cm_event; */ | ||
2923 | u32 aeq_info; | 3298 | u32 aeq_info; |
2924 | u32 next_iwarp_state = 0; | 3299 | u32 next_iwarp_state = 0; |
2925 | u16 async_event_id; | 3300 | u16 async_event_id; |
2926 | u8 tcp_state; | 3301 | u8 tcp_state; |
2927 | u8 iwarp_state; | 3302 | u8 iwarp_state; |
3303 | int must_disconn = 1; | ||
3304 | int must_terminate = 0; | ||
3305 | struct ib_event ibevent; | ||
2928 | 3306 | ||
2929 | nes_debug(NES_DBG_AEQ, "\n"); | 3307 | nes_debug(NES_DBG_AEQ, "\n"); |
2930 | aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); | 3308 | aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); |
2931 | if ((NES_AEQE_INBOUND_RDMA&aeq_info) || (!(NES_AEQE_QP&aeq_info))) { | 3309 | if ((NES_AEQE_INBOUND_RDMA & aeq_info) || (!(NES_AEQE_QP & aeq_info))) { |
2932 | context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); | 3310 | context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); |
2933 | context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; | 3311 | context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; |
2934 | } else { | 3312 | } else { |
2935 | aeqe_context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); | ||
2936 | aeqe_context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; | ||
2937 | context = (unsigned long)nesadapter->qp_table[le32_to_cpu( | 3313 | context = (unsigned long)nesadapter->qp_table[le32_to_cpu( |
2938 | aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN]; | 3314 | aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN]; |
2939 | BUG_ON(!context); | 3315 | BUG_ON(!context); |
@@ -2950,7 +3326,11 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
2950 | 3326 | ||
2951 | switch (async_event_id) { | 3327 | switch (async_event_id) { |
2952 | case NES_AEQE_AEID_LLP_FIN_RECEIVED: | 3328 | case NES_AEQE_AEID_LLP_FIN_RECEIVED: |
2953 | nesqp = *((struct nes_qp **)&context); | 3329 | nesqp = (struct nes_qp *)(unsigned long)context; |
3330 | |||
3331 | if (nesqp->term_flags) | ||
3332 | return; /* Ignore it, wait for close complete */ | ||
3333 | |||
2954 | if (atomic_inc_return(&nesqp->close_timer_started) == 1) { | 3334 | if (atomic_inc_return(&nesqp->close_timer_started) == 1) { |
2955 | nesqp->cm_id->add_ref(nesqp->cm_id); | 3335 | nesqp->cm_id->add_ref(nesqp->cm_id); |
2956 | schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp, | 3336 | schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp, |
@@ -2961,18 +3341,24 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
2961 | nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), | 3341 | nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), |
2962 | async_event_id, nesqp->last_aeq, tcp_state); | 3342 | async_event_id, nesqp->last_aeq, tcp_state); |
2963 | } | 3343 | } |
3344 | |||
2964 | if ((tcp_state != NES_AEQE_TCP_STATE_CLOSE_WAIT) || | 3345 | if ((tcp_state != NES_AEQE_TCP_STATE_CLOSE_WAIT) || |
2965 | (nesqp->ibqp_state != IB_QPS_RTS)) { | 3346 | (nesqp->ibqp_state != IB_QPS_RTS)) { |
2966 | /* FIN Received but tcp state or IB state moved on, | 3347 | /* FIN Received but tcp state or IB state moved on, |
2967 | should expect a close complete */ | 3348 | should expect a close complete */ |
2968 | return; | 3349 | return; |
2969 | } | 3350 | } |
3351 | |||
2970 | case NES_AEQE_AEID_LLP_CLOSE_COMPLETE: | 3352 | case NES_AEQE_AEID_LLP_CLOSE_COMPLETE: |
3353 | nesqp = (struct nes_qp *)(unsigned long)context; | ||
3354 | if (nesqp->term_flags) { | ||
3355 | nes_terminate_done(nesqp, 0); | ||
3356 | return; | ||
3357 | } | ||
3358 | |||
2971 | case NES_AEQE_AEID_LLP_CONNECTION_RESET: | 3359 | case NES_AEQE_AEID_LLP_CONNECTION_RESET: |
2972 | case NES_AEQE_AEID_TERMINATE_SENT: | ||
2973 | case NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE: | ||
2974 | case NES_AEQE_AEID_RESET_SENT: | 3360 | case NES_AEQE_AEID_RESET_SENT: |
2975 | nesqp = *((struct nes_qp **)&context); | 3361 | nesqp = (struct nes_qp *)(unsigned long)context; |
2976 | if (async_event_id == NES_AEQE_AEID_RESET_SENT) { | 3362 | if (async_event_id == NES_AEQE_AEID_RESET_SENT) { |
2977 | tcp_state = NES_AEQE_TCP_STATE_CLOSED; | 3363 | tcp_state = NES_AEQE_TCP_STATE_CLOSED; |
2978 | } | 3364 | } |
@@ -2984,12 +3370,7 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
2984 | if ((tcp_state == NES_AEQE_TCP_STATE_CLOSED) || | 3370 | if ((tcp_state == NES_AEQE_TCP_STATE_CLOSED) || |
2985 | (tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT)) { | 3371 | (tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT)) { |
2986 | nesqp->hte_added = 0; | 3372 | nesqp->hte_added = 0; |
2987 | spin_unlock_irqrestore(&nesqp->lock, flags); | 3373 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE; |
2988 | nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u to remove hte\n", | ||
2989 | nesqp->hwqp.qp_id); | ||
2990 | nes_hw_modify_qp(nesdev, nesqp, | ||
2991 | NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE, 0); | ||
2992 | spin_lock_irqsave(&nesqp->lock, flags); | ||
2993 | } | 3374 | } |
2994 | 3375 | ||
2995 | if ((nesqp->ibqp_state == IB_QPS_RTS) && | 3376 | if ((nesqp->ibqp_state == IB_QPS_RTS) && |
@@ -3001,151 +3382,106 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
3001 | nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING; | 3382 | nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING; |
3002 | break; | 3383 | break; |
3003 | case NES_AEQE_IWARP_STATE_TERMINATE: | 3384 | case NES_AEQE_IWARP_STATE_TERMINATE: |
3004 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE; | 3385 | must_disconn = 0; /* terminate path takes care of disconn */ |
3005 | nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_TERMINATE; | 3386 | if (nesqp->term_flags == 0) |
3006 | if (async_event_id == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) { | 3387 | must_terminate = 1; |
3007 | next_iwarp_state |= 0x02000000; | ||
3008 | nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; | ||
3009 | } | ||
3010 | break; | 3388 | break; |
3011 | default: | ||
3012 | next_iwarp_state = 0; | ||
3013 | } | ||
3014 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3015 | if (next_iwarp_state) { | ||
3016 | nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X," | ||
3017 | " also added another reference\n", | ||
3018 | nesqp->hwqp.qp_id, next_iwarp_state); | ||
3019 | nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0); | ||
3020 | } | 3389 | } |
3021 | nes_cm_disconn(nesqp); | ||
3022 | } else { | 3390 | } else { |
3023 | if (async_event_id == NES_AEQE_AEID_LLP_FIN_RECEIVED) { | 3391 | if (async_event_id == NES_AEQE_AEID_LLP_FIN_RECEIVED) { |
3024 | /* FIN Received but ib state not RTS, | 3392 | /* FIN Received but ib state not RTS, |
3025 | close complete will be on its way */ | 3393 | close complete will be on its way */ |
3026 | spin_unlock_irqrestore(&nesqp->lock, flags); | 3394 | must_disconn = 0; |
3027 | return; | ||
3028 | } | ||
3029 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3030 | if (async_event_id == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) { | ||
3031 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000; | ||
3032 | nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; | ||
3033 | nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X," | ||
3034 | " also added another reference\n", | ||
3035 | nesqp->hwqp.qp_id, next_iwarp_state); | ||
3036 | nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0); | ||
3037 | } | 3395 | } |
3038 | nes_cm_disconn(nesqp); | ||
3039 | } | 3396 | } |
3040 | break; | ||
3041 | case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED: | ||
3042 | nesqp = *((struct nes_qp **)&context); | ||
3043 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3044 | nesqp->hw_iwarp_state = iwarp_state; | ||
3045 | nesqp->hw_tcp_state = tcp_state; | ||
3046 | nesqp->last_aeq = async_event_id; | ||
3047 | spin_unlock_irqrestore(&nesqp->lock, flags); | 3397 | spin_unlock_irqrestore(&nesqp->lock, flags); |
3048 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TERMINATE_RECEIVED" | 3398 | |
3049 | " event on QP%u \n Q2 Data:\n", | 3399 | if (must_terminate) |
3050 | nesqp->hwqp.qp_id); | 3400 | nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); |
3051 | if (nesqp->ibqp.event_handler) { | 3401 | else if (must_disconn) { |
3052 | ibevent.device = nesqp->ibqp.device; | 3402 | if (next_iwarp_state) { |
3053 | ibevent.element.qp = &nesqp->ibqp; | 3403 | nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X\n", |
3054 | ibevent.event = IB_EVENT_QP_FATAL; | 3404 | nesqp->hwqp.qp_id, next_iwarp_state); |
3055 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | 3405 | nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0); |
3056 | } | 3406 | } |
3057 | if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) || | ||
3058 | ((nesqp->ibqp_state == IB_QPS_RTS)&& | ||
3059 | (async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { | ||
3060 | nes_cm_disconn(nesqp); | 3407 | nes_cm_disconn(nesqp); |
3061 | } else { | ||
3062 | nesqp->in_disconnect = 0; | ||
3063 | wake_up(&nesqp->kick_waitq); | ||
3064 | } | 3408 | } |
3065 | break; | 3409 | break; |
3066 | case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES: | 3410 | |
3067 | nesqp = *((struct nes_qp **)&context); | 3411 | case NES_AEQE_AEID_TERMINATE_SENT: |
3068 | spin_lock_irqsave(&nesqp->lock, flags); | 3412 | nesqp = (struct nes_qp *)(unsigned long)context; |
3069 | nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR; | 3413 | nes_terminate_send_fin(nesdev, nesqp, aeqe); |
3070 | nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; | ||
3071 | nesqp->last_aeq = async_event_id; | ||
3072 | if (nesqp->cm_id) { | ||
3073 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TOO_MANY_RETRIES" | ||
3074 | " event on QP%u, remote IP = 0x%08X \n", | ||
3075 | nesqp->hwqp.qp_id, | ||
3076 | ntohl(nesqp->cm_id->remote_addr.sin_addr.s_addr)); | ||
3077 | } else { | ||
3078 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TOO_MANY_RETRIES" | ||
3079 | " event on QP%u \n", | ||
3080 | nesqp->hwqp.qp_id); | ||
3081 | } | ||
3082 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3083 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_RESET; | ||
3084 | nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0); | ||
3085 | if (nesqp->ibqp.event_handler) { | ||
3086 | ibevent.device = nesqp->ibqp.device; | ||
3087 | ibevent.element.qp = &nesqp->ibqp; | ||
3088 | ibevent.event = IB_EVENT_QP_FATAL; | ||
3089 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | ||
3090 | } | ||
3091 | break; | 3414 | break; |
3092 | case NES_AEQE_AEID_AMP_BAD_STAG_INDEX: | 3415 | |
3093 | if (NES_AEQE_INBOUND_RDMA&aeq_info) { | 3416 | case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED: |
3094 | nesqp = nesadapter->qp_table[le32_to_cpu( | 3417 | nesqp = (struct nes_qp *)(unsigned long)context; |
3095 | aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN]; | 3418 | nes_terminate_received(nesdev, nesqp, aeqe); |
3096 | } else { | ||
3097 | /* TODO: get the actual WQE and mask off wqe index */ | ||
3098 | context &= ~((u64)511); | ||
3099 | nesqp = *((struct nes_qp **)&context); | ||
3100 | } | ||
3101 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3102 | nesqp->hw_iwarp_state = iwarp_state; | ||
3103 | nesqp->hw_tcp_state = tcp_state; | ||
3104 | nesqp->last_aeq = async_event_id; | ||
3105 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3106 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_AMP_BAD_STAG_INDEX event on QP%u\n", | ||
3107 | nesqp->hwqp.qp_id); | ||
3108 | if (nesqp->ibqp.event_handler) { | ||
3109 | ibevent.device = nesqp->ibqp.device; | ||
3110 | ibevent.element.qp = &nesqp->ibqp; | ||
3111 | ibevent.event = IB_EVENT_QP_ACCESS_ERR; | ||
3112 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | ||
3113 | } | ||
3114 | break; | 3419 | break; |
3420 | |||
3421 | case NES_AEQE_AEID_AMP_BAD_STAG_KEY: | ||
3422 | case NES_AEQE_AEID_AMP_BAD_STAG_INDEX: | ||
3115 | case NES_AEQE_AEID_AMP_UNALLOCATED_STAG: | 3423 | case NES_AEQE_AEID_AMP_UNALLOCATED_STAG: |
3116 | nesqp = *((struct nes_qp **)&context); | 3424 | case NES_AEQE_AEID_AMP_INVALID_STAG: |
3117 | spin_lock_irqsave(&nesqp->lock, flags); | 3425 | case NES_AEQE_AEID_AMP_RIGHTS_VIOLATION: |
3118 | nesqp->hw_iwarp_state = iwarp_state; | 3426 | case NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS: |
3119 | nesqp->hw_tcp_state = tcp_state; | ||
3120 | nesqp->last_aeq = async_event_id; | ||
3121 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3122 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_AMP_UNALLOCATED_STAG event on QP%u\n", | ||
3123 | nesqp->hwqp.qp_id); | ||
3124 | if (nesqp->ibqp.event_handler) { | ||
3125 | ibevent.device = nesqp->ibqp.device; | ||
3126 | ibevent.element.qp = &nesqp->ibqp; | ||
3127 | ibevent.event = IB_EVENT_QP_ACCESS_ERR; | ||
3128 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | ||
3129 | } | ||
3130 | break; | ||
3131 | case NES_AEQE_AEID_PRIV_OPERATION_DENIED: | 3427 | case NES_AEQE_AEID_PRIV_OPERATION_DENIED: |
3132 | nesqp = nesadapter->qp_table[le32_to_cpu(aeqe->aeqe_words | 3428 | case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: |
3133 | [NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN]; | 3429 | case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: |
3134 | spin_lock_irqsave(&nesqp->lock, flags); | 3430 | case NES_AEQE_AEID_AMP_TO_WRAP: |
3135 | nesqp->hw_iwarp_state = iwarp_state; | 3431 | nesqp = (struct nes_qp *)(unsigned long)context; |
3136 | nesqp->hw_tcp_state = tcp_state; | 3432 | nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_ACCESS_ERR); |
3137 | nesqp->last_aeq = async_event_id; | 3433 | break; |
3138 | spin_unlock_irqrestore(&nesqp->lock, flags); | 3434 | |
3139 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_PRIV_OPERATION_DENIED event on QP%u," | 3435 | case NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE: |
3140 | " nesqp = %p, AE reported %p\n", | 3436 | case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL: |
3141 | nesqp->hwqp.qp_id, nesqp, *((struct nes_qp **)&context)); | 3437 | case NES_AEQE_AEID_DDP_UBE_INVALID_MO: |
3142 | if (nesqp->ibqp.event_handler) { | 3438 | case NES_AEQE_AEID_DDP_UBE_INVALID_QN: |
3143 | ibevent.device = nesqp->ibqp.device; | 3439 | nesqp = (struct nes_qp *)(unsigned long)context; |
3144 | ibevent.element.qp = &nesqp->ibqp; | 3440 | if (iwarp_opcode(nesqp, aeq_info) > IWARP_OPCODE_TERM) { |
3145 | ibevent.event = IB_EVENT_QP_ACCESS_ERR; | 3441 | aeq_info &= 0xffff0000; |
3146 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | 3442 | aeq_info |= NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE; |
3443 | aeqe->aeqe_words[NES_AEQE_MISC_IDX] = cpu_to_le32(aeq_info); | ||
3147 | } | 3444 | } |
3445 | |||
3446 | case NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE: | ||
3447 | case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES: | ||
3448 | case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: | ||
3449 | case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: | ||
3450 | case NES_AEQE_AEID_AMP_BAD_QP: | ||
3451 | case NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH: | ||
3452 | case NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC: | ||
3453 | case NES_AEQE_AEID_DDP_NO_L_BIT: | ||
3454 | case NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN: | ||
3455 | case NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID: | ||
3456 | case NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION: | ||
3457 | case NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION: | ||
3458 | case NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE: | ||
3459 | case NES_AEQE_AEID_AMP_BAD_PD: | ||
3460 | case NES_AEQE_AEID_AMP_FASTREG_SHARED: | ||
3461 | case NES_AEQE_AEID_AMP_FASTREG_VALID_STAG: | ||
3462 | case NES_AEQE_AEID_AMP_FASTREG_MW_STAG: | ||
3463 | case NES_AEQE_AEID_AMP_FASTREG_INVALID_RIGHTS: | ||
3464 | case NES_AEQE_AEID_AMP_FASTREG_PBL_TABLE_OVERFLOW: | ||
3465 | case NES_AEQE_AEID_AMP_FASTREG_INVALID_LENGTH: | ||
3466 | case NES_AEQE_AEID_AMP_INVALIDATE_SHARED: | ||
3467 | case NES_AEQE_AEID_AMP_INVALIDATE_MR_WITH_BOUND_WINDOWS: | ||
3468 | case NES_AEQE_AEID_AMP_MWBIND_VALID_STAG: | ||
3469 | case NES_AEQE_AEID_AMP_MWBIND_OF_MR_STAG: | ||
3470 | case NES_AEQE_AEID_AMP_MWBIND_TO_ZERO_BASED_STAG: | ||
3471 | case NES_AEQE_AEID_AMP_MWBIND_TO_MW_STAG: | ||
3472 | case NES_AEQE_AEID_AMP_MWBIND_INVALID_RIGHTS: | ||
3473 | case NES_AEQE_AEID_AMP_MWBIND_INVALID_BOUNDS: | ||
3474 | case NES_AEQE_AEID_AMP_MWBIND_TO_INVALID_PARENT: | ||
3475 | case NES_AEQE_AEID_AMP_MWBIND_BIND_DISABLED: | ||
3476 | case NES_AEQE_AEID_BAD_CLOSE: | ||
3477 | case NES_AEQE_AEID_RDMA_READ_WHILE_ORD_ZERO: | ||
3478 | case NES_AEQE_AEID_STAG_ZERO_INVALID: | ||
3479 | case NES_AEQE_AEID_ROE_INVALID_RDMA_READ_REQUEST: | ||
3480 | case NES_AEQE_AEID_ROE_INVALID_RDMA_WRITE_OR_READ_RESP: | ||
3481 | nesqp = (struct nes_qp *)(unsigned long)context; | ||
3482 | nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); | ||
3148 | break; | 3483 | break; |
3484 | |||
3149 | case NES_AEQE_AEID_CQ_OPERATION_ERROR: | 3485 | case NES_AEQE_AEID_CQ_OPERATION_ERROR: |
3150 | context <<= 1; | 3486 | context <<= 1; |
3151 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u, %p\n", | 3487 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u, %p\n", |
@@ -3167,81 +3503,7 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
3167 | } | 3503 | } |
3168 | } | 3504 | } |
3169 | break; | 3505 | break; |
3170 | case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: | 3506 | |
3171 | nesqp = nesadapter->qp_table[le32_to_cpu( | ||
3172 | aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN]; | ||
3173 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3174 | nesqp->hw_iwarp_state = iwarp_state; | ||
3175 | nesqp->hw_tcp_state = tcp_state; | ||
3176 | nesqp->last_aeq = async_event_id; | ||
3177 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3178 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG" | ||
3179 | "_FOR_AVAILABLE_BUFFER event on QP%u\n", | ||
3180 | nesqp->hwqp.qp_id); | ||
3181 | if (nesqp->ibqp.event_handler) { | ||
3182 | ibevent.device = nesqp->ibqp.device; | ||
3183 | ibevent.element.qp = &nesqp->ibqp; | ||
3184 | ibevent.event = IB_EVENT_QP_ACCESS_ERR; | ||
3185 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | ||
3186 | } | ||
3187 | /* tell cm to disconnect, cm will queue work to thread */ | ||
3188 | nes_cm_disconn(nesqp); | ||
3189 | break; | ||
3190 | case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: | ||
3191 | nesqp = *((struct nes_qp **)&context); | ||
3192 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3193 | nesqp->hw_iwarp_state = iwarp_state; | ||
3194 | nesqp->hw_tcp_state = tcp_state; | ||
3195 | nesqp->last_aeq = async_event_id; | ||
3196 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3197 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_DDP_UBE_INVALID_MSN" | ||
3198 | "_NO_BUFFER_AVAILABLE event on QP%u\n", | ||
3199 | nesqp->hwqp.qp_id); | ||
3200 | if (nesqp->ibqp.event_handler) { | ||
3201 | ibevent.device = nesqp->ibqp.device; | ||
3202 | ibevent.element.qp = &nesqp->ibqp; | ||
3203 | ibevent.event = IB_EVENT_QP_FATAL; | ||
3204 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | ||
3205 | } | ||
3206 | /* tell cm to disconnect, cm will queue work to thread */ | ||
3207 | nes_cm_disconn(nesqp); | ||
3208 | break; | ||
3209 | case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: | ||
3210 | nesqp = *((struct nes_qp **)&context); | ||
3211 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3212 | nesqp->hw_iwarp_state = iwarp_state; | ||
3213 | nesqp->hw_tcp_state = tcp_state; | ||
3214 | nesqp->last_aeq = async_event_id; | ||
3215 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3216 | nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR" | ||
3217 | " event on QP%u \n Q2 Data:\n", | ||
3218 | nesqp->hwqp.qp_id); | ||
3219 | if (nesqp->ibqp.event_handler) { | ||
3220 | ibevent.device = nesqp->ibqp.device; | ||
3221 | ibevent.element.qp = &nesqp->ibqp; | ||
3222 | ibevent.event = IB_EVENT_QP_FATAL; | ||
3223 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | ||
3224 | } | ||
3225 | /* tell cm to disconnect, cm will queue work to thread */ | ||
3226 | nes_cm_disconn(nesqp); | ||
3227 | break; | ||
3228 | /* TODO: additional AEs need to be here */ | ||
3229 | case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: | ||
3230 | nesqp = *((struct nes_qp **)&context); | ||
3231 | spin_lock_irqsave(&nesqp->lock, flags); | ||
3232 | nesqp->hw_iwarp_state = iwarp_state; | ||
3233 | nesqp->hw_tcp_state = tcp_state; | ||
3234 | nesqp->last_aeq = async_event_id; | ||
3235 | spin_unlock_irqrestore(&nesqp->lock, flags); | ||
3236 | if (nesqp->ibqp.event_handler) { | ||
3237 | ibevent.device = nesqp->ibqp.device; | ||
3238 | ibevent.element.qp = &nesqp->ibqp; | ||
3239 | ibevent.event = IB_EVENT_QP_ACCESS_ERR; | ||
3240 | nesqp->ibqp.event_handler(&ibevent, | ||
3241 | nesqp->ibqp.qp_context); | ||
3242 | } | ||
3243 | nes_cm_disconn(nesqp); | ||
3244 | break; | ||
3245 | default: | 3507 | default: |
3246 | nes_debug(NES_DBG_AEQ, "Processing an iWARP related AE for QP, misc = 0x%04X\n", | 3508 | nes_debug(NES_DBG_AEQ, "Processing an iWARP related AE for QP, misc = 0x%04X\n", |
3247 | async_event_id); | 3509 | async_event_id); |
@@ -3250,7 +3512,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
3250 | 3512 | ||
3251 | } | 3513 | } |
3252 | 3514 | ||
3253 | |||
3254 | /** | 3515 | /** |
3255 | * nes_iwarp_ce_handler | 3516 | * nes_iwarp_ce_handler |
3256 | */ | 3517 | */ |
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index c3654c6383fe..4a0bfcd5a628 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h | |||
@@ -241,6 +241,7 @@ enum nes_cqp_stag_wqeword_idx { | |||
241 | }; | 241 | }; |
242 | 242 | ||
243 | #define NES_CQP_OP_IWARP_STATE_SHIFT 28 | 243 | #define NES_CQP_OP_IWARP_STATE_SHIFT 28 |
244 | #define NES_CQP_OP_TERMLEN_SHIFT 28 | ||
244 | 245 | ||
245 | enum nes_cqp_qp_bits { | 246 | enum nes_cqp_qp_bits { |
246 | NES_CQP_QP_ARP_VALID = (1<<8), | 247 | NES_CQP_QP_ARP_VALID = (1<<8), |
@@ -265,6 +266,8 @@ enum nes_cqp_qp_bits { | |||
265 | NES_CQP_QP_IWARP_STATE_TERMINATE = (5<<NES_CQP_OP_IWARP_STATE_SHIFT), | 266 | NES_CQP_QP_IWARP_STATE_TERMINATE = (5<<NES_CQP_OP_IWARP_STATE_SHIFT), |
266 | NES_CQP_QP_IWARP_STATE_ERROR = (6<<NES_CQP_OP_IWARP_STATE_SHIFT), | 267 | NES_CQP_QP_IWARP_STATE_ERROR = (6<<NES_CQP_OP_IWARP_STATE_SHIFT), |
267 | NES_CQP_QP_IWARP_STATE_MASK = (7<<NES_CQP_OP_IWARP_STATE_SHIFT), | 268 | NES_CQP_QP_IWARP_STATE_MASK = (7<<NES_CQP_OP_IWARP_STATE_SHIFT), |
269 | NES_CQP_QP_TERM_DONT_SEND_FIN = (1<<24), | ||
270 | NES_CQP_QP_TERM_DONT_SEND_TERM_MSG = (1<<25), | ||
268 | NES_CQP_QP_RESET = (1<<31), | 271 | NES_CQP_QP_RESET = (1<<31), |
269 | }; | 272 | }; |
270 | 273 | ||
@@ -633,11 +636,14 @@ enum nes_aeqe_bits { | |||
633 | NES_AEQE_INBOUND_RDMA = (1<<19), | 636 | NES_AEQE_INBOUND_RDMA = (1<<19), |
634 | NES_AEQE_IWARP_STATE_MASK = (7<<20), | 637 | NES_AEQE_IWARP_STATE_MASK = (7<<20), |
635 | NES_AEQE_TCP_STATE_MASK = (0xf<<24), | 638 | NES_AEQE_TCP_STATE_MASK = (0xf<<24), |
639 | NES_AEQE_Q2_DATA_WRITTEN = (0x3<<28), | ||
636 | NES_AEQE_VALID = (1<<31), | 640 | NES_AEQE_VALID = (1<<31), |
637 | }; | 641 | }; |
638 | 642 | ||
639 | #define NES_AEQE_IWARP_STATE_SHIFT 20 | 643 | #define NES_AEQE_IWARP_STATE_SHIFT 20 |
640 | #define NES_AEQE_TCP_STATE_SHIFT 24 | 644 | #define NES_AEQE_TCP_STATE_SHIFT 24 |
645 | #define NES_AEQE_Q2_DATA_ETHERNET (1<<28) | ||
646 | #define NES_AEQE_Q2_DATA_MPA (1<<29) | ||
641 | 647 | ||
642 | enum nes_aeqe_iwarp_state { | 648 | enum nes_aeqe_iwarp_state { |
643 | NES_AEQE_IWARP_STATE_NON_EXISTANT = 0, | 649 | NES_AEQE_IWARP_STATE_NON_EXISTANT = 0, |
@@ -1119,6 +1125,7 @@ struct nes_adapter { | |||
1119 | u8 netdev_max; /* from host nic address count in EEPROM */ | 1125 | u8 netdev_max; /* from host nic address count in EEPROM */ |
1120 | u8 port_count; | 1126 | u8 port_count; |
1121 | u8 virtwq; | 1127 | u8 virtwq; |
1128 | u8 send_term_ok; | ||
1122 | u8 et_use_adaptive_rx_coalesce; | 1129 | u8 et_use_adaptive_rx_coalesce; |
1123 | u8 adapter_fcn_count; | 1130 | u8 adapter_fcn_count; |
1124 | u8 pft_mcast_map[NES_PFT_SIZE]; | 1131 | u8 pft_mcast_map[NES_PFT_SIZE]; |
@@ -1217,6 +1224,90 @@ struct nes_ib_device { | |||
1217 | u32 num_pd; | 1224 | u32 num_pd; |
1218 | }; | 1225 | }; |
1219 | 1226 | ||
1227 | enum nes_hdrct_flags { | ||
1228 | DDP_LEN_FLAG = 0x80, | ||
1229 | DDP_HDR_FLAG = 0x40, | ||
1230 | RDMA_HDR_FLAG = 0x20 | ||
1231 | }; | ||
1232 | |||
1233 | enum nes_term_layers { | ||
1234 | LAYER_RDMA = 0, | ||
1235 | LAYER_DDP = 1, | ||
1236 | LAYER_MPA = 2 | ||
1237 | }; | ||
1238 | |||
1239 | enum nes_term_error_types { | ||
1240 | RDMAP_CATASTROPHIC = 0, | ||
1241 | RDMAP_REMOTE_PROT = 1, | ||
1242 | RDMAP_REMOTE_OP = 2, | ||
1243 | DDP_CATASTROPHIC = 0, | ||
1244 | DDP_TAGGED_BUFFER = 1, | ||
1245 | DDP_UNTAGGED_BUFFER = 2, | ||
1246 | DDP_LLP = 3 | ||
1247 | }; | ||
1248 | |||
1249 | enum nes_term_rdma_errors { | ||
1250 | RDMAP_INV_STAG = 0x00, | ||
1251 | RDMAP_INV_BOUNDS = 0x01, | ||
1252 | RDMAP_ACCESS = 0x02, | ||
1253 | RDMAP_UNASSOC_STAG = 0x03, | ||
1254 | RDMAP_TO_WRAP = 0x04, | ||
1255 | RDMAP_INV_RDMAP_VER = 0x05, | ||
1256 | RDMAP_UNEXPECTED_OP = 0x06, | ||
1257 | RDMAP_CATASTROPHIC_LOCAL = 0x07, | ||
1258 | RDMAP_CATASTROPHIC_GLOBAL = 0x08, | ||
1259 | RDMAP_CANT_INV_STAG = 0x09, | ||
1260 | RDMAP_UNSPECIFIED = 0xff | ||
1261 | }; | ||
1262 | |||
1263 | enum nes_term_ddp_errors { | ||
1264 | DDP_CATASTROPHIC_LOCAL = 0x00, | ||
1265 | DDP_TAGGED_INV_STAG = 0x00, | ||
1266 | DDP_TAGGED_BOUNDS = 0x01, | ||
1267 | DDP_TAGGED_UNASSOC_STAG = 0x02, | ||
1268 | DDP_TAGGED_TO_WRAP = 0x03, | ||
1269 | DDP_TAGGED_INV_DDP_VER = 0x04, | ||
1270 | DDP_UNTAGGED_INV_QN = 0x01, | ||
1271 | DDP_UNTAGGED_INV_MSN_NO_BUF = 0x02, | ||
1272 | DDP_UNTAGGED_INV_MSN_RANGE = 0x03, | ||
1273 | DDP_UNTAGGED_INV_MO = 0x04, | ||
1274 | DDP_UNTAGGED_INV_TOO_LONG = 0x05, | ||
1275 | DDP_UNTAGGED_INV_DDP_VER = 0x06 | ||
1276 | }; | ||
1277 | |||
1278 | enum nes_term_mpa_errors { | ||
1279 | MPA_CLOSED = 0x01, | ||
1280 | MPA_CRC = 0x02, | ||
1281 | MPA_MARKER = 0x03, | ||
1282 | MPA_REQ_RSP = 0x04, | ||
1283 | }; | ||
1284 | |||
1285 | struct nes_terminate_hdr { | ||
1286 | u8 layer_etype; | ||
1287 | u8 error_code; | ||
1288 | u8 hdrct; | ||
1289 | u8 rsvd; | ||
1290 | }; | ||
1291 | |||
1292 | /* Used to determine how to fill in terminate error codes */ | ||
1293 | #define IWARP_OPCODE_WRITE 0 | ||
1294 | #define IWARP_OPCODE_READREQ 1 | ||
1295 | #define IWARP_OPCODE_READRSP 2 | ||
1296 | #define IWARP_OPCODE_SEND 3 | ||
1297 | #define IWARP_OPCODE_SEND_INV 4 | ||
1298 | #define IWARP_OPCODE_SEND_SE 5 | ||
1299 | #define IWARP_OPCODE_SEND_SE_INV 6 | ||
1300 | #define IWARP_OPCODE_TERM 7 | ||
1301 | |||
1302 | /* These values are used only during terminate processing */ | ||
1303 | #define TERM_DDP_LEN_TAGGED 14 | ||
1304 | #define TERM_DDP_LEN_UNTAGGED 18 | ||
1305 | #define TERM_RDMA_LEN 28 | ||
1306 | #define RDMA_OPCODE_MASK 0x0f | ||
1307 | #define RDMA_READ_REQ_OPCODE 1 | ||
1308 | #define BAD_FRAME_OFFSET 64 | ||
1309 | #define CQE_MAJOR_DRV 0x8000 | ||
1310 | |||
1220 | #define nes_vlan_rx vlan_hwaccel_receive_skb | 1311 | #define nes_vlan_rx vlan_hwaccel_receive_skb |
1221 | #define nes_netif_rx netif_receive_skb | 1312 | #define nes_netif_rx netif_receive_skb |
1222 | 1313 | ||
diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c index b34072b04377..9687c397ce1a 100644 --- a/drivers/infiniband/hw/nes/nes_utils.c +++ b/drivers/infiniband/hw/nes/nes_utils.c | |||
@@ -183,6 +183,9 @@ int nes_read_eeprom_values(struct nes_device *nesdev, struct nes_adapter *nesada | |||
183 | } else if (((major_ver == 2) && (minor_ver > 21)) || ((major_ver > 2) && (major_ver != 255))) { | 183 | } else if (((major_ver == 2) && (minor_ver > 21)) || ((major_ver > 2) && (major_ver != 255))) { |
184 | nesadapter->virtwq = 1; | 184 | nesadapter->virtwq = 1; |
185 | } | 185 | } |
186 | if (((major_ver == 3) && (minor_ver >= 16)) || (major_ver > 3)) | ||
187 | nesadapter->send_term_ok = 1; | ||
188 | |||
186 | nesadapter->firmware_version = (((u32)(u8)(eeprom_data>>8)) << 16) + | 189 | nesadapter->firmware_version = (((u32)(u8)(eeprom_data>>8)) << 16) + |
187 | (u32)((u8)eeprom_data); | 190 | (u32)((u8)eeprom_data); |
188 | 191 | ||
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index c6b5873416eb..36666ac2f546 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c | |||
@@ -2923,7 +2923,7 @@ static int nes_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
2923 | * nes_hw_modify_qp | 2923 | * nes_hw_modify_qp |
2924 | */ | 2924 | */ |
2925 | int nes_hw_modify_qp(struct nes_device *nesdev, struct nes_qp *nesqp, | 2925 | int nes_hw_modify_qp(struct nes_device *nesdev, struct nes_qp *nesqp, |
2926 | u32 next_iwarp_state, u32 wait_completion) | 2926 | u32 next_iwarp_state, u32 termlen, u32 wait_completion) |
2927 | { | 2927 | { |
2928 | struct nes_hw_cqp_wqe *cqp_wqe; | 2928 | struct nes_hw_cqp_wqe *cqp_wqe; |
2929 | /* struct iw_cm_id *cm_id = nesqp->cm_id; */ | 2929 | /* struct iw_cm_id *cm_id = nesqp->cm_id; */ |
@@ -2955,6 +2955,13 @@ int nes_hw_modify_qp(struct nes_device *nesdev, struct nes_qp *nesqp, | |||
2955 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id); | 2955 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id); |
2956 | set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, (u64)nesqp->nesqp_context_pbase); | 2956 | set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, (u64)nesqp->nesqp_context_pbase); |
2957 | 2957 | ||
2958 | /* If sending a terminate message, fill in the length (in words) */ | ||
2959 | if (((next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK) == NES_CQP_QP_IWARP_STATE_TERMINATE) && | ||
2960 | !(next_iwarp_state & NES_CQP_QP_TERM_DONT_SEND_TERM_MSG)) { | ||
2961 | termlen = ((termlen + 3) >> 2) << NES_CQP_OP_TERMLEN_SHIFT; | ||
2962 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_NEW_MSS_IDX, termlen); | ||
2963 | } | ||
2964 | |||
2958 | atomic_set(&cqp_request->refcount, 2); | 2965 | atomic_set(&cqp_request->refcount, 2); |
2959 | nes_post_cqp_request(nesdev, cqp_request); | 2966 | nes_post_cqp_request(nesdev, cqp_request); |
2960 | 2967 | ||
@@ -3125,6 +3132,9 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
3125 | } | 3132 | } |
3126 | nes_debug(NES_DBG_MOD_QP, "QP%u: new state = error\n", | 3133 | nes_debug(NES_DBG_MOD_QP, "QP%u: new state = error\n", |
3127 | nesqp->hwqp.qp_id); | 3134 | nesqp->hwqp.qp_id); |
3135 | if (nesqp->term_flags) | ||
3136 | del_timer(&nesqp->terminate_timer); | ||
3137 | |||
3128 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR; | 3138 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR; |
3129 | /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */ | 3139 | /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */ |
3130 | if (nesqp->hte_added) { | 3140 | if (nesqp->hte_added) { |
@@ -3202,7 +3212,7 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
3202 | 3212 | ||
3203 | if (issue_modify_qp) { | 3213 | if (issue_modify_qp) { |
3204 | nes_debug(NES_DBG_MOD_QP, "call nes_hw_modify_qp\n"); | 3214 | nes_debug(NES_DBG_MOD_QP, "call nes_hw_modify_qp\n"); |
3205 | ret = nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 1); | 3215 | ret = nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 1); |
3206 | if (ret) | 3216 | if (ret) |
3207 | nes_debug(NES_DBG_MOD_QP, "nes_hw_modify_qp (next_iwarp_state = 0x%08X)" | 3217 | nes_debug(NES_DBG_MOD_QP, "nes_hw_modify_qp (next_iwarp_state = 0x%08X)" |
3208 | " failed for QP%u.\n", | 3218 | " failed for QP%u.\n", |
@@ -3367,6 +3377,12 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr, | |||
3367 | head = nesqp->hwqp.sq_head; | 3377 | head = nesqp->hwqp.sq_head; |
3368 | 3378 | ||
3369 | while (ib_wr) { | 3379 | while (ib_wr) { |
3380 | /* Check for QP error */ | ||
3381 | if (nesqp->term_flags) { | ||
3382 | err = -EINVAL; | ||
3383 | break; | ||
3384 | } | ||
3385 | |||
3370 | /* Check for SQ overflow */ | 3386 | /* Check for SQ overflow */ |
3371 | if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) { | 3387 | if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) { |
3372 | err = -EINVAL; | 3388 | err = -EINVAL; |
@@ -3523,6 +3539,12 @@ static int nes_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr, | |||
3523 | head = nesqp->hwqp.rq_head; | 3539 | head = nesqp->hwqp.rq_head; |
3524 | 3540 | ||
3525 | while (ib_wr) { | 3541 | while (ib_wr) { |
3542 | /* Check for QP error */ | ||
3543 | if (nesqp->term_flags) { | ||
3544 | err = -EINVAL; | ||
3545 | break; | ||
3546 | } | ||
3547 | |||
3526 | if (ib_wr->num_sge > nesdev->nesadapter->max_sge) { | 3548 | if (ib_wr->num_sge > nesdev->nesadapter->max_sge) { |
3527 | err = -EINVAL; | 3549 | err = -EINVAL; |
3528 | break; | 3550 | break; |
diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h index 7df34fea2888..d92b1ef4653b 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.h +++ b/drivers/infiniband/hw/nes/nes_verbs.h | |||
@@ -40,6 +40,10 @@ struct nes_device; | |||
40 | #define NES_MAX_USER_DB_REGIONS 4096 | 40 | #define NES_MAX_USER_DB_REGIONS 4096 |
41 | #define NES_MAX_USER_WQ_REGIONS 4096 | 41 | #define NES_MAX_USER_WQ_REGIONS 4096 |
42 | 42 | ||
43 | #define NES_TERM_SENT 0x01 | ||
44 | #define NES_TERM_RCVD 0x02 | ||
45 | #define NES_TERM_DONE 0x04 | ||
46 | |||
43 | struct nes_ucontext { | 47 | struct nes_ucontext { |
44 | struct ib_ucontext ibucontext; | 48 | struct ib_ucontext ibucontext; |
45 | struct nes_device *nesdev; | 49 | struct nes_device *nesdev; |
@@ -159,6 +163,8 @@ struct nes_qp { | |||
159 | void *pbl_vbase; | 163 | void *pbl_vbase; |
160 | dma_addr_t pbl_pbase; | 164 | dma_addr_t pbl_pbase; |
161 | struct page *page; | 165 | struct page *page; |
166 | struct timer_list terminate_timer; | ||
167 | enum ib_event_type terminate_eventtype; | ||
162 | wait_queue_head_t kick_waitq; | 168 | wait_queue_head_t kick_waitq; |
163 | u16 in_disconnect; | 169 | u16 in_disconnect; |
164 | u16 private_data_len; | 170 | u16 private_data_len; |
@@ -169,6 +175,7 @@ struct nes_qp { | |||
169 | u8 hw_iwarp_state; | 175 | u8 hw_iwarp_state; |
170 | u8 flush_issued; | 176 | u8 flush_issued; |
171 | u8 hw_tcp_state; | 177 | u8 hw_tcp_state; |
178 | u8 term_flags; | ||
172 | u8 destroyed; | 179 | u8 destroyed; |
173 | }; | 180 | }; |
174 | #endif /* NES_VERBS_H */ | 181 | #endif /* NES_VERBS_H */ |