OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [scsi/] [pcmcia/] [qlogic_stub.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*======================================================================
2
 
3
    A driver for the Qlogic SCSI card
4
 
5
    qlogic_cs.c 1.83 2001/10/13 00:08:53
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
23
    which 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 <asm/byteorder.h>
43
#include <scsi/scsi.h>
44
#include <linux/major.h>
45
#include <linux/blk.h>
46
 
47
#include <../drivers/scsi/scsi.h>
48
#include <../drivers/scsi/hosts.h>
49
#include <scsi/scsi_ioctl.h>
50
 
51
#include <../drivers/scsi/qlogicfas.h>
52
 
53
#define qlogic_reset(h) qlogicfas_reset(h, 0)
54
 
55
#include <pcmcia/version.h>
56
#include <pcmcia/cs_types.h>
57
#include <pcmcia/cs.h>
58
#include <pcmcia/cistpl.h>
59
#include <pcmcia/ds.h>
60
#include <pcmcia/ciscode.h>
61
 
62
extern void qlogicfas_preset(int port, int irq);
63
 
64
/*====================================================================*/
65
 
66
/* Module parameters */
67
 
68
MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
69
MODULE_DESCRIPTION("Qlogic PCMCIA SCSI driver");
70
MODULE_LICENSE("Dual MPL/GPL");
71
 
72
#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
73
 
74
/* Bit map of interrupts to choose from */
75
INT_MODULE_PARM(irq_mask, 0xdeb8);
76
static int irq_list[4] = { -1 };
77
MODULE_PARM(irq_list, "1-4i");
78
 
79
#ifdef PCMCIA_DEBUG
80
INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
81
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
82
static char *version =
83
"qlogic_cs.c 1.83 2001/10/13 00:08:53 (David Hinds)";
84
#else
85
#define DEBUG(n, args...)
86
#endif
87
 
88
/*====================================================================*/
89
 
90
typedef struct scsi_info_t {
91
    dev_link_t          link;
92
    u_short             manf_id;
93
    int                 ndev;
94
    dev_node_t          node[8];
95
} scsi_info_t;
96
 
97
static void qlogic_release(u_long arg);
98
static int qlogic_event(event_t event, int priority,
99
                        event_callback_args_t *args);
100
 
101
static dev_link_t *qlogic_attach(void);
102
static void qlogic_detach(dev_link_t *);
103
 
104
static Scsi_Host_Template driver_template = QLOGICFAS;
105
 
106
static dev_link_t *dev_list = NULL;
107
 
108
static dev_info_t dev_info = "qlogic_cs";
109
 
110
/*====================================================================*/
111
 
112
static void cs_error(client_handle_t handle, int func, int ret)
113
{
114
    error_info_t err = { func, ret };
115
    CardServices(ReportError, handle, &err);
116
}
117
 
118
/*====================================================================*/
119
 
120
static dev_link_t *qlogic_attach(void)
121
{
122
    scsi_info_t *info;
123
    client_reg_t client_reg;
124
    dev_link_t *link;
125
    int i, ret;
126
 
127
    DEBUG(0, "qlogic_attach()\n");
128
 
129
    /* Create new SCSI device */
130
    info = kmalloc(sizeof(*info), GFP_KERNEL);
131
    if (!info) return NULL;
132
    memset(info, 0, sizeof(*info));
133
    link = &info->link; link->priv = info;
134
 
135
    link->io.NumPorts1 = 16;
136
    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
137
    link->io.IOAddrLines = 10;
138
    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
139
    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
140
    if (irq_list[0] == -1)
141
        link->irq.IRQInfo2 = irq_mask;
142
    else
143
        for (i = 0; i < 4; i++)
144
            link->irq.IRQInfo2 |= 1 << irq_list[i];
145
    link->conf.Attributes = CONF_ENABLE_IRQ;
146
    link->conf.Vcc = 50;
147
    link->conf.IntType = INT_MEMORY_AND_IO;
148
    link->conf.Present = PRESENT_OPTION;
149
 
150
    /* Register with Card Services */
151
    link->next = dev_list;
152
    dev_list = link;
153
    client_reg.dev_info = &dev_info;
154
    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
155
    client_reg.event_handler = &qlogic_event;
156
    client_reg.EventMask =
157
        CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
158
        CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
159
        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
160
    client_reg.Version = 0x0210;
161
    client_reg.event_callback_args.client_data = link;
162
    ret = CardServices(RegisterClient, &link->handle, &client_reg);
163
    if (ret != 0) {
164
        cs_error(link->handle, RegisterClient, ret);
165
        qlogic_detach(link);
166
        return NULL;
167
    }
168
 
169
    return link;
170
} /* qlogic_attach */
171
 
172
/*====================================================================*/
173
 
174
static void qlogic_detach(dev_link_t *link)
175
{
176
    dev_link_t **linkp;
177
 
178
    DEBUG(0, "qlogic_detach(0x%p)\n", link);
179
 
180
    /* Locate device structure */
181
    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
182
        if (*linkp == link) break;
183
    if (*linkp == NULL)
184
        return;
185
 
186
    if (link->state & DEV_CONFIG) {
187
        qlogic_release((u_long)link);
188
        if (link->state & DEV_STALE_CONFIG) {
189
            link->state |= DEV_STALE_LINK;
190
            return;
191
        }
192
    }
193
 
194
    if (link->handle)
195
        CardServices(DeregisterClient, link->handle);
196
 
197
    /* Unlink device structure, free bits */
198
    *linkp = link->next;
199
    kfree(link->priv);
200
 
201
} /* qlogic_detach */
202
 
203
/*====================================================================*/
204
 
205
#define CS_CHECK(fn, args...) \
206
while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
207
 
208
#define CFG_CHECK(fn, args...) \
209
if (CardServices(fn, args) != 0) goto next_entry
210
 
211
static void qlogic_config(dev_link_t *link)
212
{
213
    client_handle_t handle = link->handle;
214
    scsi_info_t *info = link->priv;
215
    tuple_t tuple;
216
    cisparse_t parse;
217
    int i, last_ret, last_fn;
218
    u_short tuple_data[32];
219
    Scsi_Device *dev;
220
    dev_node_t **tail, *node;
221
    struct Scsi_Host *host;
222
 
223
    DEBUG(0, "qlogic_config(0x%p)\n", link);
224
 
225
    tuple.TupleData = (cisdata_t *)tuple_data;
226
    tuple.TupleDataMax = 64;
227
    tuple.TupleOffset = 0;
228
    tuple.DesiredTuple = CISTPL_CONFIG;
229
    CS_CHECK(GetFirstTuple, handle, &tuple);
230
    CS_CHECK(GetTupleData, handle, &tuple);
231
    CS_CHECK(ParseTuple, handle, &tuple, &parse);
232
    link->conf.ConfigBase = parse.config.base;
233
 
234
    tuple.DesiredTuple = CISTPL_MANFID;
235
    if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) &&
236
        (CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS))
