diff mbox series

[V8,5/5] libata: Align DMA buffer to dma_get_cache_alignment()

Message ID 1508227542-13165-5-git-send-email-chenhc@lemote.com
State Not Applicable
Delegated to: David Miller
Headers show
Series [V8,1/5] dma-mapping: Rework dma_get_cache_alignment() | expand

Commit Message

Huacai Chen Oct. 17, 2017, 8:05 a.m. UTC
In non-coherent DMA mode, kernel uses cache flushing operations to
maintain I/O coherency, so in ata_do_dev_read_id() the DMA buffer
should be aligned to ARCH_DMA_MINALIGN. Otherwise, If a DMA buffer
and a kernel structure share a same cache line, and if the kernel
structure has dirty data, cache_invalidate (no writeback) will cause
data corruption.

Cc: stable@vger.kernel.org
Signed-off-by: Huacai Chen <chenhc@lemote.com>
---
 drivers/ata/libata-core.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

Comments

Sergei Shtylyov Oct. 17, 2017, 9:43 a.m. UTC | #1
On 10/17/2017 11:05 AM, Huacai Chen wrote:

> In non-coherent DMA mode, kernel uses cache flushing operations to
> maintain I/O coherency, so in ata_do_dev_read_id() the DMA buffer
> should be aligned to ARCH_DMA_MINALIGN. Otherwise, If a DMA buffer
> and a kernel structure share a same cache line, and if the kernel
> structure has dirty data, cache_invalidate (no writeback) will cause
> data corruption.
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> ---
>   drivers/ata/libata-core.c | 15 +++++++++++++--
>   1 file changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
> index ee4c1ec..e134955 100644
> --- a/drivers/ata/libata-core.c
> +++ b/drivers/ata/libata-core.c
> @@ -1833,8 +1833,19 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
>   unsigned int ata_do_dev_read_id(struct ata_device *dev,
>   					struct ata_taskfile *tf, u16 *id)
>   {
> -	return ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE,
> -				     id, sizeof(id[0]) * ATA_ID_WORDS, 0);
> +	u16 *devid;
> +	int res, size = sizeof(u16) * ATA_ID_WORDS;
> +
> +	if (IS_ALIGNED((unsigned long)id, dma_get_cache_alignment(&dev->tdev)))
> +		res = ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE, id, size, 0);
> +	else {
> +		devid = kmalloc(size, GFP_KERNEL);
> +		res = ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE, devid, size, 0);
> +		memcpy(id, devid, size);
> +		kfree(devid);
> +	}
> +
> +	return res;

    This function is called only for the PIO mode commands, so I doubt this is 
necessary...

MBR, Sergei
--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Huacai Chen Oct. 18, 2017, 1:06 a.m. UTC | #2
Hi, Sergei,

Without this patch, in non-coherent mode, ata_do_set_mode() return with "no PIO support", and disk detection fails.

Huacai
 
 
------------------ Original ------------------
From:  "Sergei Shtylyov"<sergei.shtylyov@cogentembedded.com>;

Date:  Tue, Oct 17, 2017 05:43 PM
To:  "Huacai Chen"<chenhc@lemote.com>; "Christoph Hellwig"<hch@lst.de>; 
Cc:  "Marek Szyprowski"<m.szyprowski@samsung.com>; "Robin Murphy"<robin.murphy@arm.com>; "Andrew Morton"<akpm@linux-foundation.org>; "Fuxin Zhang"<zhangfx@lemote.com>; "linux-kernel"<linux-kernel@vger.kernel.org>; "Ralf Baechle"<ralf@linux-mips.org>; "James Hogan"<james.hogan@imgtec.com>; "linux-mips"<linux-mips@linux-mips.org>; "James E . J . Bottomley"<jejb@linux.vnet.ibm.com>; "Martin K . Petersen"<martin.petersen@oracle.com>; "linux-scsi"<linux-scsi@vger.kernel.org>; "Tejun Heo"<tj@kernel.org>; "linux-ide"<linux-ide@vger.kernel.org>; "stable"<stable@vger.kernel.org>; 
Subject:  Re: [PATCH V8 5/5] libata: Align DMA buffer todma_get_cache_alignment()

 
On 10/17/2017 11:05 AM, Huacai Chen wrote:

