libata: call ata_check_atapi_dma() with qc better prepared
[sfrench/cifs-2.6.git] / drivers / ata / libata-scsi.c
index dd81fa78cdcf62039c92993b96843c982ec06ee5..4ddf00c8c5f5d977bfb71286d8f3e6f025e750f4 100644 (file)
@@ -893,6 +893,23 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
        return queue_depth;
 }
 
+/* XXX: for spindown warning */
+static void ata_delayed_done_timerfn(unsigned long arg)
+{
+       struct scsi_cmnd *scmd = (void *)arg;
+
+       scmd->scsi_done(scmd);
+}
+
+/* XXX: for spindown warning */
+static void ata_delayed_done(struct scsi_cmnd *scmd)
+{
+       static struct timer_list timer;
+
+       setup_timer(&timer, ata_delayed_done_timerfn, (unsigned long)scmd);
+       mod_timer(&timer, jiffies + 5 * HZ);
+}
+
 /**
  *     ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
  *     @qc: Storage for translated ATA taskfile
@@ -949,22 +966,24 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
                 * removed.  Read Documentation/feature-removal-schedule.txt
                 * for more info.
                 */
-               if (ata_spindown_compat &&
+               if ((qc->dev->flags & ATA_DFLAG_SPUNDOWN) &&
                    (system_state == SYSTEM_HALT ||
                     system_state == SYSTEM_POWER_OFF)) {
-                       static int warned = 0;
+                       static unsigned long warned = 0;
 
-                       if (!warned) {
-                               spin_unlock_irq(qc->ap->lock);
+                       if (!test_and_set_bit(0, &warned)) {
                                ata_dev_printk(qc->dev, KERN_WARNING,
                                        "DISK MIGHT NOT BE SPUN DOWN PROPERLY. "
                                        "UPDATE SHUTDOWN UTILITY\n");
                                ata_dev_printk(qc->dev, KERN_WARNING,
                                        "For more info, visit "
                                        "http://linux-ata.org/shutdown.html\n");
-                               warned = 1;
-                               ssleep(5);
-                               spin_lock_irq(qc->ap->lock);
+
+                               /* ->scsi_done is not used, use it for
+                                * delayed completion.
+                                */
+                               scmd->scsi_done = qc->scsidone;
+                               qc->scsidone = ata_delayed_done;
                        }
                        scmd->result = SAM_STAT_GOOD;
                        return 1;
@@ -1031,14 +1050,15 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc)
 static void scsi_6_lba_len(const u8 *cdb, u64 *plba, u32 *plen)
 {
        u64 lba = 0;
-       u32 len = 0;
+       u32 len;
 
        VPRINTK("six-byte command\n");
 
+       lba |= ((u64)(cdb[1] & 0x1f)) << 16;
        lba |= ((u64)cdb[2]) << 8;
        lba |= ((u64)cdb[3]);
 
-       len |= ((u32)cdb[4]);
+       len = cdb[4];
 
        *plba = lba;
        *plen = len;
@@ -1343,12 +1363,22 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
         * schedule EH_REVALIDATE operation to update the IDENTIFY DEVICE
         * cache
         */
-       if (ap->ops->error_handler &&
-           !need_sense && (qc->tf.command == ATA_CMD_SET_FEATURES) &&
-           ((qc->tf.feature == SETFEATURES_WC_ON) ||
-            (qc->tf.feature == SETFEATURES_WC_OFF))) {
-               ap->eh_info.action |= ATA_EH_REVALIDATE;
-               ata_port_schedule_eh(ap);
+       if (ap->ops->error_handler && !need_sense) {
+               switch (qc->tf.command) {
+               case ATA_CMD_SET_FEATURES:
+                       if ((qc->tf.feature == SETFEATURES_WC_ON) ||
+                           (qc->tf.feature == SETFEATURES_WC_OFF)) {
+                               ap->eh_info.action |= ATA_EH_REVALIDATE;
+                               ata_port_schedule_eh(ap);
+                       }
+                       break;
+
+               case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */
+               case ATA_CMD_SET_MULTI: /* multi_count changed */
+                       ap->eh_info.action |= ATA_EH_REVALIDATE;
+                       ata_port_schedule_eh(ap);
+                       break;
+               }
        }
 
        /* For ATA pass thru (SAT) commands, generate a sense block if
@@ -1375,6 +1405,14 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
                }
        }
 
+       /* XXX: track spindown state for spindown skipping and warning */
+       if (unlikely(qc->tf.command == ATA_CMD_STANDBY ||
+                    qc->tf.command == ATA_CMD_STANDBYNOW1))
+               qc->dev->flags |= ATA_DFLAG_SPUNDOWN;
+       else if (likely(system_state != SYSTEM_HALT &&
+                       system_state != SYSTEM_POWER_OFF))
+               qc->dev->flags &= ~ATA_DFLAG_SPUNDOWN;
+
        if (need_sense && !ap->ops->error_handler)
                ata_dump_status(ap->print_id, &qc->result_tf);
 
@@ -1488,14 +1526,14 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
 
 early_finish:
         ata_qc_free(qc);
-       done(cmd);
+       qc->scsidone(cmd);
        DPRINTK("EXIT - early finish (good or error)\n");
        return 0;
 
 err_did:
        ata_qc_free(qc);
        cmd->result = (DID_ERROR << 16);
-       done(cmd);
+       qc->scsidone(cmd);
 err_mem:
        DPRINTK("EXIT - internal\n");
        return 0;
@@ -2346,11 +2384,6 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
        int using_pio = (dev->flags & ATA_DFLAG_PIO);
        int nodata = (scmd->sc_data_direction == DMA_NONE);
 
-       if (!using_pio)
-               /* Check whether ATAPI DMA is safe */
-               if (ata_check_atapi_dma(qc))
-                       using_pio = 1;
-
        memset(qc->cdb, 0, dev->cdb_len);
        memcpy(qc->cdb, scmd->cmnd, scmd->cmd_len);
 
@@ -2363,19 +2396,22 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
        }
 
        qc->tf.command = ATA_CMD_PACKET;
+       qc->nbytes = scmd->request_bufflen;
+
+       /* check whether ATAPI DMA is safe */
+       if (!using_pio && ata_check_atapi_dma(qc))
+               using_pio = 1;
 
-       /* no data, or PIO data xfer */
        if (using_pio || nodata) {
+               /* no data, or PIO data xfer */
                if (nodata)
                        qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
                else
                        qc->tf.protocol = ATA_PROT_ATAPI;
                qc->tf.lbam = (8 * 1024) & 0xff;
                qc->tf.lbah = (8 * 1024) >> 8;
-       }
-
-       /* DMA data xfer */
-       else {
+       } else {
+               /* DMA data xfer */
                qc->tf.protocol = ATA_PROT_ATAPI_DMA;
                qc->tf.feature |= ATAPI_PKT_DMA;
 
@@ -2384,8 +2420,6 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
                        qc->tf.feature |= ATAPI_DMADIR;
        }
 
-       qc->nbytes = scmd->request_bufflen;
-
        return 0;
 }
 
@@ -2478,22 +2512,21 @@ ata_scsi_map_proto(u8 byte1)
                        return ATA_PROT_NODATA;
 
                case 6:         /* DMA */
+               case 10:        /* UDMA Data-in */
+               case 11:        /* UDMA Data-Out */
                        return ATA_PROT_DMA;
 
                case 4:         /* PIO Data-in */
                case 5:         /* PIO Data-out */
                        return ATA_PROT_PIO;
 
-               case 10:        /* Device Reset */
                case 0:         /* Hard Reset */
                case 1:         /* SRST */
-               case 2:         /* Bus Idle */
-               case 7:         /* Packet */
-               case 8:         /* DMA Queued */
-               case 9:         /* Device Diagnostic */
-               case 11:        /* UDMA Data-in */
-               case 12:        /* UDMA Data-Out */
-               case 13:        /* FPDMA */
+               case 8:         /* Device Diagnostic */
+               case 9:         /* Device Reset */
+               case 7:         /* DMA Queued */
+               case 12:        /* FPDMA */
+               case 15:        /* Return Response Info */
                default:        /* Reserved */
                        break;
        }
@@ -2524,10 +2557,6 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
        if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0)
                goto invalid_fld;
 
