diff options
Diffstat (limited to 'drivers/ata/pata_serverworks.c')
| -rw-r--r-- | drivers/ata/pata_serverworks.c | 160 |
1 files changed, 53 insertions, 107 deletions
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index beaed12d50e..fc5f31d4828 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -1,6 +1,7 @@ /* * pata_serverworks.c - Serverworks PATA for new ATA layer * (C) 2005 Red Hat Inc + * (C) 2010 Bartlomiej Zolnierkiewicz * * based upon * @@ -33,7 +34,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/blkdev.h> #include <linux/delay.h> #include <scsi/scsi_host.h> @@ -57,31 +57,15 @@ static const char *csb_bad_ata100[] = { }; /** - * dell_cable - Dell serverworks cable detection + * oem_cable - Dell/Sun serverworks cable detection * @ap: ATA port to do cable detect * - * Dell hide the 40/80 pin select for their interfaces in the top two - * bits of the subsystem ID. + * Dell PowerEdge and Sun Cobalt 'Alpine' hide the 40/80 pin select + * for their interfaces in the top two bits of the subsystem ID. */ -static int dell_cable(struct ata_port *ap) { - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - - if (pdev->subsystem_device & (1 << (ap->port_no + 14))) - return ATA_CBL_PATA80; - return ATA_CBL_PATA40; -} - -/** - * sun_cable - Sun Cobalt 'Alpine' cable detection - * @ap: ATA port to do cable select - * - * Cobalt CSB5 IDE hides the 40/80pin in the top two bits of the - * subsystem ID the same as dell. We could use one function but we may - * need to extend the Dell one in future - */ - -static int sun_cable(struct ata_port *ap) { +static int oem_cable(struct ata_port *ap) +{ struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (pdev->subsystem_device & (1 << (ap->port_no + 14))) @@ -89,49 +73,21 @@ static int sun_cable(struct ata_port *ap) { return ATA_CBL_PATA40; } -/** - * osb4_cable - OSB4 cable detect - * @ap: ATA port to check - * - * The OSB4 isn't UDMA66 capable so this is easy - */ - -static int osb4_cable(struct ata_port *ap) { - return ATA_CBL_PATA40; -} - -/** - * csb_cable - CSB5/6 cable detect - * @ap: ATA port to check - * - * Serverworks default arrangement is to use the drive side detection - * only. - */ - -static int csb_cable(struct ata_port *ap) { - return ATA_CBL_PATA_UNK; -} - struct sv_cable_table { int device; int subvendor; int (*cable_detect)(struct ata_port *ap); }; -/* - * Note that we don't copy the old serverworks code because the old - * code contains obvious mistakes - */ - static struct sv_cable_table cable_detect[] = { - { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_DELL, dell_cable }, - { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_VENDOR_ID_DELL, dell_cable }, - { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_SUN, sun_cable }, - { PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, osb4_cable }, - { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, csb_cable }, - { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, csb_cable }, - { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, csb_cable }, - { PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, csb_cable }, + { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_DELL, oem_cable }, + { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_VENDOR_ID_DELL, oem_cable }, + { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_SUN, oem_cable }, + { PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, ata_cable_40wire }, + { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, ata_cable_unknown }, + { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, ata_cable_unknown }, + { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, ata_cable_unknown }, + { PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, ata_cable_unknown }, { } }; @@ -197,7 +153,7 @@ static unsigned long serverworks_osb4_filter(struct ata_device *adev, unsigned l { if (adev->class == ATA_DEV_ATA) mask &= ~ATA_MASK_UDMA; - return ata_bmdma_mode_filter(adev, mask); + return mask; } @@ -217,7 +173,7 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo /* Disk, UDMA */ if (adev->class != ATA_DEV_ATA) - return ata_bmdma_mode_filter(adev, mask); + return mask; /* Actually do need to check */ ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num)); @@ -226,7 +182,7 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo if (!strcmp(p, model_num)) mask &= ~(0xE0 << ATA_SHIFT_UDMA); } - return ata_bmdma_mode_filter(adev, mask); + return mask; } /** @@ -253,7 +209,7 @@ static void serverworks_set_piomode(struct ata_port *ap, struct ata_device *adev if (serverworks_is_csb(pdev)) { pci_read_config_word(pdev, 0x4A, &csb5_pio); csb5_pio &= ~(0x0F << devbits); - pci_write_config_byte(pdev, 0x4A, csb5_pio | (pio << devbits)); + pci_write_config_word(pdev, 0x4A, csb5_pio | (pio << devbits)); } } @@ -327,7 +283,7 @@ static int serverworks_fixup_osb4(struct pci_dev *pdev) pci_dev_put(isa_dev); return 0; } - printk(KERN_WARNING "ata_serverworks: Unable to find bridge.\n"); + printk(KERN_WARNING DRV_NAME ": Unable to find bridge.\n"); return -ENODEV; } @@ -392,6 +348,31 @@ static void serverworks_fixup_ht1000(struct pci_dev *pdev) pci_write_config_byte(pdev, 0x5A, btr); } +static int serverworks_fixup(struct pci_dev *pdev) +{ + int rc = 0; + + /* Force master latency timer to 64 PCI clocks */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40); + + switch (pdev->device) { + case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE: + rc = serverworks_fixup_osb4(pdev); + break; + case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: + ata_pci_bmdma_clear_simplex(pdev); + /* fall through */ + case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: + case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2: + rc = serverworks_fixup_csb(pdev); + break; + case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE: + serverworks_fixup_ht1000(pdev); + break; + } + + return rc; +} static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -429,13 +410,12 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id if (rc) return rc; - /* Force master latency timer to 64 PCI clocks */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40); + rc = serverworks_fixup(pdev); /* OSB4 : South Bridge and IDE */ if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { /* Select non UDMA capable OSB4 if we can't do fixups */ - if ( serverworks_fixup_osb4(pdev) < 0) + if (rc < 0) ppi[0] = &info[1]; } /* setup CSB5/CSB6 : South Bridge and IDE option RAID */ @@ -445,51 +425,28 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id /* If the returned btr is the newer revision then select the right info block */ - if (serverworks_fixup_csb(pdev) == 3) + if (rc == 3) ppi[0] = &info[3]; /* Is this the 3rd channel CSB6 IDE ? */ if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) ppi[1] = &ata_dummy_port_info; } - /* setup HT1000E */ - else if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) - serverworks_fixup_ht1000(pdev); - - if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) - ata_pci_bmdma_clear_simplex(pdev); - return ata_pci_sff_init_one(pdev, ppi, &serverworks_sht, NULL); + return ata_pci_bmdma_init_one(pdev, ppi, &serverworks_sht, NULL, 0); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int serverworks_reinit_one(struct pci_dev *pdev) { - struct ata_host *host = dev_get_drvdata(&pdev->dev); + struct ata_host *host = pci_get_drvdata(pdev); int rc; rc = ata_pci_device_do_resume(pdev); if (rc) return rc; - /* Force master latency timer to 64 PCI clocks */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40); - - switch (pdev->device) { - case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE: - serverworks_fixup_osb4(pdev); - break; - case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: - ata_pci_bmdma_clear_simplex(pdev); - /* fall through */ - case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: - case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2: - serverworks_fixup_csb(pdev); - break; - case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE: - serverworks_fixup_ht1000(pdev); - break; - } + (void)serverworks_fixup(pdev); ata_host_resume(host); return 0; @@ -511,27 +468,16 @@ static struct pci_driver serverworks_pci_driver = { .id_table = serverworks, .probe = serverworks_init_one, .remove = ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP .suspend = ata_pci_device_suspend, .resume = serverworks_reinit_one, #endif }; -static int __init serverworks_init(void) -{ - return pci_register_driver(&serverworks_pci_driver); -} - -static void __exit serverworks_exit(void) -{ - pci_unregister_driver(&serverworks_pci_driver); -} +module_pci_driver(serverworks_pci_driver); MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for Serverworks OSB4/CSB5/CSB6"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, serverworks); MODULE_VERSION(DRV_VERSION); - -module_init(serverworks_init); -module_exit(serverworks_exit); |
