diff options
Diffstat (limited to 'drivers/infiniband/ulp/isert/ib_isert.c')
| -rw-r--r-- | drivers/infiniband/ulp/isert/ib_isert.c | 181 | 
1 files changed, 109 insertions, 72 deletions
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 2b161be3c1a3..8ee228e9ab5a 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -453,6 +453,7 @@ isert_conn_create_fastreg_pool(struct isert_conn *isert_conn)  		if (ret) {  			pr_err("Failed to create fastreg descriptor err=%d\n",  			       ret); +			kfree(fr_desc);  			goto err;  		} @@ -491,12 +492,11 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)  	isert_conn->state = ISER_CONN_INIT;  	INIT_LIST_HEAD(&isert_conn->conn_accept_node);  	init_completion(&isert_conn->conn_login_comp); -	init_waitqueue_head(&isert_conn->conn_wait); -	init_waitqueue_head(&isert_conn->conn_wait_comp_err); +	init_completion(&isert_conn->conn_wait); +	init_completion(&isert_conn->conn_wait_comp_err);  	kref_init(&isert_conn->conn_kref);  	kref_get(&isert_conn->conn_kref);  	mutex_init(&isert_conn->conn_mutex); -	mutex_init(&isert_conn->conn_comp_mutex);  	spin_lock_init(&isert_conn->conn_lock);  	cma_id->context = isert_conn; @@ -687,11 +687,11 @@ isert_disconnect_work(struct work_struct *work)  	pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");  	mutex_lock(&isert_conn->conn_mutex); -	isert_conn->state = ISER_CONN_DOWN; +	if (isert_conn->state == ISER_CONN_UP) +		isert_conn->state = ISER_CONN_TERMINATING;  	if (isert_conn->post_recv_buf_count == 0 &&  	    atomic_read(&isert_conn->post_send_buf_count) == 0) { -		pr_debug("Calling wake_up(&isert_conn->conn_wait);\n");  		mutex_unlock(&isert_conn->conn_mutex);  		goto wake_up;  	} @@ -711,7 +711,7 @@ isert_disconnect_work(struct work_struct *work)  	mutex_unlock(&isert_conn->conn_mutex);  wake_up: -	wake_up(&isert_conn->conn_wait); +	complete(&isert_conn->conn_wait);  	isert_put_conn(isert_conn);  } @@ -887,16 +887,17 @@ isert_init_send_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,  	 * Coalesce send completion interrupts by only setting IB_SEND_SIGNALED  	 * bit for every ISERT_COMP_BATCH_COUNT number of ib_post_send() calls.  	 */ -	mutex_lock(&isert_conn->conn_comp_mutex); -	if (coalesce && +	mutex_lock(&isert_conn->conn_mutex); +	if (coalesce && isert_conn->state == ISER_CONN_UP &&  	    ++isert_conn->conn_comp_batch < ISERT_COMP_BATCH_COUNT) { +		tx_desc->llnode_active = true;  		llist_add(&tx_desc->comp_llnode, &isert_conn->conn_comp_llist); -		mutex_unlock(&isert_conn->conn_comp_mutex); +		mutex_unlock(&isert_conn->conn_mutex);  		return;  	}  	isert_conn->conn_comp_batch = 0;  	tx_desc->comp_llnode_batch = llist_del_all(&isert_conn->conn_comp_llist); -	mutex_unlock(&isert_conn->conn_comp_mutex); +	mutex_unlock(&isert_conn->conn_mutex);  	send_wr->send_flags = IB_SEND_SIGNALED;  } @@ -1463,7 +1464,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)  	case ISCSI_OP_SCSI_CMD:  		spin_lock_bh(&conn->cmd_lock);  		if (!list_empty(&cmd->i_conn_node)) -			list_del(&cmd->i_conn_node); +			list_del_init(&cmd->i_conn_node);  		spin_unlock_bh(&conn->cmd_lock);  		if (cmd->data_direction == DMA_TO_DEVICE) @@ -1475,7 +1476,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)  	case ISCSI_OP_SCSI_TMFUNC:  		spin_lock_bh(&conn->cmd_lock);  		if (!list_empty(&cmd->i_conn_node)) -			list_del(&cmd->i_conn_node); +			list_del_init(&cmd->i_conn_node);  		spin_unlock_bh(&conn->cmd_lock);  		transport_generic_free_cmd(&cmd->se_cmd, 0); @@ -1485,7 +1486,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)  	case ISCSI_OP_TEXT:  		spin_lock_bh(&conn->cmd_lock);  		if (!list_empty(&cmd->i_conn_node)) -			list_del(&cmd->i_conn_node); +			list_del_init(&cmd->i_conn_node);  		spin_unlock_bh(&conn->cmd_lock);  		/* @@ -1548,6 +1549,7 @@ isert_completion_rdma_read(struct iser_tx_desc *tx_desc,  	iscsit_stop_dataout_timer(cmd);  	device->unreg_rdma_mem(isert_cmd, isert_conn);  	cmd->write_data_done = wr->cur_rdma_length; +	wr->send_wr_num = 0;  	pr_debug("Cmd: %p RDMA_READ comp calling execute_cmd\n", isert_cmd);  	spin_lock_bh(&cmd->istate_lock); @@ -1588,7 +1590,7 @@ isert_do_control_comp(struct work_struct *work)  		pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n");  		/*  		 * Call atomic_dec(&isert_conn->post_send_buf_count) -		 * from isert_free_conn() +		 * from isert_wait_conn()  		 */  		isert_conn->logout_posted = true;  		iscsit_logout_post_handler(cmd, cmd->conn); @@ -1612,6 +1614,7 @@ isert_response_completion(struct iser_tx_desc *tx_desc,  			  struct ib_device *ib_dev)  {  	struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd; +	struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;  	if (cmd->i_state == ISTATE_SEND_TASKMGTRSP ||  	    cmd->i_state == ISTATE_SEND_LOGOUTRSP || @@ -1623,7 +1626,7 @@ isert_response_completion(struct iser_tx_desc *tx_desc,  		queue_work(isert_comp_wq, &isert_cmd->comp_work);  		return;  	} -	atomic_dec(&isert_conn->post_send_buf_count); +	atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);  	cmd->i_state = ISTATE_SENT_STATUS;  	isert_completion_put(tx_desc, isert_cmd, ib_dev); @@ -1661,7 +1664,7 @@ __isert_send_completion(struct iser_tx_desc *tx_desc,  	case ISER_IB_RDMA_READ:  		pr_debug("isert_send_completion: Got ISER_IB_RDMA_READ:\n"); -		atomic_dec(&isert_conn->post_send_buf_count); +		atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count);  		isert_completion_rdma_read(tx_desc, isert_cmd);  		break;  	default: @@ -1690,31 +1693,76 @@ isert_send_completion(struct iser_tx_desc *tx_desc,  }  static void -isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn) +isert_cq_drain_comp_llist(struct isert_conn *isert_conn, struct ib_device *ib_dev) +{ +	struct llist_node *llnode; +	struct isert_rdma_wr *wr; +	struct iser_tx_desc *t; + +	mutex_lock(&isert_conn->conn_mutex); +	llnode = llist_del_all(&isert_conn->conn_comp_llist); +	isert_conn->conn_comp_batch = 0; +	mutex_unlock(&isert_conn->conn_mutex); + +	while (llnode) { +		t = llist_entry(llnode, struct iser_tx_desc, comp_llnode); +		llnode = llist_next(llnode); +		wr = &t->isert_cmd->rdma_wr; + +		atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count); +		isert_completion_put(t, t->isert_cmd, ib_dev); +	} +} + +static void +isert_cq_tx_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)  {  	struct ib_device *ib_dev = isert_conn->conn_cm_id->device; +	struct isert_cmd *isert_cmd = tx_desc->isert_cmd; +	struct llist_node *llnode = tx_desc->comp_llnode_batch; +	struct isert_rdma_wr *wr; +	struct iser_tx_desc *t; -	if (tx_desc) { -		struct isert_cmd *isert_cmd = tx_desc->isert_cmd; +	while (llnode) { +		t = llist_entry(llnode, struct iser_tx_desc, comp_llnode); +		llnode = llist_next(llnode); +		wr = &t->isert_cmd->rdma_wr; -		if (!isert_cmd) -			isert_unmap_tx_desc(tx_desc, ib_dev); -		else -			isert_completion_put(tx_desc, isert_cmd, ib_dev); +		atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count); +		isert_completion_put(t, t->isert_cmd, ib_dev);  	} +	tx_desc->comp_llnode_batch = NULL; -	if (isert_conn->post_recv_buf_count == 0 && -	    atomic_read(&isert_conn->post_send_buf_count) == 0) { -		pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); -		pr_debug("Calling wake_up from isert_cq_comp_err\n"); +	if (!isert_cmd) +		isert_unmap_tx_desc(tx_desc, ib_dev); +	else +		isert_completion_put(tx_desc, isert_cmd, ib_dev); +} -		mutex_lock(&isert_conn->conn_mutex); -		if (isert_conn->state != ISER_CONN_DOWN) -			isert_conn->state = ISER_CONN_TERMINATING; -		mutex_unlock(&isert_conn->conn_mutex); +static void +isert_cq_rx_comp_err(struct isert_conn *isert_conn) +{ +	struct ib_device *ib_dev = isert_conn->conn_cm_id->device; +	struct iscsi_conn *conn = isert_conn->conn; -		wake_up(&isert_conn->conn_wait_comp_err); +	if (isert_conn->post_recv_buf_count) +		return; + +	isert_cq_drain_comp_llist(isert_conn, ib_dev); + +	if (conn->sess) { +		target_sess_cmd_list_set_waiting(conn->sess->se_sess); +		target_wait_for_sess_cmds(conn->sess->se_sess);  	} + +	while (atomic_read(&isert_conn->post_send_buf_count)) +		msleep(3000); + +	mutex_lock(&isert_conn->conn_mutex); +	isert_conn->state = ISER_CONN_DOWN; +	mutex_unlock(&isert_conn->conn_mutex); + +	complete(&isert_conn->conn_wait_comp_err);  }  static void @@ -1739,8 +1787,14 @@ isert_cq_tx_work(struct work_struct *work)  			pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");  			pr_debug("TX wc.status: 0x%08x\n", wc.status);  			pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err); -			atomic_dec(&isert_conn->post_send_buf_count); -			isert_cq_comp_err(tx_desc, isert_conn); + +			if (wc.wr_id != ISER_FASTREG_LI_WRID) { +				if (tx_desc->llnode_active) +					continue; + +				atomic_dec(&isert_conn->post_send_buf_count); +				isert_cq_tx_comp_err(tx_desc, isert_conn); +			}  		}  	} @@ -1783,7 +1837,7 @@ isert_cq_rx_work(struct work_struct *work)  					 wc.vendor_err);  			}  			isert_conn->post_recv_buf_count--; -			isert_cq_comp_err(NULL, isert_conn); +			isert_cq_rx_comp_err(isert_conn);  		}  	} @@ -2201,6 +2255,7 @@ isert_fast_reg_mr(struct fast_reg_descriptor *fr_desc,  	if (!fr_desc->valid) {  		memset(&inv_wr, 0, sizeof(inv_wr)); +		inv_wr.wr_id = ISER_FASTREG_LI_WRID;  		inv_wr.opcode = IB_WR_LOCAL_INV;  		inv_wr.ex.invalidate_rkey = fr_desc->data_mr->rkey;  		wr = &inv_wr; @@ -2211,6 +2266,7 @@ isert_fast_reg_mr(struct fast_reg_descriptor *fr_desc,  	/* Prepare FASTREG WR */  	memset(&fr_wr, 0, sizeof(fr_wr)); +	fr_wr.wr_id = ISER_FASTREG_LI_WRID;  	fr_wr.opcode = IB_WR_FAST_REG_MR;  	fr_wr.wr.fast_reg.iova_start =  		fr_desc->data_frpl->page_list[0] + page_off; @@ -2376,12 +2432,12 @@ isert_put_datain(struct iscsi_conn *conn, struct iscsi_cmd *cmd)  	isert_init_send_wr(isert_conn, isert_cmd,  			   &isert_cmd->tx_desc.send_wr, true); -	atomic_inc(&isert_conn->post_send_buf_count); +	atomic_add(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);  	rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);  	if (rc) {  		pr_warn("ib_post_send() failed for IB_WR_RDMA_WRITE\n"); -		atomic_dec(&isert_conn->post_send_buf_count); +		atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);  	}  	pr_debug("Cmd: %p posted RDMA_WRITE + Response for iSER Data READ\n",  		 isert_cmd); @@ -2409,12 +2465,12 @@ isert_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, bool recovery)  		return rc;  	} -	atomic_inc(&isert_conn->post_send_buf_count); +	atomic_add(wr->send_wr_num, &isert_conn->post_send_buf_count);  	rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);  	if (rc) {  		pr_warn("ib_post_send() failed for IB_WR_RDMA_READ\n"); -		atomic_dec(&isert_conn->post_send_buf_count); +		atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count);  	}  	pr_debug("Cmd: %p posted RDMA_READ memory for ISER Data WRITE\n",  		 isert_cmd); @@ -2701,22 +2757,11 @@ isert_free_np(struct iscsi_np *np)  	kfree(isert_np);  } -static int isert_check_state(struct isert_conn *isert_conn, int state) -{ -	int ret; - -	mutex_lock(&isert_conn->conn_mutex); -	ret = (isert_conn->state == state); -	mutex_unlock(&isert_conn->conn_mutex); - -	return ret; -} - -static void isert_free_conn(struct iscsi_conn *conn) +static void isert_wait_conn(struct iscsi_conn *conn)  {  	struct isert_conn *isert_conn = conn->context; -	pr_debug("isert_free_conn: Starting \n"); +	pr_debug("isert_wait_conn: Starting \n");  	/*  	 * Decrement post_send_buf_count for special case when called  	 * from isert_do_control_comp() -> iscsit_logout_post_handler() @@ -2726,38 +2771,29 @@ static void isert_free_conn(struct iscsi_conn *conn)  		atomic_dec(&isert_conn->post_send_buf_count);  	if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) { -		pr_debug("Calling rdma_disconnect from isert_free_conn\n"); +		pr_debug("Calling rdma_disconnect from isert_wait_conn\n");  		rdma_disconnect(isert_conn->conn_cm_id);  	}  	/*  	 * Only wait for conn_wait_comp_err if the isert_conn made it  	 * into full feature phase..  	 */ -	if (isert_conn->state == ISER_CONN_UP) { -		pr_debug("isert_free_conn: Before wait_event comp_err %d\n", -			 isert_conn->state); -		mutex_unlock(&isert_conn->conn_mutex); - -		wait_event(isert_conn->conn_wait_comp_err, -			  (isert_check_state(isert_conn, ISER_CONN_TERMINATING))); - -		wait_event(isert_conn->conn_wait, -			  (isert_check_state(isert_conn, ISER_CONN_DOWN))); - -		isert_put_conn(isert_conn); -		return; -	}  	if (isert_conn->state == ISER_CONN_INIT) {  		mutex_unlock(&isert_conn->conn_mutex); -		isert_put_conn(isert_conn);  		return;  	} -	pr_debug("isert_free_conn: wait_event conn_wait %d\n", -		 isert_conn->state); +	if (isert_conn->state == ISER_CONN_UP) +		isert_conn->state = ISER_CONN_TERMINATING;  	mutex_unlock(&isert_conn->conn_mutex); -	wait_event(isert_conn->conn_wait, -		  (isert_check_state(isert_conn, ISER_CONN_DOWN))); +	wait_for_completion(&isert_conn->conn_wait_comp_err); + +	wait_for_completion(&isert_conn->conn_wait); +} + +static void isert_free_conn(struct iscsi_conn *conn) +{ +	struct isert_conn *isert_conn = conn->context;  	isert_put_conn(isert_conn);  } @@ -2770,6 +2806,7 @@ static struct iscsit_transport iser_target_transport = {  	.iscsit_setup_np	= isert_setup_np,  	.iscsit_accept_np	= isert_accept_np,  	.iscsit_free_np		= isert_free_np, +	.iscsit_wait_conn	= isert_wait_conn,  	.iscsit_free_conn	= isert_free_conn,  	.iscsit_get_login_rx	= isert_get_login_rx,  	.iscsit_put_login_tx	= isert_put_login_tx,  | 
