Merge branch 'for-3.20/drivers' of git://git.kernel.dk/linux-block
[linux-drm-fsl-dcu.git] / drivers / ata / libata-scsi.c
index 280729325ebda91c51ada53d7e2c7f1bf3c16be0..b061ba2c31d8f51408a15f2e019a3c328e882815 100644 (file)
@@ -756,7 +756,7 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
 {
        struct ata_queued_cmd *qc;
 
-       qc = ata_qc_new_init(dev);
+       qc = ata_qc_new_init(dev, cmd->request->tag);
        if (qc) {
                qc->scsicmd = cmd;
                qc->scsidone = cmd->scsi_done;
@@ -3668,6 +3668,9 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
                 */
                shost->max_host_blocked = 1;
 
+               if (scsi_init_shared_tag_map(shost, host->n_tags))
+                       goto err_add;
+
                rc = scsi_add_host_with_dma(ap->scsi_host,
                                                &ap->tdev, ap->host->dev);
                if (rc)
@@ -4230,3 +4233,31 @@ int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap)
        return rc;
 }
 EXPORT_SYMBOL_GPL(ata_sas_queuecmd);
+
+int ata_sas_allocate_tag(struct ata_port *ap)
+{
+       unsigned int max_queue = ap->host->n_tags;
+       unsigned int i, tag;
+
+       for (i = 0, tag = ap->sas_last_tag + 1; i < max_queue; i++, tag++) {
+               if (ap->flags & ATA_FLAG_LOWTAG)
+                       tag = 1;
+               else
+                       tag = tag < max_queue ? tag : 0;
+
+               /* the last tag is reserved for internal command. */
+               if (tag == ATA_TAG_INTERNAL)
+                       continue;
+
+               if (!test_and_set_bit(tag, &ap->sas_tag_allocated)) {
+                       ap->sas_last_tag = tag;
+                       return tag;
+               }
+       }
+       return -1;
+}
+
+void ata_sas_free_tag(unsigned int tag, struct ata_port *ap)
+{
+       clear_bit(tag, &ap->sas_tag_allocated);
+}