1*c6fd2807SJeff Garzik /* 2*c6fd2807SJeff Garzik * sata_uli.c - ULi Electronics SATA 3*c6fd2807SJeff Garzik * 4*c6fd2807SJeff Garzik * 5*c6fd2807SJeff Garzik * This program is free software; you can redistribute it and/or modify 6*c6fd2807SJeff Garzik * it under the terms of the GNU General Public License as published by 7*c6fd2807SJeff Garzik * the Free Software Foundation; either version 2, or (at your option) 8*c6fd2807SJeff Garzik * any later version. 9*c6fd2807SJeff Garzik * 10*c6fd2807SJeff Garzik * This program is distributed in the hope that it will be useful, 11*c6fd2807SJeff Garzik * but WITHOUT ANY WARRANTY; without even the implied warranty of 12*c6fd2807SJeff Garzik * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*c6fd2807SJeff Garzik * GNU General Public License for more details. 14*c6fd2807SJeff Garzik * 15*c6fd2807SJeff Garzik * You should have received a copy of the GNU General Public License 16*c6fd2807SJeff Garzik * along with this program; see the file COPYING. If not, write to 17*c6fd2807SJeff Garzik * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 18*c6fd2807SJeff Garzik * 19*c6fd2807SJeff Garzik * 20*c6fd2807SJeff Garzik * libata documentation is available via 'make {ps|pdf}docs', 21*c6fd2807SJeff Garzik * as Documentation/DocBook/libata.* 22*c6fd2807SJeff Garzik * 23*c6fd2807SJeff Garzik * Hardware documentation available under NDA. 24*c6fd2807SJeff Garzik * 25*c6fd2807SJeff Garzik */ 26*c6fd2807SJeff Garzik 27*c6fd2807SJeff Garzik #include <linux/kernel.h> 28*c6fd2807SJeff Garzik #include <linux/module.h> 29*c6fd2807SJeff Garzik #include <linux/pci.h> 30*c6fd2807SJeff Garzik #include <linux/init.h> 31*c6fd2807SJeff Garzik #include <linux/blkdev.h> 32*c6fd2807SJeff Garzik #include <linux/delay.h> 33*c6fd2807SJeff Garzik #include <linux/interrupt.h> 34*c6fd2807SJeff Garzik #include <linux/device.h> 35*c6fd2807SJeff Garzik #include <scsi/scsi_host.h> 36*c6fd2807SJeff Garzik #include <linux/libata.h> 37*c6fd2807SJeff Garzik 38*c6fd2807SJeff Garzik #define DRV_NAME "sata_uli" 39*c6fd2807SJeff Garzik #define DRV_VERSION "1.0" 40*c6fd2807SJeff Garzik 41*c6fd2807SJeff Garzik enum { 42*c6fd2807SJeff Garzik uli_5289 = 0, 43*c6fd2807SJeff Garzik uli_5287 = 1, 44*c6fd2807SJeff Garzik uli_5281 = 2, 45*c6fd2807SJeff Garzik 46*c6fd2807SJeff Garzik uli_max_ports = 4, 47*c6fd2807SJeff Garzik 48*c6fd2807SJeff Garzik /* PCI configuration registers */ 49*c6fd2807SJeff Garzik ULI5287_BASE = 0x90, /* sata0 phy SCR registers */ 50*c6fd2807SJeff Garzik ULI5287_OFFS = 0x10, /* offset from sata0->sata1 phy regs */ 51*c6fd2807SJeff Garzik ULI5281_BASE = 0x60, /* sata0 phy SCR registers */ 52*c6fd2807SJeff Garzik ULI5281_OFFS = 0x60, /* offset from sata0->sata1 phy regs */ 53*c6fd2807SJeff Garzik }; 54*c6fd2807SJeff Garzik 55*c6fd2807SJeff Garzik struct uli_priv { 56*c6fd2807SJeff Garzik unsigned int scr_cfg_addr[uli_max_ports]; 57*c6fd2807SJeff Garzik }; 58*c6fd2807SJeff Garzik 59*c6fd2807SJeff Garzik static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); 60*c6fd2807SJeff Garzik static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg); 61*c6fd2807SJeff Garzik static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); 62*c6fd2807SJeff Garzik 63*c6fd2807SJeff Garzik static const struct pci_device_id uli_pci_tbl[] = { 64*c6fd2807SJeff Garzik { PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 }, 65*c6fd2807SJeff Garzik { PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 }, 66*c6fd2807SJeff Garzik { PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 }, 67*c6fd2807SJeff Garzik { } /* terminate list */ 68*c6fd2807SJeff Garzik }; 69*c6fd2807SJeff Garzik 70*c6fd2807SJeff Garzik 71*c6fd2807SJeff Garzik static struct pci_driver uli_pci_driver = { 72*c6fd2807SJeff Garzik .name = DRV_NAME, 73*c6fd2807SJeff Garzik .id_table = uli_pci_tbl, 74*c6fd2807SJeff Garzik .probe = uli_init_one, 75*c6fd2807SJeff Garzik .remove = ata_pci_remove_one, 76*c6fd2807SJeff Garzik }; 77*c6fd2807SJeff Garzik 78*c6fd2807SJeff Garzik static struct scsi_host_template uli_sht = { 79*c6fd2807SJeff Garzik .module = THIS_MODULE, 80*c6fd2807SJeff Garzik .name = DRV_NAME, 81*c6fd2807SJeff Garzik .ioctl = ata_scsi_ioctl, 82*c6fd2807SJeff Garzik .queuecommand = ata_scsi_queuecmd, 83*c6fd2807SJeff Garzik .can_queue = ATA_DEF_QUEUE, 84*c6fd2807SJeff Garzik .this_id = ATA_SHT_THIS_ID, 85*c6fd2807SJeff Garzik .sg_tablesize = LIBATA_MAX_PRD, 86*c6fd2807SJeff Garzik .cmd_per_lun = ATA_SHT_CMD_PER_LUN, 87*c6fd2807SJeff Garzik .emulated = ATA_SHT_EMULATED, 88*c6fd2807SJeff Garzik .use_clustering = ATA_SHT_USE_CLUSTERING, 89*c6fd2807SJeff Garzik .proc_name = DRV_NAME, 90*c6fd2807SJeff Garzik .dma_boundary = ATA_DMA_BOUNDARY, 91*c6fd2807SJeff Garzik .slave_configure = ata_scsi_slave_config, 92*c6fd2807SJeff Garzik .slave_destroy = ata_scsi_slave_destroy, 93*c6fd2807SJeff Garzik .bios_param = ata_std_bios_param, 94*c6fd2807SJeff Garzik }; 95*c6fd2807SJeff Garzik 96*c6fd2807SJeff Garzik static const struct ata_port_operations uli_ops = { 97*c6fd2807SJeff Garzik .port_disable = ata_port_disable, 98*c6fd2807SJeff Garzik 99*c6fd2807SJeff Garzik .tf_load = ata_tf_load, 100*c6fd2807SJeff Garzik .tf_read = ata_tf_read, 101*c6fd2807SJeff Garzik .check_status = ata_check_status, 102*c6fd2807SJeff Garzik .exec_command = ata_exec_command, 103*c6fd2807SJeff Garzik .dev_select = ata_std_dev_select, 104*c6fd2807SJeff Garzik 105*c6fd2807SJeff Garzik .bmdma_setup = ata_bmdma_setup, 106*c6fd2807SJeff Garzik .bmdma_start = ata_bmdma_start, 107*c6fd2807SJeff Garzik .bmdma_stop = ata_bmdma_stop, 108*c6fd2807SJeff Garzik .bmdma_status = ata_bmdma_status, 109*c6fd2807SJeff Garzik .qc_prep = ata_qc_prep, 110*c6fd2807SJeff Garzik .qc_issue = ata_qc_issue_prot, 111*c6fd2807SJeff Garzik .data_xfer = ata_pio_data_xfer, 112*c6fd2807SJeff Garzik 113*c6fd2807SJeff Garzik .freeze = ata_bmdma_freeze, 114*c6fd2807SJeff Garzik .thaw = ata_bmdma_thaw, 115*c6fd2807SJeff Garzik .error_handler = ata_bmdma_error_handler, 116*c6fd2807SJeff Garzik .post_internal_cmd = ata_bmdma_post_internal_cmd, 117*c6fd2807SJeff Garzik 118*c6fd2807SJeff Garzik .irq_handler = ata_interrupt, 119*c6fd2807SJeff Garzik .irq_clear = ata_bmdma_irq_clear, 120*c6fd2807SJeff Garzik 121*c6fd2807SJeff Garzik .scr_read = uli_scr_read, 122*c6fd2807SJeff Garzik .scr_write = uli_scr_write, 123*c6fd2807SJeff Garzik 124*c6fd2807SJeff Garzik .port_start = ata_port_start, 125*c6fd2807SJeff Garzik .port_stop = ata_port_stop, 126*c6fd2807SJeff Garzik .host_stop = ata_host_stop, 127*c6fd2807SJeff Garzik }; 128*c6fd2807SJeff Garzik 129*c6fd2807SJeff Garzik static struct ata_port_info uli_port_info = { 130*c6fd2807SJeff Garzik .sht = &uli_sht, 131*c6fd2807SJeff Garzik .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, 132*c6fd2807SJeff Garzik .pio_mask = 0x1f, /* pio0-4 */ 133*c6fd2807SJeff Garzik .udma_mask = 0x7f, /* udma0-6 */ 134*c6fd2807SJeff Garzik .port_ops = &uli_ops, 135*c6fd2807SJeff Garzik }; 136*c6fd2807SJeff Garzik 137*c6fd2807SJeff Garzik 138*c6fd2807SJeff Garzik MODULE_AUTHOR("Peer Chen"); 139*c6fd2807SJeff Garzik MODULE_DESCRIPTION("low-level driver for ULi Electronics SATA controller"); 140*c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 141*c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, uli_pci_tbl); 142*c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 143*c6fd2807SJeff Garzik 144*c6fd2807SJeff Garzik static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg) 145*c6fd2807SJeff Garzik { 146*c6fd2807SJeff Garzik struct uli_priv *hpriv = ap->host_set->private_data; 147*c6fd2807SJeff Garzik return hpriv->scr_cfg_addr[ap->port_no] + (4 * sc_reg); 148*c6fd2807SJeff Garzik } 149*c6fd2807SJeff Garzik 150*c6fd2807SJeff Garzik static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg) 151*c6fd2807SJeff Garzik { 152*c6fd2807SJeff Garzik struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); 153*c6fd2807SJeff Garzik unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg); 154*c6fd2807SJeff Garzik u32 val; 155*c6fd2807SJeff Garzik 156*c6fd2807SJeff Garzik pci_read_config_dword(pdev, cfg_addr, &val); 157*c6fd2807SJeff Garzik return val; 158*c6fd2807SJeff Garzik } 159*c6fd2807SJeff Garzik 160*c6fd2807SJeff Garzik static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val) 161*c6fd2807SJeff Garzik { 162*c6fd2807SJeff Garzik struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); 163*c6fd2807SJeff Garzik unsigned int cfg_addr = get_scr_cfg_addr(ap, scr); 164*c6fd2807SJeff Garzik 165*c6fd2807SJeff Garzik pci_write_config_dword(pdev, cfg_addr, val); 166*c6fd2807SJeff Garzik } 167*c6fd2807SJeff Garzik 168*c6fd2807SJeff Garzik static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg) 169*c6fd2807SJeff Garzik { 170*c6fd2807SJeff Garzik if (sc_reg > SCR_CONTROL) 171*c6fd2807SJeff Garzik return 0xffffffffU; 172*c6fd2807SJeff Garzik 173*c6fd2807SJeff Garzik return uli_scr_cfg_read(ap, sc_reg); 174*c6fd2807SJeff Garzik } 175*c6fd2807SJeff Garzik 176*c6fd2807SJeff Garzik static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) 177*c6fd2807SJeff Garzik { 178*c6fd2807SJeff Garzik if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0 179*c6fd2807SJeff Garzik return; 180*c6fd2807SJeff Garzik 181*c6fd2807SJeff Garzik uli_scr_cfg_write(ap, sc_reg, val); 182*c6fd2807SJeff Garzik } 183*c6fd2807SJeff Garzik 184*c6fd2807SJeff Garzik static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) 185*c6fd2807SJeff Garzik { 186*c6fd2807SJeff Garzik static int printed_version; 187*c6fd2807SJeff Garzik struct ata_probe_ent *probe_ent; 188*c6fd2807SJeff Garzik struct ata_port_info *ppi; 189*c6fd2807SJeff Garzik int rc; 190*c6fd2807SJeff Garzik unsigned int board_idx = (unsigned int) ent->driver_data; 191*c6fd2807SJeff Garzik int pci_dev_busy = 0; 192*c6fd2807SJeff Garzik struct uli_priv *hpriv; 193*c6fd2807SJeff Garzik 194*c6fd2807SJeff Garzik if (!printed_version++) 195*c6fd2807SJeff Garzik dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); 196*c6fd2807SJeff Garzik 197*c6fd2807SJeff Garzik rc = pci_enable_device(pdev); 198*c6fd2807SJeff Garzik if (rc) 199*c6fd2807SJeff Garzik return rc; 200*c6fd2807SJeff Garzik 201*c6fd2807SJeff Garzik rc = pci_request_regions(pdev, DRV_NAME); 202*c6fd2807SJeff Garzik if (rc) { 203*c6fd2807SJeff Garzik pci_dev_busy = 1; 204*c6fd2807SJeff Garzik goto err_out; 205*c6fd2807SJeff Garzik } 206*c6fd2807SJeff Garzik 207*c6fd2807SJeff Garzik rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); 208*c6fd2807SJeff Garzik if (rc) 209*c6fd2807SJeff Garzik goto err_out_regions; 210*c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); 211*c6fd2807SJeff Garzik if (rc) 212*c6fd2807SJeff Garzik goto err_out_regions; 213*c6fd2807SJeff Garzik 214*c6fd2807SJeff Garzik ppi = &uli_port_info; 215*c6fd2807SJeff Garzik probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); 216*c6fd2807SJeff Garzik if (!probe_ent) { 217*c6fd2807SJeff Garzik rc = -ENOMEM; 218*c6fd2807SJeff Garzik goto err_out_regions; 219*c6fd2807SJeff Garzik } 220*c6fd2807SJeff Garzik 221*c6fd2807SJeff Garzik hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL); 222*c6fd2807SJeff Garzik if (!hpriv) { 223*c6fd2807SJeff Garzik rc = -ENOMEM; 224*c6fd2807SJeff Garzik goto err_out_probe_ent; 225*c6fd2807SJeff Garzik } 226*c6fd2807SJeff Garzik 227*c6fd2807SJeff Garzik probe_ent->private_data = hpriv; 228*c6fd2807SJeff Garzik 229*c6fd2807SJeff Garzik switch (board_idx) { 230*c6fd2807SJeff Garzik case uli_5287: 231*c6fd2807SJeff Garzik hpriv->scr_cfg_addr[0] = ULI5287_BASE; 232*c6fd2807SJeff Garzik hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS; 233*c6fd2807SJeff Garzik probe_ent->n_ports = 4; 234*c6fd2807SJeff Garzik 235*c6fd2807SJeff Garzik probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8; 236*c6fd2807SJeff Garzik probe_ent->port[2].altstatus_addr = 237*c6fd2807SJeff Garzik probe_ent->port[2].ctl_addr = 238*c6fd2807SJeff Garzik (pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4; 239*c6fd2807SJeff Garzik probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16; 240*c6fd2807SJeff Garzik hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4; 241*c6fd2807SJeff Garzik 242*c6fd2807SJeff Garzik probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8; 243*c6fd2807SJeff Garzik probe_ent->port[3].altstatus_addr = 244*c6fd2807SJeff Garzik probe_ent->port[3].ctl_addr = 245*c6fd2807SJeff Garzik (pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4; 246*c6fd2807SJeff Garzik probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24; 247*c6fd2807SJeff Garzik hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5; 248*c6fd2807SJeff Garzik 249*c6fd2807SJeff Garzik ata_std_ports(&probe_ent->port[2]); 250*c6fd2807SJeff Garzik ata_std_ports(&probe_ent->port[3]); 251*c6fd2807SJeff Garzik break; 252*c6fd2807SJeff Garzik 253*c6fd2807SJeff Garzik case uli_5289: 254*c6fd2807SJeff Garzik hpriv->scr_cfg_addr[0] = ULI5287_BASE; 255*c6fd2807SJeff Garzik hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS; 256*c6fd2807SJeff Garzik break; 257*c6fd2807SJeff Garzik 258*c6fd2807SJeff Garzik case uli_5281: 259*c6fd2807SJeff Garzik hpriv->scr_cfg_addr[0] = ULI5281_BASE; 260*c6fd2807SJeff Garzik hpriv->scr_cfg_addr[1] = ULI5281_BASE + ULI5281_OFFS; 261*c6fd2807SJeff Garzik break; 262*c6fd2807SJeff Garzik 263*c6fd2807SJeff Garzik default: 264*c6fd2807SJeff Garzik BUG(); 265*c6fd2807SJeff Garzik break; 266*c6fd2807SJeff Garzik } 267*c6fd2807SJeff Garzik 268*c6fd2807SJeff Garzik pci_set_master(pdev); 269*c6fd2807SJeff Garzik pci_intx(pdev, 1); 270*c6fd2807SJeff Garzik 271*c6fd2807SJeff Garzik /* FIXME: check ata_device_add return value */ 272*c6fd2807SJeff Garzik ata_device_add(probe_ent); 273*c6fd2807SJeff Garzik kfree(probe_ent); 274*c6fd2807SJeff Garzik 275*c6fd2807SJeff Garzik return 0; 276*c6fd2807SJeff Garzik 277*c6fd2807SJeff Garzik err_out_probe_ent: 278*c6fd2807SJeff Garzik kfree(probe_ent); 279*c6fd2807SJeff Garzik err_out_regions: 280*c6fd2807SJeff Garzik pci_release_regions(pdev); 281*c6fd2807SJeff Garzik err_out: 282*c6fd2807SJeff Garzik if (!pci_dev_busy) 283*c6fd2807SJeff Garzik pci_disable_device(pdev); 284*c6fd2807SJeff Garzik return rc; 285*c6fd2807SJeff Garzik 286*c6fd2807SJeff Garzik } 287*c6fd2807SJeff Garzik 288*c6fd2807SJeff Garzik static int __init uli_init(void) 289*c6fd2807SJeff Garzik { 290*c6fd2807SJeff Garzik return pci_register_driver(&uli_pci_driver); 291*c6fd2807SJeff Garzik } 292*c6fd2807SJeff Garzik 293*c6fd2807SJeff Garzik static void __exit uli_exit(void) 294*c6fd2807SJeff Garzik { 295*c6fd2807SJeff Garzik pci_unregister_driver(&uli_pci_driver); 296*c6fd2807SJeff Garzik } 297*c6fd2807SJeff Garzik 298*c6fd2807SJeff Garzik 299*c6fd2807SJeff Garzik module_init(uli_init); 300*c6fd2807SJeff Garzik module_exit(uli_exit); 301