Merge branch '4.7/scsi-queue' of git://git.kernel.org/pub/scm/linux/kernel/git/mkp...
authorTejun Heo <tj@kernel.org>
Mon, 9 May 2016 16:34:39 +0000 (12:34 -0400)
committerTejun Heo <tj@kernel.org>
Mon, 9 May 2016 16:34:39 +0000 (12:34 -0400)
Pulling in the dependencies for further ZAC changes.

Signed-off-by: Tejun Heo <tj@kernel.org>
drivers/ata/libahci.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/libata.h
drivers/scsi/scsi_common.c
drivers/scsi/scsi_error.c
include/linux/ata.h
include/linux/libata.h
include/scsi/scsi_common.h
include/scsi/scsi_eh.h

index 3982054..e13ba72 100644 (file)
@@ -2549,8 +2549,8 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht)
 
        if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX)) {
                if (hpriv->irq_handler)
-                       dev_warn(host->dev, "both AHCI_HFLAG_MULTI_MSI flag set \
-                                and custom irq handler implemented\n");
+                       dev_warn(host->dev,
+                                "both AHCI_HFLAG_MULTI_MSI flag set and custom irq handler implemented\n");
 
                rc = ahci_host_activate_multi_irqs(host, sht);
        } else {
index 55e257c..7bdb2c4 100644 (file)
@@ -695,7 +695,7 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev)
  *     RETURNS:
  *     Block address read from @tf.
  */
-u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
+u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev)
 {
        u64 block = 0;
 
@@ -720,7 +720,7 @@ u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
                if (!sect) {
                        ata_dev_warn(dev,
                                     "device reported invalid CHS sector 0\n");
-                       sect = 1; /* oh well */
+                       return U64_MAX;
                }
 
                block = (cyl * dev->heads + head) * dev->sectors + sect - 1;
@@ -2148,6 +2148,24 @@ static int ata_dev_config_ncq(struct ata_device *dev,
        return 0;
 }
 
+static void ata_dev_config_sense_reporting(struct ata_device *dev)
+{
+       unsigned int err_mask;
+
+       if (!ata_id_has_sense_reporting(dev->id))
+               return;
+
+       if (ata_id_sense_reporting_enabled(dev->id))
+               return;
+
+       err_mask = ata_dev_set_feature(dev, SETFEATURE_SENSE_DATA, 0x1);
+       if (err_mask) {
+               ata_dev_dbg(dev,
+                           "failed to enable Sense Data Reporting, Emask 0x%x\n",
+                           err_mask);
+       }
+}
+
 /**
  *     ata_dev_configure - Configure the specified ATA/ATAPI device
  *     @dev: Target device to configure
@@ -2370,7 +2388,7 @@ int ata_dev_configure(struct ata_device *dev)
                                        dev->devslp_timing[i] = sata_setting[j];
                                }
                }
-
+               ata_dev_config_sense_reporting(dev);
                dev->cdb_len = 16;
        }
 
index 961acc7..5b340ce 100644 (file)
@@ -1600,6 +1600,8 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
        tf->hob_lbah = buf[10];
        tf->nsect = buf[12];
        tf->hob_nsect = buf[13];
+       if (ata_id_has_ncq_autosense(dev->id))
+               tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16];
 
        return 0;
 }
@@ -1635,6 +1637,56 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
        return err_mask;
 }
 
+/**
+ *     ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT
+ *     @dev: device to perform REQUEST_SENSE_SENSE_DATA_EXT to
+ *     @cmd: scsi command for which the sense code should be set
+ *
+ *     Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK
+ *     SENSE.  This function is an EH helper.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ */
+static void ata_eh_request_sense(struct ata_queued_cmd *qc,
+                                struct scsi_cmnd *cmd)
+{
+       struct ata_device *dev = qc->dev;
+       struct ata_taskfile tf;
+       unsigned int err_mask;
+
+       if (qc->ap->pflags & ATA_PFLAG_FROZEN) {
+               ata_dev_warn(dev, "sense data available but port frozen\n");
+               return;
+       }
+
+       if (!cmd)
+               return;
+
+       if (!ata_id_sense_reporting_enabled(dev->id)) {
+               ata_dev_warn(qc->dev, "sense data reporting disabled\n");
+               return;
+       }
+
+       DPRINTK("ATA request sense\n");
+
+       ata_tf_init(dev, &tf);
+       tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+       tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
+       tf.command = ATA_CMD_REQ_SENSE_DATA;
+       tf.protocol = ATA_PROT_NODATA;
+
+       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+       /* Ignore err_mask; ATA_ERR might be set */
+       if (tf.command & ATA_SENSE) {
+               ata_scsi_set_sense(dev, cmd, tf.lbah, tf.lbam, tf.lbal);
+               qc->flags |= ATA_QCFLAG_SENSE_VALID;
+       } else {
+               ata_dev_warn(dev, "request sense failed stat %02x emask %x\n",
+                            tf.command, err_mask);
+       }
+}
+
 /**
  *     atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
  *     @dev: device to perform REQUEST_SENSE to
@@ -1797,6 +1849,18 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
        memcpy(&qc->result_tf, &tf, sizeof(tf));
        qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
        qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
+       if (qc->result_tf.auxiliary) {
+               char sense_key, asc, ascq;
+
+               sense_key = (qc->result_tf.auxiliary >> 16) & 0xff;
+               asc = (qc->result_tf.auxiliary >> 8) & 0xff;
+               ascq = qc->result_tf.auxiliary & 0xff;
+               ata_scsi_set_sense(dev, qc->scsicmd, sense_key, asc, ascq);
+               ata_scsi_set_sense_information(dev, qc->scsicmd,
+                                              &qc->result_tf);
+               qc->flags |= ATA_QCFLAG_SENSE_VALID;
+       }
+
        ehc->i.err_mask &= ~AC_ERR_DEV;
 }
 
@@ -1826,14 +1890,23 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
                return ATA_EH_RESET;
        }
 
-       if (stat & (ATA_ERR | ATA_DF))
+       if (stat & (ATA_ERR | ATA_DF)) {
                qc->err_mask |= AC_ERR_DEV;
-       else
+               /*
+                * Sense data reporting does not work if the
+                * device fault bit is set.
+                */
+               if (stat & ATA_DF)
+                       stat &= ~ATA_SENSE;
+       } else {
                return 0;
+       }
 
        switch (qc->dev->class) {
        case ATA_DEV_ATA:
        case ATA_DEV_ZAC:
+               if (stat & ATA_SENSE)
+                       ata_eh_request_sense(qc, qc->scsicmd);
                if (err & ATA_ICRC)
                        qc->err_mask |= AC_ERR_ATA_BUS;
                if (err & (ATA_UNC | ATA_AMNF))
@@ -1847,20 +1920,31 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
                        tmp = atapi_eh_request_sense(qc->dev,
                                                qc->scsicmd->sense_buffer,
                                                qc->result_tf.feature >> 4);
-                       if (!tmp) {
-                               /* ATA_QCFLAG_SENSE_VALID is used to
-                                * tell atapi_qc_complete() that sense
-                                * data is already valid.
-                                *
-                                * TODO: interpret sense data and set
-                                * appropriate err_mask.
-                                */
+                       if (!tmp)
                                qc->flags |= ATA_QCFLAG_SENSE_VALID;
-                       else
+                       else
                                qc->err_mask |= tmp;
                }
        }
 
