cregit-Linux how code gets into the kernel

Release 4.11 drivers/target/iscsi/iscsi_target_erl2.c

/*******************************************************************************
 * This file contains error recovery level two functions used by
 * the iSCSI Target driver.
 *
 * (c) Copyright 2007-2013 Datera, Inc.
 *
 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 ******************************************************************************/

#include <linux/slab.h>
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>

#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_datain_values.h"
#include "iscsi_target_util.h"
#include "iscsi_target_erl0.h"
#include "iscsi_target_erl1.h"
#include "iscsi_target_erl2.h"
#include "iscsi_target.h"

/*
 *      FIXME: Does RData SNACK apply here as well?
 */

void iscsit_create_conn_recovery_datain_values( struct iscsi_cmd *cmd, __be32 exp_data_sn) { u32 data_sn = 0; struct iscsi_conn *conn = cmd->conn; cmd->next_burst_len = 0; cmd->read_data_done = 0; while (be32_to_cpu(exp_data_sn) > data_sn) { if ((cmd->next_burst_len + conn->conn_ops->MaxRecvDataSegmentLength) < conn->sess->sess_ops->MaxBurstLength) { cmd->read_data_done += conn->conn_ops->MaxRecvDataSegmentLength; cmd->next_burst_len += conn->conn_ops->MaxRecvDataSegmentLength; } else { cmd->read_data_done += (conn->sess->sess_ops->MaxBurstLength - cmd->next_burst_len); cmd->next_burst_len = 0; } data_sn++; } }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger12096.77%150.00%
Christoph Hellwig43.23%150.00%
Total124100.00%2100.00%