> In non-coherent DMA mode, kernel uses cache flushing operations to

> maintain I/O coherency, so in ata_do_dev_read_id() the DMA buffer

> should be aligned to ARCH_DMA_MINALIGN. Otherwise, If a DMA buffer

> and a kernel structure share a same cache line, and if the kernel

> structure has dirty data, cache_invalidate (no writeback) will cause

> data corruption.

> 

> Cc: stable@vger.kernel.org

> Signed-off-by: Huacai Chen <chenhc@lemote.com>

> ---

>   drivers/ata/libata-core.c | 15 +++++++++++++--

>   1 file changed, 13 insertions(+), 2 deletions(-)

> 

> diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c

> index ee4c1ec..e134955 100644

> --- a/drivers/ata/libata-core.c

> +++ b/drivers/ata/libata-core.c

> @@ -1833,8 +1833,19 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)

>   unsigned int ata_do_dev_read_id(struct ata_device *dev,

>   					struct ata_taskfile *tf, u16 *id)

>   {

> -	return ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE,

> -				     id, sizeof(id[0]) * ATA_ID_WORDS, 0);

> +	u16 *devid;

> +	int res, size = sizeof(u16) * ATA_ID_WORDS;

> +

> +	if (IS_ALIGNED((unsigned long)id, dma_get_cache_alignment(&dev->tdev)))

> +		res = ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE, id, size, 0);

> +	else {

> +		devid = kmalloc(size, GFP_KERNEL);

> +		res = ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE, devid, size, 0);

> +		memcpy(id, devid, size);

> +		kfree(devid);

> +	}

> +

> +	return res;


    This function is called only for the PIO mode commands, so I doubt this is 
necessary...

MBR, Sergei
Tejun Heo Oct. 18, 2017, 1:03 p.m. UTC | #3
On Tue, Oct 17, 2017 at 04:05:42PM +0800, Huacai Chen wrote:
> In non-coherent DMA mode, kernel uses cache flushing operations to
> maintain I/O coherency, so in ata_do_dev_read_id() the DMA buffer
> should be aligned to ARCH_DMA_MINALIGN. Otherwise, If a DMA buffer
> and a kernel structure share a same cache line, and if the kernel
> structure has dirty data, cache_invalidate (no writeback) will cause
> data corruption.
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> ---
>  drivers/ata/libata-core.c | 15 +++++++++++++--
>  1 file changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
> index ee4c1ec..e134955 100644
> --- a/drivers/ata/libata-core.c
> +++ b/drivers/ata/libata-core.c
> @@ -1833,8 +1833,19 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
>  unsigned int ata_do_dev_read_id(struct ata_device *dev,
>  					struct ata_taskfile *tf, u16 *id)
>  {
> -	return ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE,
> -				     id, sizeof(id[0]) * ATA_ID_WORDS, 0);
> +	u16 *devid;
> +	int res, size = sizeof(u16) * ATA_ID_WORDS;
> +
> +	if (IS_ALIGNED((unsigned long)id, dma_get_cache_alignment(&dev->tdev)))
> +		res = ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE, id, size, 0);
> +	else {
> +		devid = kmalloc(size, GFP_KERNEL);
> +		res = ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE, devid, size, 0);
> +		memcpy(id, devid, size);
> +		kfree(devid);
> +	}
> +
> +	return res;

Hmm... I think it'd be a lot better to ensure that the buffers are
aligned properly to begin with.  There are only two buffers which are
used for id reading - ata_port->sector_buf and ata_device->id.  Both
are embedded arrays but making them separately allocated aligned
buffers shouldn't be difficult.

Thanks.
Alan Cox Oct. 18, 2017, 7:54 p.m. UTC | #4
>     This function is called only for the PIO mode commands, so I doubt this is 
> necessary...

That is true but there are platforms out there that issue disk level PIO
commands via DMA (or can do so). Indeed the Cyrix MediaGX could do that
in the 1990s but I never add support 8)