+       if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
+               int ret = scsi_check_sense(qc->scsicmd);
+               /*
+                * SUCCESS here means that the sense code could
+                * evaluated and should be passed to the upper layers
+                * for correct evaluation.
+                * FAILED means the sense code could not interpreted
+                * and the device would need to be reset.
+                * NEEDS_RETRY and ADD_TO_MLQUEUE means that the
+                * command would need to be retried.
+                */
+               if (ret == NEEDS_RETRY || ret == ADD_TO_MLQUEUE) {
+                       qc->flags |= ATA_QCFLAG_RETRY;
+                       qc->err_mask |= AC_ERR_OTHER;
+               } else if (ret != SUCCESS) {
+                       qc->err_mask |= AC_ERR_HSM;
+               }
+       }
        if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS))
                action |= ATA_EH_RESET;
 
@@ -2569,14 +2653,15 @@ static void ata_eh_link_report(struct ata_link *link)
 
 #ifdef CONFIG_ATA_VERBOSE_ERROR
                if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ |
-                                   ATA_ERR)) {
+                                   ATA_SENSE | ATA_ERR)) {
                        if (res->command & ATA_BUSY)
                                ata_dev_err(qc->dev, "status: { Busy }\n");
                        else
-                               ata_dev_err(qc->dev, "status: { %s%s%s%s}\n",
+                               ata_dev_err(qc->dev, "status: { %s%s%s%s%s}\n",
                                  res->command & ATA_DRDY ? "DRDY " : "",
                                  res->command & ATA_DF ? "DF " : "",
                                  res->command & ATA_DRQ ? "DRQ " : "",
+                                 res->command & ATA_SENSE ? "SENSE " : "",
                                  res->command & ATA_ERR ? "ERR " : "");
                }
 
index 567859c..8b61d63 100644 (file)
@@ -270,11 +270,52 @@ DEVICE_ATTR(unload_heads, S_IRUGO | S_IWUSR,
            ata_scsi_park_show, ata_scsi_park_store);
 EXPORT_SYMBOL_GPL(dev_attr_unload_heads);
 
-static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
+void ata_scsi_set_sense(struct ata_device *dev, struct scsi_cmnd *cmd,
+                       u8 sk, u8 asc, u8 ascq)
 {
+       bool d_sense = (dev->flags & ATA_DFLAG_D_SENSE);
+
+       if (!cmd)
+               return;
+
        cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
 
-       scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq);
+       scsi_build_sense_buffer(d_sense, cmd->sense_buffer, sk, asc, ascq);
+}
+
+void ata_scsi_set_sense_information(struct ata_device *dev,
+                                   struct scsi_cmnd *cmd,
+                                   const struct ata_taskfile *tf)
+{
+       u64 information;
+
+       if (!cmd)
+               return;
+
+       information = ata_tf_read_block(tf, dev);
+       if (information == U64_MAX)
+               return;
+
+       scsi_set_sense_information(cmd->sense_buffer,
+                                  SCSI_SENSE_BUFFERSIZE, information);
+}
+
+static void ata_scsi_set_invalid_field(struct ata_device *dev,
+                                      struct scsi_cmnd *cmd, u16 field, u8 bit)
+{
+       ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x24, 0x0);
+       /* "Invalid field in cbd" */
+       scsi_set_sense_field_pointer(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+                                    field, bit, 1);
+}
+
+static void ata_scsi_set_invalid_parameter(struct ata_device *dev,
+                                          struct scsi_cmnd *cmd, u16 field)
+{
+       /* "Invalid field in parameter list" */
+       ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x26, 0x0);
+       scsi_set_sense_field_pointer(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+                                    field, 0xff, 0);
 }
 
 static ssize_t
@@ -364,10 +405,10 @@ struct device_attribute *ata_common_sdev_attrs[] = {
 };
 EXPORT_SYMBOL_GPL(ata_common_sdev_attrs);
 
-static void ata_scsi_invalid_field(struct scsi_cmnd *cmd)
+static void ata_scsi_invalid_field(struct ata_device *dev,
+                                  struct scsi_cmnd *cmd, u16 field)
 {
-       ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0);
-       /* "Invalid field in cbd" */
+       ata_scsi_set_invalid_field(dev, cmd, field, 0xff);
        cmd->scsi_done(cmd);
 }
 
@@ -980,6 +1021,7 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc)
        unsigned char *sb = cmd->sense_buffer;
        unsigned char *desc = sb + 8;
        int verbose = qc->ap->ops->error_handler == NULL;
+       u8 sense_key, asc, ascq;
 
        memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
 