-       if (cdb[1] & 0xe0)
-               /* PIO multi not supported yet */
-               goto invalid_fld;
-
        /*
         * 12 and 16 byte CDBs use different offsets to
         * provide the various register values.
@@ -2572,12 +2601,26 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
                tf->device = cdb[8];
                tf->command = cdb[9];
        }
-       /*
-        * If slave is possible, enforce correct master/slave bit
-       */
-       if (qc->ap->flags & ATA_FLAG_SLAVE_POSS)
-               tf->device = qc->dev->devno ?
-                       tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
+
+       /* enforce correct master/slave bit */
+       tf->device = dev->devno ?
+               tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
+
+       /* sanity check for pio multi commands */
+       if ((cdb[1] & 0xe0) && !is_multi_taskfile(tf))
+               goto invalid_fld;
+
+       if (is_multi_taskfile(tf)) {
+               unsigned int multi_count = 1 << (cdb[1] >> 5);
+
+               /* compare the passed through multi_count
+                * with the cached multi_count of libata
+                */
+               if (multi_count != dev->multi_count)
+                       ata_dev_printk(dev, KERN_WARNING,
+                                      "invalid multi_count %u ignored\n",
+                                      multi_count);
+       }       
 
        /* READ/WRITE LONG use a non-standard sect_size */
        qc->sect_size = ATA_SECT_SIZE;