237
        info->manf_id = le16_to_cpu(tuple.TupleData[0]);
238
 
239
    /* Configure card */
240
    driver_template.module = &__this_module;
241
    link->state |= DEV_CONFIG;
242
 
243
    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
244
    CS_CHECK(GetFirstTuple, handle, &tuple);
245
    while (1) {
246
        CFG_CHECK(GetTupleData, handle, &tuple);
247
        CFG_CHECK(ParseTuple, handle, &tuple, &parse);
248
        link->conf.ConfigIndex = parse.cftable_entry.index;
249
        link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
250
        link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
251
        if (link->io.BasePort1 != 0) {
252
            i = CardServices(RequestIO, handle, &link->io);
253
            if (i == CS_SUCCESS) break;
254
        }
255
    next_entry:
256
        CS_CHECK(GetNextTuple, handle, &tuple);
257
    }
258
 
259
    CS_CHECK(RequestIRQ, handle, &link->irq);
260
    CS_CHECK(RequestConfiguration, handle, &link->conf);
261
 
262
    if ((info->manf_id == MANFID_MACNICA) ||
263
        (info->manf_id == MANFID_PIONEER) ||
264
        (info->manf_id == 0x0098)) {
265
        /* set ATAcmd */
266
        outb(0xb4, link->io.BasePort1+0xd);
267
        outb(0x24, link->io.BasePort1+0x9);
268
        outb(0x04, link->io.BasePort1+0xd);
269
    }
270
 
271
    /* A bad hack... */
272
    release_region(link->io.BasePort1, link->io.NumPorts1);
273
 
274
    /* The KXL-810AN has a bigger IO port window */
275
    if (link->io.NumPorts1 == 32)
276
        qlogicfas_preset(link->io.BasePort1+16, link->irq.AssignedIRQ);
277
    else
278
        qlogicfas_preset(link->io.BasePort1, link->irq.AssignedIRQ);
279
 
280
    scsi_register_module(MODULE_SCSI_HA, &driver_template);
281
 
282
    tail = &link->dev;
283
    info->ndev = 0;
284
    for (host = scsi_hostlist; host; host = host->next)
285
        if (host->hostt == &driver_template)