@@ -992,47 +1034,71 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc)
        if (qc->err_mask ||
            tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
                ata_to_sense_error(qc->ap->print_id, tf->command, tf->feature,
-                                  &sb[1], &sb[2], &sb[3], verbose);
-               sb[1] &= 0x0f;
+                                  &sense_key, &asc, &ascq, verbose);
+               ata_scsi_set_sense(qc->dev, cmd, sense_key, asc, ascq);
        } else {
-               sb[1] = RECOVERED_ERROR;
-               sb[2] = 0;
-               sb[3] = 0x1D;
+               /*
+                * ATA PASS-THROUGH INFORMATION AVAILABLE
+                * Always in descriptor format sense.
+                */
+               scsi_build_sense_buffer(1, cmd->sense_buffer,
+                                       RECOVERED_ERROR, 0, 0x1D);
        }
 
-       /*
-        * Sense data is current and format is descriptor.
-        */
-       sb[0] = 0x72;
-
-       desc[0] = 0x09;
-
-       /* set length of additional sense data */
-       sb[7] = 14;
-       desc[1] = 12;
-
-       /*
-        * Copy registers into sense buffer.
-        */
-       desc[2] = 0x00;
-       desc[3] = tf->feature;  /* == error reg */
-       desc[5] = tf->nsect;
-       desc[7] = tf->lbal;
-       desc[9] = tf->lbam;
-       desc[11] = tf->lbah;
-       desc[12] = tf->device;
-       desc[13] = tf->command; /* == status reg */
+       if ((cmd->sense_buffer[0] & 0x7f) >= 0x72) {
+               u8 len;
+
+               /* descriptor format */
+               len = sb[7];
+               desc = (char *)scsi_sense_desc_find(sb, len + 8, 9);
+               if (!desc) {
+                       if (SCSI_SENSE_BUFFERSIZE < len + 14)
+                               return;
+                       sb[7] = len + 14;
+                       desc = sb + 8 + len;
+               }
+               desc[0] = 9;
+               desc[1] = 12;
+               /*
+                * Copy registers into sense buffer.
+                */
+               desc[2] = 0x00;
+               desc[3] = tf->feature;  /* == error reg */
+               desc[5] = tf->nsect;
+               desc[7] = tf->lbal;
+               desc[9] = tf->lbam;
+               desc[11] = tf->lbah;
+               desc[12] = tf->device;
+               desc[13] = tf->command; /* == status reg */
 
-       /*
-        * Fill in Extend bit, and the high order bytes
-        * if applicable.
-        */
-       if (tf->flags & ATA_TFLAG_LBA48) {
-               desc[2] |= 0x01;
-               desc[4] = tf->hob_nsect;
-               desc[6] = tf->hob_lbal;
-               desc[8] = tf->hob_lbam;
-               desc[10] = tf->hob_lbah;
+               /*
+                * Fill in Extend bit, and the high order bytes
+                * if applicable.
+                */
+               if (tf->flags & ATA_TFLAG_LBA48) {
+                       desc[2] |= 0x01;
+                       desc[4] = tf->hob_nsect;
+                       desc[6] = tf->hob_lbal;
+                       desc[8] = tf->hob_lbam;
+                       desc[10] = tf->hob_lbah;
+               }
+       } else {
+               /* Fixed sense format */
+               desc[0] = tf->feature;
+               desc[1] = tf->command; /* status */
+               desc[2] = tf->device;
+               desc[3] = tf->nsect;
+               desc[0] = 0;
+               if (tf->flags & ATA_TFLAG_LBA48)  {
+                       desc[8] |= 0x80;
+                       if (tf->hob_nsect)
+                               desc[8] |= 0x40;
+                       if (tf->hob_lbal || tf->hob_lbam || tf->hob_lbah)
+                               desc[8] |= 0x20;
+               }
+               desc[9] = tf->lbal;
+               desc[10] = tf->lbam;
+               desc[11] = tf->lbah;
        }
 }
 
@@ -1052,41 +1118,35 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc)
        struct scsi_cmnd *cmd = qc->scsicmd;
        struct ata_taskfile *tf = &qc->result_tf;
        unsigned char *sb = cmd->sense_buffer;
-       unsigned char *desc = sb + 8;
        int verbose = qc->ap->ops->error_handler == NULL;
        u64 block;
+       u8 sense_key, asc, ascq;
 
        memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
 
        cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
 
-       /* sense data is current and format is descriptor */
-       sb[0] = 0x72;
-
        /* Use ata_to_sense_error() to map status register bits
         * onto sense key, asc & ascq.
         */
        if (qc->err_mask ||
            tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
                ata_to_sense_error(qc->ap->print_id, tf->command, tf->feature,
-                                  &sb[1], &sb[2], &sb[3], verbose);
-               sb[1] &= 0x0f;
+                                  &sense_key, &asc, &ascq, verbose);
+               ata_scsi_set_sense(dev, cmd, sense_key, asc, ascq);
+       } else {
+               /* Could not decode error */
+               ata_dev_warn(dev, "could not decode error status 0x%x err_mask 0x%x\n",
+                            tf->command, qc->err_mask);
+               ata_scsi_set_sense(dev, cmd, ABORTED_COMMAND, 0, 0);
+               return;
        }
 
        block = ata_tf_read_block(&qc->result_tf, dev);
+       if (block == U64_MAX)
+               return;
 
-       /* information sense data descriptor */
-       sb[7] = 12;
-       desc[0] = 0x00;
-       desc[1] = 10;
-
-       desc[2] |= 0x80;        /* valid */
-       desc[6] = block >> 40;
-       desc[7] = block >> 32;
-       desc[8] = block >> 24;
-       desc[9] = block >> 16;
-       desc[10] = block >> 8;
-       desc[11] = block;
+       scsi_set_sense_information(sb, SCSI_SENSE_BUFFERSIZE, block);
 }
 
 static void ata_scsi_sdev_config(struct scsi_device *sdev)
