1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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/cistpl.h>
52#include <pcmcia/ds.h>
53#include <pcmcia/ciscode.h>
54
55
56
57
58
59#define INT_TYPE 0
60
61static char qlogic_name[] = "qlogic_cs";
62
63static struct scsi_host_template qlogicfas_driver_template = {
64 .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,
71 .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 {
82 struct pcmcia_device *p_dev;
83 struct Scsi_Host *host;
84 unsigned short manf_id;
85} scsi_info_t;
86
87static void qlogic_release(struct pcmcia_device *link);
88static void qlogic_detach(struct pcmcia_device *p_dev);
89static int qlogic_config(struct pcmcia_device * link);
90
91static struct Scsi_Host *qlogic_detect(struct scsi_host_template *host,
92 struct pcmcia_device *link, int qbase, int qlirq)
93{
94 int qltyp;
95 int qinitid;
96 struct Scsi_Host *shost;
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;
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}
146static int qlogic_probe(struct pcmcia_device *link)
147{
148 scsi_info_t *info;
149
150 dev_dbg(&link->dev, "qlogic_attach()\n");
151
152
153 info = kzalloc(sizeof(*info), GFP_KERNEL);
154 if (!info)
155 return -ENOMEM;
156 info->p_dev = link;
157 link->priv = info;
158 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
159 link->config_regs = PRESENT_OPTION;
160
161 return qlogic_config(link);
162}
163
164
165
166static void qlogic_detach(struct pcmcia_device *link)
167{
168 dev_dbg(&link->dev, "qlogic_detach\n");
169
170 qlogic_release(link);
171 kfree(link->priv);
172
173}
174
175
176
177static int qlogic_config_check(struct pcmcia_device *p_dev, void *priv_data)
178{
179 p_dev->io_lines = 10;
180 p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
181 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
182
183 if (p_dev->resource[0]->start == 0)
184 return -ENODEV;
185
186 return pcmcia_request_io(p_dev);
187}
188
189static int qlogic_config(struct pcmcia_device * link)
190{
191 scsi_info_t *info = link->priv;
192 int ret;
193 struct Scsi_Host *host;
194
195 dev_dbg(&link->dev, "qlogic_config\n");
196
197 ret = pcmcia_loop_config(link, qlogic_config_check, NULL);
198 if (ret)
199 goto failed;
200
201 if (!link->irq)
202 goto failed;
203
204 ret = pcmcia_enable_device(link);
205 if (ret)
206 goto failed;
207
208 if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) {
209
210 outb(0xb4, link->resource[0]->start + 0xd);
211 outb(0x24, link->resource[0]->start + 0x9);
212 outb(0x04, link->resource[0]->start + 0xd);
213 }
214
215
216 if (resource_size(link->resource[0]) == 32)
217 host = qlogic_detect(&qlogicfas_driver_template, link,
218 link->resource[0]->start + 16, link->irq);
219 else
220 host = qlogic_detect(&qlogicfas_driver_template, link,
221 link->resource[0]->start, link->irq);
222
223 if (!host) {
224 printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name);
225 goto failed;
226 }
227
228 info->host = host;
229
230 return 0;
231
232failed:
233 pcmcia_disable_device(link);
234 return -ENODEV;
235}
236
237
238
239static void qlogic_release(struct pcmcia_device *link)
240{
241 scsi_info_t *info = link->priv;
242
243 dev_dbg(&link->dev, "qlogic_release\n");
244
245 scsi_remove_host(info->host);
246
247 free_irq(link->irq, info->host);
248 pcmcia_disable_device(link);
249
250 scsi_host_put(info->host);
251}
252
253
254
255static int qlogic_resume(struct pcmcia_device *link)
256{
257 scsi_info_t *info = link->priv;
258
259 pcmcia_enable_device(link);
260 if ((info->manf_id == MANFID_MACNICA) ||
261 (info->manf_id == MANFID_PIONEER) ||
262 (info->manf_id == 0x0098)) {
263 outb(0x80, link->resource[0]->start + 0xd);
264 outb(0x24, link->resource[0]->start + 0x9);
265 outb(0x04, link->resource[0]->start + 0xd);
266 }
267
268 qlogicfas408_bus_reset(NULL);
269
270 return 0;
271}
272
273static const struct pcmcia_device_id qlogic_ids[] = {
274 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
289
290
291 PCMCIA_DEVICE_NULL,
292};
293MODULE_DEVICE_TABLE(pcmcia, qlogic_ids);
294
295static struct pcmcia_driver qlogic_cs_driver = {
296 .owner = THIS_MODULE,
297 .name = "qlogic_cs",
298 .probe = qlogic_probe,
299 .remove = qlogic_detach,
300 .id_table = qlogic_ids,
301 .resume = qlogic_resume,
302};
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);
312}
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);
319