Back to home page

OSCL-LXR

 
 

    


0001 /*======================================================================
0002 
0003     A driver for the Qlogic SCSI card
0004 
0005     qlogic_cs.c 1.79 2000/06/12 21:27:26
0006 
0007     The contents of this file are subject to the Mozilla Public
0008     License Version 1.1 (the "License"); you may not use this file
0009     except in compliance with the License. You may obtain a copy of
0010     the License at http://www.mozilla.org/MPL/
0011 
0012     Software distributed under the License is distributed on an "AS
0013     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
0014     implied. See the License for the specific language governing
0015     rights and limitations under the License.
0016 
0017     The initial developer of the original code is David A. Hinds
0018     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
0019     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
0020 
0021     Alternatively, the contents of this file may be used under the
0022     terms of the GNU General Public License version 2 (the "GPL"), in which
0023     case the provisions of the GPL are applicable instead of the
0024     above.  If you wish to allow the use of your version of this file
0025     only under the terms of the GPL and not to allow others to use
0026     your version of this file under the MPL, indicate your decision
0027     by deleting the provisions above and replace them with the notice
0028     and other provisions required by the GPL.  If you do not delete
0029     the provisions above, a recipient may use your version of this
0030     file under either the MPL or the GPL.
0031     
0032 ======================================================================*/
0033 
0034 #include <linux/module.h>
0035 #include <linux/init.h>
0036 #include <linux/kernel.h>
0037 #include <linux/slab.h>
0038 #include <linux/string.h>
0039 #include <linux/ioport.h>
0040 #include <asm/io.h>
0041 #include <linux/major.h>
0042 #include <linux/blkdev.h>
0043 #include <linux/interrupt.h>
0044 
0045 #include <scsi/scsi.h>
0046 #include <scsi/scsi_cmnd.h>
0047 #include <scsi/scsi_device.h>
0048 #include <scsi/scsi_eh.h>
0049 #include <scsi/scsi_host.h>
0050 #include <scsi/scsi_ioctl.h>
0051 #include <scsi/scsi_tcq.h>
0052 #include "../qlogicfas408.h"
0053 
0054 #include <pcmcia/cistpl.h>
0055 #include <pcmcia/ds.h>
0056 #include <pcmcia/ciscode.h>
0057 
0058 /* Set the following to 2 to use normal interrupt (active high/totempole-
0059  * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
0060  * drain
0061  */
0062 #define INT_TYPE    0
0063 
0064 static char qlogic_name[] = "qlogic_cs";
0065 
0066 static struct scsi_host_template qlogicfas_driver_template = {
0067     .module         = THIS_MODULE,
0068     .name           = qlogic_name,
0069     .proc_name      = qlogic_name,
0070     .info           = qlogicfas408_info,
0071     .queuecommand       = qlogicfas408_queuecommand,
0072     .eh_abort_handler   = qlogicfas408_abort,
0073     .eh_host_reset_handler  = qlogicfas408_host_reset,
0074     .bios_param     = qlogicfas408_biosparam,
0075     .can_queue      = 1,
0076     .this_id        = -1,
0077     .sg_tablesize       = SG_ALL,
0078     .dma_boundary       = PAGE_SIZE - 1,
0079 };
0080 
0081 /*====================================================================*/
0082 
0083 typedef struct scsi_info_t {
0084     struct pcmcia_device    *p_dev;
0085     struct Scsi_Host *host;
0086     unsigned short manf_id;
0087 } scsi_info_t;
0088 
0089 static void qlogic_release(struct pcmcia_device *link);
0090 static void qlogic_detach(struct pcmcia_device *p_dev);
0091 static int qlogic_config(struct pcmcia_device * link);
0092 
0093 static struct Scsi_Host *qlogic_detect(struct scsi_host_template *host,
0094                 struct pcmcia_device *link, int qbase, int qlirq)
0095 {
0096     int qltyp;      /* type of chip */
0097     int qinitid;
0098     struct Scsi_Host *shost;    /* registered host structure */
0099     struct qlogicfas408_priv *priv;
0100 
0101     qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE);
0102     qinitid = host->this_id;
0103     if (qinitid < 0)
0104         qinitid = 7;    /* if no ID, use 7 */
0105 
0106     qlogicfas408_setup(qbase, qinitid, INT_TYPE);
0107 
0108     host->name = qlogic_name;
0109     shost = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv));
0110     if (!shost)
0111         goto err;
0112     shost->io_port = qbase;
0113     shost->n_io_port = 16;
0114     shost->dma_channel = -1;
0115     if (qlirq != -1)
0116         shost->irq = qlirq;
0117 
0118     priv = get_priv_by_host(shost);
0119     priv->qlirq = qlirq;
0120     priv->qbase = qbase;
0121     priv->qinitid = qinitid;
0122     priv->shost = shost;
0123     priv->int_type = INT_TYPE;                  
0124 
0125     if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogic_name, shost))
0126         goto free_scsi_host;
0127 
0128     sprintf(priv->qinfo,
0129         "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
0130         qltyp, qbase, qlirq, QL_TURBO_PDMA);
0131 
0132     if (scsi_add_host(shost, NULL))
0133         goto free_interrupt;
0134 
0135     scsi_scan_host(shost);
0136 
0137     return shost;
0138 
0139 free_interrupt:
0140     free_irq(qlirq, shost);
0141 
0142 free_scsi_host:
0143     scsi_host_put(shost);
0144     
0145 err:
0146     return NULL;
0147 }
0148 static int qlogic_probe(struct pcmcia_device *link)
0149 {
0150     scsi_info_t *info;
0151 
0152     dev_dbg(&link->dev, "qlogic_attach()\n");
0153 
0154     /* Create new SCSI device */
0155     info = kzalloc(sizeof(*info), GFP_KERNEL);
0156     if (!info)
0157         return -ENOMEM;
0158     info->p_dev = link;
0159     link->priv = info;
0160     link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
0161     link->config_regs = PRESENT_OPTION;
0162 
0163     return qlogic_config(link);
0164 }               /* qlogic_attach */
0165 
0166 /*====================================================================*/
0167 
0168 static void qlogic_detach(struct pcmcia_device *link)
0169 {
0170     dev_dbg(&link->dev, "qlogic_detach\n");
0171 
0172     qlogic_release(link);
0173     kfree(link->priv);
0174 
0175 }               /* qlogic_detach */
0176 
0177 /*====================================================================*/
0178 
0179 static int qlogic_config_check(struct pcmcia_device *p_dev, void *priv_data)
0180 {
0181     p_dev->io_lines = 10;
0182     p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
0183     p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
0184 
0185     if (p_dev->resource[0]->start == 0)
0186         return -ENODEV;
0187 
0188     return pcmcia_request_io(p_dev);
0189 }
0190 
0191 static int qlogic_config(struct pcmcia_device * link)
0192 {
0193     scsi_info_t *info = link->priv;
0194     int ret;
0195     struct Scsi_Host *host;
0196 
0197     dev_dbg(&link->dev, "qlogic_config\n");
0198 
0199     ret = pcmcia_loop_config(link, qlogic_config_check, NULL);
0200     if (ret)
0201         goto failed;
0202 
0203     if (!link->irq)
0204         goto failed;
0205 
0206     ret = pcmcia_enable_device(link);
0207     if (ret)
0208         goto failed;
0209 
0210     if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) {
0211         /* set ATAcmd */
0212         outb(0xb4, link->resource[0]->start + 0xd);
0213         outb(0x24, link->resource[0]->start + 0x9);
0214         outb(0x04, link->resource[0]->start + 0xd);
0215     }
0216 
0217     /* The KXL-810AN has a bigger IO port window */
0218     if (resource_size(link->resource[0]) == 32)
0219         host = qlogic_detect(&qlogicfas_driver_template, link,
0220             link->resource[0]->start + 16, link->irq);
0221     else
0222         host = qlogic_detect(&qlogicfas_driver_template, link,
0223             link->resource[0]->start, link->irq);
0224     
0225     if (!host) {
0226         printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name);
0227         goto failed;
0228     }
0229 
0230     info->host = host;
0231 
0232     return 0;
0233 
0234 failed:
0235     pcmcia_disable_device(link);
0236     return -ENODEV;
0237 }               /* qlogic_config */
0238 
0239 /*====================================================================*/
0240 
0241 static void qlogic_release(struct pcmcia_device *link)
0242 {
0243     scsi_info_t *info = link->priv;
0244 
0245     dev_dbg(&link->dev, "qlogic_release\n");
0246 
0247     scsi_remove_host(info->host);
0248 
0249     free_irq(link->irq, info->host);
0250     pcmcia_disable_device(link);
0251 
0252     scsi_host_put(info->host);
0253 }
0254 
0255 /*====================================================================*/
0256 
0257 static int qlogic_resume(struct pcmcia_device *link)
0258 {
0259     scsi_info_t *info = link->priv;
0260     int ret;
0261 
0262     ret = pcmcia_enable_device(link);
0263     if (ret)
0264         return ret;
0265 
0266     if ((info->manf_id == MANFID_MACNICA) ||
0267         (info->manf_id == MANFID_PIONEER) ||
0268         (info->manf_id == 0x0098)) {
0269         outb(0x80, link->resource[0]->start + 0xd);
0270         outb(0x24, link->resource[0]->start + 0x9);
0271         outb(0x04, link->resource[0]->start + 0xd);
0272     }
0273     /* Ugggglllyyyy!!! */
0274     qlogicfas408_host_reset(NULL);
0275 
0276     return 0;
0277 }
0278 
0279 static const struct pcmcia_device_id qlogic_ids[] = {
0280     PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6),
0281     PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751),
0282     PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d),
0283     PCMCIA_DEVICE_PROD_ID12("MIDORI ELECTRONICS ", "CN-SC43", 0x6534382a, 0xd67eee79),
0284     PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J03R", 0x18df0ba0, 0x24662e8a),
0285     PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC003", 0x82375a27, 0xf68e5bf7),
0286     PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC004", 0x82375a27, 0x68eace54),
0287     PCMCIA_DEVICE_PROD_ID12("KME", "KXLC101", 0x3faee676, 0x194250ec),
0288     PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05", 0xd77b2930, 0xa85b2735),
0289     PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05 rev 1.10", 0xd77b2930, 0x70f8b5f8),
0290     PCMCIA_DEVICE_PROD_ID123("KME", "KXLC002", "00", 0x3faee676, 0x81896b61, 0xf99f065f),
0291     PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "SCSI2 CARD 37", 0x85c10e17, 0x1a2640c1),
0292     PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200A PC CARD SCSI", 0xb4585a1a, 0xa6f06ebe),
0293     PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200B PC CARD SCSI-10", 0xb4585a1a, 0x0a88dea0),
0294     /* these conflict with other cards! */
0295     /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
0296     /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
0297     PCMCIA_DEVICE_NULL,
0298 };
0299 MODULE_DEVICE_TABLE(pcmcia, qlogic_ids);
0300 
0301 static struct pcmcia_driver qlogic_cs_driver = {
0302     .owner      = THIS_MODULE,
0303     .name       = "qlogic_cs",
0304     .probe      = qlogic_probe,
0305     .remove     = qlogic_detach,
0306     .id_table       = qlogic_ids,
0307     .resume     = qlogic_resume,
0308 };
0309 
0310 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
0311 MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers");
0312 MODULE_LICENSE("GPL");
0313 module_pcmcia_driver(qlogic_cs_driver);