scsi: fully quiesce I/O on ioctl reset

When calling sg_reset we're calling the various EH handler functions
directly. However, the calling convention for those functions
assumes that no I/O is pending or can be submitted when these
functions are called.
The latter is provided by the 'tmf_in_progress' flag, but we don't
actually wait for all I/O to complete.
This patch introduces a completion point which ensures all I/O
has been completed before ioctl reset is issued.

Signed-off-by: Hannes Reinecke <hare@suse.com>
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index e0c52ba..1e2cac5 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -66,9 +66,14 @@
 {
 	if (atomic_read(&shost->host_busy) == shost->host_failed) {
 		trace_scsi_eh_wakeup(shost);
-		wake_up_process(shost->ehandler);
-		SCSI_LOG_ERROR_RECOVERY(5, shost_printk(KERN_INFO, shost,
-			"Waking error handler thread\n"));
+		if (shost->tmf_quiesce_done)
+			complete(shost->tmf_quiesce_done);
+		else {
+			wake_up_process(shost->ehandler);
+			SCSI_LOG_ERROR_RECOVERY(5,
+				shost_printk(KERN_INFO, shost,
+					     "Waking error handler thread\n"));
+		}
 	}
 }
 
@@ -2292,6 +2297,7 @@
 	struct Scsi_Host *shost = dev->host;
 	unsigned long flags;
 	int error = 0, rtn, val;
+	DECLARE_COMPLETION_ONSTACK(done);
 
 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
 		return -EACCES;
@@ -2306,6 +2312,13 @@
 	error = -EIO;
 	spin_lock_irqsave(shost->host_lock, flags);
 	shost->tmf_in_progress = 1;
+	shost->tmf_quiesce_done = &done;
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	wait_for_completion(&done);
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	shost->tmf_quiesce_done = NULL;
 	spin_unlock_irqrestore(shost->host_lock, flags);
 
 	switch (val & ~SG_SCSI_RESET_NO_ESCALATE) {
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 7095076..e0a6956 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -679,6 +679,8 @@
 	 */
 	struct workqueue_struct *tmf_work_q;
 
+	struct completion *tmf_quiesce_done;
+
 	/* The transport requires the LUN bits NOT to be stored in CDB[1] */
 	unsigned no_scsi2_lun_in_cdb:1;