@@ -1343,19 +1403,29 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
        struct scsi_cmnd *scmd = qc->scsicmd;
        struct ata_taskfile *tf = &qc->tf;
        const u8 *cdb = scmd->cmnd;
+       u16 fp;
+       u8 bp = 0xff;
 
-       if (scmd->cmd_len < 5)
+       if (scmd->cmd_len < 5) {
+               fp = 4;
                goto invalid_fld;
+       }
 
        tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
        tf->protocol = ATA_PROT_NODATA;
        if (cdb[1] & 0x1) {
                ;       /* ignore IMMED bit, violates sat-r05 */
        }
-       if (cdb[4] & 0x2)
+       if (cdb[4] & 0x2) {
+               fp = 4;
+               bp = 1;
                goto invalid_fld;       /* LOEJ bit set not supported */
-       if (((cdb[4] >> 4) & 0xf) != 0)
+       }
+       if (((cdb[4] >> 4) & 0xf) != 0) {
+               fp = 4;
+               bp = 3;
                goto invalid_fld;       /* power conditions not supported */
+       }
 
        if (cdb[4] & 0x1) {
                tf->nsect = 1;  /* 1 sector, lba=0 */
@@ -1401,8 +1471,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
        return 0;
 
  invalid_fld:
-       ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0);
-       /* "Invalid field in cbd" */
+       ata_scsi_set_invalid_field(qc->dev, scmd, fp, bp);
        return 1;
  skip:
        scmd->result = SAM_STAT_GOOD;
@@ -1553,20 +1622,27 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc)
        const u8 *cdb = scmd->cmnd;
        u64 block;
        u32 n_block;
+       u16 fp;
 
        tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
        tf->protocol = ATA_PROT_NODATA;
 
        if (cdb[0] == VERIFY) {
-               if (scmd->cmd_len < 10)
+               if (scmd->cmd_len < 10) {
+                       fp = 9;
                        goto invalid_fld;
+               }
                scsi_10_lba_len(cdb, &block, &n_block);
        } else if (cdb[0] == VERIFY_16) {
-               if (scmd->cmd_len < 16)
+               if (scmd->cmd_len < 16) {
+                       fp = 15;
                        goto invalid_fld;
+               }
                scsi_16_lba_len(cdb, &block, &n_block);
-       } else
+       } else {
+               fp = 0;
                goto invalid_fld;
+       }
 
        if (!n_block)
                goto nothing_to_do;
@@ -1640,12 +1716,11 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc)
        return 0;
 
 invalid_fld:
-       ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0);
-       /* "Invalid field in cbd" */
+       ata_scsi_set_invalid_field(qc->dev, scmd, fp, 0xff);
        return 1;
 
 out_of_range:
-       ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x21, 0x0);
+       ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x21, 0x0);
        /* "Logical Block Address out of range" */
        return 1;
 
@@ -1680,6 +1755,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
        u64 block;
        u32 n_block;
        int rc;
+       u16 fp = 0;
 
        if (cdb[0] == WRITE_10 || cdb[0] == WRITE_6 || cdb[0] == WRITE_16)
                tf_flags |= ATA_TFLAG_WRITE;
@@ -1688,16 +1764,20 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
        switch (cdb[0]) {
        case READ_10:
        case WRITE_10:
-               if (unlikely(scmd->cmd_len < 10))
+               if (unlikely(scmd->cmd_len < 10)) {
+                       fp = 9;
                        goto invalid_fld;
+               }
                scsi_10_lba_len(cdb, &block, &n_block);
                if (cdb[1] & (1 << 3))
                        tf_flags |= ATA_TFLAG_FUA;
                break;
        case READ_6:
        case WRITE_6:
-               if (unlikely(scmd->cmd_len < 6))
+               if (unlikely(scmd->cmd_len < 6)) {
+                       fp = 5;
                        goto invalid_fld;
+               }
                scsi_6_lba_len(cdb, &block, &n_block);
 
                /* for 6-byte r/w commands, transfer length 0
@@ -1708,14 +1788,17 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
                break;
        case READ_16:
        case WRITE_16:
-               if (unlikely(scmd->cmd_len < 16))
+               if (unlikely(scmd->cmd_len < 16)) {
+                       fp = 15;
                        goto invalid_fld;
+               }
                scsi_16_lba_len(cdb, &block, &n_block);
                if (cdb[1] & (1 << 3))
                        tf_flags |= ATA_TFLAG_FUA;
                break;
        default:
                DPRINTK("no-byte command\n");
+               fp = 0;
                goto invalid_fld;
        }
 
@@ -1742,12 +1825,11 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
                goto out_of_range;
        /* treat all other errors as -EINVAL, fall through */
 invalid_fld:
-       ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0);
-       /* "Invalid field in cbd" */
+       ata_scsi_set_invalid_field(qc->dev, scmd, fp, 0xff);
        return 1;
 
 out_of_range:
-       ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x21, 0x0);
+       ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x21, 0x0);
        /* "Logical Block Address out of range" */
        return 1;
 
@@ -1784,6 +1866,8 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
        if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) &&
            ((cdb[2] & 0x20) || need_sense))
                ata_gen_passthru_sense(qc);
+       else if (qc->flags & ATA_QCFLAG_SENSE_VALID)
+               cmd->result = SAM_STAT_CHECK_CONDITION;
        else if (need_sense)
                ata_gen_ata_sense(qc);
        else
@@ -2317,6 +2401,7 @@ static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable)
 
 /**
  *     ata_msense_ctl_mode - Simulate MODE SENSE control mode page
+ *     @dev: ATA device of interest
  *     @buf: output buffer
  *     @changeable: whether changeable parameters are requested
  *
@@ -2325,9 +2410,12 @@ static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable)
  *     LOCKING:
  *     None.
  */
-static unsigned int ata_msense_ctl_mode(u8 *buf, bool changeable)
+static unsigned int ata_msense_ctl_mode(struct ata_device *dev, u8 *buf,
+                                       bool changeable)
 {
        modecpy(buf, def_control_mpage, sizeof(def_control_mpage), changeable);
+       if (changeable && (dev->flags & ATA_DFLAG_D_SENSE))
+               buf[2] |= (1 << 2);     /* Descriptor sense requested */
        return sizeof(def_control_mpage);
 }
 