So I think it makes sense to allocate the buffers DMA aligned, but it
doesn't seem to explain the situation in this case and I think it would
be helpful to know what platform and ATA driver is tripping this and wny
they are the only people in the universe to have the problem.

Alan
--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Matt Redfearn Oct. 19, 2017, 7:52 a.m. UTC | #5
On 18/10/17 14:03, Tejun Heo wrote:
> On Tue, Oct 17, 2017 at 04:05:42PM +0800, Huacai Chen wrote:
>> In non-coherent DMA mode, kernel uses cache flushing operations to
>> maintain I/O coherency, so in ata_do_dev_read_id() the DMA buffer
>> should be aligned to ARCH_DMA_MINALIGN. Otherwise, If a DMA buffer
>> and a kernel structure share a same cache line, and if the kernel
>> structure has dirty data, cache_invalidate (no writeback) will cause
>> data corruption.
>>
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
>> ---
>>   drivers/ata/libata-core.c | 15 +++++++++++++--
>>   1 file changed, 13 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
>> index ee4c1ec..e134955 100644
>> --- a/drivers/ata/libata-core.c
>> +++ b/drivers/ata/libata-core.c
>> @@ -1833,8 +1833,19 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
>>   unsigned int ata_do_dev_read_id(struct ata_device *dev,
>>   					struct ata_taskfile *tf, u16 *id)
>>   {
>> -	return ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE,
>> -				     id, sizeof(id[0]) * ATA_ID_WORDS, 0);
>> +	u16 *devid;
>> +	int res, size = sizeof(u16) * ATA_ID_WORDS;
>> +
>> +	if (IS_ALIGNED((unsigned long)id, dma_get_cache_alignment(&dev->tdev)))
>> +		res = ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE, id, size, 0);
>> +	else {
>> +		devid = kmalloc(size, GFP_KERNEL);
>> +		res = ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE, devid, size, 0);
>> +		memcpy(id, devid, size);
>> +		kfree(devid);
>> +	}
>> +
>> +	return res;
> Hmm... I think it'd be a lot better to ensure that the buffers are
> aligned properly to begin with.  There are only two buffers which are
> used for id reading - ata_port->sector_buf and ata_device->id.  Both
> are embedded arrays but making them separately allocated aligned
> buffers shouldn't be difficult.
>
> Thanks.

