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

Configure Feed

Select the types of activity you want to include in your feed.

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