Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] libata: fix non-uniform ports handling

Non-uniform ports handling got broken while updating libata to handle
those in the same host. Only separate irq for the non-uniform
secondary port was implemented while all other fields (host flags,
transfer mode...) of the secondary port simply shared those of the
first.

For ata_piix combined mode, which ATM is the only user of non-uniform
ports, this causes the secondary port assume the wrong type. This can
cause PATA port to use SATA ops, which results in bogus check on PCS
and detection failure.

This patch adds ata_probe_ent->pinfo2 which points to optional
port_info for the secondary port. For the time being, this seems to
be the simplest solution. This workaround will be removed together
with ata_probe_ent itself after init model is updated to allow more
flexibility.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: Nelson A. de Oliveira <naoliv@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>

authored by

Tejun Heo and committed by
Jeff Garzik
fea63e38 a64f97f2

+23 -5
+13 -5
drivers/ata/libata-core.c
··· 5269 5269 ap->host = host; 5270 5270 ap->dev = ent->dev; 5271 5271 ap->port_no = port_no; 5272 - ap->pio_mask = ent->pio_mask; 5273 - ap->mwdma_mask = ent->mwdma_mask; 5274 - ap->udma_mask = ent->udma_mask; 5275 - ap->flags |= ent->port_flags; 5276 - ap->ops = ent->port_ops; 5272 + if (port_no == 1 && ent->pinfo2) { 5273 + ap->pio_mask = ent->pinfo2->pio_mask; 5274 + ap->mwdma_mask = ent->pinfo2->mwdma_mask; 5275 + ap->udma_mask = ent->pinfo2->udma_mask; 5276 + ap->flags |= ent->pinfo2->flags; 5277 + ap->ops = ent->pinfo2->port_ops; 5278 + } else { 5279 + ap->pio_mask = ent->pio_mask; 5280 + ap->mwdma_mask = ent->mwdma_mask; 5281 + ap->udma_mask = ent->udma_mask; 5282 + ap->flags |= ent->port_flags; 5283 + ap->ops = ent->port_ops; 5284 + } 5277 5285 ap->hw_sata_spd_limit = UINT_MAX; 5278 5286 ap->active_tag = ATA_TAG_POISON; 5279 5287 ap->last_ctl = 0xFF;
+2
drivers/ata/libata-sff.c
··· 858 858 probe_ent->port[p].bmdma_addr = bmdma; 859 859 } 860 860 ata_std_ports(&probe_ent->port[p]); 861 + probe_ent->pinfo2 = port[1]; 861 862 p++; 862 863 } 863 864 ··· 908 907 probe_ent->_host_flags |= ATA_HOST_SIMPLEX; 909 908 } 910 909 ata_std_ports(&probe_ent->port[1]); 910 + probe_ent->pinfo2 = port[1]; 911 911 } else 912 912 probe_ent->dummy_port_mask |= ATA_PORT_SECONDARY; 913 913
+8
include/linux/libata.h
··· 361 361 unsigned long _host_flags; 362 362 void __iomem *mmio_base; 363 363 void *private_data; 364 + 365 + /* port_info for the secondary port. Together with irq2, it's 366 + * used to implement non-uniform secondary port. Currently, 367 + * the only user is ata_piix combined mode. This workaround 368 + * will be removed together with ata_probe_ent when init model 369 + * is updated. 370 + */ 371 + const struct ata_port_info *pinfo2; 364 372 }; 365 373 366 374 struct ata_host {