Path: blob/master/drivers/infiniband/hw/qib/qib_uc.c
15112 views
/*1* Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.2* All rights reserved.3* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.4*5* This software is available to you under a choice of one of two6* licenses. You may choose to be licensed under the terms of the GNU7* General Public License (GPL) Version 2, available from the file8* COPYING in the main directory of this source tree, or the9* OpenIB.org BSD license below:10*11* Redistribution and use in source and binary forms, with or12* without modification, are permitted provided that the following13* conditions are met:14*15* - Redistributions of source code must retain the above16* copyright notice, this list of conditions and the following17* disclaimer.18*19* - Redistributions in binary form must reproduce the above20* copyright notice, this list of conditions and the following21* disclaimer in the documentation and/or other materials22* provided with the distribution.23*24* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,25* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF26* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND27* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS28* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN29* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN30* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE31* SOFTWARE.32*/3334#include "qib.h"3536/* cut down ridiculously long IB macro names */37#define OP(x) IB_OPCODE_UC_##x3839/**40* qib_make_uc_req - construct a request packet (SEND, RDMA write)41* @qp: a pointer to the QP42*43* Return 1 if constructed; otherwise, return 0.44*/45int qib_make_uc_req(struct qib_qp *qp)46{47struct qib_other_headers *ohdr;48struct qib_swqe *wqe;49unsigned long flags;50u32 hwords;51u32 bth0;52u32 len;53u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);54int ret = 0;5556spin_lock_irqsave(&qp->s_lock, flags);5758if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_SEND_OK)) {59if (!(ib_qib_state_ops[qp->state] & QIB_FLUSH_SEND))60goto bail;61/* We are in the error state, flush the work request. */62if (qp->s_last == qp->s_head)63goto bail;64/* If DMAs are in progress, we can't flush immediately. */65if (atomic_read(&qp->s_dma_busy)) {66qp->s_flags |= QIB_S_WAIT_DMA;67goto bail;68}69wqe = get_swqe_ptr(qp, qp->s_last);70qib_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);71goto done;72}7374ohdr = &qp->s_hdr.u.oth;75if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)76ohdr = &qp->s_hdr.u.l.oth;7778/* header size in 32-bit words LRH+BTH = (8+12)/4. */79hwords = 5;80bth0 = 0;8182/* Get the next send request. */83wqe = get_swqe_ptr(qp, qp->s_cur);84qp->s_wqe = NULL;85switch (qp->s_state) {86default:87if (!(ib_qib_state_ops[qp->state] &88QIB_PROCESS_NEXT_SEND_OK))89goto bail;90/* Check if send work queue is empty. */91if (qp->s_cur == qp->s_head)92goto bail;93/*94* Start a new request.95*/96wqe->psn = qp->s_next_psn;97qp->s_psn = qp->s_next_psn;98qp->s_sge.sge = wqe->sg_list[0];99qp->s_sge.sg_list = wqe->sg_list + 1;100qp->s_sge.num_sge = wqe->wr.num_sge;101qp->s_sge.total_len = wqe->length;102len = wqe->length;103qp->s_len = len;104switch (wqe->wr.opcode) {105case IB_WR_SEND:106case IB_WR_SEND_WITH_IMM:107if (len > pmtu) {108qp->s_state = OP(SEND_FIRST);109len = pmtu;110break;111}112if (wqe->wr.opcode == IB_WR_SEND)113qp->s_state = OP(SEND_ONLY);114else {115qp->s_state =116OP(SEND_ONLY_WITH_IMMEDIATE);117/* Immediate data comes after the BTH */118ohdr->u.imm_data = wqe->wr.ex.imm_data;119hwords += 1;120}121if (wqe->wr.send_flags & IB_SEND_SOLICITED)122bth0 |= IB_BTH_SOLICITED;123qp->s_wqe = wqe;124if (++qp->s_cur >= qp->s_size)125qp->s_cur = 0;126break;127128case IB_WR_RDMA_WRITE:129case IB_WR_RDMA_WRITE_WITH_IMM:130ohdr->u.rc.reth.vaddr =131cpu_to_be64(wqe->wr.wr.rdma.remote_addr);132ohdr->u.rc.reth.rkey =133cpu_to_be32(wqe->wr.wr.rdma.rkey);134ohdr->u.rc.reth.length = cpu_to_be32(len);135hwords += sizeof(struct ib_reth) / 4;136if (len > pmtu) {137qp->s_state = OP(RDMA_WRITE_FIRST);138len = pmtu;139break;140}141if (wqe->wr.opcode == IB_WR_RDMA_WRITE)142qp->s_state = OP(RDMA_WRITE_ONLY);143else {144qp->s_state =145OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE);146/* Immediate data comes after the RETH */147ohdr->u.rc.imm_data = wqe->wr.ex.imm_data;148hwords += 1;149if (wqe->wr.send_flags & IB_SEND_SOLICITED)150bth0 |= IB_BTH_SOLICITED;151}152qp->s_wqe = wqe;153if (++qp->s_cur >= qp->s_size)154qp->s_cur = 0;155break;156157default:158goto bail;159}160break;161162case OP(SEND_FIRST):163qp->s_state = OP(SEND_MIDDLE);164/* FALLTHROUGH */165case OP(SEND_MIDDLE):166len = qp->s_len;167if (len > pmtu) {168len = pmtu;169break;170}171if (wqe->wr.opcode == IB_WR_SEND)172qp->s_state = OP(SEND_LAST);173else {174qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE);175/* Immediate data comes after the BTH */176ohdr->u.imm_data = wqe->wr.ex.imm_data;177hwords += 1;178}179if (wqe->wr.send_flags & IB_SEND_SOLICITED)180bth0 |= IB_BTH_SOLICITED;181qp->s_wqe = wqe;182if (++qp->s_cur >= qp->s_size)183qp->s_cur = 0;184break;185186case OP(RDMA_WRITE_FIRST):187qp->s_state = OP(RDMA_WRITE_MIDDLE);188/* FALLTHROUGH */189case OP(RDMA_WRITE_MIDDLE):190len = qp->s_len;191if (len > pmtu) {192len = pmtu;193break;194}195if (wqe->wr.opcode == IB_WR_RDMA_WRITE)196qp->s_state = OP(RDMA_WRITE_LAST);197else {198qp->s_state =199OP(RDMA_WRITE_LAST_WITH_IMMEDIATE);200/* Immediate data comes after the BTH */201ohdr->u.imm_data = wqe->wr.ex.imm_data;202hwords += 1;203if (wqe->wr.send_flags & IB_SEND_SOLICITED)204bth0 |= IB_BTH_SOLICITED;205}206qp->s_wqe = wqe;207if (++qp->s_cur >= qp->s_size)208qp->s_cur = 0;209break;210}211qp->s_len -= len;212qp->s_hdrwords = hwords;213qp->s_cur_sge = &qp->s_sge;214qp->s_cur_size = len;215qib_make_ruc_header(qp, ohdr, bth0 | (qp->s_state << 24),216qp->s_next_psn++ & QIB_PSN_MASK);217done:218ret = 1;219goto unlock;220221bail:222qp->s_flags &= ~QIB_S_BUSY;223unlock:224spin_unlock_irqrestore(&qp->s_lock, flags);225return ret;226}227228/**229* qib_uc_rcv - handle an incoming UC packet230* @ibp: the port the packet came in on231* @hdr: the header of the packet232* @has_grh: true if the packet has a GRH233* @data: the packet data234* @tlen: the length of the packet235* @qp: the QP for this packet.236*237* This is called from qib_qp_rcv() to process an incoming UC packet238* for the given QP.239* Called at interrupt level.240*/241void qib_uc_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,242int has_grh, void *data, u32 tlen, struct qib_qp *qp)243{244struct qib_other_headers *ohdr;245unsigned long flags;246u32 opcode;247u32 hdrsize;248u32 psn;249u32 pad;250struct ib_wc wc;251u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);252struct ib_reth *reth;253int ret;254255/* Check for GRH */256if (!has_grh) {257ohdr = &hdr->u.oth;258hdrsize = 8 + 12; /* LRH + BTH */259} else {260ohdr = &hdr->u.l.oth;261hdrsize = 8 + 40 + 12; /* LRH + GRH + BTH */262}263264opcode = be32_to_cpu(ohdr->bth[0]);265spin_lock_irqsave(&qp->s_lock, flags);266if (qib_ruc_check_hdr(ibp, hdr, has_grh, qp, opcode))267goto sunlock;268spin_unlock_irqrestore(&qp->s_lock, flags);269270psn = be32_to_cpu(ohdr->bth[2]);271opcode >>= 24;272memset(&wc, 0, sizeof wc);273274/* Compare the PSN verses the expected PSN. */275if (unlikely(qib_cmp24(psn, qp->r_psn) != 0)) {276/*277* Handle a sequence error.278* Silently drop any current message.279*/280qp->r_psn = psn;281inv:282if (qp->r_state == OP(SEND_FIRST) ||283qp->r_state == OP(SEND_MIDDLE)) {284set_bit(QIB_R_REWIND_SGE, &qp->r_aflags);285qp->r_sge.num_sge = 0;286} else287while (qp->r_sge.num_sge) {288atomic_dec(&qp->r_sge.sge.mr->refcount);289if (--qp->r_sge.num_sge)290qp->r_sge.sge = *qp->r_sge.sg_list++;291}292qp->r_state = OP(SEND_LAST);293switch (opcode) {294case OP(SEND_FIRST):295case OP(SEND_ONLY):296case OP(SEND_ONLY_WITH_IMMEDIATE):297goto send_first;298299case OP(RDMA_WRITE_FIRST):300case OP(RDMA_WRITE_ONLY):301case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE):302goto rdma_first;303304default:305goto drop;306}307}308309/* Check for opcode sequence errors. */310switch (qp->r_state) {311case OP(SEND_FIRST):312case OP(SEND_MIDDLE):313if (opcode == OP(SEND_MIDDLE) ||314opcode == OP(SEND_LAST) ||315opcode == OP(SEND_LAST_WITH_IMMEDIATE))316break;317goto inv;318319case OP(RDMA_WRITE_FIRST):320case OP(RDMA_WRITE_MIDDLE):321if (opcode == OP(RDMA_WRITE_MIDDLE) ||322opcode == OP(RDMA_WRITE_LAST) ||323opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE))324break;325goto inv;326327default:328if (opcode == OP(SEND_FIRST) ||329opcode == OP(SEND_ONLY) ||330opcode == OP(SEND_ONLY_WITH_IMMEDIATE) ||331opcode == OP(RDMA_WRITE_FIRST) ||332opcode == OP(RDMA_WRITE_ONLY) ||333opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE))334break;335goto inv;336}337338if (qp->state == IB_QPS_RTR && !(qp->r_flags & QIB_R_COMM_EST)) {339qp->r_flags |= QIB_R_COMM_EST;340if (qp->ibqp.event_handler) {341struct ib_event ev;342343ev.device = qp->ibqp.device;344ev.element.qp = &qp->ibqp;345ev.event = IB_EVENT_COMM_EST;346qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);347}348}349350/* OK, process the packet. */351switch (opcode) {352case OP(SEND_FIRST):353case OP(SEND_ONLY):354case OP(SEND_ONLY_WITH_IMMEDIATE):355send_first:356if (test_and_clear_bit(QIB_R_REWIND_SGE, &qp->r_aflags))357qp->r_sge = qp->s_rdma_read_sge;358else {359ret = qib_get_rwqe(qp, 0);360if (ret < 0)361goto op_err;362if (!ret)363goto drop;364/*365* qp->s_rdma_read_sge will be the owner366* of the mr references.367*/368qp->s_rdma_read_sge = qp->r_sge;369}370qp->r_rcv_len = 0;371if (opcode == OP(SEND_ONLY))372goto send_last;373else if (opcode == OP(SEND_ONLY_WITH_IMMEDIATE))374goto send_last_imm;375/* FALLTHROUGH */376case OP(SEND_MIDDLE):377/* Check for invalid length PMTU or posted rwqe len. */378if (unlikely(tlen != (hdrsize + pmtu + 4)))379goto rewind;380qp->r_rcv_len += pmtu;381if (unlikely(qp->r_rcv_len > qp->r_len))382goto rewind;383qib_copy_sge(&qp->r_sge, data, pmtu, 0);384break;385386case OP(SEND_LAST_WITH_IMMEDIATE):387send_last_imm:388wc.ex.imm_data = ohdr->u.imm_data;389hdrsize += 4;390wc.wc_flags = IB_WC_WITH_IMM;391/* FALLTHROUGH */392case OP(SEND_LAST):393send_last:394/* Get the number of bytes the message was padded by. */395pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;396/* Check for invalid length. */397/* XXX LAST len should be >= 1 */398if (unlikely(tlen < (hdrsize + pad + 4)))399goto rewind;400/* Don't count the CRC. */401tlen -= (hdrsize + pad + 4);402wc.byte_len = tlen + qp->r_rcv_len;403if (unlikely(wc.byte_len > qp->r_len))404goto rewind;405wc.opcode = IB_WC_RECV;406last_imm:407qib_copy_sge(&qp->r_sge, data, tlen, 0);408while (qp->s_rdma_read_sge.num_sge) {409atomic_dec(&qp->s_rdma_read_sge.sge.mr->refcount);410if (--qp->s_rdma_read_sge.num_sge)411qp->s_rdma_read_sge.sge =412*qp->s_rdma_read_sge.sg_list++;413}414wc.wr_id = qp->r_wr_id;415wc.status = IB_WC_SUCCESS;416wc.qp = &qp->ibqp;417wc.src_qp = qp->remote_qpn;418wc.slid = qp->remote_ah_attr.dlid;419wc.sl = qp->remote_ah_attr.sl;420/* Signal completion event if the solicited bit is set. */421qib_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,422(ohdr->bth[0] &423cpu_to_be32(IB_BTH_SOLICITED)) != 0);424break;425426case OP(RDMA_WRITE_FIRST):427case OP(RDMA_WRITE_ONLY):428case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): /* consume RWQE */429rdma_first:430if (unlikely(!(qp->qp_access_flags &431IB_ACCESS_REMOTE_WRITE))) {432goto drop;433}434reth = &ohdr->u.rc.reth;435hdrsize += sizeof(*reth);436qp->r_len = be32_to_cpu(reth->length);437qp->r_rcv_len = 0;438qp->r_sge.sg_list = NULL;439if (qp->r_len != 0) {440u32 rkey = be32_to_cpu(reth->rkey);441u64 vaddr = be64_to_cpu(reth->vaddr);442int ok;443444/* Check rkey */445ok = qib_rkey_ok(qp, &qp->r_sge.sge, qp->r_len,446vaddr, rkey, IB_ACCESS_REMOTE_WRITE);447if (unlikely(!ok))448goto drop;449qp->r_sge.num_sge = 1;450} else {451qp->r_sge.num_sge = 0;452qp->r_sge.sge.mr = NULL;453qp->r_sge.sge.vaddr = NULL;454qp->r_sge.sge.length = 0;455qp->r_sge.sge.sge_length = 0;456}457if (opcode == OP(RDMA_WRITE_ONLY))458goto rdma_last;459else if (opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE)) {460wc.ex.imm_data = ohdr->u.rc.imm_data;461goto rdma_last_imm;462}463/* FALLTHROUGH */464case OP(RDMA_WRITE_MIDDLE):465/* Check for invalid length PMTU or posted rwqe len. */466if (unlikely(tlen != (hdrsize + pmtu + 4)))467goto drop;468qp->r_rcv_len += pmtu;469if (unlikely(qp->r_rcv_len > qp->r_len))470goto drop;471qib_copy_sge(&qp->r_sge, data, pmtu, 1);472break;473474case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE):475wc.ex.imm_data = ohdr->u.imm_data;476rdma_last_imm:477hdrsize += 4;478wc.wc_flags = IB_WC_WITH_IMM;479480/* Get the number of bytes the message was padded by. */481pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;482/* Check for invalid length. */483/* XXX LAST len should be >= 1 */484if (unlikely(tlen < (hdrsize + pad + 4)))485goto drop;486/* Don't count the CRC. */487tlen -= (hdrsize + pad + 4);488if (unlikely(tlen + qp->r_rcv_len != qp->r_len))489goto drop;490if (test_and_clear_bit(QIB_R_REWIND_SGE, &qp->r_aflags))491while (qp->s_rdma_read_sge.num_sge) {492atomic_dec(&qp->s_rdma_read_sge.sge.mr->493refcount);494if (--qp->s_rdma_read_sge.num_sge)495qp->s_rdma_read_sge.sge =496*qp->s_rdma_read_sge.sg_list++;497}498else {499ret = qib_get_rwqe(qp, 1);500if (ret < 0)501goto op_err;502if (!ret)503goto drop;504}505wc.byte_len = qp->r_len;506wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;507goto last_imm;508509case OP(RDMA_WRITE_LAST):510rdma_last:511/* Get the number of bytes the message was padded by. */512pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;513/* Check for invalid length. */514/* XXX LAST len should be >= 1 */515if (unlikely(tlen < (hdrsize + pad + 4)))516goto drop;517/* Don't count the CRC. */518tlen -= (hdrsize + pad + 4);519if (unlikely(tlen + qp->r_rcv_len != qp->r_len))520goto drop;521qib_copy_sge(&qp->r_sge, data, tlen, 1);522while (qp->r_sge.num_sge) {523atomic_dec(&qp->r_sge.sge.mr->refcount);524if (--qp->r_sge.num_sge)525qp->r_sge.sge = *qp->r_sge.sg_list++;526}527break;528529default:530/* Drop packet for unknown opcodes. */531goto drop;532}533qp->r_psn++;534qp->r_state = opcode;535return;536537rewind:538set_bit(QIB_R_REWIND_SGE, &qp->r_aflags);539qp->r_sge.num_sge = 0;540drop:541ibp->n_pkt_drops++;542return;543544op_err:545qib_rc_error(qp, IB_WC_LOC_QP_OP_ERR);546return;547548sunlock:549spin_unlock_irqrestore(&qp->s_lock, flags);550}551552553