[PATCH] libata: implement and apply ata_eh_qc_complete/retry()
[linux-2.6-microblaze.git] / drivers / scsi / libata-scsi.c
index cfbceb5..ab6b533 100644 (file)
@@ -738,17 +738,64 @@ int ata_scsi_error(struct Scsi_Host *host)
        ap = (struct ata_port *) &host->hostdata[0];
        ap->ops->eng_timeout(ap);
 
-       /* TODO: this is per-command; when queueing is supported
-        * this code will either change or move to a more
-        * appropriate place
-        */
-       host->host_failed--;
-       INIT_LIST_HEAD(&host->eh_cmd_q);
+       assert(host->host_failed == 0 && list_empty(&host->eh_cmd_q));
+
+       scsi_eh_flush_done_q(&ap->eh_done_q);
 
        DPRINTK("EXIT\n");
        return 0;
 }
 
+static void ata_eh_scsidone(struct scsi_cmnd *scmd)
+{
+       /* nada */
+}
+
+static void __ata_eh_qc_complete(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct scsi_cmnd *scmd = qc->scsicmd;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ap->host_set->lock, flags);
+       qc->scsidone = ata_eh_scsidone;
+       ata_qc_complete(qc);
+       assert(!ata_tag_valid(qc->tag));
+       spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+       scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
+}
+
+/**
+ *     ata_eh_qc_complete - Complete an active ATA command from EH
+ *     @qc: Command to complete
+ *
+ *     Indicate to the mid and upper layers that an ATA command has
+ *     completed.  To be used from EH.
+ */
+void ata_eh_qc_complete(struct ata_queued_cmd *qc)
+{
+       struct scsi_cmnd *scmd = qc->scsicmd;
+       scmd->retries = scmd->allowed;
+       __ata_eh_qc_complete(qc);
+}
+
+/**
+ *     ata_eh_qc_retry - Tell midlayer to retry an ATA command after EH
+ *     @qc: Command to retry
+ *
+ *     Indicate to the mid and upper layers that an ATA command
+ *     should be retried.  To be used from EH.
+ *
+ *     SCSI midlayer limits the number of retries to scmd->allowed.
+ *     This function might need to adjust scmd->retries for commands
+ *     which get retried due to unrelated NCQ failures.
+ */
+void ata_eh_qc_retry(struct ata_queued_cmd *qc)
+{
+       __ata_eh_qc_complete(qc);
+}
+
 /**
  *     ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
  *     @qc: Storage for translated ATA taskfile
@@ -985,9 +1032,13 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *sc
        if (dev->flags & ATA_DFLAG_LBA) {
                tf->flags |= ATA_TFLAG_LBA;
 
-               if (dev->flags & ATA_DFLAG_LBA48) {
-                       if (n_block > (64 * 1024))
-                               goto invalid_fld;
+               if (lba_28_ok(block, n_block)) {
+                       /* use LBA28 */
+                       tf->command = ATA_CMD_VERIFY;
+                       tf->device |= (block >> 24) & 0xf;
+               } else if (lba_48_ok(block, n_block)) {
+                       if (!(dev->flags & ATA_DFLAG_LBA48))
+                               goto out_of_range;
 
                        /* use LBA48 */
                        tf->flags |= ATA_TFLAG_LBA48;
@@ -998,15 +1049,9 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *sc
                        tf->hob_lbah = (block >> 40) & 0xff;
                        tf->hob_lbam = (block >> 32) & 0xff;
                        tf->hob_lbal = (block >> 24) & 0xff;
-               } else {
-                       if (n_block > 256)
-                               goto invalid_fld;
-
-                       /* use LBA28 */
-                       tf->command = ATA_CMD_VERIFY;
-
-                       tf->device |= (block >> 24) & 0xf;
-               }
+               } else
+                       /* request too large even for LBA48 */
+                       goto out_of_range;
 
                tf->nsect = n_block & 0xff;
 
@@ -1019,8 +1064,8 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *sc
                /* CHS */
                u32 sect, head, cyl, track;
 
-               if (n_block > 256)
-                       goto invalid_fld;
+               if (!lba_28_ok(block, n_block))
+                       goto out_of_range;
 
                /* Convert LBA to CHS */
                track = (u32)block / dev->sectors;
