Tejun Heo wrote:
 And this is the combined patch against ncq head of libata-dev-2.6
tree.  Commit d032ec9048ff82a704b96b93cfd6f2e8e3a06b19.

 Only ata_piix, sata_sil and ahci are converted and all other SATA
drivers are broken.  So, enable only those three SATA drivers when
compiling with this patch.

Overall, the approach of adding a timeout to the 'special' commands is a good, and necessary approach.

Comments follow...


Index: work/drivers/scsi/libata-core.c
===================================================================
--- work.orig/drivers/scsi/libata-core.c        2005-08-05 12:55:08.000000000 
+0900
+++ work/drivers/scsi/libata-core.c     2005-08-05 12:55:50.000000000 +0900
@@ -49,6 +49,10 @@
#include "libata.h" +#define ata_for_each_tag(tag, mask) \
+       for (tag = find_first_bit(&mask, ATA_MAX_CMDS); tag < ATA_MAX_CMDS; \
+            tag = find_next_bit(&mask, ATA_MAX_CMDS, tag + 1))
+
 static unsigned int ata_busy_sleep (struct ata_port *ap,
                                    unsigned long tmout_pat,
                                    unsigned long tmout);
@@ -59,7 +63,6 @@ static int fgb(u32 bitmap);
 static int ata_choose_xfer_mode(struct ata_port *ap,
                                u8 *xfer_mode_out,
                                unsigned int *xfer_shift_out);
-static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat);
 static void __ata_qc_complete(struct ata_queued_cmd *qc);
static unsigned int ata_unique_id = 1;
@@ -70,6 +73,87 @@ MODULE_DESCRIPTION("Library module for A
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
+static void ata_qc_complete_noop(struct ata_queued_cmd *qc)
+{
+       /* noop */
+}
+
+static void ata_qc_exec_special_timeout(unsigned long data)
+{
+       struct completion *wait = (void *)data;
+       complete(wait);
+}
+
+/**
+ *     ata_qc_exec_special - execute libata internal special command
+ *     @qc: Command to execute
+ *     @tmout: timeout in jiffies
+ *
+ *     Executes libata internal command with timeout.  Timeout and
+ *     error conditions are reported via return value.  No recovery
+ *     action is taken after a command times out.  It's caller's duto
+ *     to clean up after timeout.
+ *
+ *     Also, note that error condition is checked after the qc is
+ *     completed, meaning that if another command is issued before
+ *     checking the condition, we get the wrong values.  As special
+ *     cmds are used only for initialization and recovery, this
+ *     won't cause any problem currently.
+ *
+ *     LOCKING:
+ *     None.  Should be called with kernel context, might sleep.
+ */
+
+static int ata_qc_exec_special(struct ata_queued_cmd *qc, unsigned long tmout)
+{
+       struct ata_port *ap = qc->ap;
+       DECLARE_COMPLETION(wait);
+       struct timer_list timer;
+       int rc;
+
+       might_sleep();
+
+       if (ata_busy_sleep(ap, ATA_TMOUT_SPECIAL_QUICK, ATA_TMOUT_SPECIAL))
+               return -ETIMEDOUT;
+
+       qc->complete_fn = ata_qc_complete_noop;
+       qc->waiting = &wait;
+
+       if (tmout) {
+               init_timer(&timer);
+               timer.function = ata_qc_exec_special_timeout;
+               timer.data = (unsigned long)&wait;
+               timer.expires = jiffies + tmout;
+               add_timer(&timer);

Just use mod_timer(), and combine these last two lines into a single one.


+       spin_lock_irq(&ap->host_set->lock);
+       rc = ata_qc_issue(qc);
+       spin_unlock_irq(&ap->host_set->lock);
+
+       if (rc) {
+               if (tmout)
+                       del_timer(&timer);

Use del_timer_sync() here, and for every case where you are not inside a spinlock.


+               return -EAGAIN; /* any better value for issue failure? */
+       }
+
+       wait_for_completion(&wait);
+
+       if (tmout && !del_timer(&timer)) {
+               spin_lock_irq(&ap->host_set->lock);
+               if (qc->waiting == &wait) {
+                       ata_qc_complete(qc);
+                       rc = -ETIMEDOUT;
+               }
+               spin_unlock_irq(&ap->host_set->lock);
+       }
+
+       if (rc == 0 && !ata_ok(ata_chk_status(ap)))
+               rc = -EIO;

General comment on libata: we should move away from using the Status register directly, and more towards an indication that the taskfile described by the queue_cmd is in error. i.e. add an 'error' flag or something like that.

The rest seems fairly sane.

General comment on libata error handling: as soon as SATA ATAPI is complete, we can move libata to using SCSI's fine-grained error handling hooks (eh_{abort,timeout,bus,host}_handler), which will make error handling easier, and avoid the problems that keep cropping up with the ->eh_strategy_handler() approach.

        Jeff


-
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to