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_host_reset_handler = qlogicfas408_host_reset,
71 .bios_param = qlogicfas408_biosparam,
72 .can_queue = 1,
73 .this_id = -1,
74 .sg_tablesize = SG_ALL,
75 .use_clustering = DISABLE_CLUSTERING,
76};
77
78
79
80typedef struct scsi_info_t {
81 struct pcmcia_device *p_dev;
82 struct Scsi_Host *host;
83 unsigned short manf_id;
84} scsi_info_t;
85
86static void qlogic_release(struct pcmcia_device *link);
87static void qlogic_detach(struct pcmcia_device *p_dev);
88static int qlogic_config(struct pcmcia_device * link);
89
90static struct Scsi_Host *qlogic_detect(struct scsi_host_template *host,
91 struct pcmcia_device *link, int qbase, int qlirq)
92{
93 int qltyp;
94 int qinitid;
95 struct Scsi_Host *shost;
96 struct qlogicfas408_priv *priv;
97
98 qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE);
99 qinitid = host->this_id;
100 if (qinitid < 0)
101 qinitid = 7;
102
103 qlogicfas408_setup(qbase, qinitid, INT_TYPE);
104
105 host->name = qlogic_name;
106 shost = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv));
107 if (!shost)
108 goto err;
109 shost->io_port = qbase;
110 shost->n_io_port = 16;
111 shost->dma_channel = -1;
112 if (qlirq != -1)
113 shost->irq = qlirq;
114
115 priv = get_priv_by_host(shost);
116 priv->qlirq = qlirq;
117 priv->qbase = qbase;
118 priv->qinitid = qinitid;
119 priv->shost = shost;
120 priv->int_type = INT_TYPE;
121
122 if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogic_name, shost))
123 goto free_scsi_host;
124
125 sprintf(priv->qinfo,
126 "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
127 qltyp, qbase, qlirq, QL_TURBO_PDMA);
128
129 if (scsi_add_host(shost, NULL))
130 goto free_interrupt;
131
132 scsi_scan_host(shost);
133
134 return shost;
135
136free_interrupt:
137 free_irq(qlirq, shost);
138
139free_scsi_host:
140 scsi_host_put(shost);
141
142err:
143 return NULL;
144}
145static int qlogic_probe(struct pcmcia_device *link)
146{
147 scsi_info_t *info;
148
149 dev_dbg(&link->dev, "qlogic_attach()\n");
150
151
152 info = kzalloc(sizeof(*info), GFP_KERNEL);
153 if (!info)
154 return -ENOMEM;
155 info->p_dev = link;
156 link->priv = info;
157 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
158 link->config_regs = PRESENT_OPTION;
159
160 return qlogic_config(link);
161}
162
163
164
165static void qlogic_detach(struct pcmcia_device *link)
166{
167 dev_dbg(&link->dev, "qlogic_detach\n");
168
169 qlogic_release(link);
170 kfree(link->priv);
171
172}
173
174
175
176static int qlogic_config_check(struct pcmcia_device *p_dev, void *priv_data)
177{
178 p_dev->io_lines = 10;
179 p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
180 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
181
182 if (p_dev->resource[0]->start == 0)
183 return -ENODEV;
184
185 return pcmcia_request_io(p_dev);
186}
187
188static int qlogic_config(struct pcmcia_device * link)
189{
190 scsi_info_t *info = link->priv;
191 int ret;
192 struct Scsi_Host *host;
193
194 dev_dbg(&link->dev, "qlogic_config\n");
195
196 ret = pcmcia_loop_config(link, qlogic_config_check, NULL);
197 if (ret)
198 goto failed;
199
200 if (!link->irq)
201 goto failed;
202
203 ret = pcmcia_enable_device(link);
204 if (ret)
205 goto failed;
206
207 if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) {
208
209 outb(0xb4, link->resource[0]->start + 0xd);
210 outb(0x24, link->resource[0]->start + 0x9);
211 outb(0x04, link->resource[0]->start + 0xd);
212 }
213
214
215 if (resource_size(link->resource[0]) == 32)
216 host = qlogic_detect(&qlogicfas_driver_template, link,
217 link->resource[0]->start + 16, link->irq);
218 else
219 host = qlogic_detect(&qlogicfas_driver_template, link,
220 link->resource[0]->start, link->irq);
221
222 if (!host) {
223 printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name);
224 goto failed;
225 }
226
227 info->host = host;
228
229 return 0;
230
231failed:
232 pcmcia_disable_device(link);
233 return -ENODEV;
234}
235
236
237
238static void qlogic_release(struct pcmcia_device *link)
239{
240 scsi_info_t *info = link->priv;
241
242 dev_dbg(&link->dev, "qlogic_release\n");
243
244 scsi_remove_host(info->host);
245
246 free_irq(link->irq, info->host);
247 pcmcia_disable_device(link);
248
249 scsi_host_put(info->host);
250}
251
252
253
254static int qlogic_resume(struct pcmcia_device *link)
255{
256 scsi_info_t *info = link->priv;
257
258 pcmcia_enable_device(link);
259 if ((info->manf_id == MANFID_MACNICA) ||
260 (info->manf_id == MANFID_PIONEER) ||
261 (info->manf_id == 0x0098)) {
262 outb(0x80, link->resource[0]->start + 0xd);
263 outb(0x24, link->resource[0]->start + 0x9);
264 outb(0x04, link->resource[0]->start + 0xd);
265 }
266
267 qlogicfas408_host_reset(NULL);
268
269 return 0;
270}
271
272static const struct pcmcia_device_id qlogic_ids[] = {
273 PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6),
274 PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751),
275 PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d),
276 PCMCIA_DEVICE_PROD_ID12("MIDORI ELECTRONICS ", "CN-SC43", 0x6534382a, 0xd67eee79),
277 PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J03R", 0x18df0ba0, 0x24662e8a),
278 PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC003", 0x82375a27, 0xf68e5bf7),
279 PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC004", 0x82375a27, 0x68eace54),
280 PCMCIA_DEVICE_PROD_ID12("KME", "KXLC101", 0x3faee676, 0x194250ec),
281 PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05", 0xd77b2930, 0xa85b2735),
282 PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05 rev 1.10", 0xd77b2930, 0x70f8b5f8),
283 PCMCIA_DEVICE_PROD_ID123("KME", "KXLC002", "00", 0x3faee676, 0x81896b61, 0xf99f065f),
284 PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "SCSI2 CARD 37", 0x85c10e17, 0x1a2640c1),
285 PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200A PC CARD SCSI", 0xb4585a1a, 0xa6f06ebe),
286 PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200B PC CARD SCSI-10", 0xb4585a1a, 0x0a88dea0),
287
288
289
290 PCMCIA_DEVICE_NULL,
291};
292MODULE_DEVICE_TABLE(pcmcia, qlogic_ids);
293
294static struct pcmcia_driver qlogic_cs_driver = {
295 .owner = THIS_MODULE,
296 .name = "qlogic_cs",
297 .probe = qlogic_probe,
298 .remove = qlogic_detach,
299 .id_table = qlogic_ids,
300 .resume = qlogic_resume,
301};
302
303static int __init init_qlogic_cs(void)
304{
305 return pcmcia_register_driver(&qlogic_cs_driver);
306}
307
308static void __exit exit_qlogic_cs(void)
309{
310 pcmcia_unregister_driver(&qlogic_cs_driver);
311}
312
313MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
314MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers");
315MODULE_LICENSE("GPL");
316module_init(init_qlogic_cs);
317module_exit(exit_qlogic_cs);
318