Merge branch 'upstream'
[pandora-kernel.git] / drivers / scsi / libata-scsi.c
index 094c9c8..0e65bfe 100644 (file)
@@ -396,6 +396,22 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf)
        }
 }
 
        }
 }
 
+int ata_scsi_device_resume(struct scsi_device *sdev)
+{
+       struct ata_port *ap = (struct ata_port *) &sdev->host->hostdata[0];
+       struct ata_device *dev = &ap->device[sdev->id];
+
+       return ata_device_resume(ap, dev);
+}
+
+int ata_scsi_device_suspend(struct scsi_device *sdev)
+{
+       struct ata_port *ap = (struct ata_port *) &sdev->host->hostdata[0];
+       struct ata_device *dev = &ap->device[sdev->id];
+
+       return ata_device_suspend(ap, dev);
+}
+
 /**
  *     ata_to_sense_error - convert ATA error to SCSI error
  *     @id: ATA device number
 /**
  *     ata_to_sense_error - convert ATA error to SCSI error
  *     @id: ATA device number
@@ -1078,11 +1094,13 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
            scsicmd[0] == WRITE_16)
                tf->flags |= ATA_TFLAG_WRITE;
 
            scsicmd[0] == WRITE_16)
                tf->flags |= ATA_TFLAG_WRITE;
 
-       /* Calculate the SCSI LBA and transfer length. */
+       /* Calculate the SCSI LBA, transfer length and FUA. */
        switch (scsicmd[0]) {
        case READ_10:
        case WRITE_10:
                scsi_10_lba_len(scsicmd, &block, &n_block);
        switch (scsicmd[0]) {
        case READ_10:
        case WRITE_10:
                scsi_10_lba_len(scsicmd, &block, &n_block);
+               if (unlikely(scsicmd[1] & (1 << 3)))
+                       tf->flags |= ATA_TFLAG_FUA;
                break;
        case READ_6:
        case WRITE_6:
                break;
        case READ_6:
        case WRITE_6:
@@ -1097,6 +1115,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
        case READ_16:
        case WRITE_16:
                scsi_16_lba_len(scsicmd, &block, &n_block);
        case READ_16:
        case WRITE_16:
                scsi_16_lba_len(scsicmd, &block, &n_block);
+               if (unlikely(scsicmd[1] & (1 << 3)))
+                       tf->flags |= ATA_TFLAG_FUA;
                break;
        default:
                DPRINTK("no-byte command\n");
                break;
        default:
                DPRINTK("no-byte command\n");
@@ -1136,7 +1156,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
                        /* request too large even for LBA48 */
                        goto out_of_range;
 
                        /* request too large even for LBA48 */
                        goto out_of_range;
 
-               ata_rwcmd_protocol(qc);
+               if (unlikely(ata_rwcmd_protocol(qc) < 0))
+                       goto invalid_fld;
 
                qc->nsect = n_block;
                tf->nsect = n_block & 0xff;
 
                qc->nsect = n_block;
                tf->nsect = n_block & 0xff;
@@ -1154,7 +1175,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
                if (!lba_28_ok(block, n_block))
                        goto out_of_range;
 
                if (!lba_28_ok(block, n_block))
                        goto out_of_range;
 
-               ata_rwcmd_protocol(qc);
+               if (unlikely(ata_rwcmd_protocol(qc) < 0))
+                       goto invalid_fld;
 
                /* Convert LBA to CHS */
                track = (u32)block / dev->sectors;
 
                /* Convert LBA to CHS */
                track = (u32)block / dev->sectors;
@@ -1689,6 +1711,7 @@ static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
 unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
                                  unsigned int buflen)
 {
 unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
                                  unsigned int buflen)
 {
+       struct ata_device *dev = args->dev;
        u8 *scsicmd = args->cmd->cmnd, *p, *last;
        const u8 sat_blk_desc[] = {
                0, 0, 0, 0,     /* number of blocks: sat unspecified */
        u8 *scsicmd = args->cmd->cmnd, *p, *last;
        const u8 sat_blk_desc[] = {
                0, 0, 0, 0,     /* number of blocks: sat unspecified */
@@ -1697,6 +1720,7 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
        };
        u8 pg, spg;
        unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen;
        };
        u8 pg, spg;
        unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen;
+       u8 dpofua;
 
        VPRINTK("ENTER\n");
 
 
        VPRINTK("ENTER\n");
 
@@ -1765,9 +1789,17 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
 
        if (minlen < 1)
                return 0;
 
        if (minlen < 1)
                return 0;
+
+       dpofua = 0;
+       if (ata_id_has_fua(args->id) && dev->flags & ATA_DFLAG_LBA48 &&
+           (!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count))
+               dpofua = 1 << 4;
+
        if (six_byte) {
                output_len--;
                rbuf[0] = output_len;
        if (six_byte) {
                output_len--;
                rbuf[0] = output_len;
+               if (minlen > 2)
+                       rbuf[2] |= dpofua;
                if (ebd) {
                        if (minlen > 3)
                                rbuf[3] = sizeof(sat_blk_desc);
                if (ebd) {
                        if (minlen > 3)
                                rbuf[3] = sizeof(sat_blk_desc);
@@ -1780,6 +1812,8 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
                rbuf[0] = output_len >> 8;
                if (minlen > 1)
                        rbuf[1] = output_len;
                rbuf[0] = output_len >> 8;
                if (minlen > 1)
                        rbuf[1] = output_len;
+               if (minlen > 3)
+                       rbuf[3] |= dpofua;
                if (ebd) {
                        if (minlen > 7)
                                rbuf[7] = sizeof(sat_blk_desc);
                if (ebd) {
                        if (minlen > 7)
                                rbuf[7] = sizeof(sat_blk_desc);
@@ -2440,7 +2474,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
                if (xlat_func)
                        ata_scsi_translate(ap, dev, cmd, done, xlat_func);
                else
                if (xlat_func)
                        ata_scsi_translate(ap, dev, cmd, done, xlat_func);
                else
-                       ata_scsi_simulate(dev->id, cmd, done);
+                       ata_scsi_simulate(ap, dev, cmd, done);
        } else
                ata_scsi_translate(ap, dev, cmd, done, atapi_xlat);
 
        } else
                ata_scsi_translate(ap, dev, cmd, done, atapi_xlat);
 
@@ -2463,14 +2497,16 @@ out_unlock:
  *     spin_lock_irqsave(host_set lock)
  */
 
  *     spin_lock_irqsave(host_set lock)
  */
 
-void ata_scsi_simulate(u16 *id,
+void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev,
                      struct scsi_cmnd *cmd,
                      void (*done)(struct scsi_cmnd *))
 {
        struct ata_scsi_args args;
        const u8 *scsicmd = cmd->cmnd;
 
                      struct scsi_cmnd *cmd,
                      void (*done)(struct scsi_cmnd *))
 {
        struct ata_scsi_args args;
        const u8 *scsicmd = cmd->cmnd;
 
-       args.id = id;
+       args.ap = ap;
+       args.dev = dev;
+       args.id = dev->id;
        args.cmd = cmd;
        args.done = done;
 
        args.cmd = cmd;
        args.done = done;