1/*======================================================================
2
3    A driver for Adaptec AHA152X-compatible PCMCIA SCSI cards.
4
5    This driver supports the Adaptec AHA-1460, the New Media Bus
6    Toaster, and the New Media Toast & Jam.
7
8    aha152x_cs.c 1.54 2000/06/12 21:27:25
9
10    The contents of this file are subject to the Mozilla Public
11    License Version 1.1 (the "License"); you may not use this file
12    except in compliance with the License. You may obtain a copy of
13    the License at http://www.mozilla.org/MPL/
14
15    Software distributed under the License is distributed on an "AS
16    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
17    implied. See the License for the specific language governing
18    rights and limitations under the License.
19
20    The initial developer of the original code is David A. Hinds
21    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
22    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
23
24    Alternatively, the contents of this file may be used under the
25    terms of the GNU General Public License version 2 (the "GPL"), in which
26    case the provisions of the GPL are applicable instead of the
27    above.  If you wish to allow the use of your version of this file
28    only under the terms of the GPL and not to allow others to use
29    your version of this file under the MPL, indicate your decision
30    by deleting the provisions above and replace them with the notice
31    and other provisions required by the GPL.  If you do not delete
32    the provisions above, a recipient may use your version of this
33    file under either the MPL or the GPL.
34
35======================================================================*/
36
37#include <linux/module.h>
38#include <linux/init.h>
39#include <linux/kernel.h>
40#include <linux/slab.h>
41#include <linux/string.h>
42#include <linux/ioport.h>
43#include <linux/major.h>
44#include <linux/blkdev.h>
45
46#include <scsi/scsi.h>
47#include <scsi/scsi_cmnd.h>
48#include <scsi/scsi_device.h>
49#include <scsi/scsi_eh.h>
50#include <scsi/scsi_host.h>
51#include <scsi/scsi_ioctl.h>
52#include <scsi/scsi_tcq.h>
53#include "aha152x.h"
54
55#include <pcmcia/cistpl.h>
56#include <pcmcia/ds.h>
57
58
59/*====================================================================*/
60
61/* Parameters that can be set with 'insmod' */
62
63/* SCSI bus setup options */
64static int host_id = 7;
65static int reconnect = 1;
66static int parity = 1;
67static int synchronous = 1;
68static int reset_delay = 100;
69static int ext_trans = 0;
70
71module_param(host_id, int, 0);
72module_param(reconnect, int, 0);
73module_param(parity, int, 0);
74module_param(synchronous, int, 0);
75module_param(reset_delay, int, 0);
76module_param(ext_trans, int, 0);
77
78MODULE_LICENSE("Dual MPL/GPL");
79
80/*====================================================================*/
81
82typedef struct scsi_info_t {
83	struct pcmcia_device	*p_dev;
84    struct Scsi_Host	*host;
85} scsi_info_t;
86
87static void aha152x_release_cs(struct pcmcia_device *link);
88static void aha152x_detach(struct pcmcia_device *p_dev);
89static int aha152x_config_cs(struct pcmcia_device *link);
90
91static int aha152x_probe(struct pcmcia_device *link)
92{
93    scsi_info_t *info;
94
95    dev_dbg(&link->dev, "aha152x_attach()\n");
96
97    /* Create new SCSI device */
98    info = kzalloc(sizeof(*info), GFP_KERNEL);
99    if (!info) return -ENOMEM;
100    info->p_dev = link;
101    link->priv = info;
102
103    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
104    link->config_regs = PRESENT_OPTION;
105
106    return aha152x_config_cs(link);
107} /* aha152x_attach */
108
109/*====================================================================*/
110
111static void aha152x_detach(struct pcmcia_device *link)
112{
113    dev_dbg(&link->dev, "aha152x_detach\n");
114
115    aha152x_release_cs(link);
116
117    /* Unlink device structure, free bits */
118    kfree(link->priv);
119} /* aha152x_detach */
120
121/*====================================================================*/
122
123static int aha152x_config_check(struct pcmcia_device *p_dev, void *priv_data)
124{
125	p_dev->io_lines = 10;
126
127	/* For New Media T&J, look for a SCSI window */
128	if ((p_dev->resource[0]->end < 0x20) &&
129		(p_dev->resource[1]->end >= 0x20))
130		p_dev->resource[0]->start = p_dev->resource[1]->start;
131
132	if (p_dev->resource[0]->start >= 0xffff)
133		return -EINVAL;
134
135	p_dev->resource[1]->start = p_dev->resource[1]->end = 0;
136	p_dev->resource[0]->end = 0x20;
137	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
138	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
139
140	return pcmcia_request_io(p_dev);
141}
142
143static int aha152x_config_cs(struct pcmcia_device *link)
144{
145    scsi_info_t *info = link->priv;
146    struct aha152x_setup s;
147    int ret;
148    struct Scsi_Host *host;
149
150    dev_dbg(&link->dev, "aha152x_config\n");
151
152    ret = pcmcia_loop_config(link, aha152x_config_check, NULL);
153    if (ret)
154	    goto failed;
155
156    if (!link->irq)
157	    goto failed;
158
159    ret = pcmcia_enable_device(link);
160    if (ret)
161	    goto failed;
162
163    /* Set configuration options for the aha152x driver */
164    memset(&s, 0, sizeof(s));
165    s.conf        = "PCMCIA setup";
166    s.io_port     = link->resource[0]->start;
167    s.irq         = link->irq;
168    s.scsiid      = host_id;
169    s.reconnect   = reconnect;
170    s.parity      = parity;
171    s.synchronous = synchronous;
172    s.delay       = reset_delay;
173    if (ext_trans)
174        s.ext_trans = ext_trans;
175
176    host = aha152x_probe_one(&s);
177    if (host == NULL) {
178	printk(KERN_INFO "aha152x_cs: no SCSI devices found\n");
179	goto failed;
180    }
181
182    info->host = host;
183
184    return 0;
185
186failed:
187    aha152x_release_cs(link);
188    return -ENODEV;
189}
190
191static void aha152x_release_cs(struct pcmcia_device *link)
192{
193	scsi_info_t *info = link->priv;
194
195	aha152x_release(info->host);
196	pcmcia_disable_device(link);
197}
198
199static int aha152x_resume(struct pcmcia_device *link)
200{
201	scsi_info_t *info = link->priv;
202
203	aha152x_host_reset_host(info->host);
204
205	return 0;
206}
207
208static const struct pcmcia_device_id aha152x_ids[] = {
209	PCMCIA_DEVICE_PROD_ID123("New Media", "SCSI", "Bus Toaster", 0xcdf7e4cc, 0x35f26476, 0xa8851d6e),
210	PCMCIA_DEVICE_PROD_ID123("NOTEWORTHY", "SCSI", "Bus Toaster", 0xad89c6e8, 0x35f26476, 0xa8851d6e),
211	PCMCIA_DEVICE_PROD_ID12("Adaptec, Inc.", "APA-1460 SCSI Host Adapter", 0x24ba9738, 0x3a3c3d20),
212	PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Multimedia Sound/SCSI", 0x085a850b, 0x80a6535c),
213	PCMCIA_DEVICE_PROD_ID12("NOTEWORTHY", "NWCOMB02 SCSI/AUDIO COMBO CARD", 0xad89c6e8, 0x5f9a615b),
214	PCMCIA_DEVICE_NULL,
215};
216MODULE_DEVICE_TABLE(pcmcia, aha152x_ids);
217
218static struct pcmcia_driver aha152x_cs_driver = {
219	.owner		= THIS_MODULE,
220	.name		= "aha152x_cs",
221	.probe		= aha152x_probe,
222	.remove		= aha152x_detach,
223	.id_table       = aha152x_ids,
224	.resume		= aha152x_resume,
225};
226module_pcmcia_driver(aha152x_cs_driver);
227