Merge 'acpi-2.6.12' branch into to-akpm
[linux-2.6] / 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/sched.h>
38 #include <linux/slab.h>
39 #include <linux/string.h>
40 #include <linux/ioport.h>
41 #include <asm/io.h>
42 #include <scsi/scsi.h>
43 #include <linux/major.h>
44 #include <linux/blkdev.h>
45 #include <scsi/scsi_ioctl.h>
46 #include <linux/interrupt.h>
47
48 #include "scsi.h"
49 #include <scsi/scsi_host.h>
50 #include "../qlogicfas408.h"
51
52 #include <pcmcia/cs_types.h>
53 #include <pcmcia/cs.h>
54 #include <pcmcia/cistpl.h>
55 #include <pcmcia/ds.h>
56 #include <pcmcia/ciscode.h>
57
58 /* Set the following to 2 to use normal interrupt (active high/totempole-
59  * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
60  * drain
61  */
62 #define INT_TYPE        0
63
64 static char qlogic_name[] = "qlogic_cs";
65
66 #ifdef PCMCIA_DEBUG
67 static int pc_debug = PCMCIA_DEBUG;
68 module_param(pc_debug, int, 0644);
69 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
70 static char *version = "qlogic_cs.c 1.79-ac 2002/10/26 (David Hinds)";
71 #else
72 #define DEBUG(n, args...)
73 #endif
74
75 static Scsi_Host_Template qlogicfas_driver_template = {
76         .module                 = THIS_MODULE,
77         .name                   = qlogic_name,
78         .proc_name              = qlogic_name,
79         .info                   = qlogicfas408_info,
80         .queuecommand           = qlogicfas408_queuecommand,
81         .eh_abort_handler       = qlogicfas408_abort,
82         .eh_bus_reset_handler   = qlogicfas408_bus_reset,
83         .bios_param             = qlogicfas408_biosparam,
84         .can_queue              = 1,
85         .this_id                = -1,
86         .sg_tablesize           = SG_ALL,
87         .cmd_per_lun            = 1,
88         .use_clustering         = DISABLE_CLUSTERING,
89 };
90
91 /*====================================================================*/
92
93 typedef struct scsi_info_t {
94         dev_link_t link;
95         dev_node_t node;
96         struct Scsi_Host *host;
97         unsigned short manf_id;
98 } scsi_info_t;
99
100 static void qlogic_release(dev_link_t *link);
101 static int qlogic_event(event_t event, int priority, event_callback_args_t * args);
102
103 static dev_link_t *qlogic_attach(void);
104 static void qlogic_detach(dev_link_t *);
105
106
107 static dev_link_t *dev_list = NULL;
108
109 static dev_info_t dev_info = "qlogic_cs";
110
111 static struct Scsi_Host *qlogic_detect(Scsi_Host_Template *host,
112                                 dev_link_t *link, int qbase, int qlirq)
113 {
114         int qltyp;              /* type of chip */
115         int qinitid;
116         struct Scsi_Host *shost;        /* registered host structure */
117         struct qlogicfas408_priv *priv;
118
119         qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE);
120         qinitid = host->this_id;
121         if (qinitid < 0)
122                 qinitid = 7;    /* if no ID, use 7 */
123
124         qlogicfas408_setup(qbase, qinitid, INT_TYPE);
125
126         host->name = qlogic_name;
127         shost = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv));
128         if (!shost)
129                 goto err;
130         shost->io_port = qbase;
131         shost->n_io_port = 16;
132         shost->dma_channel = -1;
133         if (qlirq != -1)
134                 shost->irq = qlirq;
135
136         priv = get_priv_by_host(shost);
137         priv->qlirq = qlirq;
138         priv->qbase = qbase;
139         priv->qinitid = qinitid;
140         priv->shost = shost;
141         priv->int_type = INT_TYPE;                                      
142
143         if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogic_name, shost))
144                 goto free_scsi_host;
145
146         sprintf(priv->qinfo,
147                 "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
148                 qltyp, qbase, qlirq, QL_TURBO_PDMA);
149
150         if (scsi_add_host(shost, NULL))
151                 goto free_interrupt;
152
153         scsi_scan_host(shost);
154
155         return shost;
156
157 free_interrupt:
158         free_irq(qlirq, shost);
159
160 free_scsi_host:
161         scsi_host_put(shost);
162         
163 err:
164         return NULL;
165 }
166 static dev_link_t *qlogic_attach(void)
167 {
168         scsi_info_t *info;
169         client_reg_t client_reg;
170         dev_link_t *link;
171         int ret;
172
173         DEBUG(0, "qlogic_attach()\n");
174
175         /* Create new SCSI device */
176         info = kmalloc(sizeof(*info), GFP_KERNEL);
177         if (!info)
178                 return NULL;
179         memset(info, 0, sizeof(*info));
180         link = &info->link;
181         link->priv = info;
182         link->io.NumPorts1 = 16;
183         link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
184         link->io.IOAddrLines = 10;
185         link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
186         link->irq.IRQInfo1 = IRQ_LEVEL_ID;
187         link->conf.Attributes = CONF_ENABLE_IRQ;
188         link->conf.Vcc = 50;
189         link->conf.IntType = INT_MEMORY_AND_IO;
190         link->conf.Present = PRESENT_OPTION;
191
192         /* Register with Card Services */
193         link->next = dev_list;
194         dev_list = link;
195         client_reg.dev_info = &dev_info;
196         client_reg.Version = 0x0210;
197         client_reg.event_callback_args.client_data = link;
198         ret = pcmcia_register_client(&link->handle, &client_reg);
199         if (ret != 0) {
200                 cs_error(link->handle, RegisterClient, ret);
201                 qlogic_detach(link);
202                 return NULL;
203         }
204
205         return link;
206 }                               /* qlogic_attach */
207
208 /*====================================================================*/
209
210 static void qlogic_detach(dev_link_t * link)
211 {
212         dev_link_t **linkp;
213
214         DEBUG(0, "qlogic_detach(0x%p)\n", link);
215
216         /* Locate device structure */
217         for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
218                 if (*linkp == link)
219                         break;
220         if (*linkp == NULL)
221                 return;
222
223         if (link->state & DEV_CONFIG)
224                 qlogic_release(link);
225
226         if (link->handle)
227                 pcmcia_deregister_client(link->handle);
228
229         /* Unlink device structure, free bits */
230         *linkp = link->next;
231         kfree(link->priv);
232
233 }                               /* qlogic_detach */
234
235 /*====================================================================*/
236
237 #define CS_CHECK(fn, ret) \
238 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
239
240 static void qlogic_config(dev_link_t * link)
241 {
242         client_handle_t handle = link->handle;
243         scsi_info_t *info = link->priv;
244         tuple_t tuple;
245         cisparse_t parse;
246         int i, last_ret, last_fn;
247         unsigned short tuple_data[32];
248         struct Scsi_Host *host;
249
250         DEBUG(0, "qlogic_config(0x%p)\n", link);
251
252         tuple.TupleData = (cisdata_t *) tuple_data;
253         tuple.TupleDataMax = 64;
254         tuple.TupleOffset = 0;
255         tuple.DesiredTuple = CISTPL_CONFIG;
256         CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
257         CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
258         CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
259         link->conf.ConfigBase = parse.config.base;
260
261         tuple.DesiredTuple = CISTPL_MANFID;
262         if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) && (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS))
263                 info->manf_id = le16_to_cpu(tuple.TupleData[0]);
264
265         /* Configure card */
266         link->state |= DEV_CONFIG;
267
268         tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
269         CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
270         while (1) {
271                 if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
272                                 pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
273                         goto next_entry;
274                 link->conf.ConfigIndex = parse.cftable_entry.index;
275                 link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
276                 link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
277                 if (link->io.BasePort1 != 0) {
278                         i = pcmcia_request_io(handle, &link->io);
279                         if (i == CS_SUCCESS)
280                                 break;
281                 }
282               next_entry:
283                 CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
284         }
285
286         CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
287         CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
288
289         if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) {
290                 /* set ATAcmd */
291                 outb(0xb4, link->io.BasePort1 + 0xd);
292                 outb(0x24, link->io.BasePort1 + 0x9);
293                 outb(0x04, link->io.BasePort1 + 0xd);
294         }
295
296         /* The KXL-810AN has a bigger IO port window */
297         if (link->io.NumPorts1 == 32)
298                 host = qlogic_detect(&qlogicfas_driver_template, link,
299                         link->io.BasePort1 + 16, link->irq.AssignedIRQ);
300         else
301                 host = qlogic_detect(&qlogicfas_driver_template, link,
302                         link->io.BasePort1, link->irq.AssignedIRQ);
303         
304         if (!host) {
305                 printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name);
306                 goto out;
307         }
308
309         sprintf(info->node.dev_name, "scsi%d", host->host_no);
310         link->dev = &info->node;
311         info->host = host;
312
313 out:
314         link->state &= ~DEV_CONFIG_PENDING;
315         return;
316
317 cs_failed:
318         cs_error(link->handle, last_fn, last_ret);
319         link->dev = NULL;
320         pcmcia_release_configuration(link->handle);
321         pcmcia_release_io(link->handle, &link->io);
322         pcmcia_release_irq(link->handle, &link->irq);
323         link->state &= ~DEV_CONFIG;
324         return;
325
326 }                               /* qlogic_config */
327
328 /*====================================================================*/
329
330 static void qlogic_release(dev_link_t *link)
331 {
332         scsi_info_t *info = link->priv;
333
334         DEBUG(0, "qlogic_release(0x%p)\n", link);
335
336         scsi_remove_host(info->host);
337         link->dev = NULL;
338
339         free_irq(link->irq.AssignedIRQ, info->host);
340
341         pcmcia_release_configuration(link->handle);
342         pcmcia_release_io(link->handle, &link->io);
343         pcmcia_release_irq(link->handle, &link->irq);
344
345         scsi_host_put(info->host);
346
347         link->state &= ~DEV_CONFIG;
348 }
349
350 /*====================================================================*/
351
352 static int qlogic_event(event_t event, int priority, event_callback_args_t * args)
353 {
354         dev_link_t *link = args->client_data;
355
356         DEBUG(1, "qlogic_event(0x%06x)\n", event);
357
358         switch (event) {
359         case CS_EVENT_CARD_REMOVAL:
360                 link->state &= ~DEV_PRESENT;
361                 if (link->state & DEV_CONFIG)
362                         qlogic_release(link);
363                 break;
364         case CS_EVENT_CARD_INSERTION:
365                 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
366                 qlogic_config(link);
367                 break;
368         case CS_EVENT_PM_SUSPEND:
369                 link->state |= DEV_SUSPEND;
370                 /* Fall through... */
371         case CS_EVENT_RESET_PHYSICAL:
372                 if (link->state & DEV_CONFIG)
373                         pcmcia_release_configuration(link->handle);
374                 break;
375         case CS_EVENT_PM_RESUME:
376                 link->state &= ~DEV_SUSPEND;
377                 /* Fall through... */
378         case CS_EVENT_CARD_RESET:
379                 if (link->state & DEV_CONFIG) {
380                         scsi_info_t *info = link->priv;
381                         pcmcia_request_configuration(link->handle, &link->conf);
382                         if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) {
383                                 outb(0x80, link->io.BasePort1 + 0xd);
384                                 outb(0x24, link->io.BasePort1 + 0x9);
385                                 outb(0x04, link->io.BasePort1 + 0xd);
386                         }
387                         /* Ugggglllyyyy!!! */
388                         qlogicfas408_bus_reset(NULL);
389                 }
390                 break;
391         }
392         return 0;
393 }                               /* qlogic_event */
394
395 static struct pcmcia_device_id qlogic_ids[] = {
396         PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6),
397         PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751),
398         PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d),
399         PCMCIA_DEVICE_PROD_ID12("MIDORI ELECTRONICS ", "CN-SC43", 0x6534382a, 0xd67eee79),
400         PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J03R", 0x18df0ba0, 0x24662e8a),
401         PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC003", 0x82375a27, 0xf68e5bf7),
402         PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC004", 0x82375a27, 0x68eace54),
403         PCMCIA_DEVICE_PROD_ID12("KME", "KXLC101", 0x3faee676, 0x194250ec),
404         PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05", 0xd77b2930, 0xa85b2735),
405         PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05 rev 1.10", 0xd77b2930, 0x70f8b5f8),
406         PCMCIA_DEVICE_PROD_ID123("KME", "KXLC002", "00", 0x3faee676, 0x81896b61, 0xf99f065f),
407         PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "SCSI2 CARD 37", 0x85c10e17, 0x1a2640c1),
408         PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200A PC CARD SCSI", 0xb4585a1a, 0xa6f06ebe),
409         PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200B PC CARD SCSI-10", 0xb4585a1a, 0x0a88dea0),
410         /* these conflict with other cards! */
411         /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
412         /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
413         PCMCIA_DEVICE_NULL,
414 };
415 MODULE_DEVICE_TABLE(pcmcia, qlogic_ids);
416
417 static struct pcmcia_driver qlogic_cs_driver = {
418         .owner          = THIS_MODULE,
419         .drv            = {
420         .name           = "qlogic_cs",
421         },
422         .attach         = qlogic_attach,
423         .event          = qlogic_event,
424         .detach         = qlogic_detach,
425         .id_table       = qlogic_ids,
426 };
427
428 static int __init init_qlogic_cs(void)
429 {
430         return pcmcia_register_driver(&qlogic_cs_driver);
431 }
432
433 static void __exit exit_qlogic_cs(void)
434 {
435         pcmcia_unregister_driver(&qlogic_cs_driver);
436         BUG_ON(dev_list != NULL);
437 }
438
439 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
440 MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers");
441 MODULE_LICENSE("GPL");
442 module_init(init_qlogic_cs);
443 module_exit(exit_qlogic_cs);