diff options
| -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 */ |