@@ -1139,9 +1184,11 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
        if (dev->flags & ATA_DFLAG_LBA) {
                tf->flags |= ATA_TFLAG_LBA;
 
-               if (dev->flags & ATA_DFLAG_LBA48) {
-                       /* The request -may- be too large for LBA48. */
-                       if ((block >> 48) || (n_block > 65536))
+               if (lba_28_ok(block, n_block)) {
+                       /* use LBA28 */
+                       tf->device |= (block >> 24) & 0xf;
+               } else if (lba_48_ok(block, n_block)) {
+                       if (!(dev->flags & ATA_DFLAG_LBA48))
                                goto out_of_range;
 
                        /* use LBA48 */
@@ -1152,15 +1199,9 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
                        tf->hob_lbah = (block >> 40) & 0xff;
                        tf->hob_lbam = (block >> 32) & 0xff;
                        tf->hob_lbal = (block >> 24) & 0xff;
-               } else { 
-                       /* use LBA28 */
-
-                       /* The request -may- be too large for LBA28. */
-                       if ((block >> 28) || (n_block > 256))
-                               goto out_of_range;
-
-                       tf->device |= (block >> 24) & 0xf;
-               }
+               } else
+                       /* request too large even for LBA48 */
+                       goto out_of_range;
 
                if (unlikely(ata_rwcmd_protocol(qc) < 0))
                        goto invalid_fld;
@@ -1178,7 +1219,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
                u32 sect, head, cyl, track;
 
                /* The request -may- be too large for CHS addressing. */
-               if ((block >> 28) || (n_block > 256))
+               if (!lba_28_ok(block, n_block))
                        goto out_of_range;
 
                if (unlikely(ata_rwcmd_protocol(qc) < 0))
@@ -1225,7 +1266,7 @@ nothing_to_do:
        return 1;
 }
 
-static int ata_scsi_qc_complete(struct ata_queued_cmd *qc)
+static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
 {
        struct scsi_cmnd *cmd = qc->scsicmd;
        u8 *cdb = cmd->cmnd;
@@ -1262,7 +1303,7 @@ static int ata_scsi_qc_complete(struct ata_queued_cmd *qc)
 
        qc->scsidone(cmd);
 
-       return 0;
+       ata_qc_free(qc);
 }
 
 /**
@@ -1328,8 +1369,9 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev,
                goto early_finish;
 
        /* select device, send command to hardware */
-       if (ata_qc_issue(qc))
-               goto err_did;
+       qc->err_mask = ata_qc_issue(qc);
+       if (qc->err_mask)
+               ata_qc_complete(qc);
 
        VPRINTK("EXIT\n");
        return;
@@ -1988,7 +2030,7 @@ void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8
        done(cmd);
 }
 
-static int atapi_sense_complete(struct ata_queued_cmd *qc)
+static void atapi_sense_complete(struct ata_queued_cmd *qc)
 {
        if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0))
                /* FIXME: not quite right; we don't want the
@@ -1999,7 +2041,7 @@ static int atapi_sense_complete(struct ata_queued_cmd *qc)
                ata_gen_ata_desc_sense(qc);
 
        qc->scsidone(qc->scsicmd);
-       return 0;
+       ata_qc_free(qc);
 }
 
 /* is it pointless to prefer PIO for "safety reasons"? */
@@ -2048,15 +2090,14 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
 
        qc->complete_fn = atapi_sense_complete;
 
-       if (ata_qc_issue(qc)) {
-               qc->err_mask |= AC_ERR_OTHER;
+       qc->err_mask = ata_qc_issue(qc);
+       if (qc->err_mask)
                ata_qc_complete(qc);
-       }
 
        DPRINTK("EXIT\n");
 }
 
-static int atapi_qc_complete(struct ata_queued_cmd *qc)
+static void atapi_qc_complete(struct ata_queued_cmd *qc)
 {
        struct scsi_cmnd *cmd = qc->scsicmd;
        unsigned int err_mask = qc->err_mask;
@@ -2066,7 +2107,7 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc)
        if (unlikely(err_mask & AC_ERR_DEV)) {
                cmd->result = SAM_STAT_CHECK_CONDITION;
                atapi_request_sense(qc);
-               return 1;
+               return;
        }
 
        else if (unlikely(err_mask))
@@ -2106,7 +2147,7 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc)
        }
 
        qc->scsidone(cmd);
-       return 0;
+       ata_qc_free(qc);
 }
 /**
  *     atapi_xlat - Initialize PACKET taskfile