Merge ../linux-2.6-watchdog-mm
[linux-drm-fsl-dcu.git] / drivers / ata / libata-scsi.c
index 3986ec8741b4157ba46e1415f0487cb05b4fb8d0..47ea111d5acee837d20d8939b9c52c6a46f0357e 100644 (file)
@@ -164,10 +164,10 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
 {
        int rc = 0;
        u8 scsi_cmd[MAX_COMMAND_SIZE];
-       u8 args[4], *argbuf = NULL;
+       u8 args[4], *argbuf = NULL, *sensebuf = NULL;
        int argsize = 0;
-       struct scsi_sense_hdr sshdr;
        enum dma_data_direction data_dir;
+       int cmd_result;
 
        if (arg == NULL)
                return -EINVAL;
@@ -175,6 +175,10 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
        if (copy_from_user(args, arg, sizeof(args)))
                return -EFAULT;
 
+       sensebuf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO);
+       if (!sensebuf)
+               return -ENOMEM;
+
        memset(scsi_cmd, 0, sizeof(scsi_cmd));
 
        if (args[3]) {
@@ -191,7 +195,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
                data_dir = DMA_FROM_DEVICE;
        } else {
                scsi_cmd[1]  = (3 << 1); /* Non-data */
-               /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */
+               scsi_cmd[2]  = 0x20;     /* cc but no off.line or data xfer */
                data_dir = DMA_NONE;
        }
 
@@ -210,18 +214,46 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
 
        /* Good values for timeout and retries?  Values below
           from scsi_ioctl_send_command() for default case... */
-       if (scsi_execute_req(scsidev, scsi_cmd, data_dir, argbuf, argsize,
-                            &sshdr, (10*HZ), 5)) {
+       cmd_result = scsi_execute(scsidev, scsi_cmd, data_dir, argbuf, argsize,
+                                 sensebuf, (10*HZ), 5, 0);
+
+       if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */
+               u8 *desc = sensebuf + 8;
+               cmd_result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */
+
+               /* If we set cc then ATA pass-through will cause a
+                * check condition even if no error. Filter that. */
+               if (cmd_result & SAM_STAT_CHECK_CONDITION) {
+                       struct scsi_sense_hdr sshdr;
+                       scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE,
+                                             &sshdr);
+                       if (sshdr.sense_key==0 &&
+                           sshdr.asc==0 && sshdr.ascq==0)
+                               cmd_result &= ~SAM_STAT_CHECK_CONDITION;
+               }
+
+               /* Send userspace a few ATA registers (same as drivers/ide) */
+               if (sensebuf[0] == 0x72 &&     /* format is "descriptor" */
+                   desc[0] == 0x09 ) {        /* code is "ATA Descriptor" */
+                       args[0] = desc[13];    /* status */
+                       args[1] = desc[3];     /* error */
+                       args[2] = desc[5];     /* sector count (0:7) */
+                       if (copy_to_user(arg, args, sizeof(args)))
+                               rc = -EFAULT;
+               }
+       }
+
+
+       if (cmd_result) {
                rc = -EIO;
                goto error;
        }
 
-       /* Need code to retrieve data from check condition? */
-
        if ((argbuf)
         && copy_to_user(arg + sizeof(args), argbuf, argsize))
                rc = -EFAULT;
 error:
+       kfree(sensebuf);
        kfree(argbuf);
        return rc;
 }
@@ -889,6 +921,7 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
 {
        struct ata_port *ap = ata_shost_to_port(sdev->host);
        struct ata_device *dev;
+       unsigned long flags;
        int max_depth;
 
        if (queue_depth < 1)
@@ -904,6 +937,14 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
                queue_depth = max_depth;
 
        scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
+
+       spin_lock_irqsave(ap->lock, flags);
+       if (queue_depth > 1)
+               dev->flags &= ~ATA_DFLAG_NCQ_OFF;
+       else
+               dev->flags |= ATA_DFLAG_NCQ_OFF;
+       spin_unlock_irqrestore(ap->lock, flags);
+
        return queue_depth;
 }
 
@@ -1293,7 +1334,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
                 */
                goto nothing_to_do;
 
-       if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
+       if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF |
+                          ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
                /* yay, NCQ */
                if (!lba_48_ok(block, n_block))
                        goto out_of_range;
@@ -1409,6 +1451,7 @@ nothing_to_do:
 
 static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
 {
+       struct ata_port *ap = qc->ap;
        struct scsi_cmnd *cmd = qc->scsicmd;
        u8 *cdb = cmd->cmnd;
        int need_sense = (qc->err_mask != 0);
@@ -1417,11 +1460,12 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
         * schedule EH_REVALIDATE operation to update the IDENTIFY DEVICE
         * cache
         */
-       if (!need_sense && (qc->tf.command == ATA_CMD_SET_FEATURES) &&
+       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))) {
-               qc->ap->eh_info.action |= ATA_EH_REVALIDATE;
-               ata_port_schedule_eh(qc->ap);
+               ap->eh_info.action |= ATA_EH_REVALIDATE;
+               ata_port_schedule_eh(ap);
        }
 
        /* For ATA pass thru (SAT) commands, generate a sense block if
@@ -1448,8 +1492,8 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
                }
        }
 
-       if (need_sense && !qc->ap->ops->error_handler)
-               ata_dump_status(qc->ap->id, &qc->result_tf);
+       if (need_sense && !ap->ops->error_handler)
+               ata_dump_status(ap->id, &qc->result_tf);
 
        qc->scsidone(cmd);
 
@@ -1570,9 +1614,9 @@ early_finish:
 
 err_did:
        ata_qc_free(qc);
-err_mem:
        cmd->result = (DID_ERROR << 16);
        done(cmd);
+err_mem:
        DPRINTK("EXIT - internal\n");
        return 0;
 
@@ -3174,7 +3218,7 @@ void ata_scsi_dev_rescan(void *data)
 
 /**
  *     ata_sas_port_alloc - Allocate port for a SAS attached SATA device
- *     @pdev: PCI device that the scsi device is attached to
+ *     @host: ATA host container for all SAS ports
  *     @port_info: Information from low-level host driver
  *     @shost: SCSI host that the scsi device is attached to
  *
@@ -3303,20 +3347,23 @@ EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
  *     @ap:    ATA port to which the command is being sent
  *
  *     RETURNS:
- *     Zero.
+ *     Return value from __ata_scsi_queuecmd() if @cmd can be queued,
+ *     0 otherwise.
  */
 
 int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
                     struct ata_port *ap)
 {
+       int rc = 0;
+
        ata_scsi_dump_cdb(ap, cmd);
 
        if (likely(ata_scsi_dev_enabled(ap->device)))
-               __ata_scsi_queuecmd(cmd, done, ap->device);
+               rc = __ata_scsi_queuecmd(cmd, done, ap->device);
        else {
                cmd->result = (DID_BAD_TARGET << 16);
                done(cmd);
        }
-       return 0;
+       return rc;
 }
 EXPORT_SYMBOL_GPL(ata_sas_queuecmd);