1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * sim710.c - Copyright (C) 1999 Richard Hirst <richard@sleepie.demon.co.uk> 4 * 5 *---------------------------------------------------------------------------- 6 *---------------------------------------------------------------------------- 7 * 8 * MCA card detection code by Trent McNair. (now deleted) 9 * Fixes to not explicitly nul bss data from Xavier Bestel. 10 * Some multiboard fixes from Rolf Eike Beer. 11 * Auto probing of EISA config space from Trevor Hemsley. 12 * 13 * Rewritten to use 53c700.c by James.Bottomley@SteelEye.com 14 */ 15 16 #include <linux/module.h> 17 #include <linux/slab.h> 18 19 #include <linux/blkdev.h> 20 #include <linux/device.h> 21 #include <linux/init.h> 22 #include <linux/eisa.h> 23 #include <linux/interrupt.h> 24 #include <scsi/scsi_host.h> 25 #include <scsi/scsi_device.h> 26 #include <scsi/scsi_transport.h> 27 #include <scsi/scsi_transport_spi.h> 28 29 #include "53c700.h" 30 31 32 /* Must be enough for EISA */ 33 #define MAX_SLOTS 8 34 static __u8 __initdata id_array[MAX_SLOTS] = { [0 ... MAX_SLOTS-1] = 7 }; 35 36 static char *sim710; /* command line passed by insmod */ 37 38 MODULE_AUTHOR("Richard Hirst"); 39 MODULE_DESCRIPTION("Simple NCR53C710 driver"); 40 MODULE_LICENSE("GPL"); 41 42 module_param(sim710, charp, 0); 43 44 #ifdef MODULE 45 #define ARG_SEP ' ' 46 #else 47 #define ARG_SEP ',' 48 #endif 49 50 static __init int 51 param_setup(char *str) 52 { 53 char *pos = str, *next; 54 int slot = -1; 55 56 while(pos != NULL && (next = strchr(pos, ':')) != NULL) { 57 int val = (int)simple_strtoul(++next, NULL, 0); 58 59 if(!strncmp(pos, "slot:", 5)) 60 slot = val; 61 else if(!strncmp(pos, "id:", 3)) { 62 if(slot == -1) { 63 printk(KERN_WARNING "sim710: Must specify slot for id parameter\n"); 64 } else if(slot >= MAX_SLOTS) { 65 printk(KERN_WARNING "sim710: Illegal slot %d for id %d\n", slot, val); 66 } else { 67 id_array[slot] = val; 68 } 69 } 70 if((pos = strchr(pos, ARG_SEP)) != NULL) 71 pos++; 72 } 73 return 1; 74 } 75 __setup("sim710=", param_setup); 76 77 static struct scsi_host_template sim710_driver_template = { 78 .name = "LSI (Symbios) 710 EISA", 79 .proc_name = "sim710", 80 .this_id = 7, 81 .module = THIS_MODULE, 82 }; 83 84 static int sim710_probe_common(struct device *dev, unsigned long base_addr, 85 int irq, int clock, int differential, 86 int scsi_id) 87 { 88 struct Scsi_Host * host = NULL; 89 struct NCR_700_Host_Parameters *hostdata = 90 kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); 91 92 printk(KERN_NOTICE "sim710: %s\n", dev_name(dev)); 93 printk(KERN_NOTICE "sim710: irq = %d, clock = %d, base = 0x%lx, scsi_id = %d\n", 94 irq, clock, base_addr, scsi_id); 95 96 if(hostdata == NULL) { 97 printk(KERN_ERR "sim710: Failed to allocate host data\n"); 98 goto out; 99 } 100 101 if(request_region(base_addr, 64, "sim710") == NULL) { 102 printk(KERN_ERR "sim710: Failed to reserve IO region 0x%lx\n", 103 base_addr); 104 goto out_free; 105 } 106 107 /* Fill in the three required pieces of hostdata */ 108 hostdata->base = ioport_map(base_addr, 64); 109 hostdata->differential = differential; 110 hostdata->clock = clock; 111 hostdata->chip710 = 1; 112 hostdata->burst_length = 8; 113 114 /* and register the chip */ 115 if((host = NCR_700_detect(&sim710_driver_template, hostdata, dev)) 116 == NULL) { 117 printk(KERN_ERR "sim710: No host detected; card configuration problem?\n"); 118 goto out_release; 119 } 120 host->this_id = scsi_id; 121 host->base = base_addr; 122 host->irq = irq; 123 if (request_irq(irq, NCR_700_intr, IRQF_SHARED, "sim710", host)) { 124 printk(KERN_ERR "sim710: request_irq failed\n"); 125 goto out_put_host; 126 } 127 128 dev_set_drvdata(dev, host); 129 scsi_scan_host(host); 130 131 return 0; 132 133 out_put_host: 134 scsi_host_put(host); 135 out_release: 136 release_region(base_addr, 64); 137 out_free: 138 kfree(hostdata); 139 out: 140 return -ENODEV; 141 } 142 143 static int sim710_device_remove(struct device *dev) 144 { 145 struct Scsi_Host *host = dev_get_drvdata(dev); 146 struct NCR_700_Host_Parameters *hostdata = 147 (struct NCR_700_Host_Parameters *)host->hostdata[0]; 148 149 scsi_remove_host(host); 150 NCR_700_release(host); 151 kfree(hostdata); 152 free_irq(host->irq, host); 153 release_region(host->base, 64); 154 return 0; 155 } 156 157 #ifdef CONFIG_EISA 158 static struct eisa_device_id sim710_eisa_ids[] = { 159 { "CPQ4410" }, 160 { "CPQ4411" }, 161 { "HWP0C80" }, 162 { "" } 163 }; 164 MODULE_DEVICE_TABLE(eisa, sim710_eisa_ids); 165 166 static int sim710_eisa_probe(struct device *dev) 167 { 168 struct eisa_device *edev = to_eisa_device(dev); 169 unsigned long io_addr = edev->base_addr; 170 char eisa_cpq_irqs[] = { 11, 14, 15, 10, 9, 0 }; 171 char eisa_hwp_irqs[] = { 3, 4, 5, 7, 12, 10, 11, 0}; 172 char *eisa_irqs; 173 unsigned char irq_index; 174 unsigned char irq, differential = 0, scsi_id = 7; 175 176 if(strcmp(edev->id.sig, "HWP0C80") == 0) { 177 __u8 val; 178 eisa_irqs = eisa_hwp_irqs; 179 irq_index = (inb(io_addr + 0xc85) & 0x7) - 1; 180 181 val = inb(io_addr + 0x4); 182 scsi_id = ffs(val) - 1; 183 184 if(scsi_id > 7 || (val & ~(1<<scsi_id)) != 0) { 185 printk(KERN_ERR "sim710.c, EISA card %s has incorrect scsi_id, setting to 7\n", dev_name(dev)); 186 scsi_id = 7; 187 } 188 } else { 189 eisa_irqs = eisa_cpq_irqs; 190 irq_index = inb(io_addr + 0xc88) & 0x07; 191 } 192 193 if(irq_index >= strlen(eisa_irqs)) { 194 printk("sim710.c: irq nasty\n"); 195 return -ENODEV; 196 } 197 198 irq = eisa_irqs[irq_index]; 199 200 return sim710_probe_common(dev, io_addr, irq, 50, 201 differential, scsi_id); 202 } 203 204 static struct eisa_driver sim710_eisa_driver = { 205 .id_table = sim710_eisa_ids, 206 .driver = { 207 .name = "sim710", 208 .probe = sim710_eisa_probe, 209 .remove = sim710_device_remove, 210 }, 211 }; 212 #endif /* CONFIG_EISA */ 213 214 static int __init sim710_init(void) 215 { 216 #ifdef MODULE 217 if (sim710) 218 param_setup(sim710); 219 #endif 220 221 #ifdef CONFIG_EISA 222 /* 223 * FIXME: We'd really like to return -ENODEV if no devices have actually 224 * been found. However eisa_driver_register() only reports problems 225 * with kobject_register() so simply return success for now. 226 */ 227 eisa_driver_register(&sim710_eisa_driver); 228 #endif 229 return 0; 230 } 231 232 static void __exit sim710_exit(void) 233 { 234 #ifdef CONFIG_EISA 235 eisa_driver_unregister(&sim710_eisa_driver); 236 #endif 237 } 238 239 module_init(sim710_init); 240 module_exit(sim710_exit); 241