xref: /openbmc/linux/drivers/infiniband/ulp/iser/iser_memory.c (revision 1188f7f111c61394ec56beb8e30322305a8220b6)
16461f64aSOr Gerlitz /*
26461f64aSOr Gerlitz  * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
33ee07d27SOr Gerlitz  * Copyright (c) 2013-2014 Mellanox Technologies. All rights reserved.
46461f64aSOr Gerlitz  *
56461f64aSOr Gerlitz  * This software is available to you under a choice of one of two
66461f64aSOr Gerlitz  * licenses.  You may choose to be licensed under the terms of the GNU
76461f64aSOr Gerlitz  * General Public License (GPL) Version 2, available from the file
86461f64aSOr Gerlitz  * COPYING in the main directory of this source tree, or the
96461f64aSOr Gerlitz  * OpenIB.org BSD license below:
106461f64aSOr Gerlitz  *
116461f64aSOr Gerlitz  *     Redistribution and use in source and binary forms, with or
126461f64aSOr Gerlitz  *     without modification, are permitted provided that the following
136461f64aSOr Gerlitz  *     conditions are met:
146461f64aSOr Gerlitz  *
156461f64aSOr Gerlitz  *	- Redistributions of source code must retain the above
166461f64aSOr Gerlitz  *	  copyright notice, this list of conditions and the following
176461f64aSOr Gerlitz  *	  disclaimer.
186461f64aSOr Gerlitz  *
196461f64aSOr Gerlitz  *	- Redistributions in binary form must reproduce the above
206461f64aSOr Gerlitz  *	  copyright notice, this list of conditions and the following
216461f64aSOr Gerlitz  *	  disclaimer in the documentation and/or other materials
226461f64aSOr Gerlitz  *	  provided with the distribution.
236461f64aSOr Gerlitz  *
246461f64aSOr Gerlitz  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
256461f64aSOr Gerlitz  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
266461f64aSOr Gerlitz  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
276461f64aSOr Gerlitz  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
286461f64aSOr Gerlitz  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
296461f64aSOr Gerlitz  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
306461f64aSOr Gerlitz  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
316461f64aSOr Gerlitz  * SOFTWARE.
326461f64aSOr Gerlitz  */
336461f64aSOr Gerlitz #include <linux/kernel.h>
346461f64aSOr Gerlitz #include <linux/slab.h>
356461f64aSOr Gerlitz #include <linux/mm.h>
36a1f8e7f7SAl Viro #include <linux/highmem.h>
376461f64aSOr Gerlitz #include <linux/scatterlist.h>
386461f64aSOr Gerlitz 
396461f64aSOr Gerlitz #include "iscsi_iser.h"
4048afbff6SSagi Grimberg 
iser_reg_comp(struct ib_cq * cq,struct ib_wc * wc)41cfeb91b3SChristoph Hellwig void iser_reg_comp(struct ib_cq *cq, struct ib_wc *wc)
42cfeb91b3SChristoph Hellwig {
43cfeb91b3SChristoph Hellwig 	iser_err_comp(wc, "memreg");
44cfeb91b3SChristoph Hellwig }
45cfeb91b3SChristoph Hellwig 
iser_reg_desc_get_fr(struct ib_conn * ib_conn)46ca2770c6SMax Gurtovoy static struct iser_fr_desc *iser_reg_desc_get_fr(struct ib_conn *ib_conn)
47bd8b944eSSagi Grimberg {
48385ad87dSSagi Grimberg 	struct iser_fr_pool *fr_pool = &ib_conn->fr_pool;
495190cc26SSagi Grimberg 	struct iser_fr_desc *desc;
50bd8b944eSSagi Grimberg 	unsigned long flags;
51bd8b944eSSagi Grimberg 
52385ad87dSSagi Grimberg 	spin_lock_irqsave(&fr_pool->lock, flags);
532b3bf958SAdir Lev 	desc = list_first_entry(&fr_pool->list,
545190cc26SSagi Grimberg 				struct iser_fr_desc, list);
55bd8b944eSSagi Grimberg 	list_del(&desc->list);
56385ad87dSSagi Grimberg 	spin_unlock_irqrestore(&fr_pool->lock, flags);
57bd8b944eSSagi Grimberg 
58bd8b944eSSagi Grimberg 	return desc;
59bd8b944eSSagi Grimberg }
60bd8b944eSSagi Grimberg 
iser_reg_desc_put_fr(struct ib_conn * ib_conn,struct iser_fr_desc * desc)61ca2770c6SMax Gurtovoy static void iser_reg_desc_put_fr(struct ib_conn *ib_conn,
625190cc26SSagi Grimberg 				 struct iser_fr_desc *desc)
63bd8b944eSSagi Grimberg {
64385ad87dSSagi Grimberg 	struct iser_fr_pool *fr_pool = &ib_conn->fr_pool;
65bd8b944eSSagi Grimberg 	unsigned long flags;
66bd8b944eSSagi Grimberg 
67385ad87dSSagi Grimberg 	spin_lock_irqsave(&fr_pool->lock, flags);
682b3bf958SAdir Lev 	list_add(&desc->list, &fr_pool->list);
69385ad87dSSagi Grimberg 	spin_unlock_irqrestore(&fr_pool->lock, flags);
70bd8b944eSSagi Grimberg }
71bd8b944eSSagi Grimberg 
iser_dma_map_task_data(struct iscsi_iser_task * iser_task,enum iser_data_dir iser_dir,enum dma_data_direction dma_dir)722261ec3dSMike Christie int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
7374a20780SErez Zilber 			   enum iser_data_dir iser_dir,
7474a20780SErez Zilber 			   enum dma_data_direction dma_dir)
7574a20780SErez Zilber {
7680303ee2SMax Gurtovoy 	struct iser_data_buf *data = &iser_task->data[iser_dir];
775180311fSRalph Campbell 	struct ib_device *dev;
7874a20780SErez Zilber 
792261ec3dSMike Christie 	iser_task->dir[iser_dir] = 1;
80a4ee3539SSagi Grimberg 	dev = iser_task->iser_conn->ib_conn.device->ib_device;
8174a20780SErez Zilber 
82e3784bd1SSagi Grimberg 	data->dma_nents = ib_dma_map_sg(dev, data->sg, data->size, dma_dir);
8370bcc63fSMax Gurtovoy 	if (unlikely(data->dma_nents == 0)) {
8474a20780SErez Zilber 		iser_err("dma_map_sg failed!!!\n");
8574a20780SErez Zilber 		return -EINVAL;
8674a20780SErez Zilber 	}
8780303ee2SMax Gurtovoy 
8880303ee2SMax Gurtovoy 	if (scsi_prot_sg_count(iser_task->sc)) {
8980303ee2SMax Gurtovoy 		struct iser_data_buf *pdata = &iser_task->prot[iser_dir];
9080303ee2SMax Gurtovoy 
9180303ee2SMax Gurtovoy 		pdata->dma_nents = ib_dma_map_sg(dev, pdata->sg, pdata->size, dma_dir);
9280303ee2SMax Gurtovoy 		if (unlikely(pdata->dma_nents == 0)) {
9380303ee2SMax Gurtovoy 			iser_err("protection dma_map_sg failed!!!\n");
9480303ee2SMax Gurtovoy 			goto out_unmap;
9580303ee2SMax Gurtovoy 		}
9674a20780SErez Zilber 	}
9774a20780SErez Zilber 
9880303ee2SMax Gurtovoy 	return 0;
9980303ee2SMax Gurtovoy 
10080303ee2SMax Gurtovoy out_unmap:
10180303ee2SMax Gurtovoy 	ib_dma_unmap_sg(dev, data->sg, data->size, dma_dir);
10280303ee2SMax Gurtovoy 	return -EINVAL;
10380303ee2SMax Gurtovoy }
10480303ee2SMax Gurtovoy 
10580303ee2SMax Gurtovoy 
iser_dma_unmap_task_data(struct iscsi_iser_task * iser_task,enum iser_data_dir iser_dir,enum dma_data_direction dma_dir)1069a8b08faSSagi Grimberg void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task,
10780303ee2SMax Gurtovoy 			      enum iser_data_dir iser_dir,
10880303ee2SMax Gurtovoy 			      enum dma_data_direction dma_dir)
10974a20780SErez Zilber {
11080303ee2SMax Gurtovoy 	struct iser_data_buf *data = &iser_task->data[iser_dir];
1115180311fSRalph Campbell 	struct ib_device *dev;
11274a20780SErez Zilber 
113a4ee3539SSagi Grimberg 	dev = iser_task->iser_conn->ib_conn.device->ib_device;
11480303ee2SMax Gurtovoy 	ib_dma_unmap_sg(dev, data->sg, data->size, dma_dir);
11580303ee2SMax Gurtovoy 
11680303ee2SMax Gurtovoy 	if (scsi_prot_sg_count(iser_task->sc)) {
11780303ee2SMax Gurtovoy 		struct iser_data_buf *pdata = &iser_task->prot[iser_dir];
11880303ee2SMax Gurtovoy 
11980303ee2SMax Gurtovoy 		ib_dma_unmap_sg(dev, pdata->sg, pdata->size, dma_dir);
12080303ee2SMax Gurtovoy 	}
12174a20780SErez Zilber }
12274a20780SErez Zilber 
iser_reg_dma(struct iser_device * device,struct iser_data_buf * mem,struct iser_mem_reg * reg)123ca2770c6SMax Gurtovoy static int iser_reg_dma(struct iser_device *device, struct iser_data_buf *mem,
124ad1e5672SSagi Grimberg 			struct iser_mem_reg *reg)
125ad1e5672SSagi Grimberg {
126ad1e5672SSagi Grimberg 	struct scatterlist *sg = mem->sg;
127ad1e5672SSagi Grimberg 
128256b7ad2SJason Gunthorpe 	reg->sge.lkey = device->pd->local_dma_lkey;
129b5f04b00SJenny Derzhavetz 	/*
130b5f04b00SJenny Derzhavetz 	 * FIXME: rework the registration code path to differentiate
131b5f04b00SJenny Derzhavetz 	 * rkey/lkey use cases
132b5f04b00SJenny Derzhavetz 	 */
1338e61212dSChristoph Hellwig 
1348e61212dSChristoph Hellwig 	if (device->pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY)
1358e61212dSChristoph Hellwig 		reg->rkey = device->pd->unsafe_global_rkey;
1368e61212dSChristoph Hellwig 	else
1378e61212dSChristoph Hellwig 		reg->rkey = 0;
138a163afc8SBart Van Assche 	reg->sge.addr = sg_dma_address(&sg[0]);
139a163afc8SBart Van Assche 	reg->sge.length = sg_dma_len(&sg[0]);
140ad1e5672SSagi Grimberg 
141ad1e5672SSagi Grimberg 	iser_dbg("Single DMA entry: lkey=0x%x, rkey=0x%x, addr=0x%llx,"
142ad1e5672SSagi Grimberg 		 " length=0x%x\n", reg->sge.lkey, reg->rkey,
143ad1e5672SSagi Grimberg 		 reg->sge.addr, reg->sge.length);
144ad1e5672SSagi Grimberg 
145ad1e5672SSagi Grimberg 	return 0;
146ad1e5672SSagi Grimberg }
147ad1e5672SSagi Grimberg 
iser_unreg_mem_fastreg(struct iscsi_iser_task * iser_task,enum iser_data_dir cmd_dir)148d03e61d0SSagi Grimberg void iser_unreg_mem_fastreg(struct iscsi_iser_task *iser_task,
149d03e61d0SSagi Grimberg 			    enum iser_data_dir cmd_dir)
150d03e61d0SSagi Grimberg {
151b130ededSSagi Grimberg 	struct iser_mem_reg *reg = &iser_task->rdma_reg[cmd_dir];
15226e28debSSergey Gorenko 	struct iser_fr_desc *desc;
15326e28debSSergey Gorenko 	struct ib_mr_status mr_status;
154d03e61d0SSagi Grimberg 
155ee4efeaeSMax Gurtovoy 	desc = reg->desc;
15626e28debSSergey Gorenko 	if (!desc)
157d03e61d0SSagi Grimberg 		return;
158d03e61d0SSagi Grimberg 
15926e28debSSergey Gorenko 	/*
16026e28debSSergey Gorenko 	 * The signature MR cannot be invalidated and reused without checking.
16126e28debSSergey Gorenko 	 * libiscsi calls the check_protection transport handler only if
16226e28debSSergey Gorenko 	 * SCSI-Response is received. And the signature MR is not checked if
16326e28debSSergey Gorenko 	 * the task is completed for some other reason like a timeout or error
16426e28debSSergey Gorenko 	 * handling. That's why we must check the signature MR here before
16526e28debSSergey Gorenko 	 * putting it to the free pool.
16626e28debSSergey Gorenko 	 */
16726e28debSSergey Gorenko 	if (unlikely(desc->sig_protected)) {
16826e28debSSergey Gorenko 		desc->sig_protected = false;
16926e28debSSergey Gorenko 		ib_check_mr_status(desc->rsc.sig_mr, IB_MR_CHECK_SIG_STATUS,
17026e28debSSergey Gorenko 				   &mr_status);
17126e28debSSergey Gorenko 	}
172ee4efeaeSMax Gurtovoy 	iser_reg_desc_put_fr(&iser_task->iser_conn->ib_conn, reg->desc);
173ee4efeaeSMax Gurtovoy 	reg->desc = NULL;
174d03e61d0SSagi Grimberg }
175d03e61d0SSagi Grimberg 
iser_set_dif_domain(struct scsi_cmnd * sc,struct ib_sig_domain * domain)176ca2770c6SMax Gurtovoy static void iser_set_dif_domain(struct scsi_cmnd *sc,
177ca2770c6SMax Gurtovoy 				struct ib_sig_domain *domain)
17892792c0aSSagi Grimberg {
17978eda2bbSSagi Grimberg 	domain->sig_type = IB_SIG_TYPE_T10_DIF;
1805bb6e543SSagi Grimberg 	domain->sig.dif.pi_interval = scsi_prot_interval(sc);
18199247108SBart Van Assche 	domain->sig.dif.ref_tag = t10_pi_ref_tag(scsi_cmd_to_rq(sc));
18278eda2bbSSagi Grimberg 	/*
18378eda2bbSSagi Grimberg 	 * At the moment we hard code those, but in the future
18478eda2bbSSagi Grimberg 	 * we will take them from sc.
18578eda2bbSSagi Grimberg 	 */
18678eda2bbSSagi Grimberg 	domain->sig.dif.apptag_check_mask = 0xffff;
18778eda2bbSSagi Grimberg 	domain->sig.dif.app_escape = true;
18878eda2bbSSagi Grimberg 	domain->sig.dif.ref_escape = true;
1895bb6e543SSagi Grimberg 	if (sc->prot_flags & SCSI_PROT_REF_INCREMENT)
19078eda2bbSSagi Grimberg 		domain->sig.dif.ref_remap = true;
1915bf0e4b8SMax Gurtovoy }
192177e31bdSSagi Grimberg 
iser_set_sig_attrs(struct scsi_cmnd * sc,struct ib_sig_attrs * sig_attrs)193ca2770c6SMax Gurtovoy static int iser_set_sig_attrs(struct scsi_cmnd *sc,
194ca2770c6SMax Gurtovoy 			      struct ib_sig_attrs *sig_attrs)
195177e31bdSSagi Grimberg {
196177e31bdSSagi Grimberg 	switch (scsi_get_prot_op(sc)) {
197177e31bdSSagi Grimberg 	case SCSI_PROT_WRITE_INSERT:
198177e31bdSSagi Grimberg 	case SCSI_PROT_READ_STRIP:
19978eda2bbSSagi Grimberg 		sig_attrs->mem.sig_type = IB_SIG_TYPE_NONE;
2000cc2896fSIsrael Rukshin 		iser_set_dif_domain(sc, &sig_attrs->wire);
201177e31bdSSagi Grimberg 		sig_attrs->wire.sig.dif.bg_type = IB_T10DIF_CRC;
202177e31bdSSagi Grimberg 		break;
203177e31bdSSagi Grimberg 	case SCSI_PROT_READ_INSERT:
204177e31bdSSagi Grimberg 	case SCSI_PROT_WRITE_STRIP:
20578eda2bbSSagi Grimberg 		sig_attrs->wire.sig_type = IB_SIG_TYPE_NONE;
2060cc2896fSIsrael Rukshin 		iser_set_dif_domain(sc, &sig_attrs->mem);
2075bb6e543SSagi Grimberg 		sig_attrs->mem.sig.dif.bg_type = sc->prot_flags & SCSI_PROT_IP_CHECKSUM ?
2085bb6e543SSagi Grimberg 						IB_T10DIF_CSUM : IB_T10DIF_CRC;
209177e31bdSSagi Grimberg 		break;
210177e31bdSSagi Grimberg 	case SCSI_PROT_READ_PASS:
211177e31bdSSagi Grimberg 	case SCSI_PROT_WRITE_PASS:
2120cc2896fSIsrael Rukshin 		iser_set_dif_domain(sc, &sig_attrs->wire);
213177e31bdSSagi Grimberg 		sig_attrs->wire.sig.dif.bg_type = IB_T10DIF_CRC;
2140cc2896fSIsrael Rukshin 		iser_set_dif_domain(sc, &sig_attrs->mem);
2155bb6e543SSagi Grimberg 		sig_attrs->mem.sig.dif.bg_type = sc->prot_flags & SCSI_PROT_IP_CHECKSUM ?
2165bb6e543SSagi Grimberg 						IB_T10DIF_CSUM : IB_T10DIF_CRC;
217177e31bdSSagi Grimberg 		break;
218177e31bdSSagi Grimberg 	default:
219177e31bdSSagi Grimberg 		iser_err("Unsupported PI operation %d\n",
220177e31bdSSagi Grimberg 			 scsi_get_prot_op(sc));
221177e31bdSSagi Grimberg 		return -EINVAL;
222177e31bdSSagi Grimberg 	}
22378eda2bbSSagi Grimberg 
224177e31bdSSagi Grimberg 	return 0;
225177e31bdSSagi Grimberg }
226177e31bdSSagi Grimberg 
iser_set_prot_checks(struct scsi_cmnd * sc,u8 * mask)227ca2770c6SMax Gurtovoy static inline void iser_set_prot_checks(struct scsi_cmnd *sc, u8 *mask)
228177e31bdSSagi Grimberg {
2295bb6e543SSagi Grimberg 	*mask = 0;
2305bb6e543SSagi Grimberg 	if (sc->prot_flags & SCSI_PROT_REF_CHECK)
231c6c2c03aSMax Gurtovoy 		*mask |= IB_SIG_CHECK_REFTAG;
2325bb6e543SSagi Grimberg 	if (sc->prot_flags & SCSI_PROT_GUARD_CHECK)
233c6c2c03aSMax Gurtovoy 		*mask |= IB_SIG_CHECK_GUARD;
234177e31bdSSagi Grimberg }
235177e31bdSSagi Grimberg 
iser_inv_rkey(struct ib_send_wr * inv_wr,struct ib_mr * mr,struct ib_cqe * cqe,struct ib_send_wr * next_wr)236ca2770c6SMax Gurtovoy static inline void iser_inv_rkey(struct ib_send_wr *inv_wr, struct ib_mr *mr,
237ca2770c6SMax Gurtovoy 				 struct ib_cqe *cqe, struct ib_send_wr *next_wr)
238a11b3e69SSagi Grimberg {
239a11b3e69SSagi Grimberg 	inv_wr->opcode = IB_WR_LOCAL_INV;
240cfeb91b3SChristoph Hellwig 	inv_wr->wr_cqe = cqe;
241a11b3e69SSagi Grimberg 	inv_wr->ex.invalidate_rkey = mr->rkey;
2427332bed0SSagi Grimberg 	inv_wr->send_flags = 0;
2437332bed0SSagi Grimberg 	inv_wr->num_sge = 0;
244b9294f8bSIsrael Rukshin 	inv_wr->next = next_wr;
245a11b3e69SSagi Grimberg }
246a11b3e69SSagi Grimberg 
iser_reg_sig_mr(struct iscsi_iser_task * iser_task,struct iser_data_buf * mem,struct iser_data_buf * sig_mem,struct iser_reg_resources * rsc,struct iser_mem_reg * sig_reg)247ca2770c6SMax Gurtovoy static int iser_reg_sig_mr(struct iscsi_iser_task *iser_task,
248b76a4399SIsrael Rukshin 			   struct iser_data_buf *mem,
249b76a4399SIsrael Rukshin 			   struct iser_data_buf *sig_mem,
250b76a4399SIsrael Rukshin 			   struct iser_reg_resources *rsc,
2516ef8bb83SSagi Grimberg 			   struct iser_mem_reg *sig_reg)
252177e31bdSSagi Grimberg {
2537332bed0SSagi Grimberg 	struct iser_tx_desc *tx_desc = &iser_task->desc;
254cfeb91b3SChristoph Hellwig 	struct ib_cqe *cqe = &iser_task->iser_conn->ib_conn.reg_cqe;
255b76a4399SIsrael Rukshin 	struct ib_mr *mr = rsc->sig_mr;
256b76a4399SIsrael Rukshin 	struct ib_sig_attrs *sig_attrs = mr->sig_attrs;
257b9294f8bSIsrael Rukshin 	struct ib_reg_wr *wr = &tx_desc->reg_wr;
258177e31bdSSagi Grimberg 	int ret;
259177e31bdSSagi Grimberg 
2607332bed0SSagi Grimberg 	memset(sig_attrs, 0, sizeof(*sig_attrs));
2617332bed0SSagi Grimberg 	ret = iser_set_sig_attrs(iser_task->sc, sig_attrs);
262177e31bdSSagi Grimberg 	if (ret)
263177e31bdSSagi Grimberg 		goto err;
264177e31bdSSagi Grimberg 
2657332bed0SSagi Grimberg 	iser_set_prot_checks(iser_task->sc, &sig_attrs->check_mask);
266177e31bdSSagi Grimberg 
267*2d8f9e4eSSergey Gorenko 	if (rsc->sig_mr->need_inval)
268b9294f8bSIsrael Rukshin 		iser_inv_rkey(&tx_desc->inv_wr, mr, cqe, &wr->wr);
269e26d2d21SSagi Grimberg 
270e26d2d21SSagi Grimberg 	ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey));
271177e31bdSSagi Grimberg 
272b76a4399SIsrael Rukshin 	ret = ib_map_mr_sg_pi(mr, mem->sg, mem->dma_nents, NULL,
273b76a4399SIsrael Rukshin 			      sig_mem->sg, sig_mem->dma_nents, NULL, SZ_4K);
274b76a4399SIsrael Rukshin 	if (unlikely(ret)) {
275b76a4399SIsrael Rukshin 		iser_err("failed to map PI sg (%d)\n",
276b76a4399SIsrael Rukshin 			 mem->dma_nents + sig_mem->dma_nents);
277b76a4399SIsrael Rukshin 		goto err;
278b76a4399SIsrael Rukshin 	}
279b76a4399SIsrael Rukshin 
280b76a4399SIsrael Rukshin 	memset(wr, 0, sizeof(*wr));
281b9294f8bSIsrael Rukshin 	wr->wr.next = &tx_desc->send_wr;
282b76a4399SIsrael Rukshin 	wr->wr.opcode = IB_WR_REG_MR_INTEGRITY;
283cfeb91b3SChristoph Hellwig 	wr->wr.wr_cqe = cqe;
284b76a4399SIsrael Rukshin 	wr->wr.num_sge = 0;
285e622f2f4SChristoph Hellwig 	wr->wr.send_flags = 0;
286b76a4399SIsrael Rukshin 	wr->mr = mr;
287b76a4399SIsrael Rukshin 	wr->key = mr->rkey;
288b76a4399SIsrael Rukshin 	wr->access = IB_ACCESS_LOCAL_WRITE |
289177e31bdSSagi Grimberg 		     IB_ACCESS_REMOTE_READ |
290177e31bdSSagi Grimberg 		     IB_ACCESS_REMOTE_WRITE;
291*2d8f9e4eSSergey Gorenko 	rsc->sig_mr->need_inval = true;
292177e31bdSSagi Grimberg 
293e26d2d21SSagi Grimberg 	sig_reg->sge.lkey = mr->lkey;
294e26d2d21SSagi Grimberg 	sig_reg->rkey = mr->rkey;
295b76a4399SIsrael Rukshin 	sig_reg->sge.addr = mr->iova;
296b76a4399SIsrael Rukshin 	sig_reg->sge.length = mr->length;
297177e31bdSSagi Grimberg 
29839405885SSagi Grimberg 	iser_dbg("lkey=0x%x rkey=0x%x addr=0x%llx length=%u\n",
2996ef8bb83SSagi Grimberg 		 sig_reg->sge.lkey, sig_reg->rkey, sig_reg->sge.addr,
3006ef8bb83SSagi Grimberg 		 sig_reg->sge.length);
301177e31bdSSagi Grimberg err:
302177e31bdSSagi Grimberg 	return ret;
303177e31bdSSagi Grimberg }
304177e31bdSSagi Grimberg 
iser_fast_reg_mr(struct iscsi_iser_task * iser_task,struct iser_data_buf * mem,struct iser_reg_resources * rsc,struct iser_mem_reg * reg)305d11ec4ecSSagi Grimberg static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task,
306d11ec4ecSSagi Grimberg 			    struct iser_data_buf *mem,
307d711d81dSSagi Grimberg 			    struct iser_reg_resources *rsc,
3086ef8bb83SSagi Grimberg 			    struct iser_mem_reg *reg)
3095587856cSSagi Grimberg {
3107332bed0SSagi Grimberg 	struct iser_tx_desc *tx_desc = &iser_task->desc;
311cfeb91b3SChristoph Hellwig 	struct ib_cqe *cqe = &iser_task->iser_conn->ib_conn.reg_cqe;
31239405885SSagi Grimberg 	struct ib_mr *mr = rsc->mr;
313b9294f8bSIsrael Rukshin 	struct ib_reg_wr *wr = &tx_desc->reg_wr;
31439405885SSagi Grimberg 	int n;
3155587856cSSagi Grimberg 
316*2d8f9e4eSSergey Gorenko 	if (rsc->mr->need_inval)
317b9294f8bSIsrael Rukshin 		iser_inv_rkey(&tx_desc->inv_wr, mr, cqe, &wr->wr);
3185587856cSSagi Grimberg 
319e26d2d21SSagi Grimberg 	ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey));
320e26d2d21SSagi Grimberg 
3216eeff06dSMax Gurtovoy 	n = ib_map_mr_sg(mr, mem->sg, mem->dma_nents, NULL, SZ_4K);
32257b26497SIsrael Rukshin 	if (unlikely(n != mem->dma_nents)) {
32339405885SSagi Grimberg 		iser_err("failed to map sg (%d/%d)\n",
32457b26497SIsrael Rukshin 			 n, mem->dma_nents);
32539405885SSagi Grimberg 		return n < 0 ? n : -EINVAL;
32639405885SSagi Grimberg 	}
32739405885SSagi Grimberg 
328b9294f8bSIsrael Rukshin 	wr->wr.next = &tx_desc->send_wr;
32939405885SSagi Grimberg 	wr->wr.opcode = IB_WR_REG_MR;
330cfeb91b3SChristoph Hellwig 	wr->wr.wr_cqe = cqe;
331e622f2f4SChristoph Hellwig 	wr->wr.send_flags = 0;
33239405885SSagi Grimberg 	wr->wr.num_sge = 0;
33339405885SSagi Grimberg 	wr->mr = mr;
33439405885SSagi Grimberg 	wr->key = mr->rkey;
33539405885SSagi Grimberg 	wr->access = IB_ACCESS_LOCAL_WRITE  |
3365587856cSSagi Grimberg 		     IB_ACCESS_REMOTE_WRITE |
33739405885SSagi Grimberg 		     IB_ACCESS_REMOTE_READ;
33839405885SSagi Grimberg 
339*2d8f9e4eSSergey Gorenko 	rsc->mr->need_inval = true;
3405587856cSSagi Grimberg 
3416ef8bb83SSagi Grimberg 	reg->sge.lkey = mr->lkey;
3426ef8bb83SSagi Grimberg 	reg->rkey = mr->rkey;
34339405885SSagi Grimberg 	reg->sge.addr = mr->iova;
34439405885SSagi Grimberg 	reg->sge.length = mr->length;
3455587856cSSagi Grimberg 
34639405885SSagi Grimberg 	iser_dbg("lkey=0x%x rkey=0x%x addr=0x%llx length=0x%x\n",
34739405885SSagi Grimberg 		 reg->sge.lkey, reg->rkey, reg->sge.addr, reg->sge.length);
3481b16c989SSagi Grimberg 
3497332bed0SSagi Grimberg 	return 0;
3505587856cSSagi Grimberg }
3515587856cSSagi Grimberg 
iser_reg_mem_fastreg(struct iscsi_iser_task * task,enum iser_data_dir dir,bool all_imm)3521fc43132SIsrael Rukshin int iser_reg_mem_fastreg(struct iscsi_iser_task *task,
353b5f04b00SJenny Derzhavetz 			 enum iser_data_dir dir,
354b5f04b00SJenny Derzhavetz 			 bool all_imm)
35532467c42SSagi Grimberg {
35632467c42SSagi Grimberg 	struct ib_conn *ib_conn = &task->iser_conn->ib_conn;
3577f68d749SMax Gurtovoy 	struct iser_device *device = ib_conn->device;
35832467c42SSagi Grimberg 	struct iser_data_buf *mem = &task->data[dir];
35932467c42SSagi Grimberg 	struct iser_mem_reg *reg = &task->rdma_reg[dir];
3607f68d749SMax Gurtovoy 	struct iser_fr_desc *desc;
3613cffd930SSagi Grimberg 	bool use_dma_key;
36232467c42SSagi Grimberg 	int err;
36332467c42SSagi Grimberg 
364b5f04b00SJenny Derzhavetz 	use_dma_key = mem->dma_nents == 1 && (all_imm || !iser_always_reg) &&
365b5f04b00SJenny Derzhavetz 		      scsi_get_prot_op(task->sc) == SCSI_PROT_NORMAL;
3667f68d749SMax Gurtovoy 	if (use_dma_key)
3677f68d749SMax Gurtovoy 		return iser_reg_dma(device, mem, reg);
3683cffd930SSagi Grimberg 
3691fc43132SIsrael Rukshin 	desc = iser_reg_desc_get_fr(ib_conn);
370b76a4399SIsrael Rukshin 	if (scsi_get_prot_op(task->sc) == SCSI_PROT_NORMAL) {
3717f68d749SMax Gurtovoy 		err = iser_fast_reg_mr(task, mem, &desc->rsc, reg);
372b76a4399SIsrael Rukshin 		if (unlikely(err))
373b76a4399SIsrael Rukshin 			goto err_reg;
374b76a4399SIsrael Rukshin 	} else {
375b76a4399SIsrael Rukshin 		err = iser_reg_sig_mr(task, mem, &task->prot[dir],
376b76a4399SIsrael Rukshin 				      &desc->rsc, reg);
37732467c42SSagi Grimberg 		if (unlikely(err))
3785587856cSSagi Grimberg 			goto err_reg;
379d11ec4ecSSagi Grimberg 
380c934833eSzhengbin 		desc->sig_protected = true;
381177e31bdSSagi Grimberg 	}
382d11ec4ecSSagi Grimberg 
383ee4efeaeSMax Gurtovoy 	reg->desc = desc;
3847f68d749SMax Gurtovoy 
3855587856cSSagi Grimberg 	return 0;
38632467c42SSagi Grimberg 
3875587856cSSagi Grimberg err_reg:
3881fc43132SIsrael Rukshin 	iser_reg_desc_put_fr(ib_conn, desc);
389d11ec4ecSSagi Grimberg 
3905587856cSSagi Grimberg 	return err;
3915587856cSSagi Grimberg }
392