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

pata_via: Cache and rewrite the device bit

Some VIA chipsets will reset the DEV bit after IEN changes on ctl. Our
optimised write path avoids doing this but we need to remove the
optimisation on these devices.

[Identified and some original patches proposed by Josehn Chan @ VIA but
discussion then all ground to a halt so given a test case I dug it back out]

Signed-off-by: Alan Cox <alan@lxorguk.ukuu.org.uk
Tested-by: Christoph Bisping (bug #13086)
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>

authored by

Alan Cox and committed by
Jeff Garzik
b4746ed7 299b3f8d

+67 -7
+67 -7
drivers/ata/pata_via.c
··· 62 62 #include <linux/dmi.h> 63 63 64 64 #define DRV_NAME "pata_via" 65 - #define DRV_VERSION "0.3.3" 65 + #define DRV_VERSION "0.3.4" 66 66 67 67 /* 68 68 * The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx ··· 136 136 { NULL } 137 137 }; 138 138 139 + struct via_port { 140 + u8 cached_device; 141 + }; 139 142 140 143 /* 141 144 * Cable special cases ··· 349 346 */ 350 347 static void via_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) 351 348 { 352 - struct ata_taskfile tmp_tf; 349 + struct ata_ioports *ioaddr = &ap->ioaddr; 350 + struct via_port *vp = ap->private_data; 351 + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; 352 + int newctl = 0; 353 353 354 - if (ap->ctl != ap->last_ctl && !(tf->flags & ATA_TFLAG_DEVICE)) { 355 - tmp_tf = *tf; 356 - tmp_tf.flags |= ATA_TFLAG_DEVICE; 357 - tf = &tmp_tf; 354 + if (tf->ctl != ap->last_ctl) { 355 + iowrite8(tf->ctl, ioaddr->ctl_addr); 356 + ap->last_ctl = tf->ctl; 357 + ata_wait_idle(ap); 358 + newctl = 1; 358 359 } 359 - ata_sff_tf_load(ap, tf); 360 + 361 + if (tf->flags & ATA_TFLAG_DEVICE) { 362 + iowrite8(tf->device, ioaddr->device_addr); 363 + vp->cached_device = tf->device; 364 + } else if (newctl) 365 + iowrite8(vp->cached_device, ioaddr->device_addr); 366 + 367 + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { 368 + WARN_ON_ONCE(!ioaddr->ctl_addr); 369 + iowrite8(tf->hob_feature, ioaddr->feature_addr); 370 + iowrite8(tf->hob_nsect, ioaddr->nsect_addr); 371 + iowrite8(tf->hob_lbal, ioaddr->lbal_addr); 372 + iowrite8(tf->hob_lbam, ioaddr->lbam_addr); 373 + iowrite8(tf->hob_lbah, ioaddr->lbah_addr); 374 + VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", 375 + tf->hob_feature, 376 + tf->hob_nsect, 377 + tf->hob_lbal, 378 + tf->hob_lbam, 379 + tf->hob_lbah); 380 + } 381 + 382 + if (is_addr) { 383 + iowrite8(tf->feature, ioaddr->feature_addr); 384 + iowrite8(tf->nsect, ioaddr->nsect_addr); 385 + iowrite8(tf->lbal, ioaddr->lbal_addr); 386 + iowrite8(tf->lbam, ioaddr->lbam_addr); 387 + iowrite8(tf->lbah, ioaddr->lbah_addr); 388 + VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", 389 + tf->feature, 390 + tf->nsect, 391 + tf->lbal, 392 + tf->lbam, 393 + tf->lbah); 394 + } 395 + 396 + ata_wait_idle(ap); 397 + } 398 + 399 + static int via_port_start(struct ata_port *ap) 400 + { 401 + struct via_port *vp; 402 + struct pci_dev *pdev = to_pci_dev(ap->host->dev); 403 + 404 + int ret = ata_sff_port_start(ap); 405 + if (ret < 0) 406 + return ret; 407 + 408 + vp = devm_kzalloc(&pdev->dev, sizeof(struct via_port), GFP_KERNEL); 409 + if (vp == NULL) 410 + return -ENOMEM; 411 + ap->private_data = vp; 412 + return 0; 360 413 } 361 414 362 415 static struct scsi_host_template via_sht = { ··· 426 367 .set_dmamode = via_set_dmamode, 427 368 .prereset = via_pre_reset, 428 369 .sff_tf_load = via_tf_load, 370 + .port_start = via_port_start, 429 371 }; 430 372 431 373 static struct ata_port_operations via_port_ops_noirq = {