@@ -2395,7 +2483,8 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
        };
        u8 pg, spg;
        unsigned int ebd, page_control, six_byte;
-       u8 dpofua;
+       u8 dpofua, bp = 0xff;
+       u16 fp;
 
        VPRINTK("ENTER\n");
 
@@ -2414,6 +2503,8 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
        case 3: /* saved */
                goto saving_not_supp;
        default:
+               fp = 2;
+               bp = 6;
                goto invalid_fld;
        }
 
@@ -2428,8 +2519,10 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
         * No mode subpages supported (yet) but asking for _all_
         * subpages may be valid
         */
-       if (spg && (spg != ALL_SUB_MPAGES))
+       if (spg && (spg != ALL_SUB_MPAGES)) {
+               fp = 3;
                goto invalid_fld;
+       }
 
        switch(pg) {
        case RW_RECOVERY_MPAGE:
@@ -2441,16 +2534,17 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
                break;
 
        case CONTROL_MPAGE:
-               p += ata_msense_ctl_mode(p, page_control == 1);
+               p += ata_msense_ctl_mode(args->dev, p, page_control == 1);
                break;
 
        case ALL_MPAGES:
                p += ata_msense_rw_recovery(p, page_control == 1);
                p += ata_msense_caching(args->id, p, page_control == 1);
-               p += ata_msense_ctl_mode(p, page_control == 1);
+               p += ata_msense_ctl_mode(args->dev, p, page_control == 1);
                break;
 
        default:                /* invalid page code */
+               fp = 2;
                goto invalid_fld;
        }
 
@@ -2480,12 +2574,11 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
        return 0;
 
 invalid_fld:
-       ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x24, 0x0);
-       /* "Invalid field in cbd" */
+       ata_scsi_set_invalid_field(dev, args->cmd, fp, bp);
        return 1;
 
 saving_not_supp:
-       ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x39, 0x0);
+       ata_scsi_set_sense(dev, args->cmd, ILLEGAL_REQUEST, 0x39, 0x0);
         /* "Saving parameters not supported" */
        return 1;
 }
@@ -2942,9 +3035,12 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
        struct scsi_cmnd *scmd = qc->scsicmd;
        struct ata_device *dev = qc->dev;
        const u8 *cdb = scmd->cmnd;
+       u16 fp;
 
-       if ((tf->protocol = ata_scsi_map_proto(cdb[1])) == ATA_PROT_UNKNOWN)
+       if ((tf->protocol = ata_scsi_map_proto(cdb[1])) == ATA_PROT_UNKNOWN) {
+               fp = 1;
                goto invalid_fld;
+       }
 
        /* enable LBA */
        tf->flags |= ATA_TFLAG_LBA;
@@ -3008,8 +3104,10 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
        case ATA_CMD_READ_LONG_ONCE:
        case ATA_CMD_WRITE_LONG:
        case ATA_CMD_WRITE_LONG_ONCE:
-               if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
+               if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1) {
+                       fp = 1;
                        goto invalid_fld;
+               }
                qc->sect_size = scsi_bufflen(scmd);
                break;
 
@@ -3072,12 +3170,16 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
        ata_qc_set_pc_nbytes(qc);
 
        /* We may not issue DMA commands if no DMA mode is set */
-       if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0)
+       if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0) {
+               fp = 1;
                goto invalid_fld;
+       }
 
        /* sanity check for pio multi commands */
-       if ((cdb[1] & 0xe0) && !is_multi_taskfile(tf))
+       if ((cdb[1] & 0xe0) && !is_multi_taskfile(tf)) {
+               fp = 1;
                goto invalid_fld;
+       }
 
        if (is_multi_taskfile(tf)) {
                unsigned int multi_count = 1 << (cdb[1] >> 5);
@@ -3098,8 +3200,10 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
         * ->set_dmamode(), and ->post_set_mode() hooks).
         */
        if (tf->command == ATA_CMD_SET_FEATURES &&
-           tf->feature == SETFEATURES_XFER)
+           tf->feature == SETFEATURES_XFER) {
+               fp = (cdb[0] == ATA_16) ? 4 : 3;
                goto invalid_fld;
+       }
 
        /*
         * Filter TPM commands by default. These provide an
@@ -3116,14 +3220,15 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
         * so that we comply with the TC consortium stated goal that the user
         * can turn off TC features of their system.
         */
-       if (tf->command >= 0x5C && tf->command <= 0x5F && !libata_allow_tpm)
+       if (tf->command >= 0x5C && tf->command <= 0x5F && !libata_allow_tpm) {
+               fp = (cdb[0] == ATA_16) ? 14 : 9;
                goto invalid_fld;
+       }
 
        return 0;
 
  invalid_fld:
-       ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x00);
-       /* "Invalid field in cdb" */
+       ata_scsi_set_invalid_field(dev, scmd, fp, 0xff);
        return 1;
 }
 
@@ -3137,25 +3242,32 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
        u32 n_block;
        u32 size;
        void *buf;
+       u16 fp;
+       u8 bp = 0xff;
 
        /* we may not issue DMA commands if no DMA mode is set */
        if (unlikely(!dev->dma_mode))
-               goto invalid_fld;
+               goto invalid_opcode;
 
-       if (unlikely(scmd->cmd_len < 16))
+       if (unlikely(scmd->cmd_len < 16)) {
+               fp = 15;
                goto invalid_fld;
+       }
        scsi_16_lba_len(cdb, &block, &n_block);
 
        /* for now we only support WRITE SAME with the unmap bit set */
-       if (unlikely(!(cdb[1] & 0x8)))
+       if (unlikely(!(cdb[1] & 0x8))) {
+               fp = 1;
+               bp = 3;
                goto invalid_fld;
+       }
 
        /*
         * WRITE SAME always has a sector sized buffer as payload, this
         * should never be a multiple entry S/G list.
         */
        if (!scsi_sg_count(scmd))
