Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 91163006 authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik
Browse files

libata: automatically use DMADIR if drive/bridge requires it



Back in 2.6.17-rc2, a libata module parameter was added for atapi_dmadir.

That's nice, but most SATA devices which need it will tell us about it
in their IDENTIFY PACKET response, as bit-15 of word-62 of the
returned data (as per ATA7, ATA8 specifications).

So for those which specify it, we should automatically use the DMADIR bit.
Otherwise, disc writing will fail by default on many SATA-ATAPI drives.

This patch adds ATA_DFLAG_DMADIR and make ata_dev_configure() set it
if atapi_dmadir is set or identify data indicates DMADIR is necessary.
atapi_xlat() is converted to check ATA_DFLAG_DMADIR before setting
DMADIR.

Original patch is from Mark Lord.

Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Cc: Mark Lord <mlord@pobox.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 559bbe6c
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -2396,6 +2396,7 @@ int ata_dev_configure(struct ata_device *dev)
	else if (dev->class == ATA_DEV_ATAPI) {
		const char *cdb_intr_string = "";
		const char *atapi_an_string = "";
		const char *dma_dir_string = "";
		u32 sntf;

		rc = atapi_cdb_len(id);
@@ -2436,13 +2437,19 @@ int ata_dev_configure(struct ata_device *dev)
			cdb_intr_string = ", CDB intr";
		}

		if (atapi_dmadir || atapi_id_dmadir(dev->id)) {
			dev->flags |= ATA_DFLAG_DMADIR;
			dma_dir_string = ", DMADIR";
		}

		/* print device info to dmesg */
		if (ata_msg_drv(ap) && print_info)
			ata_dev_printk(dev, KERN_INFO,
				       "ATAPI: %s, %s, max %s%s%s\n",
				       "ATAPI: %s, %s, max %s%s%s%s\n",
				       modelbuf, fwrevbuf,
				       ata_mode_string(xfer_mask),
				       cdb_intr_string, atapi_an_string);
				       cdb_intr_string, atapi_an_string,
				       dma_dir_string);
	}

	/* determine max_sectors */
+2 −1
Original line number Diff line number Diff line
@@ -2582,7 +2582,8 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
		qc->tf.protocol = ATAPI_PROT_DMA;
		qc->tf.feature |= ATAPI_PKT_DMA;

		if (atapi_dmadir && (scmd->sc_data_direction != DMA_TO_DEVICE))
		if ((dev->flags & ATA_DFLAG_DMADIR) &&
		    (scmd->sc_data_direction != DMA_TO_DEVICE))
			/* some SATA bridges need us to indicate data xfer direction */
			qc->tf.feature |= ATAPI_DMADIR;
	}
+5 −0
Original line number Diff line number Diff line
@@ -659,6 +659,11 @@ static inline int atapi_command_packet_set(const u16 *dev_id)
	return (dev_id[0] >> 8) & 0x1f;
}

static inline int atapi_id_dmadir(const u16 *dev_id)
{
	return ata_id_major_version(dev_id) >= 7 && (dev_id[62] & 0x8000);
}

static inline int is_multi_taskfile(struct ata_taskfile *tf)
{
	return (tf->command == ATA_CMD_READ_MULTI) ||
+1 −0
Original line number Diff line number Diff line
@@ -138,6 +138,7 @@ enum {
	ATA_DFLAG_AN		= (1 << 7), /* AN configured */
	ATA_DFLAG_HIPM		= (1 << 8), /* device supports HIPM */
	ATA_DFLAG_DIPM		= (1 << 9), /* device supports DIPM */
	ATA_DFLAG_DMADIR	= (1 << 10), /* device requires DMADIR */
	ATA_DFLAG_CFG_MASK	= (1 << 12) - 1,

	ATA_DFLAG_PIO		= (1 << 12), /* device limited to PIO mode */