xref: /linux/drivers/scsi/pcmcia/qlogic_stub.c (revision d39d0ed196aa1685bb24771e92f78633c66ac9cb)
1 /*======================================================================
2 
3     A driver for the Qlogic SCSI card
4 
5     qlogic_cs.c 1.79 2000/06/12 21:27:26
6 
7     The contents of this file are subject to the Mozilla Public
8     License Version 1.1 (the "License"); you may not use this file
9     except in compliance with the License. You may obtain a copy of
10     the License at http://www.mozilla.org/MPL/
11 
12     Software distributed under the License is distributed on an "AS
13     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14     implied. See the License for the specific language governing
15     rights and limitations under the License.
16 
17     The initial developer of the original code is David A. Hinds
18     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
19     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
20 
21     Alternatively, the contents of this file may be used under the
22     terms of the GNU General Public License version 2 (the "GPL"), in which
23     case the provisions of the GPL are applicable instead of the
24     above.  If you wish to allow the use of your version of this file
25     only under the terms of the GPL and not to allow others to use
26     your version of this file under the MPL, indicate your decision
27     by deleting the provisions above and replace them with the notice
28     and other provisions required by the GPL.  If you do not delete
29     the provisions above, a recipient may use your version of this
30     file under either the MPL or the GPL.
31 
32 ======================================================================*/
33 
34 #include <linux/module.h>
35 #include <linux/init.h>
36 #include <linux/kernel.h>
37 #include <linux/slab.h>
38 #include <linux/string.h>
39 #include <linux/ioport.h>
40 #include <asm/io.h>
41 #include <scsi/scsi.h>
42 #include <linux/major.h>
43 #include <linux/blkdev.h>
44 #include <scsi/scsi_ioctl.h>
45 #include <linux/interrupt.h>
46 
47 #include "scsi.h"
48 #include <scsi/scsi_host.h>
49 #include "../qlogicfas408.h"
50 
51 #include <pcmcia/cs.h>
52 #include <pcmcia/cistpl.h>
53 #include <pcmcia/ds.h>
54 #include <pcmcia/ciscode.h>
55 
56 /* Set the following to 2 to use normal interrupt (active high/totempole-
57  * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
58  * drain
59  */
60 #define INT_TYPE	0
61 
62 static char qlogic_name[] = "qlogic_cs";
63 
64 static struct scsi_host_template qlogicfas_driver_template = {
65 	.module			= THIS_MODULE,
66 	.name			= qlogic_name,
67 	.proc_name		= qlogic_name,
68 	.info			= qlogicfas408_info,
69 	.queuecommand		= qlogicfas408_queuecommand,
70 	.eh_abort_handler	= qlogicfas408_abort,
71 	.eh_bus_reset_handler	= qlogicfas408_bus_reset,
72 	.bios_param		= qlogicfas408_biosparam,
73 	.can_queue		= 1,
74 	.this_id		= -1,
75 	.sg_tablesize		= SG_ALL,
76 	.cmd_per_lun		= 1,
77 	.use_clustering		= DISABLE_CLUSTERING,
78 };
79 
80 /*====================================================================*/
81 
82 typedef struct scsi_info_t {
83 	struct pcmcia_device	*p_dev;
84 	struct Scsi_Host *host;
85 	unsigned short manf_id;
86 } scsi_info_t;
87 
88 static void qlogic_release(struct pcmcia_device *link);
89 static void qlogic_detach(struct pcmcia_device *p_dev);
90 static int qlogic_config(struct pcmcia_device * link);
91 
92 static struct Scsi_Host *qlogic_detect(struct scsi_host_template *host,
93 				struct pcmcia_device *link, int qbase, int qlirq)
94 {
95 	int qltyp;		/* type of chip */
96 	int qinitid;
97 	struct Scsi_Host *shost;	/* registered host structure */
98 	struct qlogicfas408_priv *priv;
99 
100 	qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE);
101 	qinitid = host->this_id;
102 	if (qinitid < 0)
103 		qinitid = 7;	/* if no ID, use 7 */
104 
105 	qlogicfas408_setup(qbase, qinitid, INT_TYPE);
106 
107 	host->name = qlogic_name;
108 	shost = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv));
109 	if (!shost)
110 		goto err;
111 	shost->io_port = qbase;
112 	shost->n_io_port = 16;
113 	shost->dma_channel = -1;
114 	if (qlirq != -1)
115 		shost->irq = qlirq;
116 
117 	priv = get_priv_by_host(shost);
118 	priv->qlirq = qlirq;
119 	priv->qbase = qbase;
120 	priv->qinitid = qinitid;
121 	priv->shost = shost;
122 	priv->int_type = INT_TYPE;
123 
124 	if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogic_name, shost))
125 		goto free_scsi_host;
126 
127 	sprintf(priv->qinfo,
128 		"Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
129 		qltyp, qbase, qlirq, QL_TURBO_PDMA);
130 
131 	if (scsi_add_host(shost, NULL))
132 		goto free_interrupt;
133 
134 	scsi_scan_host(shost);
135 
136 	return shost;
137 
138 free_interrupt:
139 	free_irq(qlirq, shost);
140 
141 free_scsi_host:
142 	scsi_host_put(shost);
143 
144 err:
145 	return NULL;
146 }
147 static int qlogic_probe(struct pcmcia_device *link)
148 {
149 	scsi_info_t *info;
150 
151 	dev_dbg(&link->dev, "qlogic_attach()\n");
152 
153 	/* Create new SCSI device */
154 	info = kzalloc(sizeof(*info), GFP_KERNEL);
155 	if (!info)
156 		return -ENOMEM;
157 	info->p_dev = link;
158 	link->priv = info;
159 	link->resource[0]->end = 16;
160 	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
161 	link->conf.Attributes = CONF_ENABLE_IRQ;
162 	link->conf.IntType = INT_MEMORY_AND_IO;
163 	link->conf.Present = PRESENT_OPTION;
164 
165 	return qlogic_config(link);
166 }				/* qlogic_attach */
167 
168 /*====================================================================*/
169 
170 static void qlogic_detach(struct pcmcia_device *link)
171 {
172 	dev_dbg(&link->dev, "qlogic_detach\n");
173 
174 	qlogic_release(link);
175 	kfree(link->priv);
176 
177 }				/* qlogic_detach */
178 
179 /*====================================================================*/
180 
181 static int qlogic_config_check(struct pcmcia_device *p_dev,
182 			       cistpl_cftable_entry_t *cfg,
183 			       cistpl_cftable_entry_t *dflt,
184 			       unsigned int vcc,
185 			       void *priv_data)
186 {
187 	p_dev->io_lines = 10;
188 	p_dev->resource[0]->start = cfg->io.win[0].base;
189 	p_dev->resource[0]->end = cfg->io.win[0].len;
190 
191 	if (p_dev->resource[0]->start == 0)
192 		return -ENODEV;
193 
194 	return pcmcia_request_io(p_dev);
195 }
196 
197 static int qlogic_config(struct pcmcia_device * link)
198 {
199 	scsi_info_t *info = link->priv;
200 	int ret;
201 	struct Scsi_Host *host;
202 
203 	dev_dbg(&link->dev, "qlogic_config\n");
204 
205 	ret = pcmcia_loop_config(link, qlogic_config_check, NULL);
206 	if (ret)
207 		goto failed;
208 
209 	if (!link->irq)
210 		goto failed;
211 
212 	ret = pcmcia_request_configuration(link, &link->conf);
213 	if (ret)
214 		goto failed;
215 
216 	if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) {
217 		/* set ATAcmd */
218 		outb(0xb4, link->resource[0]->start + 0xd);
219 		outb(0x24, link->resource[0]->start + 0x9);
220 		outb(0x04, link->resource[0]->start + 0xd);
221 	}
222 
223 	/* The KXL-810AN has a bigger IO port window */
224 	if (resource_size(link->resource[0]) == 32)
225 		host = qlogic_detect(&qlogicfas_driver_template, link,
226 			link->resource[0]->start + 16, link->irq);
227 	else
228 		host = qlogic_detect(&qlogicfas_driver_template, link,
229 			link->resource[0]->start, link->irq);
230 
231 	if (!host) {
232 		printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name);
233 		goto failed;
234 	}
235 
236 	info->host = host;
237 
238 	return 0;
239 
240 failed:
241 	pcmcia_disable_device(link);
242 	return -ENODEV;
243 }				/* qlogic_config */
244 
245 /*====================================================================*/
246 
247 static void qlogic_release(struct pcmcia_device *link)
248 {
249 	scsi_info_t *info = link->priv;
250 
251 	dev_dbg(&link->dev, "qlogic_release\n");
252 
253 	scsi_remove_host(info->host);
254 
255 	free_irq(link->irq, info->host);
256 	pcmcia_disable_device(link);
257 
258 	scsi_host_put(info->host);
259 }
260 
261 /*====================================================================*/
262 
263 static int qlogic_resume(struct pcmcia_device *link)
264 {
265 	scsi_info_t *info = link->priv;
266 
267 	pcmcia_request_configuration(link, &link->conf);
268 	if ((info->manf_id == MANFID_MACNICA) ||
269 	    (info->manf_id == MANFID_PIONEER) ||
270 	    (info->manf_id == 0x0098)) {
271 		outb(0x80, link->resource[0]->start + 0xd);
272 		outb(0x24, link->resource[0]->start + 0x9);
273 		outb(0x04, link->resource[0]->start + 0xd);
274 	}
275 	/* Ugggglllyyyy!!! */
276 	qlogicfas408_bus_reset(NULL);
277 
278 	return 0;
279 }
280 
281 static struct pcmcia_device_id qlogic_ids[] = {
282 	PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6),
283 	PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751),
284 	PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d),
285 	PCMCIA_DEVICE_PROD_ID12("MIDORI ELECTRONICS ", "CN-SC43", 0x6534382a, 0xd67eee79),
286 	PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J03R", 0x18df0ba0, 0x24662e8a),
287 	PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC003", 0x82375a27, 0xf68e5bf7),
288 	PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC004", 0x82375a27, 0x68eace54),
289 	PCMCIA_DEVICE_PROD_ID12("KME", "KXLC101", 0x3faee676, 0x194250ec),
290 	PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05", 0xd77b2930, 0xa85b2735),
291 	PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05 rev 1.10", 0xd77b2930, 0x70f8b5f8),
292 	PCMCIA_DEVICE_PROD_ID123("KME", "KXLC002", "00", 0x3faee676, 0x81896b61, 0xf99f065f),
293 	PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "SCSI2 CARD 37", 0x85c10e17, 0x1a2640c1),
294 	PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200A PC CARD SCSI", 0xb4585a1a, 0xa6f06ebe),
295 	PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200B PC CARD SCSI-10", 0xb4585a1a, 0x0a88dea0),
296 	/* these conflict with other cards! */
297 	/* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
298 	/* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
299 	PCMCIA_DEVICE_NULL,
300 };
301 MODULE_DEVICE_TABLE(pcmcia, qlogic_ids);
302 
303 static struct pcmcia_driver qlogic_cs_driver = {
304 	.owner		= THIS_MODULE,
305 	.drv		= {
306 	.name		= "qlogic_cs",
307 	},
308 	.probe		= qlogic_probe,
309 	.remove		= qlogic_detach,
310 	.id_table       = qlogic_ids,
311 	.resume		= qlogic_resume,
312 };
313 
314 static int __init init_qlogic_cs(void)
315 {
316 	return pcmcia_register_driver(&qlogic_cs_driver);
317 }
318 
319 static void __exit exit_qlogic_cs(void)
320 {
321 	pcmcia_unregister_driver(&qlogic_cs_driver);
322 }
323 
324 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
325 MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers");
326 MODULE_LICENSE("GPL");
327 module_init(init_qlogic_cs);
328 module_exit(exit_qlogic_cs);
329