module_param_named(noacpi, libata_noacpi, int, 0444);
 MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in probe/suspend/resume when set");
 
+int libata_allow_tpm = 0;
+module_param_named(allow_tpm, libata_allow_tpm, int, 0444);
+MODULE_PARM_DESC(allow_tpm, "Permit the use of TPM commands");
+
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Library module for ATA devices");
 MODULE_LICENSE("GPL");
                                               "supports DRM functions and may "
                                               "not be fully accessable.\n");
                        snprintf(revbuf, 7, "CFA");
-               } else
+               } else {
                        snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id));
+                       /* Warn the user if the device has TPM extensions */
+                       if (ata_id_has_tpm(id))
+                               ata_dev_printk(dev, KERN_WARNING,
+                                              "supports DRM functions and may "
+                                              "not be fully accessable.\n");
+               }
 
                dev->n_sectors = ata_id_n_sectors(id);
 
 
        if ((tf->protocol = ata_scsi_map_proto(cdb[1])) == ATA_PROT_UNKNOWN)
                goto invalid_fld;
 
+       /*
+        * Filter TPM commands by default. These provide an
+        * essentially uncontrolled encrypted "back door" between
+        * applications and the disk. Set libata.allow_tpm=1 if you
+        * have a real reason for wanting to use them. This ensures
+        * that installed software cannot easily mess stuff up without
+        * user intent. DVR type users will probably ship with this enabled
+        * for movie content management.
+        *
+        * Note that for ATA8 we can issue a DCS change and DCS freeze lock
+        * for this and should do in future but that it is not sufficient as
+        * DCS is an optional feature set. Thus we also do the software filter
+        * 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)
+               goto invalid_fld;
+
        /* We may not issue DMA commands if no DMA mode is set */
        if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0)
                goto invalid_fld;
 
 extern int atapi_passthru16;
 extern int libata_fua;
 extern int libata_noacpi;
+extern int libata_allow_tpm;
 extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
 extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
                           u64 block, u32 n_block, unsigned int tf_flags,
 
 #define ata_id_has_ncq(id)     ((id)[76] & (1 << 8))
 #define ata_id_queue_depth(id) (((id)[75] & 0x1f) + 1)
 #define ata_id_removeable(id)  ((id)[0] & (1 << 7))
-#define ata_id_has_dword_io(id)        ((id)[48] & (1 << 0))
 #define ata_id_has_atapi_AN(id)        \
        ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \
          ((id)[78] & (1 << 5)) )
        return val & (1 << 3);
 }
 
+
 static inline int ata_id_has_fua(const u16 *id)
 {
        if ((id[84] & 0xC000) != 0x4000)
        return ata_id_major_version(id) >= 5 && id[93] == 0;
 }
 
+static inline int ata_id_has_tpm(const u16 *id)
+{
+       /* The TPM bits are only valid on ATA8 */
+       if (ata_id_major_version(id) < 8)
+               return 0;
+       if ((id[48] & 0xC000) != 0x4000)
+               return 0;
+       return id[48] & (1 << 0);
+}
+
+static inline int ata_id_has_dword_io(const u16 *id)
+{
+       /* ATA 8 reuses this flag for "trusted" computing */
+       if (ata_id_major_version(id) > 7)
+               return 0;
+       if (id[48] & (1 << 0))
+               return 1;
+       return 0;
+}
+
 static inline int ata_id_current_chs_valid(const u16 *id)
 {
        /* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command