void iscsit_create_conn_recovery_dataout_values( struct iscsi_cmd *cmd) { u32 write_data_done = 0; struct iscsi_conn *conn = cmd->conn; cmd->data_sn = 0; cmd->next_burst_len = 0; while (cmd->write_data_done > write_data_done) { if ((write_data_done + conn->sess->sess_ops->MaxBurstLength) <= cmd->write_data_done) write_data_done += conn->sess->sess_ops->MaxBurstLength; else break; } cmd->write_data_done = write_data_done; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger82100.00%1100.00%
Total82100.00%1100.00%


static int iscsit_attach_active_connection_recovery_entry( struct iscsi_session *sess, struct iscsi_conn_recovery *cr) { spin_lock(&sess->cr_a_lock); list_add_tail(&cr->cr_list, &sess->cr_active_list); spin_unlock(&sess->cr_a_lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger48100.00%1100.00%
Total48100.00%1100.00%


static int iscsit_attach_inactive_connection_recovery_entry( struct iscsi_session *sess, struct iscsi_conn_recovery *cr) { spin_lock(&sess->cr_i_lock); list_add_tail(&cr->cr_list, &sess->cr_inactive_list); sess->conn_recovery_count++; pr_debug("Incremented connection recovery count to %u for" " SID: %u\n", sess->conn_recovery_count, sess->sid); spin_unlock(&sess->cr_i_lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger67100.00%1100.00%
Total67100.00%1100.00%


struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry( struct iscsi_session *sess, u16 cid) { struct iscsi_conn_recovery *cr; spin_lock(&sess->cr_i_lock); list_for_each_entry(cr, &sess->cr_inactive_list, cr_list) { if (cr->cid == cid) { spin_unlock(&sess->cr_i_lock); return cr; } } spin_unlock(&sess->cr_i_lock); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger70100.00%1100.00%
Total70100.00%1100.00%


void iscsit_free_connection_recovery_entires(struct iscsi_session *sess) { struct iscsi_cmd *cmd, *cmd_tmp; struct iscsi_conn_recovery *cr, *cr_tmp; spin_lock(&sess->cr_a_lock); list_for_each_entry_safe(cr, cr_tmp, &sess->cr_active_list, cr_list) { list_del(&cr->cr_list); spin_unlock(&sess->cr_a_lock); spin_lock(&cr->conn_recovery_cmd_lock); list_for_each_entry_safe(cmd, cmd_tmp, &cr->conn_recovery_cmd_list, i_conn_node) { list_del_init(&cmd->i_conn_node); cmd->conn = NULL; spin_unlock(&cr->conn_recovery_cmd_lock); iscsit_free_cmd(cmd, true); spin_lock(&cr->conn_recovery_cmd_lock); } spin_unlock(&cr->conn_recovery_cmd_lock); spin_lock(&sess->cr_a_lock); kfree(cr); } spin_unlock(&sess->cr_a_lock); spin_lock(&sess->cr_i_lock); list_for_each_entry_safe(cr, cr_tmp, &sess->cr_inactive_list, cr_list) { list_del(&cr->cr_list); spin_unlock(&sess->cr_i_lock); spin_lock(&cr->conn_recovery_cmd_lock); list_for_each_entry_safe(cmd, cmd_tmp, &cr->conn_recovery_cmd_list, i_conn_node) { list_del_init(&cmd->i_conn_node); cmd->conn = NULL; spin_unlock(&cr->conn_recovery_cmd_lock); iscsit_free_cmd(cmd, true); spin_lock(&cr->conn_recovery_cmd_lock); } spin_unlock(&cr->conn_recovery_cmd_lock); spin_lock(&sess->cr_i_lock); kfree(cr); } spin_unlock(&sess->cr_i_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger26698.52%480.00%
Andy Grover41.48%120.00%
Total270100.00%5100.00%


int iscsit_remove_active_connection_recovery_entry( struct iscsi_conn_recovery *cr, struct iscsi_session *sess) { spin_lock(&sess->cr_a_lock); list_del(&cr->cr_list); sess->conn_recovery_count--; pr_debug("Decremented connection recovery count to %u for" " SID: %u\n", sess->conn_recovery_count, sess->sid); spin_unlock(&sess->cr_a_lock); kfree(cr); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger66100.00%1100.00%
Total66100.00%1100.00%


static void iscsit_remove_inactive_connection_recovery_entry( struct iscsi_conn_recovery *cr, struct iscsi_session *sess) { spin_lock(&sess->cr_i_lock); list_del(&cr->cr_list); spin_unlock(&sess->cr_i_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger3895.00%150.00%
Christoph Hellwig25.00%150.00%
Total40100.00%2100.00%

/* * Called with cr->conn_recovery_cmd_lock help. */
int iscsit_remove_cmd_from_connection_recovery( struct iscsi_cmd *cmd, struct iscsi_session *sess) { struct iscsi_conn_recovery *cr; if (!cmd->cr) { pr_err("struct iscsi_conn_recovery pointer for ITT: 0x%08x" " is NULL!\n", cmd->init_task_tag); BUG(); } cr = cmd->cr; list_del_init(&cmd->i_conn_node); return --cr->cmd_count; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger6198.39%266.67%
Andy Grover11.61%133.33%
Total62100.00%3100.00%


void iscsit_discard_cr_cmds_by_expstatsn( struct iscsi_conn_recovery *cr, u32 exp_statsn) { u32 dropped_count = 0; struct iscsi_cmd *cmd, *cmd_tmp; struct iscsi_session *sess = cr->sess; spin_lock(&cr->conn_recovery_cmd_lock); list_for_each_entry_safe(cmd, cmd_tmp, &cr->conn_recovery_cmd_list, i_conn_node) { if (((cmd->deferred_i_state != ISTATE_SENT_STATUS) && (cmd->deferred_i_state != ISTATE_REMOVE)) || (cmd->stat_sn >= exp_statsn)) { continue; } dropped_count++; pr_debug("Dropping Acknowledged ITT: 0x%08x, StatSN:" " 0x%08x, CID: %hu.\n", cmd->init_task_tag, cmd->stat_sn, cr->cid); iscsit_remove_cmd_from_connection_recovery(cmd, sess); spin_unlock(&cr->conn_recovery_cmd_lock); iscsit_free_cmd(cmd, true); spin_lock(&cr->conn_recovery_cmd_lock); } spin_unlock(&cr->conn_recovery_cmd_lock); pr_debug("Dropped %u total acknowledged commands on" " CID: %hu less than old ExpStatSN: 0x%08x\n", dropped_count, cr->cid, exp_statsn); if (!cr->cmd_count) { pr_debug("No commands to be reassigned for failed" " connection CID: %hu on SID: %u\n", cr->cid, sess->sid); iscsit_remove_inactive_connection_recovery_entry(cr, sess); iscsit_attach_active_connection_recovery_entry(sess, cr); pr_debug("iSCSI connection recovery successful for CID:" " %hu on SID: %u\n", cr->cid, sess->sid); iscsit_remove_active_connection_recovery_entry(cr, sess); } else { iscsit_remove_inactive_connection_recovery_entry(cr, sess); iscsit_attach_active_connection_recovery_entry(sess, cr); } }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger23399.57%375.00%
Andy Grover10.43%125.00%
Total234100.00%4100.00%


int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn) { u32 dropped_count = 0; struct iscsi_cmd *cmd, *cmd_tmp; struct iscsi_ooo_cmdsn *ooo_cmdsn, *ooo_cmdsn_tmp; struct iscsi_session *sess = conn->sess; mutex_lock(&sess->cmdsn_mutex); list_for_each_entry_safe(ooo_cmdsn, ooo_cmdsn_tmp, &sess->sess_ooo_cmdsn_list, ooo_list) { if (ooo_cmdsn->cid != conn->cid) continue; dropped_count++; pr_debug("Dropping unacknowledged CmdSN:" " 0x%08x during connection recovery on CID: %hu\n", ooo_cmdsn->cmdsn, conn->cid); iscsit_remove_ooo_cmdsn(sess, ooo_cmdsn); } mutex_unlock(&sess->cmdsn_mutex); spin_lock_bh(&conn->cmd_lock); list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) { if (!(cmd->cmd_flags & ICF_OOO_CMDSN)) continue; list_del_init(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_free_cmd(cmd, true); spin_lock_bh(&conn->cmd_lock); } spin_unlock_bh(&conn->cmd_lock); pr_debug("Dropped %u total unacknowledged commands on CID:" " %hu for ExpCmdSN: 0x%08x.\n", dropped_count, conn->cid, sess->exp_cmd_sn); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger19198.96%480.00%
Andy Grover21.04%120.00%
Total193100.00%5100.00%


int iscsit_prepare_cmds_for_reallegiance(struct iscsi_conn *conn) { u32 cmd_count = 0; struct iscsi_cmd *cmd, *cmd_tmp; struct iscsi_conn_recovery *cr; /* * Allocate an struct iscsi_conn_recovery for this connection. * Each struct iscsi_cmd contains an struct iscsi_conn_recovery pointer * (struct iscsi_cmd->cr) so we need to allocate this before preparing the * connection's command list for connection recovery. */ cr = kzalloc(sizeof(struct iscsi_conn_recovery), GFP_KERNEL); if (!cr) { pr_err("Unable to allocate memory for" " struct iscsi_conn_recovery.\n"); return -1; } INIT_LIST_HEAD(&cr->cr_list); INIT_LIST_HEAD(&cr->conn_recovery_cmd_list); spin_lock_init(&cr->conn_recovery_cmd_lock); /* * Only perform connection recovery on ISCSI_OP_SCSI_CMD or * ISCSI_OP_NOOP_OUT opcodes. For all other opcodes call * list_del_init(&cmd->i_conn_node); to release the command to the * session pool and remove it from the connection's list. * * Also stop the DataOUT timer, which will be restarted after * sending the TMR response. */ spin_lock_bh(&conn->cmd_lock); list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) { if ((cmd->iscsi_opcode != ISCSI_OP_SCSI_CMD) && (cmd->iscsi_opcode != ISCSI_OP_NOOP_OUT)) { pr_debug("Not performing reallegiance on" " Opcode: 0x%02x, ITT: 0x%08x, CmdSN: 0x%08x," " CID: %hu\n", cmd->iscsi_opcode, cmd->init_task_tag, cmd->cmd_sn, conn->cid); list_del_init(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_free_cmd(cmd, true); spin_lock_bh(&conn->cmd_lock); continue; } /* * Special case where commands greater than or equal to * the session's ExpCmdSN are attached to the connection * list but not to the out of order CmdSN list. The one * obvious case is when a command with immediate data * attached must only check the CmdSN against ExpCmdSN * after the data is received. The special case below * is when the connection fails before data is received, * but also may apply to other PDUs, so it has been * made generic here. */ if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd && iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) { list_del_init(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_free_cmd(cmd, true); spin_lock_bh(&conn->cmd_lock); continue; } cmd_count++; pr_debug("Preparing Opcode: 0x%02x, ITT: 0x%08x," " CmdSN: 0x%08x, StatSN: 0x%08x, CID: %hu for" " reallegiance.\n", cmd->iscsi_opcode, cmd->init_task_tag, cmd->cmd_sn, cmd->stat_sn, conn->cid); cmd->deferred_i_state = cmd->i_state; cmd->i_state = ISTATE_IN_CONNECTION_RECOVERY; if (cmd->data_direction == DMA_TO_DEVICE) iscsit_stop_dataout_timer(cmd); cmd->sess = conn->sess; list_del_init(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_free_all_datain_reqs(cmd); transport_wait_for_tasks(&cmd->se_cmd); /* * Add the struct iscsi_cmd to the connection recovery cmd list */ spin_lock(&cr->conn_recovery_cmd_lock); list_add_tail(&cmd->i_conn_node, &cr->conn_recovery_cmd_list); spin_unlock(&cr->conn_recovery_cmd_lock); spin_lock_bh(&conn->cmd_lock); cmd->cr = cr; cmd->conn = NULL; } spin_unlock_bh(&conn->cmd_lock); /* * Fill in the various values in the preallocated struct iscsi_conn_recovery. */ cr->cid = conn->cid; cr->cmd_count = cmd_count; cr->maxrecvdatasegmentlength = conn->conn_ops->MaxRecvDataSegmentLength; cr->maxxmitdatasegmentlength = conn->conn_ops->MaxXmitDataSegmentLength; cr->sess = conn->sess; iscsit_attach_inactive_connection_recovery_entry(conn->sess, cr); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger43797.11%555.56%
Andy Grover51.11%111.11%
Steve Hodgson40.89%111.11%
Bart Van Assche30.67%111.11%
Roland Dreier10.22%111.11%
Total450100.00%9100.00%


int iscsit_connection_recovery_transport_reset(struct iscsi_conn *conn) { atomic_set(&conn->connection_recovery, 1); if (iscsit_close_connection(conn) < 0) return -1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger36100.00%1100.00%
Total36100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Nicholas Bellinger174698.20%640.00%
Andy Grover130.73%16.67%
Christoph Hellwig70.39%320.00%
Bart Van Assche60.34%213.33%
Steve Hodgson40.22%16.67%
Roland Dreier10.06%16.67%
Sagi Grimberg10.06%16.67%
Total1778100.00%15100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.