From: Jeff Garzik <jgarzik@pobox.com>

The SCSI part of this change was ACK'd by James, and is needed anyway for
anybody using the SCSI layer's ->eh_strategy_handler().  I was just the
first to actually use ->eh_strategy_handler(), it looks like :)

Long term probably better to kill ->eh_strategy_handler(), but I leave that
up to James, Christoph, and the wiser heads of scsi land.


[libata] Use scsi_finish_command as completion function, in our
         error handling thread callback.  This also exports
         scsi_finish_command in the SCSI layer.  Thanks much to James
         Bottomley and his patience, as this solution was figured out.



---

 drivers/scsi/libata-core.c |    8 ++++++++
 drivers/scsi/scsi.c        |    1 +
 drivers/scsi/scsi_priv.h   |    1 -
 include/scsi/scsi_cmnd.h   |    1 +
 4 files changed, 10 insertions(+), 1 deletion(-)

diff -puN drivers/scsi/libata-core.c~libata-fix drivers/scsi/libata-core.c
--- 25/drivers/scsi/libata-core.c~libata-fix	2004-02-28 16:55:51.000000000 -0800
+++ 25-akpm/drivers/scsi/libata-core.c	2004-02-28 16:55:51.000000000 -0800
@@ -2005,6 +2005,14 @@ void ata_eng_timeout(struct ata_port *ap
 		goto out;
 	}
 
+	/* hack alert!  We cannot use the supplied completion
+	 * function from inside the ->eh_strategy_handler() thread.
+	 * libata is the only user of ->eh_strategy_handler() in
+	 * any kernel, so the default scsi_done() assumes it is
+	 * not being called from the SCSI EH.
+	 */
+	qc->scsidone = scsi_finish_command;
+
 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA_READ:
 	case ATA_PROT_DMA_WRITE:
diff -puN drivers/scsi/scsi.c~libata-fix drivers/scsi/scsi.c
--- 25/drivers/scsi/scsi.c~libata-fix	2004-02-28 16:55:51.000000000 -0800
+++ 25-akpm/drivers/scsi/scsi.c	2004-02-28 16:55:51.000000000 -0800
@@ -849,6 +849,7 @@ void scsi_finish_command(struct scsi_cmn
 
 	cmd->done(cmd);
 }
+EXPORT_SYMBOL(scsi_finish_command);
 
 /*
  * Function:	scsi_adjust_queue_depth()
diff -puN drivers/scsi/scsi_priv.h~libata-fix drivers/scsi/scsi_priv.h
--- 25/drivers/scsi/scsi_priv.h~libata-fix	2004-02-28 16:55:51.000000000 -0800
+++ 25-akpm/drivers/scsi/scsi_priv.h	2004-02-28 16:55:51.000000000 -0800
@@ -77,7 +77,6 @@ extern int scsi_dispatch_cmd(struct scsi
 extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
 extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
 extern void scsi_done(struct scsi_cmnd *cmd);
-extern void scsi_finish_command(struct scsi_cmnd *cmd);
 extern int scsi_retry_command(struct scsi_cmnd *cmd);
 extern int scsi_insert_special_req(struct scsi_request *sreq, int);
 extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd,
diff -puN include/scsi/scsi_cmnd.h~libata-fix include/scsi/scsi_cmnd.h
--- 25/include/scsi/scsi_cmnd.h~libata-fix	2004-02-28 16:55:51.000000000 -0800
+++ 25-akpm/include/scsi/scsi_cmnd.h	2004-02-28 16:55:51.000000000 -0800
@@ -159,5 +159,6 @@ struct scsi_cmnd {
 extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, int);
 extern void scsi_put_command(struct scsi_cmnd *);
 extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int);
+extern void scsi_finish_command(struct scsi_cmnd *cmd);
 
 #endif /* _SCSI_SCSI_CMND_H */

_