286
            for (dev = host->host_queue; dev; dev = dev->next) {
287
            u_long arg[2], id;
288
            kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
289
            id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
290
                ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
291
            node = &info->node[info->ndev];
292
            node->minor = 0;
293
            switch (dev->type) {
294
            case TYPE_TAPE:
295
                node->major = SCSI_TAPE_MAJOR;
296
                sprintf(node->dev_name, "st#%04lx", id);
297
                break;
298
            case TYPE_DISK:
299
            case TYPE_MOD:
300
                node->major = SCSI_DISK0_MAJOR;
301
                sprintf(node->dev_name, "sd#%04lx", id);
302
                break;
303
            case TYPE_ROM:
304
            case TYPE_WORM:
305
                node->major = SCSI_CDROM_MAJOR;
306
                sprintf(node->dev_name, "sr#%04lx", id);
307
                break;
308
            default:
309
                node->major = SCSI_GENERIC_MAJOR;
310
                sprintf(node->dev_name, "sg#%04lx", id);
311
                break;
312
            }
313
            *tail = node; tail = &node->next;
314
            info->ndev++;
315
        }
316
    *tail = NULL;
317
    if (info->ndev == 0)
318
        printk(KERN_INFO "qlogic_cs: no SCSI devices found\n");
319
 
320
    link->state &= ~DEV_CONFIG_PENDING;
321
    return;
322
 
323
cs_failed:
324
    cs_error(link->handle, last_fn, last_ret);
325
    qlogic_release((u_long)link);
326
    return;
327
 
328
} /* qlogic_config */
329
 
330
/*====================================================================*/
331
 
332
static void qlogic_release(u_long arg)
333
{
334
    dev_link_t *link = (dev_link_t *)arg;
335
 
336
    DEBUG(0, "qlogic_release(0x%p)\n", link);
337
 
338
    if (GET_USE_COUNT(&__this_module) != 0) {
339
        DEBUG(0, "qlogic_cs: release postponed, device still open\n");
340
        link->state |= DEV_STALE_CONFIG;
341
        return;
342
    }
343
 
344
    scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
345
    link->dev = NULL;
346
 
347
    CardServices(ReleaseConfiguration, link->handle);
348
    CardServices(ReleaseIO, link->handle, &link->io);
349
    CardServices(ReleaseIRQ, link->handle, &link->irq);
350
 
351
    link->state &= ~DEV_CONFIG;
352
    if (link->state & DEV_STALE_LINK)
353
        qlogic_detach(link);
354
 
355
} /* qlogic_release */
356
 
357
/*====================================================================*/
358
 
359
static int qlogic_event(event_t event, int priority,
360
                        event_callback_args_t *args)
361
{
362
    dev_link_t *link = args->client_data;
363
 
364
    DEBUG(1, "qlogic_event(0x%06x)\n", event);
365
 
366
    switch (event) {
367
    case CS_EVENT_CARD_REMOVAL:
368
        link->state &= ~DEV_PRESENT;
369
        if (link->state & DEV_CONFIG)
370
            qlogic_release((u_long)link);
371
        break;
372
    case CS_EVENT_CARD_INSERTION:
373
        link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
374
        qlogic_config(link);
375
        break;
376
    case CS_EVENT_PM_SUSPEND:
377
        link->state |= DEV_SUSPEND;
378
        /* Fall through... */
379
    case CS_EVENT_RESET_PHYSICAL:
380
        if (link->state & DEV_CONFIG)
381
            CardServices(ReleaseConfiguration, link->handle);
382
        break;
383
    case CS_EVENT_PM_RESUME:
384
        link->state &= ~DEV_SUSPEND;
385
        /* Fall through... */
386
    case CS_EVENT_CARD_RESET:
387
        if (link->state & DEV_CONFIG) {
388
            scsi_info_t *info = link->priv;
389
            CardServices(RequestConfiguration, link->handle, &link->conf);
390
            if ((info->manf_id == MANFID_MACNICA) ||
391
                (info->manf_id == MANFID_PIONEER) ||
392
                (info->manf_id == 0x0098)) {
393
                outb( 0x80, link->io.BasePort1+0xd);
394
                outb( 0x24, link->io.BasePort1+0x9);
395
                outb( 0x04, link->io.BasePort1+0xd);
396
            }
397
            qlogic_reset(NULL);
398
        }
399
        break;
400
    }
401
    return 0;
402
} /* qlogic_event */
403
 
404
/*====================================================================*/
405
 
406
static int __init init_qlogic_cs(void) {
407
    servinfo_t serv;
408
    DEBUG(0, "%s\n", version);
409
    CardServices(GetCardServicesInfo, &serv);
410
    if (serv.Revision != CS_RELEASE_CODE) {
411
        printk(KERN_NOTICE "qlogic_cs: Card Services release "
412
               "does not match!\n");
413
        return -1;
414
    }
415
    register_pccard_driver(&dev_info, &qlogic_attach, &qlogic_detach);
416
    return 0;
417
}
418
 
419
static void __exit exit_qlogic_cs(void) {
420
    DEBUG(0, "qlogic_cs: unloading\n");
421
    unregister_pccard_driver(&dev_info);
422
    while (dev_list != NULL)
423
        qlogic_detach(dev_list);
424
}
425
 
426
module_init(init_qlogic_cs);
427
module_exit(exit_qlogic_cs);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.