-               goto invalid_fld;
+               goto invalid_param_len;
 
        buf = page_address(sg_page(scsi_sglist(scmd)));
        size = ata_set_lba_range_entries(buf, 512, block, n_block);
@@ -3186,9 +3298,16 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
 
        return 0;
 
- invalid_fld:
-       ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x00);
-       /* "Invalid field in cdb" */
+invalid_fld:
+       ata_scsi_set_invalid_field(dev, scmd, fp, bp);
+       return 1;
+invalid_param_len:
+       /* "Parameter list length error" */
+       ata_scsi_set_sense(dev, scmd, ILLEGAL_REQUEST, 0x1a, 0x0);
+       return 1;
+invalid_opcode:
+       /* "Invalid command operation code" */
+       ata_scsi_set_sense(dev, scmd, ILLEGAL_REQUEST, 0x20, 0x0);
        return 1;
 }
 
@@ -3197,6 +3316,7 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
  *     @qc: Storage for translated ATA taskfile
  *     @buf: input buffer
  *     @len: number of valid bytes in the input buffer
+ *     @fp: out parameter for the failed field on error
  *
  *     Prepare a taskfile to modify caching information for the device.
  *
@@ -3204,20 +3324,26 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
  *     None.
  */
 static int ata_mselect_caching(struct ata_queued_cmd *qc,
-                              const u8 *buf, int len)
+                              const u8 *buf, int len, u16 *fp)
 {
        struct ata_taskfile *tf = &qc->tf;
        struct ata_device *dev = qc->dev;
        char mpage[CACHE_MPAGE_LEN];
        u8 wce;
+       int i;
 
        /*
         * The first two bytes of def_cache_mpage are a header, so offsets
         * in mpage are off by 2 compared to buf.  Same for len.
         */
 
-       if (len != CACHE_MPAGE_LEN - 2)
+       if (len != CACHE_MPAGE_LEN - 2) {
+               if (len < CACHE_MPAGE_LEN - 2)
+                       *fp = len;
+               else
+                       *fp = CACHE_MPAGE_LEN - 2;
                return -EINVAL;
+       }
 
        wce = buf[0] & (1 << 2);
 
@@ -3225,10 +3351,14 @@ static int ata_mselect_caching(struct ata_queued_cmd *qc,
         * Check that read-only bits are not modified.
         */
        ata_msense_caching(dev->id, mpage, false);
-       mpage[2] &= ~(1 << 2);
-       mpage[2] |= wce;
-       if (memcmp(mpage + 2, buf, CACHE_MPAGE_LEN - 2) != 0)
-               return -EINVAL;
+       for (i = 0; i < CACHE_MPAGE_LEN - 2; i++) {
+               if (i == 0)
+                       continue;
+               if (mpage[i + 2] != buf[i]) {
+                       *fp = i;
+                       return -EINVAL;
+               }
+       }
 
        tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
        tf->protocol = ATA_PROT_NODATA;
@@ -3238,6 +3368,62 @@ static int ata_mselect_caching(struct ata_queued_cmd *qc,
        return 0;
 }
 
+/**
+ *     ata_mselect_control - Simulate MODE SELECT for control page
+ *     @qc: Storage for translated ATA taskfile
+ *     @buf: input buffer
+ *     @len: number of valid bytes in the input buffer
+ *     @fp: out parameter for the failed field on error
+ *
+ *     Prepare a taskfile to modify caching information for the device.
+ *
+ *     LOCKING:
+ *     None.
+ */
+static int ata_mselect_control(struct ata_queued_cmd *qc,
+                              const u8 *buf, int len, u16 *fp)
+{
+       struct ata_device *dev = qc->dev;
+       char mpage[CONTROL_MPAGE_LEN];
+       u8 d_sense;
+       int i;
+
+       /*
+        * The first two bytes of def_control_mpage are a header, so offsets
+        * in mpage are off by 2 compared to buf.  Same for len.
+        */
+
+       if (len != CONTROL_MPAGE_LEN - 2) {
+               if (len < CONTROL_MPAGE_LEN - 2)
+                       *fp = len;
+               else
+                       *fp = CONTROL_MPAGE_LEN - 2;
+               return -EINVAL;
+       }
+
+       d_sense = buf[0] & (1 << 2);
+
+       /*
+        * Check that read-only bits are not modified.
+        */
+       ata_msense_ctl_mode(dev, mpage, false);
+       for (i = 0; i < CONTROL_MPAGE_LEN - 2; i++) {
+               if (i == 0)
+                       continue;
+               if (mpage[2 + i] != buf[i]) {
+                       *fp = i;
+                       return -EINVAL;
+               }
+       }
+       if (d_sense & (1 << 2))
+               dev->flags |= ATA_DFLAG_D_SENSE;
+       else
+               dev->flags &= ~ATA_DFLAG_D_SENSE;
+       qc->scsicmd->result = SAM_STAT_GOOD;
+       qc->scsicmd->scsi_done(qc->scsicmd);
+       return 0;
+}
+
 /**
  *     ata_scsiop_mode_select - Simulate MODE SELECT 6, 10 commands
  *     @qc: Storage for translated ATA taskfile
@@ -3257,27 +3443,36 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc)
        u8 pg, spg;
        unsigned six_byte, pg_len, hdr_len, bd_len;
        int len;
+       u16 fp = (u16)-1;
+       u8 bp = 0xff;
 
        VPRINTK("ENTER\n");
 
        six_byte = (cdb[0] == MODE_SELECT);
        if (six_byte) {
-               if (scmd->cmd_len < 5)
+               if (scmd->cmd_len < 5) {
+                       fp = 4;
                        goto invalid_fld;
+               }
 
                len = cdb[4];
                hdr_len = 4;
        } else {
-               if (scmd->cmd_len < 9)
+               if (scmd->cmd_len < 9) {
+                       fp = 8;
                        goto invalid_fld;
+               }
 
                len = (cdb[7] << 8) + cdb[8];
                hdr_len = 8;
        }
 
        /* We only support PF=1, SP=0.  */
-       if ((cdb[1] & 0x11) != 0x10)
+       if ((cdb[1] & 0x11) != 0x10) {
+               fp = 1;
+               bp = (cdb[1] & 0x01) ? 1 : 5;
                goto invalid_fld;
+       }
 
        /* Test early for possible overrun.  */
        if (!scsi_sg_count(scmd) || scsi_sglist(scmd)->length < len)
@@ -3298,8 +3493,11 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc)
        p += hdr_len;
        if (len < bd_len)
                goto invalid_param_len;
-       if (bd_len != 0 && bd_len != 8)
+       if (bd_len != 0 && bd_len != 8) {
+               fp = (six_byte) ? 3 : 6;
+               fp += bd_len + hdr_len;
                goto invalid_param;
+       }
 
        len -= bd_len;
        p += bd_len;
@@ -3330,18 +3528,29 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc)
         * No mode subpages supported (yet) but asking for _all_
         * subpages may be valid
         */
