Path: blob/master/drivers/infiniband/core/mad_rmpp.c
37212 views
/*1* Copyright (c) 2005 Intel Inc. All rights reserved.2* Copyright (c) 2005-2006 Voltaire, Inc. All rights reserved.3*4* This software is available to you under a choice of one of two5* licenses. You may choose to be licensed under the terms of the GNU6* General Public License (GPL) Version 2, available from the file7* COPYING in the main directory of this source tree, or the8* OpenIB.org BSD license below:9*10* Redistribution and use in source and binary forms, with or11* without modification, are permitted provided that the following12* conditions are met:13*14* - Redistributions of source code must retain the above15* copyright notice, this list of conditions and the following16* disclaimer.17*18* - Redistributions in binary form must reproduce the above19* copyright notice, this list of conditions and the following20* disclaimer in the documentation and/or other materials21* provided with the distribution.22*23* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,24* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF25* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30* SOFTWARE.31*/3233#include <linux/slab.h>3435#include "mad_priv.h"36#include "mad_rmpp.h"3738enum rmpp_state {39RMPP_STATE_ACTIVE,40RMPP_STATE_TIMEOUT,41RMPP_STATE_COMPLETE,42RMPP_STATE_CANCELING43};4445struct mad_rmpp_recv {46struct ib_mad_agent_private *agent;47struct list_head list;48struct delayed_work timeout_work;49struct delayed_work cleanup_work;50struct completion comp;51enum rmpp_state state;52spinlock_t lock;53atomic_t refcount;5455struct ib_ah *ah;56struct ib_mad_recv_wc *rmpp_wc;57struct ib_mad_recv_buf *cur_seg_buf;58int last_ack;59int seg_num;60int newwin;61int repwin;6263__be64 tid;64u32 src_qp;65u16 slid;66u8 mgmt_class;67u8 class_version;68u8 method;69};7071static inline void deref_rmpp_recv(struct mad_rmpp_recv *rmpp_recv)72{73if (atomic_dec_and_test(&rmpp_recv->refcount))74complete(&rmpp_recv->comp);75}7677static void destroy_rmpp_recv(struct mad_rmpp_recv *rmpp_recv)78{79deref_rmpp_recv(rmpp_recv);80wait_for_completion(&rmpp_recv->comp);81ib_destroy_ah(rmpp_recv->ah);82kfree(rmpp_recv);83}8485void ib_cancel_rmpp_recvs(struct ib_mad_agent_private *agent)86{87struct mad_rmpp_recv *rmpp_recv, *temp_rmpp_recv;88unsigned long flags;8990spin_lock_irqsave(&agent->lock, flags);91list_for_each_entry(rmpp_recv, &agent->rmpp_list, list) {92if (rmpp_recv->state != RMPP_STATE_COMPLETE)93ib_free_recv_mad(rmpp_recv->rmpp_wc);94rmpp_recv->state = RMPP_STATE_CANCELING;95}96spin_unlock_irqrestore(&agent->lock, flags);9798list_for_each_entry(rmpp_recv, &agent->rmpp_list, list) {99cancel_delayed_work(&rmpp_recv->timeout_work);100cancel_delayed_work(&rmpp_recv->cleanup_work);101}102103flush_workqueue(agent->qp_info->port_priv->wq);104105list_for_each_entry_safe(rmpp_recv, temp_rmpp_recv,106&agent->rmpp_list, list) {107list_del(&rmpp_recv->list);108destroy_rmpp_recv(rmpp_recv);109}110}111112static void format_ack(struct ib_mad_send_buf *msg,113struct ib_rmpp_mad *data,114struct mad_rmpp_recv *rmpp_recv)115{116struct ib_rmpp_mad *ack = msg->mad;117unsigned long flags;118119memcpy(ack, &data->mad_hdr, msg->hdr_len);120121ack->mad_hdr.method ^= IB_MGMT_METHOD_RESP;122ack->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_ACK;123ib_set_rmpp_flags(&ack->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);124125spin_lock_irqsave(&rmpp_recv->lock, flags);126rmpp_recv->last_ack = rmpp_recv->seg_num;127ack->rmpp_hdr.seg_num = cpu_to_be32(rmpp_recv->seg_num);128ack->rmpp_hdr.paylen_newwin = cpu_to_be32(rmpp_recv->newwin);129spin_unlock_irqrestore(&rmpp_recv->lock, flags);130}131132static void ack_recv(struct mad_rmpp_recv *rmpp_recv,133struct ib_mad_recv_wc *recv_wc)134{135struct ib_mad_send_buf *msg;136int ret, hdr_len;137138hdr_len = ib_get_mad_data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);139msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp,140recv_wc->wc->pkey_index, 1, hdr_len,1410, GFP_KERNEL);142if (IS_ERR(msg))143return;144145format_ack(msg, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, rmpp_recv);146msg->ah = rmpp_recv->ah;147ret = ib_post_send_mad(msg, NULL);148if (ret)149ib_free_send_mad(msg);150}151152static struct ib_mad_send_buf *alloc_response_msg(struct ib_mad_agent *agent,153struct ib_mad_recv_wc *recv_wc)154{155struct ib_mad_send_buf *msg;156struct ib_ah *ah;157int hdr_len;158159ah = ib_create_ah_from_wc(agent->qp->pd, recv_wc->wc,160recv_wc->recv_buf.grh, agent->port_num);161if (IS_ERR(ah))162return (void *) ah;163164hdr_len = ib_get_mad_data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);165msg = ib_create_send_mad(agent, recv_wc->wc->src_qp,166recv_wc->wc->pkey_index, 1,167hdr_len, 0, GFP_KERNEL);168if (IS_ERR(msg))169ib_destroy_ah(ah);170else {171msg->ah = ah;172msg->context[0] = ah;173}174175return msg;176}177178static void ack_ds_ack(struct ib_mad_agent_private *agent,179struct ib_mad_recv_wc *recv_wc)180{181struct ib_mad_send_buf *msg;182struct ib_rmpp_mad *rmpp_mad;183int ret;184185msg = alloc_response_msg(&agent->agent, recv_wc);186if (IS_ERR(msg))187return;188189rmpp_mad = msg->mad;190memcpy(rmpp_mad, recv_wc->recv_buf.mad, msg->hdr_len);191192rmpp_mad->mad_hdr.method ^= IB_MGMT_METHOD_RESP;193ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);194rmpp_mad->rmpp_hdr.seg_num = 0;195rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(1);196197ret = ib_post_send_mad(msg, NULL);198if (ret) {199ib_destroy_ah(msg->ah);200ib_free_send_mad(msg);201}202}203204void ib_rmpp_send_handler(struct ib_mad_send_wc *mad_send_wc)205{206if (mad_send_wc->send_buf->context[0] == mad_send_wc->send_buf->ah)207ib_destroy_ah(mad_send_wc->send_buf->ah);208ib_free_send_mad(mad_send_wc->send_buf);209}210211static void nack_recv(struct ib_mad_agent_private *agent,212struct ib_mad_recv_wc *recv_wc, u8 rmpp_status)213{214struct ib_mad_send_buf *msg;215struct ib_rmpp_mad *rmpp_mad;216int ret;217218msg = alloc_response_msg(&agent->agent, recv_wc);219if (IS_ERR(msg))220return;221222rmpp_mad = msg->mad;223memcpy(rmpp_mad, recv_wc->recv_buf.mad, msg->hdr_len);224225rmpp_mad->mad_hdr.method ^= IB_MGMT_METHOD_RESP;226rmpp_mad->rmpp_hdr.rmpp_version = IB_MGMT_RMPP_VERSION;227rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_ABORT;228ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);229rmpp_mad->rmpp_hdr.rmpp_status = rmpp_status;230rmpp_mad->rmpp_hdr.seg_num = 0;231rmpp_mad->rmpp_hdr.paylen_newwin = 0;232233ret = ib_post_send_mad(msg, NULL);234if (ret) {235ib_destroy_ah(msg->ah);236ib_free_send_mad(msg);237}238}239240static void recv_timeout_handler(struct work_struct *work)241{242struct mad_rmpp_recv *rmpp_recv =243container_of(work, struct mad_rmpp_recv, timeout_work.work);244struct ib_mad_recv_wc *rmpp_wc;245unsigned long flags;246247spin_lock_irqsave(&rmpp_recv->agent->lock, flags);248if (rmpp_recv->state != RMPP_STATE_ACTIVE) {249spin_unlock_irqrestore(&rmpp_recv->agent->lock, flags);250return;251}252rmpp_recv->state = RMPP_STATE_TIMEOUT;253list_del(&rmpp_recv->list);254spin_unlock_irqrestore(&rmpp_recv->agent->lock, flags);255256rmpp_wc = rmpp_recv->rmpp_wc;257nack_recv(rmpp_recv->agent, rmpp_wc, IB_MGMT_RMPP_STATUS_T2L);258destroy_rmpp_recv(rmpp_recv);259ib_free_recv_mad(rmpp_wc);260}261262static void recv_cleanup_handler(struct work_struct *work)263{264struct mad_rmpp_recv *rmpp_recv =265container_of(work, struct mad_rmpp_recv, cleanup_work.work);266unsigned long flags;267268spin_lock_irqsave(&rmpp_recv->agent->lock, flags);269if (rmpp_recv->state == RMPP_STATE_CANCELING) {270spin_unlock_irqrestore(&rmpp_recv->agent->lock, flags);271return;272}273list_del(&rmpp_recv->list);274spin_unlock_irqrestore(&rmpp_recv->agent->lock, flags);275destroy_rmpp_recv(rmpp_recv);276}277278static struct mad_rmpp_recv *279create_rmpp_recv(struct ib_mad_agent_private *agent,280struct ib_mad_recv_wc *mad_recv_wc)281{282struct mad_rmpp_recv *rmpp_recv;283struct ib_mad_hdr *mad_hdr;284285rmpp_recv = kmalloc(sizeof *rmpp_recv, GFP_KERNEL);286if (!rmpp_recv)287return NULL;288289rmpp_recv->ah = ib_create_ah_from_wc(agent->agent.qp->pd,290mad_recv_wc->wc,291mad_recv_wc->recv_buf.grh,292agent->agent.port_num);293if (IS_ERR(rmpp_recv->ah))294goto error;295296rmpp_recv->agent = agent;297init_completion(&rmpp_recv->comp);298INIT_DELAYED_WORK(&rmpp_recv->timeout_work, recv_timeout_handler);299INIT_DELAYED_WORK(&rmpp_recv->cleanup_work, recv_cleanup_handler);300spin_lock_init(&rmpp_recv->lock);301rmpp_recv->state = RMPP_STATE_ACTIVE;302atomic_set(&rmpp_recv->refcount, 1);303304rmpp_recv->rmpp_wc = mad_recv_wc;305rmpp_recv->cur_seg_buf = &mad_recv_wc->recv_buf;306rmpp_recv->newwin = 1;307rmpp_recv->seg_num = 1;308rmpp_recv->last_ack = 0;309rmpp_recv->repwin = 1;310311mad_hdr = &mad_recv_wc->recv_buf.mad->mad_hdr;312rmpp_recv->tid = mad_hdr->tid;313rmpp_recv->src_qp = mad_recv_wc->wc->src_qp;314rmpp_recv->slid = mad_recv_wc->wc->slid;315rmpp_recv->mgmt_class = mad_hdr->mgmt_class;316rmpp_recv->class_version = mad_hdr->class_version;317rmpp_recv->method = mad_hdr->method;318return rmpp_recv;319320error: kfree(rmpp_recv);321return NULL;322}323324static struct mad_rmpp_recv *325find_rmpp_recv(struct ib_mad_agent_private *agent,326struct ib_mad_recv_wc *mad_recv_wc)327{328struct mad_rmpp_recv *rmpp_recv;329struct ib_mad_hdr *mad_hdr = &mad_recv_wc->recv_buf.mad->mad_hdr;330331list_for_each_entry(rmpp_recv, &agent->rmpp_list, list) {332if (rmpp_recv->tid == mad_hdr->tid &&333rmpp_recv->src_qp == mad_recv_wc->wc->src_qp &&334rmpp_recv->slid == mad_recv_wc->wc->slid &&335rmpp_recv->mgmt_class == mad_hdr->mgmt_class &&336rmpp_recv->class_version == mad_hdr->class_version &&337rmpp_recv->method == mad_hdr->method)338return rmpp_recv;339}340return NULL;341}342343static struct mad_rmpp_recv *344acquire_rmpp_recv(struct ib_mad_agent_private *agent,345struct ib_mad_recv_wc *mad_recv_wc)346{347struct mad_rmpp_recv *rmpp_recv;348unsigned long flags;349350spin_lock_irqsave(&agent->lock, flags);351rmpp_recv = find_rmpp_recv(agent, mad_recv_wc);352if (rmpp_recv)353atomic_inc(&rmpp_recv->refcount);354spin_unlock_irqrestore(&agent->lock, flags);355return rmpp_recv;356}357358static struct mad_rmpp_recv *359insert_rmpp_recv(struct ib_mad_agent_private *agent,360struct mad_rmpp_recv *rmpp_recv)361{362struct mad_rmpp_recv *cur_rmpp_recv;363364cur_rmpp_recv = find_rmpp_recv(agent, rmpp_recv->rmpp_wc);365if (!cur_rmpp_recv)366list_add_tail(&rmpp_recv->list, &agent->rmpp_list);367368return cur_rmpp_recv;369}370371static inline int get_last_flag(struct ib_mad_recv_buf *seg)372{373struct ib_rmpp_mad *rmpp_mad;374375rmpp_mad = (struct ib_rmpp_mad *) seg->mad;376return ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_LAST;377}378379static inline int get_seg_num(struct ib_mad_recv_buf *seg)380{381struct ib_rmpp_mad *rmpp_mad;382383rmpp_mad = (struct ib_rmpp_mad *) seg->mad;384return be32_to_cpu(rmpp_mad->rmpp_hdr.seg_num);385}386387static inline struct ib_mad_recv_buf * get_next_seg(struct list_head *rmpp_list,388struct ib_mad_recv_buf *seg)389{390if (seg->list.next == rmpp_list)391return NULL;392393return container_of(seg->list.next, struct ib_mad_recv_buf, list);394}395396static inline int window_size(struct ib_mad_agent_private *agent)397{398return max(agent->qp_info->recv_queue.max_active >> 3, 1);399}400401static struct ib_mad_recv_buf * find_seg_location(struct list_head *rmpp_list,402int seg_num)403{404struct ib_mad_recv_buf *seg_buf;405int cur_seg_num;406407list_for_each_entry_reverse(seg_buf, rmpp_list, list) {408cur_seg_num = get_seg_num(seg_buf);409if (seg_num > cur_seg_num)410return seg_buf;411if (seg_num == cur_seg_num)412break;413}414return NULL;415}416417static void update_seg_num(struct mad_rmpp_recv *rmpp_recv,418struct ib_mad_recv_buf *new_buf)419{420struct list_head *rmpp_list = &rmpp_recv->rmpp_wc->rmpp_list;421422while (new_buf && (get_seg_num(new_buf) == rmpp_recv->seg_num + 1)) {423rmpp_recv->cur_seg_buf = new_buf;424rmpp_recv->seg_num++;425new_buf = get_next_seg(rmpp_list, new_buf);426}427}428429static inline int get_mad_len(struct mad_rmpp_recv *rmpp_recv)430{431struct ib_rmpp_mad *rmpp_mad;432int hdr_size, data_size, pad;433434rmpp_mad = (struct ib_rmpp_mad *)rmpp_recv->cur_seg_buf->mad;435436hdr_size = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class);437data_size = sizeof(struct ib_rmpp_mad) - hdr_size;438pad = IB_MGMT_RMPP_DATA - be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);439if (pad > IB_MGMT_RMPP_DATA || pad < 0)440pad = 0;441442return hdr_size + rmpp_recv->seg_num * data_size - pad;443}444445static struct ib_mad_recv_wc * complete_rmpp(struct mad_rmpp_recv *rmpp_recv)446{447struct ib_mad_recv_wc *rmpp_wc;448449ack_recv(rmpp_recv, rmpp_recv->rmpp_wc);450if (rmpp_recv->seg_num > 1)451cancel_delayed_work(&rmpp_recv->timeout_work);452453rmpp_wc = rmpp_recv->rmpp_wc;454rmpp_wc->mad_len = get_mad_len(rmpp_recv);455/* 10 seconds until we can find the packet lifetime */456queue_delayed_work(rmpp_recv->agent->qp_info->port_priv->wq,457&rmpp_recv->cleanup_work, msecs_to_jiffies(10000));458return rmpp_wc;459}460461static struct ib_mad_recv_wc *462continue_rmpp(struct ib_mad_agent_private *agent,463struct ib_mad_recv_wc *mad_recv_wc)464{465struct mad_rmpp_recv *rmpp_recv;466struct ib_mad_recv_buf *prev_buf;467struct ib_mad_recv_wc *done_wc;468int seg_num;469unsigned long flags;470471rmpp_recv = acquire_rmpp_recv(agent, mad_recv_wc);472if (!rmpp_recv)473goto drop1;474475seg_num = get_seg_num(&mad_recv_wc->recv_buf);476477spin_lock_irqsave(&rmpp_recv->lock, flags);478if ((rmpp_recv->state == RMPP_STATE_TIMEOUT) ||479(seg_num > rmpp_recv->newwin))480goto drop3;481482if ((seg_num <= rmpp_recv->last_ack) ||483(rmpp_recv->state == RMPP_STATE_COMPLETE)) {484spin_unlock_irqrestore(&rmpp_recv->lock, flags);485ack_recv(rmpp_recv, mad_recv_wc);486goto drop2;487}488489prev_buf = find_seg_location(&rmpp_recv->rmpp_wc->rmpp_list, seg_num);490if (!prev_buf)491goto drop3;492493done_wc = NULL;494list_add(&mad_recv_wc->recv_buf.list, &prev_buf->list);495if (rmpp_recv->cur_seg_buf == prev_buf) {496update_seg_num(rmpp_recv, &mad_recv_wc->recv_buf);497if (get_last_flag(rmpp_recv->cur_seg_buf)) {498rmpp_recv->state = RMPP_STATE_COMPLETE;499spin_unlock_irqrestore(&rmpp_recv->lock, flags);500done_wc = complete_rmpp(rmpp_recv);501goto out;502} else if (rmpp_recv->seg_num == rmpp_recv->newwin) {503rmpp_recv->newwin += window_size(agent);504spin_unlock_irqrestore(&rmpp_recv->lock, flags);505ack_recv(rmpp_recv, mad_recv_wc);506goto out;507}508}509spin_unlock_irqrestore(&rmpp_recv->lock, flags);510out:511deref_rmpp_recv(rmpp_recv);512return done_wc;513514drop3: spin_unlock_irqrestore(&rmpp_recv->lock, flags);515drop2: deref_rmpp_recv(rmpp_recv);516drop1: ib_free_recv_mad(mad_recv_wc);517return NULL;518}519520static struct ib_mad_recv_wc *521start_rmpp(struct ib_mad_agent_private *agent,522struct ib_mad_recv_wc *mad_recv_wc)523{524struct mad_rmpp_recv *rmpp_recv;525unsigned long flags;526527rmpp_recv = create_rmpp_recv(agent, mad_recv_wc);528if (!rmpp_recv) {529ib_free_recv_mad(mad_recv_wc);530return NULL;531}532533spin_lock_irqsave(&agent->lock, flags);534if (insert_rmpp_recv(agent, rmpp_recv)) {535spin_unlock_irqrestore(&agent->lock, flags);536/* duplicate first MAD */537destroy_rmpp_recv(rmpp_recv);538return continue_rmpp(agent, mad_recv_wc);539}540atomic_inc(&rmpp_recv->refcount);541542if (get_last_flag(&mad_recv_wc->recv_buf)) {543rmpp_recv->state = RMPP_STATE_COMPLETE;544spin_unlock_irqrestore(&agent->lock, flags);545complete_rmpp(rmpp_recv);546} else {547spin_unlock_irqrestore(&agent->lock, flags);548/* 40 seconds until we can find the packet lifetimes */549queue_delayed_work(agent->qp_info->port_priv->wq,550&rmpp_recv->timeout_work,551msecs_to_jiffies(40000));552rmpp_recv->newwin += window_size(agent);553ack_recv(rmpp_recv, mad_recv_wc);554mad_recv_wc = NULL;555}556deref_rmpp_recv(rmpp_recv);557return mad_recv_wc;558}559560static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr)561{562struct ib_rmpp_mad *rmpp_mad;563int timeout;564u32 paylen = 0;565566rmpp_mad = mad_send_wr->send_buf.mad;567ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);568rmpp_mad->rmpp_hdr.seg_num = cpu_to_be32(++mad_send_wr->seg_num);569570if (mad_send_wr->seg_num == 1) {571rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_FIRST;572paylen = mad_send_wr->send_buf.seg_count * IB_MGMT_RMPP_DATA -573mad_send_wr->pad;574}575576if (mad_send_wr->seg_num == mad_send_wr->send_buf.seg_count) {577rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_LAST;578paylen = IB_MGMT_RMPP_DATA - mad_send_wr->pad;579}580rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen);581582/* 2 seconds for an ACK until we can find the packet lifetime */583timeout = mad_send_wr->send_buf.timeout_ms;584if (!timeout || timeout > 2000)585mad_send_wr->timeout = msecs_to_jiffies(2000);586587return ib_send_mad(mad_send_wr);588}589590static void abort_send(struct ib_mad_agent_private *agent,591struct ib_mad_recv_wc *mad_recv_wc, u8 rmpp_status)592{593struct ib_mad_send_wr_private *mad_send_wr;594struct ib_mad_send_wc wc;595unsigned long flags;596597spin_lock_irqsave(&agent->lock, flags);598mad_send_wr = ib_find_send_mad(agent, mad_recv_wc);599if (!mad_send_wr)600goto out; /* Unmatched send */601602if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) ||603(!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))604goto out; /* Send is already done */605606ib_mark_mad_done(mad_send_wr);607spin_unlock_irqrestore(&agent->lock, flags);608609wc.status = IB_WC_REM_ABORT_ERR;610wc.vendor_err = rmpp_status;611wc.send_buf = &mad_send_wr->send_buf;612ib_mad_complete_send_wr(mad_send_wr, &wc);613return;614out:615spin_unlock_irqrestore(&agent->lock, flags);616}617618static inline void adjust_last_ack(struct ib_mad_send_wr_private *wr,619int seg_num)620{621struct list_head *list;622623wr->last_ack = seg_num;624list = &wr->last_ack_seg->list;625list_for_each_entry(wr->last_ack_seg, list, list)626if (wr->last_ack_seg->num == seg_num)627break;628}629630static void process_ds_ack(struct ib_mad_agent_private *agent,631struct ib_mad_recv_wc *mad_recv_wc, int newwin)632{633struct mad_rmpp_recv *rmpp_recv;634635rmpp_recv = find_rmpp_recv(agent, mad_recv_wc);636if (rmpp_recv && rmpp_recv->state == RMPP_STATE_COMPLETE)637rmpp_recv->repwin = newwin;638}639640static void process_rmpp_ack(struct ib_mad_agent_private *agent,641struct ib_mad_recv_wc *mad_recv_wc)642{643struct ib_mad_send_wr_private *mad_send_wr;644struct ib_rmpp_mad *rmpp_mad;645unsigned long flags;646int seg_num, newwin, ret;647648rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;649if (rmpp_mad->rmpp_hdr.rmpp_status) {650abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);651nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);652return;653}654655seg_num = be32_to_cpu(rmpp_mad->rmpp_hdr.seg_num);656newwin = be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);657if (newwin < seg_num) {658abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S);659nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S);660return;661}662663spin_lock_irqsave(&agent->lock, flags);664mad_send_wr = ib_find_send_mad(agent, mad_recv_wc);665if (!mad_send_wr) {666if (!seg_num)667process_ds_ack(agent, mad_recv_wc, newwin);668goto out; /* Unmatched or DS RMPP ACK */669}670671if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) &&672(mad_send_wr->timeout)) {673spin_unlock_irqrestore(&agent->lock, flags);674ack_ds_ack(agent, mad_recv_wc);675return; /* Repeated ACK for DS RMPP transaction */676}677678if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) ||679(!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))680goto out; /* Send is already done */681682if (seg_num > mad_send_wr->send_buf.seg_count ||683seg_num > mad_send_wr->newwin) {684spin_unlock_irqrestore(&agent->lock, flags);685abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B);686nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B);687return;688}689690if (newwin < mad_send_wr->newwin || seg_num < mad_send_wr->last_ack)691goto out; /* Old ACK */692693if (seg_num > mad_send_wr->last_ack) {694adjust_last_ack(mad_send_wr, seg_num);695mad_send_wr->retries_left = mad_send_wr->max_retries;696}697mad_send_wr->newwin = newwin;698if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) {699/* If no response is expected, the ACK completes the send */700if (!mad_send_wr->send_buf.timeout_ms) {701struct ib_mad_send_wc wc;702703ib_mark_mad_done(mad_send_wr);704spin_unlock_irqrestore(&agent->lock, flags);705706wc.status = IB_WC_SUCCESS;707wc.vendor_err = 0;708wc.send_buf = &mad_send_wr->send_buf;709ib_mad_complete_send_wr(mad_send_wr, &wc);710return;711}712if (mad_send_wr->refcount == 1)713ib_reset_mad_timeout(mad_send_wr,714mad_send_wr->send_buf.timeout_ms);715spin_unlock_irqrestore(&agent->lock, flags);716ack_ds_ack(agent, mad_recv_wc);717return;718} else if (mad_send_wr->refcount == 1 &&719mad_send_wr->seg_num < mad_send_wr->newwin &&720mad_send_wr->seg_num < mad_send_wr->send_buf.seg_count) {721/* Send failure will just result in a timeout/retry */722ret = send_next_seg(mad_send_wr);723if (ret)724goto out;725726mad_send_wr->refcount++;727list_move_tail(&mad_send_wr->agent_list,728&mad_send_wr->mad_agent_priv->send_list);729}730out:731spin_unlock_irqrestore(&agent->lock, flags);732}733734static struct ib_mad_recv_wc *735process_rmpp_data(struct ib_mad_agent_private *agent,736struct ib_mad_recv_wc *mad_recv_wc)737{738struct ib_rmpp_hdr *rmpp_hdr;739u8 rmpp_status;740741rmpp_hdr = &((struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad)->rmpp_hdr;742743if (rmpp_hdr->rmpp_status) {744rmpp_status = IB_MGMT_RMPP_STATUS_BAD_STATUS;745goto bad;746}747748if (rmpp_hdr->seg_num == cpu_to_be32(1)) {749if (!(ib_get_rmpp_flags(rmpp_hdr) & IB_MGMT_RMPP_FLAG_FIRST)) {750rmpp_status = IB_MGMT_RMPP_STATUS_BAD_SEG;751goto bad;752}753return start_rmpp(agent, mad_recv_wc);754} else {755if (ib_get_rmpp_flags(rmpp_hdr) & IB_MGMT_RMPP_FLAG_FIRST) {756rmpp_status = IB_MGMT_RMPP_STATUS_BAD_SEG;757goto bad;758}759return continue_rmpp(agent, mad_recv_wc);760}761bad:762nack_recv(agent, mad_recv_wc, rmpp_status);763ib_free_recv_mad(mad_recv_wc);764return NULL;765}766767static void process_rmpp_stop(struct ib_mad_agent_private *agent,768struct ib_mad_recv_wc *mad_recv_wc)769{770struct ib_rmpp_mad *rmpp_mad;771772rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;773774if (rmpp_mad->rmpp_hdr.rmpp_status != IB_MGMT_RMPP_STATUS_RESX) {775abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);776nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);777} else778abort_send(agent, mad_recv_wc, rmpp_mad->rmpp_hdr.rmpp_status);779}780781static void process_rmpp_abort(struct ib_mad_agent_private *agent,782struct ib_mad_recv_wc *mad_recv_wc)783{784struct ib_rmpp_mad *rmpp_mad;785786rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;787788if (rmpp_mad->rmpp_hdr.rmpp_status < IB_MGMT_RMPP_STATUS_ABORT_MIN ||789rmpp_mad->rmpp_hdr.rmpp_status > IB_MGMT_RMPP_STATUS_ABORT_MAX) {790abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);791nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS);792} else793abort_send(agent, mad_recv_wc, rmpp_mad->rmpp_hdr.rmpp_status);794}795796struct ib_mad_recv_wc *797ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent,798struct ib_mad_recv_wc *mad_recv_wc)799{800struct ib_rmpp_mad *rmpp_mad;801802rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;803if (!(rmpp_mad->rmpp_hdr.rmpp_rtime_flags & IB_MGMT_RMPP_FLAG_ACTIVE))804return mad_recv_wc;805806if (rmpp_mad->rmpp_hdr.rmpp_version != IB_MGMT_RMPP_VERSION) {807abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV);808nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV);809goto out;810}811812switch (rmpp_mad->rmpp_hdr.rmpp_type) {813case IB_MGMT_RMPP_TYPE_DATA:814return process_rmpp_data(agent, mad_recv_wc);815case IB_MGMT_RMPP_TYPE_ACK:816process_rmpp_ack(agent, mad_recv_wc);817break;818case IB_MGMT_RMPP_TYPE_STOP:819process_rmpp_stop(agent, mad_recv_wc);820break;821case IB_MGMT_RMPP_TYPE_ABORT:822process_rmpp_abort(agent, mad_recv_wc);823break;824default:825abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT);826nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT);827break;828}829out:830ib_free_recv_mad(mad_recv_wc);831return NULL;832}833834static int init_newwin(struct ib_mad_send_wr_private *mad_send_wr)835{836struct ib_mad_agent_private *agent = mad_send_wr->mad_agent_priv;837struct ib_mad_hdr *mad_hdr = mad_send_wr->send_buf.mad;838struct mad_rmpp_recv *rmpp_recv;839struct ib_ah_attr ah_attr;840unsigned long flags;841int newwin = 1;842843if (!(mad_hdr->method & IB_MGMT_METHOD_RESP))844goto out;845846spin_lock_irqsave(&agent->lock, flags);847list_for_each_entry(rmpp_recv, &agent->rmpp_list, list) {848if (rmpp_recv->tid != mad_hdr->tid ||849rmpp_recv->mgmt_class != mad_hdr->mgmt_class ||850rmpp_recv->class_version != mad_hdr->class_version ||851(rmpp_recv->method & IB_MGMT_METHOD_RESP))852continue;853854if (ib_query_ah(mad_send_wr->send_buf.ah, &ah_attr))855continue;856857if (rmpp_recv->slid == ah_attr.dlid) {858newwin = rmpp_recv->repwin;859break;860}861}862spin_unlock_irqrestore(&agent->lock, flags);863out:864return newwin;865}866867int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr)868{869struct ib_rmpp_mad *rmpp_mad;870int ret;871872rmpp_mad = mad_send_wr->send_buf.mad;873if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &874IB_MGMT_RMPP_FLAG_ACTIVE))875return IB_RMPP_RESULT_UNHANDLED;876877if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) {878mad_send_wr->seg_num = 1;879return IB_RMPP_RESULT_INTERNAL;880}881882mad_send_wr->newwin = init_newwin(mad_send_wr);883884/* We need to wait for the final ACK even if there isn't a response */885mad_send_wr->refcount += (mad_send_wr->timeout == 0);886ret = send_next_seg(mad_send_wr);887if (!ret)888return IB_RMPP_RESULT_CONSUMED;889return ret;890}891892int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr,893struct ib_mad_send_wc *mad_send_wc)894{895struct ib_rmpp_mad *rmpp_mad;896int ret;897898rmpp_mad = mad_send_wr->send_buf.mad;899if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &900IB_MGMT_RMPP_FLAG_ACTIVE))901return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */902903if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA)904return IB_RMPP_RESULT_INTERNAL; /* ACK, STOP, or ABORT */905906if (mad_send_wc->status != IB_WC_SUCCESS ||907mad_send_wr->status != IB_WC_SUCCESS)908return IB_RMPP_RESULT_PROCESSED; /* Canceled or send error */909910if (!mad_send_wr->timeout)911return IB_RMPP_RESULT_PROCESSED; /* Response received */912913if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) {914mad_send_wr->timeout =915msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms);916return IB_RMPP_RESULT_PROCESSED; /* Send done */917}918919if (mad_send_wr->seg_num == mad_send_wr->newwin ||920mad_send_wr->seg_num == mad_send_wr->send_buf.seg_count)921return IB_RMPP_RESULT_PROCESSED; /* Wait for ACK */922923ret = send_next_seg(mad_send_wr);924if (ret) {925mad_send_wc->status = IB_WC_GENERAL_ERR;926return IB_RMPP_RESULT_PROCESSED;927}928return IB_RMPP_RESULT_CONSUMED;929}930931int ib_retry_rmpp(struct ib_mad_send_wr_private *mad_send_wr)932{933struct ib_rmpp_mad *rmpp_mad;934int ret;935936rmpp_mad = mad_send_wr->send_buf.mad;937if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &938IB_MGMT_RMPP_FLAG_ACTIVE))939return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */940941if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count)942return IB_RMPP_RESULT_PROCESSED;943944mad_send_wr->seg_num = mad_send_wr->last_ack;945mad_send_wr->cur_seg = mad_send_wr->last_ack_seg;946947ret = send_next_seg(mad_send_wr);948if (ret)949return IB_RMPP_RESULT_PROCESSED;950951return IB_RMPP_RESULT_CONSUMED;952}953954955