c3a4428dbcffa321fa48c71cb0290e4d74457cb2
[pandora-kernel.git] / drivers / scsi / pcmcia / qlogic_stub.c
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_types.h>
52 #include <pcmcia/cs.h>
53 #include <pcmcia/cistpl.h>
54 #include <pcmcia/ds.h>
55 #include <pcmcia/ciscode.h>
56
57 /* Set the following to 2 to use normal interrupt (active high/totempole-
58  * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
59  * drain
60  */
61 #define INT_TYPE        0
62
63 static char qlogic_name[] = "qlogic_cs";
64
65 static struct scsi_host_template qlogicfas_driver_template = {
66         .module                 = THIS_MODULE,
67         .name                   = qlogic_name,
68         .proc_name              = qlogic_name,
69         .info                   = qlogicfas408_info,
70         .queuecommand           = qlogicfas408_queuecommand,
71         .eh_abort_handler       = qlogicfas408_abort,
72         .eh_bus_reset_handler   = qlogicfas408_bus_reset,
73         .bios_param             = qlogicfas408_biosparam,
74         .can_queue              = 1,
75         .this_id                = -1,
76         .sg_tablesize           = SG_ALL,
77         .cmd_per_lun            = 1,
78         .use_clustering         = DISABLE_CLUSTERING,
79 };
80
81 /*====================================================================*/
82
83 typedef struct scsi_info_t {
84         struct pcmcia_device    *p_dev;
85         dev_node_t node;
86         struct Scsi_Host *host;
87         unsigned short manf_id;
88 } scsi_info_t;
89
90 static void qlogic_release(struct pcmcia_device *link);
91 static void qlogic_detach(struct pcmcia_device *p_dev);
92 static int qlogic_config(struct pcmcia_device * link);
93
94 static struct Scsi_Host *qlogic_detect(struct scsi_host_template *host,
95                                 struct pcmcia_device *link, int qbase, int qlirq)
96 {
97         int qltyp;              /* type of chip */
98         int qinitid;
99         struct Scsi_Host *shost;        /* registered host structure */
100         struct qlogicfas408_priv *priv;
101
102         qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE);
103         qinitid = host->this_id;
104         if (qinitid < 0)
105                 qinitid = 7;    /* if no ID, use 7 */
106
107         qlogicfas408_setup(qbase, qinitid, INT_TYPE);
108
109         host->name = qlogic_name;
110         shost = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv));
111         if (!shost)
112                 goto err;
113         shost->io_port = qbase;
114         shost->n_io_port = 16;
115         shost->dma_channel = -1;
116         if (qlirq != -1)
117                 shost->irq = qlirq;
118
119         priv = get_priv_by_host(shost);
120         priv->qlirq = qlirq;
121         priv->qbase = qbase;
122         priv->qinitid = qinitid;
123         priv->shost = shost;
124         priv->int_type = INT_TYPE;                                      
125
126         if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogic_name, shost))
127                 goto free_scsi_host;
128
129         sprintf(priv->qinfo,
130                 "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
131                 qltyp, qbase, qlirq, QL_TURBO_PDMA);
132
133         if (scsi_add_host(shost, NULL))
134                 goto free_interrupt;
135
136         scsi_scan_host(shost);
137
138         return shost;
139
140 free_interrupt:
141         free_irq(qlirq, shost);
142
143 free_scsi_host:
144         scsi_host_put(shost);
145         
146 err:
147         return NULL;
148 }
149 static int qlogic_probe(struct pcmcia_device *link)
150 {
151         scsi_info_t *info;
152
153         dev_dbg(&link->dev, "qlogic_attach()\n");
154
155         /* Create new SCSI device */
156         info = kzalloc(sizeof(*info), GFP_KERNEL);
157         if (!info)
158                 return -ENOMEM;
159         info->p_dev = link;
160         link->priv = info;
161         link->io.NumPorts1 = 16;
162         link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
163         link->io.IOAddrLines = 10;
164         link->conf.Attributes = CONF_ENABLE_IRQ;
165         link->conf.IntType = INT_MEMORY_AND_IO;
166         link->conf.Present = PRESENT_OPTION;
167
168         return qlogic_config(link);
169 }                               /* qlogic_attach */
170
171 /*====================================================================*/
172
173 static void qlogic_detach(struct pcmcia_device *link)
174 {
175         dev_dbg(&link->dev, "qlogic_detach\n");
176
177         qlogic_release(link);
178         kfree(link->priv);
179
180 }                               /* qlogic_detach */
181
182 /*====================================================================*/
183
184 static int qlogic_config_check(struct pcmcia_device *p_dev,
185                                cistpl_cftable_entry_t *cfg,
186                                cistpl_cftable_entry_t *dflt,
187                                unsigned int vcc,
188                                void *priv_data)
189 {
190         p_dev->io.BasePort1 = cfg->io.win[0].base;
191         p_dev->io.NumPorts1 = cfg->io.win[0].len;
192
193         if (p_dev->io.BasePort1 == 0)
194                 return -ENODEV;
195
196         return pcmcia_request_io(p_dev, &p_dev->io);
197 }
198
199 static int qlogic_config(struct pcmcia_device * link)
200 {
201         scsi_info_t *info = link->priv;
202         int ret;
203         struct Scsi_Host *host;
204
205         dev_dbg(&link->dev, "qlogic_config\n");
206
207         ret = pcmcia_loop_config(link, qlogic_config_check, NULL);
208         if (ret)
209                 goto failed;
210
211         if (!link->irq)
212                 goto failed;
213
214         ret = pcmcia_request_configuration(link, &link->conf);
215         if (ret)
216                 goto failed;
217
218         if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) {
219                 /* set ATAcmd */
220                 outb(0xb4, link->io.BasePort1 + 0xd);
221                 outb(0x24, link->io.BasePort1 + 0x9);
222                 outb(0x04, link->io.BasePort1 + 0xd);
223         }
224
225         /* The KXL-810AN has a bigger IO port window */
226         if (link->io.NumPorts1 == 32)
227                 host = qlogic_detect(&qlogicfas_driver_template, link,
228                         link->io.BasePort1 + 16, link->irq);
229         else
230                 host = qlogic_detect(&qlogicfas_driver_template, link,
231                         link->io.BasePort1, link->irq);
232         
233         if (!host) {
234                 printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name);
235                 goto failed;
236         }
237
238         sprintf(info->node.dev_name, "scsi%d", host->host_no);
239         link->dev_node = &info->node;
240         info->host = host;
241
242         return 0;
243
244 failed:
245         pcmcia_disable_device(link);
246         return -ENODEV;
247 }                               /* qlogic_config */
248
249 /*====================================================================*/
250
251 static void qlogic_release(struct pcmcia_device *link)
252 {
253         scsi_info_t *info = link->priv;
254
255         dev_dbg(&link->dev, "qlogic_release\n");
256
257         scsi_remove_host(info->host);
258
259         free_irq(link->irq, info->host);
260         pcmcia_disable_device(link);
261
262         scsi_host_put(info->host);
263 }
264
265 /*====================================================================*/
266
267 static int qlogic_resume(struct pcmcia_device *link)
268 {
269         scsi_info_t *info = link->priv;
270
271         pcmcia_request_configuration(link, &link->conf);
272         if ((info->manf_id == MANFID_MACNICA) ||
273             (info->manf_id == MANFID_PIONEER) ||
274             (info->manf_id == 0x0098)) {
275                 outb(0x80, link->io.BasePort1 + 0xd);
276                 outb(0x24, link->io.BasePort1 + 0x9);
277                 outb(0x04, link->io.BasePort1 + 0xd);
278         }
279         /* Ugggglllyyyy!!! */
280         qlogicfas408_bus_reset(NULL);
281
282         return 0;
283 }
284
285 static struct pcmcia_device_id qlogic_ids[] = {
286         PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6),
287         PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751),
288         PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d),
289         PCMCIA_DEVICE_PROD_ID12("MIDORI ELECTRONICS ", "CN-SC43", 0x6534382a, 0xd67eee79),
290         PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J03R", 0x18df0ba0, 0x24662e8a),
291         PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC003", 0x82375a27, 0xf68e5bf7),
292         PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC004", 0x82375a27, 0x68eace54),
293         PCMCIA_DEVICE_PROD_ID12("KME", "KXLC101", 0x3faee676, 0x194250ec),
294         PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05", 0xd77b2930, 0xa85b2735),
295         PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05 rev 1.10", 0xd77b2930, 0x70f8b5f8),
296         PCMCIA_DEVICE_PROD_ID123("KME", "KXLC002", "00", 0x3faee676, 0x81896b61, 0xf99f065f),
297         PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "SCSI2 CARD 37", 0x85c10e17, 0x1a2640c1),
298         PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200A PC CARD SCSI", 0xb4585a1a, 0xa6f06ebe),
299         PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200B PC CARD SCSI-10", 0xb4585a1a, 0x0a88dea0),
300         /* these conflict with other cards! */
301         /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
302         /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
303         PCMCIA_DEVICE_NULL,
304 };
305 MODULE_DEVICE_TABLE(pcmcia, qlogic_ids);
306
307 static struct pcmcia_driver qlogic_cs_driver = {
308         .owner          = THIS_MODULE,
309         .drv            = {
310         .name           = "qlogic_cs",
311         },
312         .probe          = qlogic_probe,
313         .remove         = qlogic_detach,
314         .id_table       = qlogic_ids,
315         .resume         = qlogic_resume,
316 };
317
318 static int __init init_qlogic_cs(void)
319 {
320         return pcmcia_register_driver(&qlogic_cs_driver);
321 }
322
323 static void __exit exit_qlogic_cs(void)
324 {
325         pcmcia_unregister_driver(&qlogic_cs_driver);
326 }
327
328 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
329 MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers");
330 MODULE_LICENSE("GPL");
331 module_init(init_qlogic_cs);
332 module_exit(exit_qlogic_cs);