Blame view

drivers/scsi/sim710.c 6.52 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  /*
   * sim710.c - Copyright (C) 1999 Richard Hirst <richard@sleepie.demon.co.uk>
   *
   *----------------------------------------------------------------------------
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by 
   *  the Free Software Foundation; either version 2 of the License, or
   *  (at your option) any later version.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with this program; if not, write to the Free Software
   *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   *----------------------------------------------------------------------------
   *
a88dc06cd   Paul Gortmaker   scsi: delete the ...
20
   * MCA card detection code by Trent McNair. (now deleted)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
25
26
27
   * Fixes to not explicitly nul bss data from Xavier Bestel.
   * Some multiboard fixes from Rolf Eike Beer.
   * Auto probing of EISA config space from Trevor Hemsley.
   *
   * Rewritten to use 53c700.c by James.Bottomley@SteelEye.com
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
29
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
  
  #include <linux/blkdev.h>
  #include <linux/device.h>
  #include <linux/init.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
39
40
41
  #include <linux/eisa.h>
  #include <linux/interrupt.h>
  #include <scsi/scsi_host.h>
  #include <scsi/scsi_device.h>
  #include <scsi/scsi_transport.h>
  #include <scsi/scsi_transport_spi.h>
  
  #include "53c700.h"
a88dc06cd   Paul Gortmaker   scsi: delete the ...
42
  /* Must be enough for EISA */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  #define MAX_SLOTS 8
  static __u8 __initdata id_array[MAX_SLOTS] = { [0 ... MAX_SLOTS-1] = 7 };
  
  static char *sim710;		/* command line passed by insmod */
  
  MODULE_AUTHOR("Richard Hirst");
  MODULE_DESCRIPTION("Simple NCR53C710 driver");
  MODULE_LICENSE("GPL");
  
  module_param(sim710, charp, 0);
  
  #ifdef MODULE
  #define ARG_SEP ' '
  #else
  #define ARG_SEP ','
  #endif
  
  static __init int
  param_setup(char *str)
  {
  	char *pos = str, *next;
  	int slot = -1;
  
  	while(pos != NULL && (next = strchr(pos, ':')) != NULL) {
  		int val = (int)simple_strtoul(++next, NULL, 0);
  
  		if(!strncmp(pos, "slot:", 5))
  			slot = val;
  		else if(!strncmp(pos, "id:", 3)) {
  			if(slot == -1) {
  				printk(KERN_WARNING "sim710: Must specify slot for id parameter
  ");
1a34456bb   Eric Sesterhenn   [SCSI] Overrun in...
75
  			} else if(slot >= MAX_SLOTS) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  				printk(KERN_WARNING "sim710: Illegal slot %d for id %d
  ", slot, val);
  			} else {
  				id_array[slot] = val;
  			}
  		}
  		if((pos = strchr(pos, ARG_SEP)) != NULL)
  			pos++;
  	}
  	return 1;
  }
  __setup("sim710=", param_setup);
  
  static struct scsi_host_template sim710_driver_template = {
a88dc06cd   Paul Gortmaker   scsi: delete the ...
90
  	.name			= "LSI (Symbios) 710 EISA",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
94
  	.proc_name		= "sim710",
  	.this_id		= 7,
  	.module			= THIS_MODULE,
  };
6f0397905   Greg Kroah-Hartman   Drivers: scsi: re...
95
96
97
  static int sim710_probe_common(struct device *dev, unsigned long base_addr,
  			       int irq, int clock, int differential,
  			       int scsi_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
  {
  	struct Scsi_Host * host = NULL;
  	struct NCR_700_Host_Parameters *hostdata =
dd00cc486   Yoann Padioleau   some kmalloc/mems...
101
  		kzalloc(sizeof(struct NCR_700_Host_Parameters),	GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102

71610f55f   Kay Sievers   [SCSI] struct dev...
103
104
  	printk(KERN_NOTICE "sim710: %s
  ", dev_name(dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
107
108
109
110
111
112
113
  	printk(KERN_NOTICE "sim710: irq = %d, clock = %d, base = 0x%lx, scsi_id = %d
  ",
  	       irq, clock, base_addr, scsi_id);
  
  	if(hostdata == NULL) {
  		printk(KERN_ERR "sim710: Failed to allocate host data
  ");
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
118
119
120
121
122
  
  	if(request_region(base_addr, 64, "sim710") == NULL) {
  		printk(KERN_ERR "sim710: Failed to reserve IO region 0x%lx
  ",
  		       base_addr);
  		goto out_free;
  	}
  
  	/* Fill in the three required pieces of hostdata */
56fece200   James Bottomley   [PATCH] finally f...
123
  	hostdata->base = ioport_map(base_addr, 64);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
  	hostdata->differential = differential;
  	hostdata->clock = clock;
  	hostdata->chip710 = 1;
f67a9c159   Thomas Bogendoerfer   [SCSI] 53c700: Al...
127
  	hostdata->burst_length = 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
131
132
133
134
135
136
  
  	/* and register the chip */
  	if((host = NCR_700_detect(&sim710_driver_template, hostdata, dev))
  	   == NULL) {
  		printk(KERN_ERR "sim710: No host detected; card configuration problem?
  ");
  		goto out_release;
  	}
  	host->this_id = scsi_id;
56fece200   James Bottomley   [PATCH] finally f...
137
  	host->base = base_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
  	host->irq = irq;
1d6f359a2   Thomas Gleixner   [PATCH] irq-flags...
139
  	if (request_irq(irq, NCR_700_intr, IRQF_SHARED, "sim710", host)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
  		printk(KERN_ERR "sim710: request_irq failed
  ");
  		goto out_put_host;
  	}
3ac709c11   Matthew Wilcox   [SCSI] a4000t, zo...
144
  	dev_set_drvdata(dev, host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
149
150
151
  	scsi_scan_host(host);
  
  	return 0;
  
   out_put_host:
  	scsi_host_put(host);
   out_release:
a1d4f73a0   Adrian Bunk   [SCSI] sim710: fi...
152
  	release_region(base_addr, 64);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
157
   out_free:
  	kfree(hostdata);
   out:
  	return -ENODEV;
  }
6f0397905   Greg Kroah-Hartman   Drivers: scsi: re...
158
  static int sim710_device_remove(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  {
3ac709c11   Matthew Wilcox   [SCSI] a4000t, zo...
160
  	struct Scsi_Host *host = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
165
166
167
  	struct NCR_700_Host_Parameters *hostdata =
  		(struct NCR_700_Host_Parameters *)host->hostdata[0];
  
  	scsi_remove_host(host);
  	NCR_700_release(host);
  	kfree(hostdata);
  	free_irq(host->irq, host);
56fece200   James Bottomley   [PATCH] finally f...
168
  	release_region(host->base, 64);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
173
174
175
176
177
  #ifdef CONFIG_EISA
  static struct eisa_device_id sim710_eisa_ids[] = {
  	{ "CPQ4410" },
  	{ "CPQ4411" },
  	{ "HWP0C80" },
  	{ "" }
  };
07563c711   Michael Tokarev   [PATCH] EISA bus ...
178
  MODULE_DEVICE_TABLE(eisa, sim710_eisa_ids);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  
  static __init int
  sim710_eisa_probe(struct device *dev)
  {
  	struct eisa_device *edev = to_eisa_device(dev);
  	unsigned long io_addr = edev->base_addr;
  	char eisa_cpq_irqs[] = { 11, 14, 15, 10, 9, 0 };
  	char eisa_hwp_irqs[] = { 3, 4, 5, 7, 12, 10, 11, 0};
  	char *eisa_irqs;
  	unsigned char irq_index;
  	unsigned char irq, differential = 0, scsi_id = 7;
  
  	if(strcmp(edev->id.sig, "HWP0C80") == 0) {
  		__u8 val;
  		eisa_irqs =  eisa_hwp_irqs;
  		irq_index = (inb(io_addr + 0xc85) & 0x7) - 1;
  
  		val = inb(io_addr + 0x4);
  		scsi_id = ffs(val) - 1;
  
  		if(scsi_id > 7 || (val & ~(1<<scsi_id)) != 0) {
71610f55f   Kay Sievers   [SCSI] struct dev...
200
201
  			printk(KERN_ERR "sim710.c, EISA card %s has incorrect scsi_id, setting to 7
  ", dev_name(dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
  			scsi_id = 7;
  		}
  	} else {
  		eisa_irqs = eisa_cpq_irqs;
  		irq_index = inb(io_addr + 0xc88) & 0x07;
  	}
  
  	if(irq_index >= strlen(eisa_irqs)) {
  		printk("sim710.c: irq nasty
  ");
  		return -ENODEV;
  	}
  
  	irq = eisa_irqs[irq_index];
  		
  	return sim710_probe_common(dev, io_addr, irq, 50,
  				   differential, scsi_id);
  }
  
  static struct eisa_driver sim710_eisa_driver = {
  	.id_table		= sim710_eisa_ids,
  	.driver = {
  		.name		= "sim710",
  		.probe		= sim710_eisa_probe,
6f0397905   Greg Kroah-Hartman   Drivers: scsi: re...
226
  		.remove		= sim710_device_remove,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
231
232
233
234
235
236
237
238
  	},
  };
  #endif /* CONFIG_EISA */
  
  static int __init sim710_init(void)
  {
  	int err = -ENODEV;
  
  #ifdef MODULE
  	if (sim710)
  		param_setup(sim710);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
242
243
244
245
246
247
248
249
250
251
  #ifdef CONFIG_EISA
  	err = eisa_driver_register(&sim710_eisa_driver);
  #endif
  	/* FIXME: what we'd really like to return here is -ENODEV if
  	 * no devices have actually been found.  Instead, the err
  	 * above actually only reports problems with kobject_register,
  	 * so for the moment return success */
  
  	return 0;
  }
  
  static void __exit sim710_exit(void)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
255
256
257
258
  #ifdef CONFIG_EISA
  	eisa_driver_unregister(&sim710_eisa_driver);
  #endif
  }
  
  module_init(sim710_init);
  module_exit(sim710_exit);