-       if (spg && (spg != ALL_SUB_MPAGES))
+       if (spg && (spg != ALL_SUB_MPAGES)) {
+               fp = (p[0] & 0x40) ? 1 : 0;
+               fp += hdr_len + bd_len;
                goto invalid_param;
+       }
        if (pg_len > len)
                goto invalid_param_len;
 
        switch (pg) {
        case CACHE_MPAGE:
-               if (ata_mselect_caching(qc, p, pg_len) < 0)
+               if (ata_mselect_caching(qc, p, pg_len, &fp) < 0) {
+                       fp += hdr_len + bd_len;
                        goto invalid_param;
+               }
+               break;
+       case CONTROL_MPAGE:
+               if (ata_mselect_control(qc, p, pg_len, &fp) < 0) {
+                       fp += hdr_len + bd_len;
+                       goto invalid_param;
+               }
                break;
-
        default:                /* invalid page code */
+               fp = bd_len + hdr_len;
                goto invalid_param;
        }
 
@@ -3355,18 +3564,16 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc)
        return 0;
 
  invalid_fld:
-       /* "Invalid field in CDB" */
-       ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0);
+       ata_scsi_set_invalid_field(qc->dev, scmd, fp, bp);
        return 1;
 
  invalid_param:
-       /* "Invalid field in parameter list" */
-       ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x26, 0x0);
+       ata_scsi_set_invalid_parameter(qc->dev, scmd, fp);
        return 1;
 
  invalid_param_len:
        /* "Parameter list length error" */
-       ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x1a, 0x0);
+       ata_scsi_set_sense(qc->dev, scmd, ILLEGAL_REQUEST, 0x1a, 0x0);
        return 1;
 
  skip:
@@ -3570,12 +3777,12 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
        switch(scsicmd[0]) {
        /* TODO: worth improving? */
        case FORMAT_UNIT:
-               ata_scsi_invalid_field(cmd);
+               ata_scsi_invalid_field(dev, cmd, 0);
                break;
 
        case INQUIRY:
-               if (scsicmd[1] & 2)                /* is CmdDt set?  */
-                       ata_scsi_invalid_field(cmd);
+               if (scsicmd[1] & 2)                /* is CmdDt set?  */
+                   ata_scsi_invalid_field(dev, cmd, 1);
                else if ((scsicmd[1] & 1) == 0)    /* is EVPD clear? */
                        ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
                else switch (scsicmd[2]) {
@@ -3601,7 +3808,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
                        ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b2);
                        break;
                default:
-                       ata_scsi_invalid_field(cmd);
+                       ata_scsi_invalid_field(dev, cmd, 2);
                        break;
                }
                break;
@@ -3619,7 +3826,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
                if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
                        ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
                else
-                       ata_scsi_invalid_field(cmd);
+                       ata_scsi_invalid_field(dev, cmd, 1);
                break;
 
        case REPORT_LUNS:
@@ -3627,7 +3834,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
                break;
 
        case REQUEST_SENSE:
-               ata_scsi_set_sense(cmd, 0, 0, 0);
+               ata_scsi_set_sense(dev, cmd, 0, 0, 0);
                cmd->result = (DRIVER_SENSE << 24);
                cmd->scsi_done(cmd);
                break;
@@ -3651,12 +3858,12 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
                if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4]))
                        ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
                else
-                       ata_scsi_invalid_field(cmd);
+                       ata_scsi_invalid_field(dev, cmd, 1);
                break;
 
        /* all other commands */
        default:
-               ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0);
+               ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x20, 0x0);
                /* "Invalid command operation code" */
                cmd->scsi_done(cmd);
                break;
index f840ca1..3b301a4 100644 (file)
@@ -67,7 +67,8 @@ extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag);
 extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
                           u64 block, u32 n_block, unsigned int tf_flags,
                           unsigned int tag);
-extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev);
+extern u64 ata_tf_read_block(const struct ata_taskfile *tf,
+                            struct ata_device *dev);
 extern unsigned ata_exec_internal(struct ata_device *dev,
                                  struct ata_taskfile *tf, const u8 *cdb,
                                  int dma_dir, void *buf, unsigned int buflen,
@@ -137,6 +138,11 @@ extern int ata_scsi_add_hosts(struct ata_host *host,
                              struct scsi_host_template *sht);
 extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
 extern int ata_scsi_offline_dev(struct ata_device *dev);
+extern void ata_scsi_set_sense(struct ata_device *dev,
+                              struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq);
+extern void ata_scsi_set_sense_information(struct ata_device *dev,
+                                          struct scsi_cmnd *cmd,
+                                          const struct ata_taskfile *tf);
 extern void ata_scsi_media_change_notify(struct ata_device *dev);
 extern void ata_scsi_hotplug(struct work_struct *work);
 extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
index ce79de8..b1383a7 100644 (file)
@@ -293,3 +293,56 @@ int scsi_set_sense_information(u8 *buf, int buf_len, u64 info)
        return 0;
 }
 EXPORT_SYMBOL(scsi_set_sense_information);
