blob: bcaf89fe0c9ed886099925a53d1f2cc27b46f412 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*======================================================================
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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#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
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <pcmcia/cistpl.h>
52#include <pcmcia/ds.h>
53#include <pcmcia/ciscode.h>
54
55/* Set the following to 2 to use normal interrupt (active high/totempole-
56 * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
57 * drain
58 */
59#define INT_TYPE 0
60
61static char qlogic_name[] = "qlogic_cs";
62
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +010063static struct scsi_host_template qlogicfas_driver_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 .module = THIS_MODULE,
65 .name = qlogic_name,
66 .proc_name = qlogic_name,
67 .info = qlogicfas408_info,
68 .queuecommand = qlogicfas408_queuecommand,
69 .eh_abort_handler = qlogicfas408_abort,
70 .eh_bus_reset_handler = qlogicfas408_bus_reset,
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 .bios_param = qlogicfas408_biosparam,
72 .can_queue = 1,
73 .this_id = -1,
74 .sg_tablesize = SG_ALL,
75 .cmd_per_lun = 1,
76 .use_clustering = DISABLE_CLUSTERING,
77};
78
79/*====================================================================*/
80
81typedef struct scsi_info_t {
Dominik Brodowskifd238232006-03-05 10:45:09 +010082 struct pcmcia_device *p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 struct Scsi_Host *host;
84 unsigned short manf_id;
85} scsi_info_t;
86
Dominik Brodowskifba395e2006-03-31 17:21:06 +020087static void qlogic_release(struct pcmcia_device *link);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +010088static void qlogic_detach(struct pcmcia_device *p_dev);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +020089static int qlogic_config(struct pcmcia_device * link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +010091static struct Scsi_Host *qlogic_detect(struct scsi_host_template *host,
Dominik Brodowskifba395e2006-03-31 17:21:06 +020092 struct pcmcia_device *link, int qbase, int qlirq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070093{
94 int qltyp; /* type of chip */
95 int qinitid;
96 struct Scsi_Host *shost; /* registered host structure */
97 struct qlogicfas408_priv *priv;
98
99 qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE);
100 qinitid = host->this_id;
101 if (qinitid < 0)
102 qinitid = 7; /* if no ID, use 7 */
103
104 qlogicfas408_setup(qbase, qinitid, INT_TYPE);
105
106 host->name = qlogic_name;
107 shost = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv));
108 if (!shost)
109 goto err;
110 shost->io_port = qbase;
111 shost->n_io_port = 16;
112 shost->dma_channel = -1;
113 if (qlirq != -1)
114 shost->irq = qlirq;
115
116 priv = get_priv_by_host(shost);
117 priv->qlirq = qlirq;
118 priv->qbase = qbase;
119 priv->qinitid = qinitid;
120 priv->shost = shost;
121 priv->int_type = INT_TYPE;
122
123 if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogic_name, shost))
124 goto free_scsi_host;
125
126 sprintf(priv->qinfo,
127 "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
128 qltyp, qbase, qlirq, QL_TURBO_PDMA);
129
130 if (scsi_add_host(shost, NULL))
131 goto free_interrupt;
132
133 scsi_scan_host(shost);
134
135 return shost;
136
137free_interrupt:
138 free_irq(qlirq, shost);
139
140free_scsi_host:
141 scsi_host_put(shost);
142
143err:
144 return NULL;
145}
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200146static int qlogic_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147{
148 scsi_info_t *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Dominik Brodowski3e716612009-10-24 15:54:14 +0200150 dev_dbg(&link->dev, "qlogic_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
152 /* Create new SCSI device */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700153 info = kzalloc(sizeof(*info), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 if (!info)
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100155 return -ENOMEM;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200156 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 link->priv = info;
Dominik Brodowski00990e72010-07-30 13:13:46 +0200158 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200159 link->config_regs = PRESENT_OPTION;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200161 return qlogic_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162} /* qlogic_attach */
163
164/*====================================================================*/
165
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200166static void qlogic_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167{
Dominik Brodowski3e716612009-10-24 15:54:14 +0200168 dev_dbg(&link->dev, "qlogic_detach\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100170 qlogic_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 kfree(link->priv);
172
173} /* qlogic_detach */
174
175/*====================================================================*/
176
Dominik Brodowski00990e72010-07-30 13:13:46 +0200177static int qlogic_config_check(struct pcmcia_device *p_dev, void *priv_data)
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +0200178{
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200179 p_dev->io_lines = 10;
Dominik Brodowski00990e72010-07-30 13:13:46 +0200180 p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
181 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +0200182
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200183 if (p_dev->resource[0]->start == 0)
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +0200184 return -ENODEV;
185
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200186 return pcmcia_request_io(p_dev);
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +0200187}
188
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200189static int qlogic_config(struct pcmcia_device * link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 scsi_info_t *info = link->priv;
Dominik Brodowski3e716612009-10-24 15:54:14 +0200192 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 struct Scsi_Host *host;
194
Dominik Brodowski3e716612009-10-24 15:54:14 +0200195 dev_dbg(&link->dev, "qlogic_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
Dominik Brodowski3e716612009-10-24 15:54:14 +0200197 ret = pcmcia_loop_config(link, qlogic_config_check, NULL);
198 if (ret)
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +0200199 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
Dominik Brodowskieb141202010-03-07 12:21:16 +0100201 if (!link->irq)
Dominik Brodowski3e716612009-10-24 15:54:14 +0200202 goto failed;
203
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200204 ret = pcmcia_enable_device(link);
Dominik Brodowski3e716612009-10-24 15:54:14 +0200205 if (ret)
206 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
208 if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) {
209 /* set ATAcmd */
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200210 outb(0xb4, link->resource[0]->start + 0xd);
211 outb(0x24, link->resource[0]->start + 0x9);
212 outb(0x04, link->resource[0]->start + 0xd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 }
214
215 /* The KXL-810AN has a bigger IO port window */
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200216 if (resource_size(link->resource[0]) == 32)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 host = qlogic_detect(&qlogicfas_driver_template, link,
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200218 link->resource[0]->start + 16, link->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 else
220 host = qlogic_detect(&qlogicfas_driver_template, link,
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200221 link->resource[0]->start, link->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
223 if (!host) {
224 printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name);
Dominik Brodowski3e716612009-10-24 15:54:14 +0200225 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 }
227
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 info->host = host;
229
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200230 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +0200232failed:
Dominik Brodowski3e716612009-10-24 15:54:14 +0200233 pcmcia_disable_device(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200234 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235} /* qlogic_config */
236
237/*====================================================================*/
238
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200239static void qlogic_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240{
241 scsi_info_t *info = link->priv;
242
Dominik Brodowski3e716612009-10-24 15:54:14 +0200243 dev_dbg(&link->dev, "qlogic_release\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
245 scsi_remove_host(info->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Dominik Brodowskieb141202010-03-07 12:21:16 +0100247 free_irq(link->irq, info->host);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200248 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250 scsi_host_put(info->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251}
252
253/*====================================================================*/
254
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200255static int qlogic_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100256{
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100257 scsi_info_t *info = link->priv;
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100258
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200259 pcmcia_enable_device(link);
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100260 if ((info->manf_id == MANFID_MACNICA) ||
261 (info->manf_id == MANFID_PIONEER) ||
262 (info->manf_id == 0x0098)) {
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200263 outb(0x80, link->resource[0]->start + 0xd);
264 outb(0x24, link->resource[0]->start + 0x9);
265 outb(0x04, link->resource[0]->start + 0xd);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100266 }
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100267 /* Ugggglllyyyy!!! */
268 qlogicfas408_bus_reset(NULL);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100269
270 return 0;
271}
272
Joe Perches25f8f542011-05-03 19:29:01 -0700273static const struct pcmcia_device_id qlogic_ids[] = {
Dominik Brodowski7a5a6ee2005-06-27 16:28:26 -0700274 PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6),
275 PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751),
276 PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d),
277 PCMCIA_DEVICE_PROD_ID12("MIDORI ELECTRONICS ", "CN-SC43", 0x6534382a, 0xd67eee79),
278 PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J03R", 0x18df0ba0, 0x24662e8a),
279 PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC003", 0x82375a27, 0xf68e5bf7),
280 PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC004", 0x82375a27, 0x68eace54),
281 PCMCIA_DEVICE_PROD_ID12("KME", "KXLC101", 0x3faee676, 0x194250ec),
282 PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05", 0xd77b2930, 0xa85b2735),
283 PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05 rev 1.10", 0xd77b2930, 0x70f8b5f8),
284 PCMCIA_DEVICE_PROD_ID123("KME", "KXLC002", "00", 0x3faee676, 0x81896b61, 0xf99f065f),
285 PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "SCSI2 CARD 37", 0x85c10e17, 0x1a2640c1),
286 PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200A PC CARD SCSI", 0xb4585a1a, 0xa6f06ebe),
287 PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200B PC CARD SCSI-10", 0xb4585a1a, 0x0a88dea0),
288 /* these conflict with other cards! */
289 /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
290 /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
291 PCMCIA_DEVICE_NULL,
292};
293MODULE_DEVICE_TABLE(pcmcia, qlogic_ids);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295static struct pcmcia_driver qlogic_cs_driver = {
296 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 .name = "qlogic_cs",
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200298 .probe = qlogic_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100299 .remove = qlogic_detach,
Dominik Brodowski7a5a6ee2005-06-27 16:28:26 -0700300 .id_table = qlogic_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100301 .resume = qlogic_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302};
303
304static int __init init_qlogic_cs(void)
305{
306 return pcmcia_register_driver(&qlogic_cs_driver);
307}
308
309static void __exit exit_qlogic_cs(void)
310{
311 pcmcia_unregister_driver(&qlogic_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312}
313
314MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
315MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers");
316MODULE_LICENSE("GPL");
317module_init(init_qlogic_cs);
318module_exit(exit_qlogic_cs);