linux/drivers/scsi/pcmcia/qlogic_stub.c
<<
>>
Prefs
   1/*======================================================================
   2
   3    A driver for the Qlogic SCSI card
   4
   5    qlogic_cs.c 1.79 2000/06/12 21:27:26
   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 which
  23    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/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/* Set the following to 2 to use normal interrupt (active high/totempole-
  56 * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
  57 * drain
  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        .dma_boundary           = PAGE_SIZE - 1,
  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;              /* type of chip */
  94        int qinitid;
  95        struct Scsi_Host *shost;        /* registered host structure */
  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;    /* if no ID, use 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        /* Create new SCSI device */
 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}                               /* qlogic_attach */
 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}                               /* qlogic_detach */
 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                /* set ATAcmd */
 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        /* The KXL-810AN has a bigger IO port window */
 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}                               /* qlogic_config */
 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        int ret;
 258
 259        ret = pcmcia_enable_device(link);
 260        if (ret)
 261                return ret;
 262
 263        if ((info->manf_id == MANFID_MACNICA) ||
 264            (info->manf_id == MANFID_PIONEER) ||
 265            (info->manf_id == 0x0098)) {
 266                outb(0x80, link->resource[0]->start + 0xd);
 267                outb(0x24, link->resource[0]->start + 0x9);
 268                outb(0x04, link->resource[0]->start + 0xd);
 269        }
 270        /* Ugggglllyyyy!!! */
 271        qlogicfas408_host_reset(NULL);
 272
 273        return 0;
 274}
 275
 276static const struct pcmcia_device_id qlogic_ids[] = {
 277        PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6),
 278        PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751),
 279        PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d),
 280        PCMCIA_DEVICE_PROD_ID12("MIDORI ELECTRONICS ", "CN-SC43", 0x6534382a, 0xd67eee79),
 281        PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J03R", 0x18df0ba0, 0x24662e8a),
 282        PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC003", 0x82375a27, 0xf68e5bf7),
 283        PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC004", 0x82375a27, 0x68eace54),
 284        PCMCIA_DEVICE_PROD_ID12("KME", "KXLC101", 0x3faee676, 0x194250ec),
 285        PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05", 0xd77b2930, 0xa85b2735),
 286        PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05 rev 1.10", 0xd77b2930, 0x70f8b5f8),
 287        PCMCIA_DEVICE_PROD_ID123("KME", "KXLC002", "00", 0x3faee676, 0x81896b61, 0xf99f065f),
 288        PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "SCSI2 CARD 37", 0x85c10e17, 0x1a2640c1),
 289        PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200A PC CARD SCSI", 0xb4585a1a, 0xa6f06ebe),
 290        PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200B PC CARD SCSI-10", 0xb4585a1a, 0x0a88dea0),
 291        /* these conflict with other cards! */
 292        /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
 293        /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
 294        PCMCIA_DEVICE_NULL,
 295};
 296MODULE_DEVICE_TABLE(pcmcia, qlogic_ids);
 297
 298static struct pcmcia_driver qlogic_cs_driver = {
 299        .owner          = THIS_MODULE,
 300        .name           = "qlogic_cs",
 301        .probe          = qlogic_probe,
 302        .remove         = qlogic_detach,
 303        .id_table       = qlogic_ids,
 304        .resume         = qlogic_resume,
 305};
 306
 307MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
 308MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers");
 309MODULE_LICENSE("GPL");
 310module_pcmcia_driver(qlogic_cs_driver);
 311