11da177e4SLinus Torvalds /*======================================================================
21da177e4SLinus Torvalds 
31da177e4SLinus Torvalds     A driver for Adaptec AHA152X-compatible PCMCIA SCSI cards.
41da177e4SLinus Torvalds 
51da177e4SLinus Torvalds     This driver supports the Adaptec AHA-1460, the New Media Bus
61da177e4SLinus Torvalds     Toaster, and the New Media Toast & Jam.
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds     aha152x_cs.c 1.54 2000/06/12 21:27:25
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds     The contents of this file are subject to the Mozilla Public
111da177e4SLinus Torvalds     License Version 1.1 (the "License"); you may not use this file
121da177e4SLinus Torvalds     except in compliance with the License. You may obtain a copy of
131da177e4SLinus Torvalds     the License at http://www.mozilla.org/MPL/
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds     Software distributed under the License is distributed on an "AS
161da177e4SLinus Torvalds     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
171da177e4SLinus Torvalds     implied. See the License for the specific language governing
181da177e4SLinus Torvalds     rights and limitations under the License.
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds     The initial developer of the original code is David A. Hinds
211da177e4SLinus Torvalds     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
221da177e4SLinus Torvalds     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds     Alternatively, the contents of this file may be used under the
251da177e4SLinus Torvalds     terms of the GNU General Public License version 2 (the "GPL"), in which
261da177e4SLinus Torvalds     case the provisions of the GPL are applicable instead of the
271da177e4SLinus Torvalds     above.  If you wish to allow the use of your version of this file
281da177e4SLinus Torvalds     only under the terms of the GPL and not to allow others to use
291da177e4SLinus Torvalds     your version of this file under the MPL, indicate your decision
301da177e4SLinus Torvalds     by deleting the provisions above and replace them with the notice
311da177e4SLinus Torvalds     and other provisions required by the GPL.  If you do not delete
321da177e4SLinus Torvalds     the provisions above, a recipient may use your version of this
331da177e4SLinus Torvalds     file under either the MPL or the GPL.
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds ======================================================================*/
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds #include <linux/module.h>
381da177e4SLinus Torvalds #include <linux/init.h>
391da177e4SLinus Torvalds #include <linux/kernel.h>
401da177e4SLinus Torvalds #include <linux/slab.h>
411da177e4SLinus Torvalds #include <linux/string.h>
421da177e4SLinus Torvalds #include <linux/ioport.h>
431da177e4SLinus Torvalds #include <linux/major.h>
441da177e4SLinus Torvalds #include <linux/blkdev.h>
451da177e4SLinus Torvalds 
46*53555fb7SBart Van Assche #include <scsi/scsi.h>
47*53555fb7SBart Van Assche #include <scsi/scsi_cmnd.h>
48*53555fb7SBart Van Assche #include <scsi/scsi_device.h>
49*53555fb7SBart Van Assche #include <scsi/scsi_eh.h>
501da177e4SLinus Torvalds #include <scsi/scsi_host.h>
51*53555fb7SBart Van Assche #include <scsi/scsi_ioctl.h>
52*53555fb7SBart Van Assche #include <scsi/scsi_tcq.h>
531da177e4SLinus Torvalds #include "aha152x.h"
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds #include <pcmcia/cistpl.h>
561da177e4SLinus Torvalds #include <pcmcia/ds.h>
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds /*====================================================================*/
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds /* Parameters that can be set with 'insmod' */
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds /* SCSI bus setup options */
641da177e4SLinus Torvalds static int host_id = 7;
651da177e4SLinus Torvalds static int reconnect = 1;
661da177e4SLinus Torvalds static int parity = 1;
671da177e4SLinus Torvalds static int synchronous = 1;
681da177e4SLinus Torvalds static int reset_delay = 100;
691da177e4SLinus Torvalds static int ext_trans = 0;
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds module_param(host_id, int, 0);
721da177e4SLinus Torvalds module_param(reconnect, int, 0);
731da177e4SLinus Torvalds module_param(parity, int, 0);
741da177e4SLinus Torvalds module_param(synchronous, int, 0);
751da177e4SLinus Torvalds module_param(reset_delay, int, 0);
761da177e4SLinus Torvalds module_param(ext_trans, int, 0);
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds MODULE_LICENSE("Dual MPL/GPL");
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds /*====================================================================*/
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds typedef struct scsi_info_t {
83fd238232SDominik Brodowski 	struct pcmcia_device	*p_dev;
841da177e4SLinus Torvalds     struct Scsi_Host	*host;
851da177e4SLinus Torvalds } scsi_info_t;
861da177e4SLinus Torvalds 
87fba395eeSDominik Brodowski static void aha152x_release_cs(struct pcmcia_device *link);
88cc3b4866SDominik Brodowski static void aha152x_detach(struct pcmcia_device *p_dev);
8915b99ac1SDominik Brodowski static int aha152x_config_cs(struct pcmcia_device *link);
901da177e4SLinus Torvalds 
aha152x_probe(struct pcmcia_device * link)9115b99ac1SDominik Brodowski static int aha152x_probe(struct pcmcia_device *link)
921da177e4SLinus Torvalds {
931da177e4SLinus Torvalds     scsi_info_t *info;
941da177e4SLinus Torvalds 
953e716617SDominik Brodowski     dev_dbg(&link->dev, "aha152x_attach()\n");
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds     /* Create new SCSI device */
98dd00cc48SYoann Padioleau     info = kzalloc(sizeof(*info), GFP_KERNEL);
99f8cfa618SDominik Brodowski     if (!info) return -ENOMEM;
100fba395eeSDominik Brodowski     info->p_dev = link;
101fd238232SDominik Brodowski     link->priv = info;
1021da177e4SLinus Torvalds 
10300990e7cSDominik Brodowski     link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
1047feabb64SDominik Brodowski     link->config_regs = PRESENT_OPTION;
1051da177e4SLinus Torvalds 
10615b99ac1SDominik Brodowski     return aha152x_config_cs(link);
1071da177e4SLinus Torvalds } /* aha152x_attach */
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds /*====================================================================*/
1101da177e4SLinus Torvalds 
aha152x_detach(struct pcmcia_device * link)111fba395eeSDominik Brodowski static void aha152x_detach(struct pcmcia_device *link)
1121da177e4SLinus Torvalds {
1133e716617SDominik Brodowski     dev_dbg(&link->dev, "aha152x_detach\n");
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds     aha152x_release_cs(link);
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds     /* Unlink device structure, free bits */
1181da177e4SLinus Torvalds     kfree(link->priv);
1191da177e4SLinus Torvalds } /* aha152x_detach */
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds /*====================================================================*/
1221da177e4SLinus Torvalds 
aha152x_config_check(struct pcmcia_device * p_dev,void * priv_data)12300990e7cSDominik Brodowski static int aha152x_config_check(struct pcmcia_device *p_dev, void *priv_data)
1240e6f9d27SDominik Brodowski {
12590abdc3bSDominik Brodowski 	p_dev->io_lines = 10;
12600990e7cSDominik Brodowski 
1270e6f9d27SDominik Brodowski 	/* For New Media T&J, look for a SCSI window */
12800990e7cSDominik Brodowski 	if ((p_dev->resource[0]->end < 0x20) &&
12900990e7cSDominik Brodowski 		(p_dev->resource[1]->end >= 0x20))
13000990e7cSDominik Brodowski 		p_dev->resource[0]->start = p_dev->resource[1]->start;
13100990e7cSDominik Brodowski 
13200990e7cSDominik Brodowski 	if (p_dev->resource[0]->start >= 0xffff)
1330e6f9d27SDominik Brodowski 		return -EINVAL;
13400990e7cSDominik Brodowski 
13500990e7cSDominik Brodowski 	p_dev->resource[1]->start = p_dev->resource[1]->end = 0;
13600990e7cSDominik Brodowski 	p_dev->resource[0]->end = 0x20;
13700990e7cSDominik Brodowski 	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
13800990e7cSDominik Brodowski 	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
13900990e7cSDominik Brodowski 
14000990e7cSDominik Brodowski 	return pcmcia_request_io(p_dev);
1410e6f9d27SDominik Brodowski }
1420e6f9d27SDominik Brodowski 
aha152x_config_cs(struct pcmcia_device * link)14315b99ac1SDominik Brodowski static int aha152x_config_cs(struct pcmcia_device *link)
1441da177e4SLinus Torvalds {
1451da177e4SLinus Torvalds     scsi_info_t *info = link->priv;
1461da177e4SLinus Torvalds     struct aha152x_setup s;
1473e716617SDominik Brodowski     int ret;
1481da177e4SLinus Torvalds     struct Scsi_Host *host;
1491da177e4SLinus Torvalds 
1503e716617SDominik Brodowski     dev_dbg(&link->dev, "aha152x_config\n");
1511da177e4SLinus Torvalds 
1523e716617SDominik Brodowski     ret = pcmcia_loop_config(link, aha152x_config_check, NULL);
1533e716617SDominik Brodowski     if (ret)
1540e6f9d27SDominik Brodowski 	    goto failed;
1551da177e4SLinus Torvalds 
156eb14120fSDominik Brodowski     if (!link->irq)
1573e716617SDominik Brodowski 	    goto failed;
1583e716617SDominik Brodowski 
1591ac71e5aSDominik Brodowski     ret = pcmcia_enable_device(link);
1603e716617SDominik Brodowski     if (ret)
1613e716617SDominik Brodowski 	    goto failed;
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds     /* Set configuration options for the aha152x driver */
1641da177e4SLinus Torvalds     memset(&s, 0, sizeof(s));
1651da177e4SLinus Torvalds     s.conf        = "PCMCIA setup";
1669a017a91SDominik Brodowski     s.io_port     = link->resource[0]->start;
167eb14120fSDominik Brodowski     s.irq         = link->irq;
1681da177e4SLinus Torvalds     s.scsiid      = host_id;
1691da177e4SLinus Torvalds     s.reconnect   = reconnect;
1701da177e4SLinus Torvalds     s.parity      = parity;
1711da177e4SLinus Torvalds     s.synchronous = synchronous;
1721da177e4SLinus Torvalds     s.delay       = reset_delay;
1731da177e4SLinus Torvalds     if (ext_trans)
1741da177e4SLinus Torvalds         s.ext_trans = ext_trans;
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds     host = aha152x_probe_one(&s);
1771da177e4SLinus Torvalds     if (host == NULL) {
1781da177e4SLinus Torvalds 	printk(KERN_INFO "aha152x_cs: no SCSI devices found\n");
1793e716617SDominik Brodowski 	goto failed;
1801da177e4SLinus Torvalds     }
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds     info->host = host;
1831da177e4SLinus Torvalds 
18415b99ac1SDominik Brodowski     return 0;
1851da177e4SLinus Torvalds 
1860e6f9d27SDominik Brodowski failed:
1871da177e4SLinus Torvalds     aha152x_release_cs(link);
18815b99ac1SDominik Brodowski     return -ENODEV;
1891da177e4SLinus Torvalds }
1901da177e4SLinus Torvalds 
aha152x_release_cs(struct pcmcia_device * link)191fba395eeSDominik Brodowski static void aha152x_release_cs(struct pcmcia_device *link)
1921da177e4SLinus Torvalds {
1931da177e4SLinus Torvalds 	scsi_info_t *info = link->priv;
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds 	aha152x_release(info->host);
196fba395eeSDominik Brodowski 	pcmcia_disable_device(link);
1971da177e4SLinus Torvalds }
1981da177e4SLinus Torvalds 
aha152x_resume(struct pcmcia_device * link)199fba395eeSDominik Brodowski static int aha152x_resume(struct pcmcia_device *link)
20098e4c28bSDominik Brodowski {
20198e4c28bSDominik Brodowski 	scsi_info_t *info = link->priv;
20298e4c28bSDominik Brodowski 
203e2482fa1SJürgen E. Fischer 	aha152x_host_reset_host(info->host);
20498e4c28bSDominik Brodowski 
20598e4c28bSDominik Brodowski 	return 0;
20698e4c28bSDominik Brodowski }
20798e4c28bSDominik Brodowski 
20825f8f54fSJoe Perches static const struct pcmcia_device_id aha152x_ids[] = {
2092dc27daaSDominik Brodowski 	PCMCIA_DEVICE_PROD_ID123("New Media", "SCSI", "Bus Toaster", 0xcdf7e4cc, 0x35f26476, 0xa8851d6e),
2102dc27daaSDominik Brodowski 	PCMCIA_DEVICE_PROD_ID123("NOTEWORTHY", "SCSI", "Bus Toaster", 0xad89c6e8, 0x35f26476, 0xa8851d6e),
2112dc27daaSDominik Brodowski 	PCMCIA_DEVICE_PROD_ID12("Adaptec, Inc.", "APA-1460 SCSI Host Adapter", 0x24ba9738, 0x3a3c3d20),
2122dc27daaSDominik Brodowski 	PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Multimedia Sound/SCSI", 0x085a850b, 0x80a6535c),
2132dc27daaSDominik Brodowski 	PCMCIA_DEVICE_PROD_ID12("NOTEWORTHY", "NWCOMB02 SCSI/AUDIO COMBO CARD", 0xad89c6e8, 0x5f9a615b),
2142dc27daaSDominik Brodowski 	PCMCIA_DEVICE_NULL,
2152dc27daaSDominik Brodowski };
2162dc27daaSDominik Brodowski MODULE_DEVICE_TABLE(pcmcia, aha152x_ids);
2172dc27daaSDominik Brodowski 
2181da177e4SLinus Torvalds static struct pcmcia_driver aha152x_cs_driver = {
2191da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
2201da177e4SLinus Torvalds 	.name		= "aha152x_cs",
22115b99ac1SDominik Brodowski 	.probe		= aha152x_probe,
222cc3b4866SDominik Brodowski 	.remove		= aha152x_detach,
2232dc27daaSDominik Brodowski 	.id_table       = aha152x_ids,
22498e4c28bSDominik Brodowski 	.resume		= aha152x_resume,
2251da177e4SLinus Torvalds };
226dc245cfaSVaishali Thakkar module_pcmcia_driver(aha152x_cs_driver);
227