diff options
Diffstat (limited to 'drivers/scsi/libiscsi.c')
| -rw-r--r-- | drivers/scsi/libiscsi.c | 31 | 
1 files changed, 24 insertions, 7 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 703eb6a8879..633e0903635 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -25,6 +25,7 @@  #include <linux/kfifo.h>  #include <linux/delay.h>  #include <linux/log2.h> +#include <linux/slab.h>  #include <asm/unaligned.h>  #include <net/tcp.h>  #include <scsi/scsi_cmnd.h> @@ -470,12 +471,12 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)  	WARN_ON(hdrlength >= 256);  	hdr->hlength = hdrlength & 0xFF; +	hdr->cmdsn = task->cmdsn = cpu_to_be32(session->cmdsn);  	if (session->tt->init_task && session->tt->init_task(task))  		return -EIO;  	task->state = ISCSI_TASK_RUNNING; -	hdr->cmdsn = task->cmdsn = cpu_to_be32(session->cmdsn);  	session->cmdsn++;  	conn->scsicmd_pdus_cnt++; @@ -2338,7 +2339,7 @@ EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout);   * This function will wait for a relogin, session termination from   * userspace, or a recovery/replacement timeout.   */ -static int iscsi_eh_session_reset(struct scsi_cmnd *sc) +int iscsi_eh_session_reset(struct scsi_cmnd *sc)  {  	struct iscsi_cls_session *cls_session;  	struct iscsi_session *session; @@ -2389,6 +2390,7 @@ failed:  	mutex_unlock(&session->eh_mutex);  	return SUCCESS;  } +EXPORT_SYMBOL_GPL(iscsi_eh_session_reset);  static void iscsi_prep_tgt_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)  { @@ -2403,8 +2405,7 @@ static void iscsi_prep_tgt_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)   * iscsi_eh_target_reset - reset target   * @sc: scsi command   * - * This will attempt to send a warm target reset. If that fails - * then we will drop the session and attempt ERL0 recovery. + * This will attempt to send a warm target reset.   */  int iscsi_eh_target_reset(struct scsi_cmnd *sc)  { @@ -2476,12 +2477,27 @@ done:  	ISCSI_DBG_EH(session, "tgt %s reset result = %s\n", session->targetname,  		     rc == SUCCESS ? "SUCCESS" : "FAILED");  	mutex_unlock(&session->eh_mutex); +	return rc; +} +EXPORT_SYMBOL_GPL(iscsi_eh_target_reset); + +/** + * iscsi_eh_recover_target - reset target and possibly the session + * @sc: scsi command + * + * This will attempt to send a warm target reset. If that fails, + * we will escalate to ERL0 session recovery. + */ +int iscsi_eh_recover_target(struct scsi_cmnd *sc) +{ +	int rc; +	rc = iscsi_eh_target_reset(sc);  	if (rc == FAILED)  		rc = iscsi_eh_session_reset(sc);  	return rc;  } -EXPORT_SYMBOL_GPL(iscsi_eh_target_reset); +EXPORT_SYMBOL_GPL(iscsi_eh_recover_target);  /*   * Pre-allocate a pool of @max items of @item_size. By default, the pool @@ -3072,14 +3088,15 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,  		session->state = ISCSI_STATE_TERMINATE;  	else if (conn->stop_stage != STOP_CONN_RECOVER)  		session->state = ISCSI_STATE_IN_RECOVERY; + +	old_stop_stage = conn->stop_stage; +	conn->stop_stage = flag;  	spin_unlock_bh(&session->lock);  	del_timer_sync(&conn->transport_timer);  	iscsi_suspend_tx(conn);  	spin_lock_bh(&session->lock); -	old_stop_stage = conn->stop_stage; -	conn->stop_stage = flag;  	conn->c_stage = ISCSI_CONN_STOPPED;  	spin_unlock_bh(&session->lock);  |