18c2ecf20Sopenharmony_ci/*====================================================================== 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci A driver for the Qlogic SCSI card 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci qlogic_cs.c 1.79 2000/06/12 21:27:26 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci The contents of this file are subject to the Mozilla Public 88c2ecf20Sopenharmony_ci License Version 1.1 (the "License"); you may not use this file 98c2ecf20Sopenharmony_ci except in compliance with the License. You may obtain a copy of 108c2ecf20Sopenharmony_ci the License at http://www.mozilla.org/MPL/ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci Software distributed under the License is distributed on an "AS 138c2ecf20Sopenharmony_ci IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 148c2ecf20Sopenharmony_ci implied. See the License for the specific language governing 158c2ecf20Sopenharmony_ci rights and limitations under the License. 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci The initial developer of the original code is David A. Hinds 188c2ecf20Sopenharmony_ci <dahinds@users.sourceforge.net>. Portions created by David A. Hinds 198c2ecf20Sopenharmony_ci are Copyright (C) 1999 David A. Hinds. All Rights Reserved. 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci Alternatively, the contents of this file may be used under the 228c2ecf20Sopenharmony_ci terms of the GNU General Public License version 2 (the "GPL"), in which 238c2ecf20Sopenharmony_ci case the provisions of the GPL are applicable instead of the 248c2ecf20Sopenharmony_ci above. If you wish to allow the use of your version of this file 258c2ecf20Sopenharmony_ci only under the terms of the GPL and not to allow others to use 268c2ecf20Sopenharmony_ci your version of this file under the MPL, indicate your decision 278c2ecf20Sopenharmony_ci by deleting the provisions above and replace them with the notice 288c2ecf20Sopenharmony_ci and other provisions required by the GPL. If you do not delete 298c2ecf20Sopenharmony_ci the provisions above, a recipient may use your version of this 308c2ecf20Sopenharmony_ci file under either the MPL or the GPL. 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci======================================================================*/ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/module.h> 358c2ecf20Sopenharmony_ci#include <linux/init.h> 368c2ecf20Sopenharmony_ci#include <linux/kernel.h> 378c2ecf20Sopenharmony_ci#include <linux/slab.h> 388c2ecf20Sopenharmony_ci#include <linux/string.h> 398c2ecf20Sopenharmony_ci#include <linux/ioport.h> 408c2ecf20Sopenharmony_ci#include <asm/io.h> 418c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 428c2ecf20Sopenharmony_ci#include <linux/major.h> 438c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 448c2ecf20Sopenharmony_ci#include <scsi/scsi_ioctl.h> 458c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#include "scsi.h" 488c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 498c2ecf20Sopenharmony_ci#include "../qlogicfas408.h" 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#include <pcmcia/cistpl.h> 528c2ecf20Sopenharmony_ci#include <pcmcia/ds.h> 538c2ecf20Sopenharmony_ci#include <pcmcia/ciscode.h> 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* Set the following to 2 to use normal interrupt (active high/totempole- 568c2ecf20Sopenharmony_ci * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open 578c2ecf20Sopenharmony_ci * drain 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci#define INT_TYPE 0 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic char qlogic_name[] = "qlogic_cs"; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic struct scsi_host_template qlogicfas_driver_template = { 648c2ecf20Sopenharmony_ci .module = THIS_MODULE, 658c2ecf20Sopenharmony_ci .name = qlogic_name, 668c2ecf20Sopenharmony_ci .proc_name = qlogic_name, 678c2ecf20Sopenharmony_ci .info = qlogicfas408_info, 688c2ecf20Sopenharmony_ci .queuecommand = qlogicfas408_queuecommand, 698c2ecf20Sopenharmony_ci .eh_abort_handler = qlogicfas408_abort, 708c2ecf20Sopenharmony_ci .eh_host_reset_handler = qlogicfas408_host_reset, 718c2ecf20Sopenharmony_ci .bios_param = qlogicfas408_biosparam, 728c2ecf20Sopenharmony_ci .can_queue = 1, 738c2ecf20Sopenharmony_ci .this_id = -1, 748c2ecf20Sopenharmony_ci .sg_tablesize = SG_ALL, 758c2ecf20Sopenharmony_ci .dma_boundary = PAGE_SIZE - 1, 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/*====================================================================*/ 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_citypedef struct scsi_info_t { 818c2ecf20Sopenharmony_ci struct pcmcia_device *p_dev; 828c2ecf20Sopenharmony_ci struct Scsi_Host *host; 838c2ecf20Sopenharmony_ci unsigned short manf_id; 848c2ecf20Sopenharmony_ci} scsi_info_t; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic void qlogic_release(struct pcmcia_device *link); 878c2ecf20Sopenharmony_cistatic void qlogic_detach(struct pcmcia_device *p_dev); 888c2ecf20Sopenharmony_cistatic int qlogic_config(struct pcmcia_device * link); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic struct Scsi_Host *qlogic_detect(struct scsi_host_template *host, 918c2ecf20Sopenharmony_ci struct pcmcia_device *link, int qbase, int qlirq) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci int qltyp; /* type of chip */ 948c2ecf20Sopenharmony_ci int qinitid; 958c2ecf20Sopenharmony_ci struct Scsi_Host *shost; /* registered host structure */ 968c2ecf20Sopenharmony_ci struct qlogicfas408_priv *priv; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE); 998c2ecf20Sopenharmony_ci qinitid = host->this_id; 1008c2ecf20Sopenharmony_ci if (qinitid < 0) 1018c2ecf20Sopenharmony_ci qinitid = 7; /* if no ID, use 7 */ 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci qlogicfas408_setup(qbase, qinitid, INT_TYPE); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci host->name = qlogic_name; 1068c2ecf20Sopenharmony_ci shost = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv)); 1078c2ecf20Sopenharmony_ci if (!shost) 1088c2ecf20Sopenharmony_ci goto err; 1098c2ecf20Sopenharmony_ci shost->io_port = qbase; 1108c2ecf20Sopenharmony_ci shost->n_io_port = 16; 1118c2ecf20Sopenharmony_ci shost->dma_channel = -1; 1128c2ecf20Sopenharmony_ci if (qlirq != -1) 1138c2ecf20Sopenharmony_ci shost->irq = qlirq; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci priv = get_priv_by_host(shost); 1168c2ecf20Sopenharmony_ci priv->qlirq = qlirq; 1178c2ecf20Sopenharmony_ci priv->qbase = qbase; 1188c2ecf20Sopenharmony_ci priv->qinitid = qinitid; 1198c2ecf20Sopenharmony_ci priv->shost = shost; 1208c2ecf20Sopenharmony_ci priv->int_type = INT_TYPE; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogic_name, shost)) 1238c2ecf20Sopenharmony_ci goto free_scsi_host; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci sprintf(priv->qinfo, 1268c2ecf20Sopenharmony_ci "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d", 1278c2ecf20Sopenharmony_ci qltyp, qbase, qlirq, QL_TURBO_PDMA); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (scsi_add_host(shost, NULL)) 1308c2ecf20Sopenharmony_ci goto free_interrupt; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci scsi_scan_host(shost); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return shost; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cifree_interrupt: 1378c2ecf20Sopenharmony_ci free_irq(qlirq, shost); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cifree_scsi_host: 1408c2ecf20Sopenharmony_ci scsi_host_put(shost); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cierr: 1438c2ecf20Sopenharmony_ci return NULL; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_cistatic int qlogic_probe(struct pcmcia_device *link) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci scsi_info_t *info; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci dev_dbg(&link->dev, "qlogic_attach()\n"); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* Create new SCSI device */ 1528c2ecf20Sopenharmony_ci info = kzalloc(sizeof(*info), GFP_KERNEL); 1538c2ecf20Sopenharmony_ci if (!info) 1548c2ecf20Sopenharmony_ci return -ENOMEM; 1558c2ecf20Sopenharmony_ci info->p_dev = link; 1568c2ecf20Sopenharmony_ci link->priv = info; 1578c2ecf20Sopenharmony_ci link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; 1588c2ecf20Sopenharmony_ci link->config_regs = PRESENT_OPTION; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return qlogic_config(link); 1618c2ecf20Sopenharmony_ci} /* qlogic_attach */ 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/*====================================================================*/ 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void qlogic_detach(struct pcmcia_device *link) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci dev_dbg(&link->dev, "qlogic_detach\n"); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci qlogic_release(link); 1708c2ecf20Sopenharmony_ci kfree(link->priv); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci} /* qlogic_detach */ 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci/*====================================================================*/ 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic int qlogic_config_check(struct pcmcia_device *p_dev, void *priv_data) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci p_dev->io_lines = 10; 1798c2ecf20Sopenharmony_ci p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; 1808c2ecf20Sopenharmony_ci p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (p_dev->resource[0]->start == 0) 1838c2ecf20Sopenharmony_ci return -ENODEV; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return pcmcia_request_io(p_dev); 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int qlogic_config(struct pcmcia_device * link) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci scsi_info_t *info = link->priv; 1918c2ecf20Sopenharmony_ci int ret; 1928c2ecf20Sopenharmony_ci struct Scsi_Host *host; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci dev_dbg(&link->dev, "qlogic_config\n"); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci ret = pcmcia_loop_config(link, qlogic_config_check, NULL); 1978c2ecf20Sopenharmony_ci if (ret) 1988c2ecf20Sopenharmony_ci goto failed; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (!link->irq) 2018c2ecf20Sopenharmony_ci goto failed; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci ret = pcmcia_enable_device(link); 2048c2ecf20Sopenharmony_ci if (ret) 2058c2ecf20Sopenharmony_ci goto failed; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) { 2088c2ecf20Sopenharmony_ci /* set ATAcmd */ 2098c2ecf20Sopenharmony_ci outb(0xb4, link->resource[0]->start + 0xd); 2108c2ecf20Sopenharmony_ci outb(0x24, link->resource[0]->start + 0x9); 2118c2ecf20Sopenharmony_ci outb(0x04, link->resource[0]->start + 0xd); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* The KXL-810AN has a bigger IO port window */ 2158c2ecf20Sopenharmony_ci if (resource_size(link->resource[0]) == 32) 2168c2ecf20Sopenharmony_ci host = qlogic_detect(&qlogicfas_driver_template, link, 2178c2ecf20Sopenharmony_ci link->resource[0]->start + 16, link->irq); 2188c2ecf20Sopenharmony_ci else 2198c2ecf20Sopenharmony_ci host = qlogic_detect(&qlogicfas_driver_template, link, 2208c2ecf20Sopenharmony_ci link->resource[0]->start, link->irq); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (!host) { 2238c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name); 2248c2ecf20Sopenharmony_ci goto failed; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci info->host = host; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return 0; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cifailed: 2328c2ecf20Sopenharmony_ci pcmcia_disable_device(link); 2338c2ecf20Sopenharmony_ci return -ENODEV; 2348c2ecf20Sopenharmony_ci} /* qlogic_config */ 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci/*====================================================================*/ 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic void qlogic_release(struct pcmcia_device *link) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci scsi_info_t *info = link->priv; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci dev_dbg(&link->dev, "qlogic_release\n"); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci scsi_remove_host(info->host); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci free_irq(link->irq, info->host); 2478c2ecf20Sopenharmony_ci pcmcia_disable_device(link); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci scsi_host_put(info->host); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/*====================================================================*/ 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int qlogic_resume(struct pcmcia_device *link) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci scsi_info_t *info = link->priv; 2578c2ecf20Sopenharmony_ci int ret; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci ret = pcmcia_enable_device(link); 2608c2ecf20Sopenharmony_ci if (ret) 2618c2ecf20Sopenharmony_ci return ret; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if ((info->manf_id == MANFID_MACNICA) || 2648c2ecf20Sopenharmony_ci (info->manf_id == MANFID_PIONEER) || 2658c2ecf20Sopenharmony_ci (info->manf_id == 0x0098)) { 2668c2ecf20Sopenharmony_ci outb(0x80, link->resource[0]->start + 0xd); 2678c2ecf20Sopenharmony_ci outb(0x24, link->resource[0]->start + 0x9); 2688c2ecf20Sopenharmony_ci outb(0x04, link->resource[0]->start + 0xd); 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci /* Ugggglllyyyy!!! */ 2718c2ecf20Sopenharmony_ci qlogicfas408_host_reset(NULL); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic const struct pcmcia_device_id qlogic_ids[] = { 2778c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6), 2788c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751), 2798c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d), 2808c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("MIDORI ELECTRONICS ", "CN-SC43", 0x6534382a, 0xd67eee79), 2818c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J03R", 0x18df0ba0, 0x24662e8a), 2828c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC003", 0x82375a27, 0xf68e5bf7), 2838c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC004", 0x82375a27, 0x68eace54), 2848c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("KME", "KXLC101", 0x3faee676, 0x194250ec), 2858c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05", 0xd77b2930, 0xa85b2735), 2868c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05 rev 1.10", 0xd77b2930, 0x70f8b5f8), 2878c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID123("KME", "KXLC002", "00", 0x3faee676, 0x81896b61, 0xf99f065f), 2888c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "SCSI2 CARD 37", 0x85c10e17, 0x1a2640c1), 2898c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200A PC CARD SCSI", 0xb4585a1a, 0xa6f06ebe), 2908c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200B PC CARD SCSI-10", 0xb4585a1a, 0x0a88dea0), 2918c2ecf20Sopenharmony_ci /* these conflict with other cards! */ 2928c2ecf20Sopenharmony_ci /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */ 2938c2ecf20Sopenharmony_ci /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */ 2948c2ecf20Sopenharmony_ci PCMCIA_DEVICE_NULL, 2958c2ecf20Sopenharmony_ci}; 2968c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pcmcia, qlogic_ids); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic struct pcmcia_driver qlogic_cs_driver = { 2998c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3008c2ecf20Sopenharmony_ci .name = "qlogic_cs", 3018c2ecf20Sopenharmony_ci .probe = qlogic_probe, 3028c2ecf20Sopenharmony_ci .remove = qlogic_detach, 3038c2ecf20Sopenharmony_ci .id_table = qlogic_ids, 3048c2ecf20Sopenharmony_ci .resume = qlogic_resume, 3058c2ecf20Sopenharmony_ci}; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ciMODULE_AUTHOR("Tom Zerucha, Michael Griffith"); 3088c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers"); 3098c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3108c2ecf20Sopenharmony_cimodule_pcmcia_driver(qlogic_cs_driver); 311