FWIW, I agree that the buffers used for DMA should be split out from the 
structure. We ran into this problem on MIPS last year, 
4ee34ea3a12396f35b26d90a094c75db95080baa ("libata: Align ata_device's id 
on a cacheline") partially fixed it, but likely should have also 
cacheline aligned the following devslp_timing in the struct such that we 
guarantee that members of the struct not used for DMA do not share the 
same cacheline as the DMA buffer. Not having this means that 
architectures, such as MIPS, which in some cases have to perform manual 
invalidation of DMA buffer can clobber valid adjacent data if it is in 
the same cacheline.

Thanks,
Matt


--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Huacai Chen Oct. 20, 2017, 4:25 a.m. UTC | #6
SGksIE1hdHQsDQoNCkkgZm91bmQgdGhhdCA0ZWUzNGVhM2ExMjM5NmYzNWIyNmQ5MGEwOTRj
NzVkYiAoImxpYmF0YTogQWxpZ24gYXRhX2RldmljZSdzIGlkIG9uIGEgY2FjaGVsaW5lIikg
Y2FuIHJlc29sdmUgZXZlcnl0aGluZy4gQmVjYXVzZSB0aGUgc2l6ZSBvZiBpZFtBVEFfSURf
V09SRFNdIGlzIGFscmVhZHkgYWxpZ25lZCBhbmQgZGV2c2xwX3RpbWluZyBuZWVkbid0IHRv
IGJlIGFsaWduZWQuIFNvLCBJbiBWOSBvZiB0aGlzIHNlcmllcyBJIHdpbGwgZHJvcCB0aGlz
IHBhdGNoLiBXaHkgSSBoYWQgcHJvYmxlbXMgYmVmb3JlPyBiZWNhdXNlIEkgdXNlZCBsaW51
eC00LjQuDQoNCkh1YWNhaQ0KIA0KIA0KLS0tLS0tLS0tLS0tLS0tLS0tIE9yaWdpbmFsIC0t
LS0tLS0tLS0tLS0tLS0tLQ0KRnJvbTogICJNYXR0IFJlZGZlYXJuIjxtYXR0LnJlZGZlYXJu
QG1pcHMuY29tPjsNCkRhdGU6ICBUaHUsIE9jdCAxOSwgMjAxNyAwMzo1MiBQTQ0KVG86ICAi
VGVqdW4gSGVvIjx0akBrZXJuZWwub3JnPjsgIkh1YWNhaSBDaGVuIjxjaGVuaGNAbGVtb3Rl
LmNvbT47IA0KQ2M6ICAiQ2hyaXN0b3BoIEhlbGx3aWciPGhjaEBsc3QuZGU+OyAiTWFyZWsg
U3p5cHJvd3NraSI8bS5zenlwcm93c2tpQHNhbXN1bmcuY29tPjsgIlJvYmluIE11cnBoeSI8
cm9iaW4ubXVycGh5QGFybS5jb20+OyAiQW5kcmV3TW9ydG9uIjxha3BtQGxpbnV4LWZvdW5k
YXRpb24ub3JnPjsgIkZ1eGluIFpoYW5nIjx6aGFuZ2Z4QGxlbW90ZS5jb20+OyAibGludXgt
a2VybmVsIjxsaW51eC1rZXJuZWxAdmdlci5rZXJuZWwub3JnPjsgIlJhbGYgQmFlY2hsZSI8
cmFsZkBsaW51eC1taXBzLm9yZz47ICJKYW1lc0hvZ2FuIjxqYW1lcy5ob2dhbkBpbWd0ZWMu
Y29tPjsgImxpbnV4LW1pcHMiPGxpbnV4LW1pcHNAbGludXgtbWlwcy5vcmc+OyAiSmFtZXMg
RSAuIEogLkJvdHRvbWxleSI8amVqYkBsaW51eC52bmV0LmlibS5jb20+OyAiTWFydGluIEsg
LiBQZXRlcnNlbiI8bWFydGluLnBldGVyc2VuQG9yYWNsZS5jb20+OyAibGludXgtc2NzaSI8
bGludXgtc2NzaUB2Z2VyLmtlcm5lbC5vcmc+OyAibGludXgtaWRlIjxsaW51eC1pZGVAdmdl
ci5rZXJuZWwub3JnPjsgInN0YWJsZSI8c3RhYmxlQHZnZXIua2VybmVsLm9yZz47IA0KU3Vi
amVjdDogIFJlOiBbUEFUQ0ggVjggNS81XSBsaWJhdGE6IEFsaWduIERNQSBidWZmZXIgdG9k
bWFfZ2V0X2NhY2hlX2FsaWdubWVudCgpDQoNCiANCg0KDQpPbiAxOC8xMC8xNyAxNDowMywg
VGVqdW4gSGVvIHdyb3RlOg0KPiBPbiBUdWUsIE9jdCAxNywgMjAxNyBhdCAwNDowNTo0MlBN
ICswODAwLCBIdWFjYWkgQ2hlbiB3cm90ZToNCj4+IEluIG5vbi1jb2hlcmVudCBETUEgbW9k
ZSwga2VybmVsIHVzZXMgY2FjaGUgZmx1c2hpbmcgb3BlcmF0aW9ucyB0bw0KPj4gbWFpbnRh
aW4gSS9PIGNvaGVyZW5jeSwgc28gaW4gYXRhX2RvX2Rldl9yZWFkX2lkKCkgdGhlIERNQSBi
dWZmZXINCj4+IHNob3VsZCBiZSBhbGlnbmVkIHRvIEFSQ0hfRE1BX01JTkFMSUdOLiBPdGhl
cndpc2UsIElmIGEgRE1BIGJ1ZmZlcg0KPj4gYW5kIGEga2VybmVsIHN0cnVjdHVyZSBzaGFy
ZSBhIHNhbWUgY2FjaGUgbGluZSwgYW5kIGlmIHRoZSBrZXJuZWwNCj4+IHN0cnVjdHVyZSBo
YXMgZGlydHkgZGF0YSwgY2FjaGVfaW52YWxpZGF0ZSAobm8gd3JpdGViYWNrKSB3aWxsIGNh
dXNlDQo+PiBkYXRhIGNvcnJ1cHRpb24uDQo+Pg0KPj4gQ2M6IHN0YWJsZUB2Z2VyLmtlcm5l
bC5vcmcNCj4+IFNpZ25lZC1vZmYtYnk6IEh1YWNhaSBDaGVuIDxjaGVuaGNAbGVtb3RlLmNv
bT4NCj4+IC0tLQ0KPj4gICBkcml2ZXJzL2F0YS9saWJhdGEtY29yZS5jIHwgMTUgKysrKysr
KysrKysrKy0tDQo+PiAgIDEgZmlsZSBjaGFuZ2VkLCAxMyBpbnNlcnRpb25zKCspLCAyIGRl
bGV0aW9ucygtKQ0KPj4NCj4+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2F0YS9saWJhdGEtY29y
ZS5jIGIvZHJpdmVycy9hdGEvbGliYXRhLWNvcmUuYw0KPj4gaW5kZXggZWU0YzFlYy4uZTEz
NDk1NSAxMDA2NDQNCj4+IC0tLSBhL2RyaXZlcnMvYXRhL2xpYmF0YS1jb3JlLmMNCj4+ICsr
KyBiL2RyaXZlcnMvYXRhL2xpYmF0YS1jb3JlLmMNCj4+IEBAIC0xODMzLDggKzE4MzMsMTkg
QEAgc3RhdGljIHUzMiBhdGFfcGlvX21hc2tfbm9faW9yZHkoY29uc3Qgc3RydWN0IGF0YV9k
ZXZpY2UgKmFkZXYpDQo+PiAgIHVuc2lnbmVkIGludCBhdGFfZG9fZGV2X3JlYWRfaWQoc3Ry
dWN0IGF0YV9kZXZpY2UgKmRldiwNCj4+ICAgCQkJCQlzdHJ1Y3QgYXRhX3Rhc2tmaWxlICp0
ZiwgdTE2ICppZCkNCj4+ICAgew0KPj4gLQlyZXR1cm4gYXRhX2V4ZWNfaW50ZXJuYWwoZGV2
LCB0ZiwgTlVMTCwgRE1BX0ZST01fREVWSUNFLA0KPj4gLQkJCQkgICAgIGlkLCBzaXplb2Yo
aWRbMF0pICogQVRBX0lEX1dPUkRTLCAwKTsNCj4+ICsJdTE2ICpkZXZpZDsNCj4+ICsJaW50
IHJlcywgc2l6ZSA9IHNpemVvZih1MTYpICogQVRBX0lEX1dPUkRTOw0KPj4gKw0KPj4gKwlp
ZiAoSVNfQUxJR05FRCgodW5zaWduZWQgbG9uZylpZCwgZG1hX2dldF9jYWNoZV9hbGlnbm1l
bnQoJmRldi0+dGRldikpKQ0KPj4gKwkJcmVzID0gYXRhX2V4ZWNfaW50ZXJuYWwoZGV2LCB0
ZiwgTlVMTCwgRE1BX0ZST01fREVWSUNFLCBpZCwgc2l6ZSwgMCk7DQo+PiArCWVsc2Ugew0K
Pj4gKwkJZGV2aWQgPSBrbWFsbG9jKHNpemUsIEdGUF9LRVJORUwpOw0KPj4gKwkJcmVzID0g
YXRhX2V4ZWNfaW50ZXJuYWwoZGV2LCB0ZiwgTlVMTCwgRE1BX0ZST01fREVWSUNFLCBkZXZp
ZCwgc2l6ZSwgMCk7DQo+PiArCQltZW1jcHkoaWQsIGRldmlkLCBzaXplKTsNCj4+ICsJCWtm
cmVlKGRldmlkKTsNCj4+ICsJfQ0KPj4gKw0KPj4gKwlyZXR1cm4gcmVzOw0KPiBIbW0uLi4g
SSB0aGluayBpdCdkIGJlIGEgbG90IGJldHRlciB0byBlbnN1cmUgdGhhdCB0aGUgYnVmZmVy
cyBhcmUNCj4gYWxpZ25lZCBwcm9wZXJseSB0byBiZWdpbiB3aXRoLiAgVGhlcmUgYXJlIG9u
bHkgdHdvIGJ1ZmZlcnMgd2hpY2ggYXJlDQo+IHVzZWQgZm9yIGlkIHJlYWRpbmcgLSBhdGFf
cG9ydC0+c2VjdG9yX2J1ZiBhbmQgYXRhX2RldmljZS0+aWQuICBCb3RoDQo+IGFyZSBlbWJl
ZGRlZCBhcnJheXMgYnV0IG1ha2luZyB0aGVtIHNlcGFyYXRlbHkgYWxsb2NhdGVkIGFsaWdu
ZWQNCj4gYnVmZmVycyBzaG91bGRuJ3QgYmUgZGlmZmljdWx0Lg0KPg0KPiBUaGFua3MuDQoN
CkZXSVcsIEkgYWdyZWUgdGhhdCB0aGUgYnVmZmVycyB1c2VkIGZvciBETUEgc2hvdWxkIGJl
IHNwbGl0IG91dCBmcm9tIHRoZSANCnN0cnVjdHVyZS4gV2UgcmFuIGludG8gdGhpcyBwcm9i
bGVtIG9uIE1JUFMgbGFzdCB5ZWFyLCANCjRlZTM0ZWEzYTEyMzk2ZjM1YjI2ZDkwYTA5NGM3
NWRiOTUwODBiYWEgKCJsaWJhdGE6IEFsaWduIGF0YV9kZXZpY2UncyBpZCANCm9uIGEgY2Fj
aGVsaW5lIikgcGFydGlhbGx5IGZpeGVkIGl0LCBidXQgbGlrZWx5IHNob3VsZCBoYXZlIGFs
c28gDQpjYWNoZWxpbmUgYWxpZ25lZCB0aGUgZm9sbG93aW5nIGRldnNscF90aW1pbmcgaW4g
dGhlIHN0cnVjdCBzdWNoIHRoYXQgd2UgDQpndWFyYW50ZWUgdGhhdCBtZW1iZXJzIG9mIHRo
ZSBzdHJ1Y3Qgbm90IHVzZWQgZm9yIERNQSBkbyBub3Qgc2hhcmUgdGhlIA0Kc2FtZSBjYWNo
ZWxpbmUgYXMgdGhlIERNQSBidWZmZXIuIE5vdCBoYXZpbmcgdGhpcyBtZWFucyB0aGF0IA0K
YXJjaGl0ZWN0dXJlcywgc3VjaCBhcyBNSVBTLCB3aGljaCBpbiBzb21lIGNhc2VzIGhhdmUg
dG8gcGVyZm9ybSBtYW51YWwgDQppbnZhbGlkYXRpb24gb2YgRE1BIGJ1ZmZlciBjYW4gY2xv
YmJlciB2YWxpZCBhZGphY2VudCBkYXRhIGlmIGl0IGlzIGluIA0KdGhlIHNhbWUgY2FjaGVs
aW5lLg0KDQpUaGFua3MsDQpNYXR0



--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox series

Patch

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index ee4c1ec..e134955 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1833,8 +1833,19 @@  static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
 unsigned int ata_do_dev_read_id(struct ata_device *dev,
 					struct ata_taskfile *tf, u16 *id)
 {
-	return ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE,
-				     id, sizeof(id[0]) * ATA_ID_WORDS, 0);
+	u16 *devid;
+	int res, size = sizeof(u16) * ATA_ID_WORDS;
+
+	if (IS_ALIGNED((unsigned long)id, dma_get_cache_alignment(&dev->tdev)))
+		res = ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE, id, size, 0);
+	else {
+		devid = kmalloc(size, GFP_KERNEL);
+		res = ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE, devid, size, 0);
+		memcpy(id, devid, size);
+		kfree(devid);
+	}
+
+	return res;
 }
 
 /**