+
+/**
+ * scsi_set_sense_field_pointer - set the field pointer sense key
+ *             specific information in a formatted sense data buffer
+ * @buf:       Where to build sense data
+ * @buf_len:    buffer length
+ * @fp:                field pointer to be set
+ * @bp:                bit pointer to be set
+ * @cd:                command/data bit
+ *
+ * Return value:
+ *     0 on success or EINVAL for invalid sense buffer length
+ */
+int scsi_set_sense_field_pointer(u8 *buf, int buf_len, u16 fp, u8 bp, bool cd)
+{
+       u8 *ucp, len;
+
+       if ((buf[0] & 0x7f) == 0x72) {
+               len = buf[7];
+               ucp = (char *)scsi_sense_desc_find(buf, len + 8, 2);
+               if (!ucp) {
+                       buf[7] = len + 8;
+                       ucp = buf + 8 + len;
+               }
+
+               if (buf_len < len + 8)
+                       /* Not enough room for info */
+                       return -EINVAL;
+
+               ucp[0] = 2;
+               ucp[1] = 6;
+               ucp[4] = 0x80; /* Valid bit */
+               if (cd)
+                       ucp[4] |= 0x40;
+               if (bp < 0x8)
+                       ucp[4] |= 0x8 | bp;
+               put_unaligned_be16(fp, &ucp[5]);
+       } else if ((buf[0] & 0x7f) == 0x70) {
+               len = buf[7];
+               if (len < 18)
+                       buf[7] = 18;
+
+               buf[15] = 0x80;
+               if (cd)
+                       buf[15] |= 0x40;
+               if (bp < 0x8)
+                       buf[15] |= 0x8 | bp;
+               put_unaligned_be16(fp, &buf[16]);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(scsi_set_sense_field_pointer);
index 984ddcb..a8b610e 100644 (file)
@@ -452,7 +452,7 @@ static void scsi_report_sense(struct scsi_device *sdev,
  *     When a deferred error is detected the current command has
  *     not been executed and needs retrying.
  */
-static int scsi_check_sense(struct scsi_cmnd *scmd)
+int scsi_check_sense(struct scsi_cmnd *scmd)
 {
        struct scsi_device *sdev = scmd->device;
        struct scsi_sense_hdr sshdr;
@@ -602,6 +602,7 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
                return SUCCESS;
        }
 }
+EXPORT_SYMBOL_GPL(scsi_check_sense);
 
 static void scsi_handle_queue_ramp_up(struct scsi_device *sdev)
 {
index c1a2f34..00aebc4 100644 (file)
@@ -385,6 +385,8 @@ enum {
        SATA_SSP                = 0x06, /* Software Settings Preservation */
        SATA_DEVSLP             = 0x09, /* Device Sleep */
 
+       SETFEATURE_SENSE_DATA   = 0xC3, /* Sense Data Reporting feature */
+
        /* feature values for SET_MAX */
        ATA_SET_MAX_ADDR        = 0x00,
        ATA_SET_MAX_PASSWD      = 0x01,
@@ -528,6 +530,8 @@ struct ata_bmdma_prd {
 #define ata_id_cdb_intr(id)    (((id)[ATA_ID_CONFIG] & 0x60) == 0x20)
 #define ata_id_has_da(id)      ((id)[ATA_ID_SATA_CAPABILITY_2] & (1 << 4))
 #define ata_id_has_devslp(id)  ((id)[ATA_ID_FEATURE_SUPP] & (1 << 8))
+#define ata_id_has_ncq_autosense(id) \
+                               ((id)[ATA_ID_FEATURE_SUPP] & (1 << 7))
 
 static inline bool ata_id_has_hipm(const u16 *id)
 {
@@ -716,6 +720,20 @@ static inline bool ata_id_has_read_log_dma_ext(const u16 *id)
        return false;
 }
 
+static inline bool ata_id_has_sense_reporting(const u16 *id)
+{
+       if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
+               return false;
+       return id[ATA_ID_COMMAND_SET_3] & (1 << 6);
+}
+
+static inline bool ata_id_sense_reporting_enabled(const u16 *id)
+{
+       if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
+               return false;
+       return id[ATA_ID_COMMAND_SET_4] & (1 << 6);
+}
+
 /**
  *     ata_id_major_version    -       get ATA level of drive
  *     @id: Identify data
index 2c4ebef..a418bca 100644 (file)
@@ -180,6 +180,7 @@ enum {
        ATA_DFLAG_DA            = (1 << 26), /* device supports Device Attention */
        ATA_DFLAG_DEVSLP        = (1 << 27), /* device supports Device Sleep */
        ATA_DFLAG_ACPI_DISABLED = (1 << 28), /* ACPI for the device is disabled */
+       ATA_DFLAG_D_SENSE       = (1 << 29), /* Descriptor sense requested */
 
        ATA_DEV_UNKNOWN         = 0,    /* unknown device */
        ATA_DEV_ATA             = 1,    /* ATA device */
index 11571b2..20bf7ea 100644 (file)
@@ -63,6 +63,7 @@ extern bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
 
 extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq);
 int scsi_set_sense_information(u8 *buf, int buf_len, u64 info);
+int scsi_set_sense_field_pointer(u8 *buf, int buf_len, u16 fp, u8 bp, bool cd);
 extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
                                       int desc_type);
 
index dbb8c64..98d366b 100644 (file)
@@ -16,6 +16,7 @@ extern void scsi_report_device_reset(struct Scsi_Host *, int, int);
 extern int scsi_block_when_processing_errors(struct scsi_device *);
 extern bool scsi_command_normalize_sense(const struct scsi_cmnd *cmd,
                                         struct scsi_sense_hdr *sshdr);
+extern int scsi_check_sense(struct scsi_cmnd *);
 
 static inline bool scsi_sense_is_deferred(const struct scsi_sense_hdr *sshdr)
 {