cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

qlogicfas.c (5791B)


      1/*
      2 * Qlogic FAS408 ISA card driver
      3 *
      4 * Copyright 1994, Tom Zerucha.   
      5 * tz@execpc.com
      6 * 
      7 * Redistributable under terms of the GNU General Public License
      8 *
      9 * For the avoidance of doubt the "preferred form" of this code is one which
     10 * is in an open non patent encumbered format. Where cryptographic key signing
     11 * forms part of the process of creating an executable the information
     12 * including keys needed to generate an equivalently functional executable
     13 * are deemed to be part of the source code.
     14 *
     15 * Check qlogicfas408.c for more credits and info.
     16 */
     17
     18#include <linux/module.h>
     19#include <linux/blkdev.h>		/* to get disk capacity */
     20#include <linux/kernel.h>
     21#include <linux/string.h>
     22#include <linux/init.h>
     23#include <linux/interrupt.h>
     24#include <linux/ioport.h>
     25#include <linux/proc_fs.h>
     26#include <linux/unistd.h>
     27#include <linux/spinlock.h>
     28#include <linux/stat.h>
     29
     30#include <asm/io.h>
     31#include <asm/irq.h>
     32#include <asm/dma.h>
     33
     34#include <scsi/scsi.h>
     35#include <scsi/scsi_cmnd.h>
     36#include <scsi/scsi_device.h>
     37#include <scsi/scsi_eh.h>
     38#include <scsi/scsi_host.h>
     39#include <scsi/scsi_tcq.h>
     40#include "qlogicfas408.h"
     41
     42/* Set the following to 2 to use normal interrupt (active high/totempole-
     43 * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
     44 * drain
     45 */
     46#define INT_TYPE	2
     47
     48static char qlogicfas_name[] = "qlogicfas";
     49
     50/*
     51 *	Look for qlogic card and init if found 
     52 */
     53 
     54static struct Scsi_Host *__qlogicfas_detect(struct scsi_host_template *host,
     55								int qbase,
     56								int qlirq)
     57{
     58	int qltyp;		/* type of chip */
     59	int qinitid;
     60	struct Scsi_Host *hreg;	/* registered host structure */
     61	struct qlogicfas408_priv *priv;
     62
     63	/*	Qlogic Cards only exist at 0x230 or 0x330 (the chip itself
     64	 *	decodes the address - I check 230 first since MIDI cards are
     65	 *	typically at 0x330
     66	 *
     67	 *	Theoretically, two Qlogic cards can coexist in the same system.
     68	 *	This should work by simply using this as a loadable module for
     69	 *	the second card, but I haven't tested this.
     70	 */
     71
     72	if (!qbase || qlirq == -1)
     73		goto err;
     74
     75	if (!request_region(qbase, 0x10, qlogicfas_name)) {
     76		printk(KERN_INFO "%s: address %#x is busy\n", qlogicfas_name,
     77							      qbase);
     78		goto err;
     79	}
     80
     81	if (!qlogicfas408_detect(qbase, INT_TYPE)) {
     82		printk(KERN_WARNING "%s: probe failed for %#x\n",
     83								qlogicfas_name,
     84								qbase);
     85		goto err_release_mem;
     86	}
     87
     88	printk(KERN_INFO "%s: Using preset base address of %03x,"
     89			 " IRQ %d\n", qlogicfas_name, qbase, qlirq);
     90
     91	qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE);
     92	qinitid = host->this_id;
     93	if (qinitid < 0)
     94		qinitid = 7;	/* if no ID, use 7 */
     95
     96	qlogicfas408_setup(qbase, qinitid, INT_TYPE);
     97
     98	hreg = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv));
     99	if (!hreg)
    100		goto err_release_mem;
    101	priv = get_priv_by_host(hreg);
    102	hreg->io_port = qbase;
    103	hreg->n_io_port = 16;
    104	hreg->dma_channel = -1;
    105	if (qlirq != -1)
    106		hreg->irq = qlirq;
    107	priv->qbase = qbase;
    108	priv->qlirq = qlirq;
    109	priv->qinitid = qinitid;
    110	priv->shost = hreg;
    111	priv->int_type = INT_TYPE;
    112
    113	sprintf(priv->qinfo,
    114		"Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
    115		qltyp, qbase, qlirq, QL_TURBO_PDMA);
    116	host->name = qlogicfas_name;
    117
    118	if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogicfas_name, hreg))
    119		goto free_scsi_host;
    120
    121	if (scsi_add_host(hreg, NULL))
    122		goto free_interrupt;
    123
    124	scsi_scan_host(hreg);
    125
    126	return hreg;
    127
    128free_interrupt:
    129	free_irq(qlirq, hreg);
    130
    131free_scsi_host:
    132	scsi_host_put(hreg);
    133
    134err_release_mem:
    135	release_region(qbase, 0x10);
    136err:
    137	return NULL;
    138}
    139
    140#define MAX_QLOGICFAS	8
    141static struct qlogicfas408_priv *cards;
    142static int iobase[MAX_QLOGICFAS];
    143static int irq[MAX_QLOGICFAS] = { [0 ... MAX_QLOGICFAS-1] = -1 };
    144module_param_hw_array(iobase, int, ioport, NULL, 0);
    145module_param_hw_array(irq, int, irq, NULL, 0);
    146MODULE_PARM_DESC(iobase, "I/O address");
    147MODULE_PARM_DESC(irq, "IRQ");
    148
    149static int qlogicfas_detect(struct scsi_host_template *sht)
    150{
    151	struct Scsi_Host *shost;
    152	struct qlogicfas408_priv *priv;
    153	int num;
    154
    155	for (num = 0; num < MAX_QLOGICFAS; num++) {
    156		shost = __qlogicfas_detect(sht, iobase[num], irq[num]);
    157		if (shost == NULL) {
    158			/* no more devices */
    159			break;
    160		}
    161		priv = get_priv_by_host(shost);
    162		priv->next = cards;
    163		cards = priv;
    164	}
    165
    166	return num;
    167}
    168
    169static int qlogicfas_release(struct Scsi_Host *shost)
    170{
    171	struct qlogicfas408_priv *priv = get_priv_by_host(shost);
    172
    173	scsi_remove_host(shost);
    174	if (shost->irq) {
    175		qlogicfas408_disable_ints(priv);	
    176		free_irq(shost->irq, shost);
    177	}
    178	if (shost->io_port && shost->n_io_port)
    179		release_region(shost->io_port, shost->n_io_port);
    180	scsi_host_put(shost);
    181
    182	return 0;
    183}
    184
    185/*
    186 *	The driver template is also needed for PCMCIA
    187 */
    188static struct scsi_host_template qlogicfas_driver_template = {
    189	.module			= THIS_MODULE,
    190	.name			= qlogicfas_name,
    191	.proc_name		= qlogicfas_name,
    192	.info			= qlogicfas408_info,
    193	.queuecommand		= qlogicfas408_queuecommand,
    194	.eh_abort_handler	= qlogicfas408_abort,
    195	.eh_host_reset_handler	= qlogicfas408_host_reset,
    196	.bios_param		= qlogicfas408_biosparam,
    197	.can_queue		= 1,
    198	.this_id		= -1,
    199	.sg_tablesize		= SG_ALL,
    200	.dma_boundary		= PAGE_SIZE - 1,
    201};
    202
    203static __init int qlogicfas_init(void)
    204{
    205	if (!qlogicfas_detect(&qlogicfas_driver_template)) {
    206		/* no cards found */
    207		printk(KERN_INFO "%s: no cards were found, please specify "
    208				 "I/O address and IRQ using iobase= and irq= "
    209				 "options", qlogicfas_name);
    210		return -ENODEV;
    211	}
    212
    213	return 0;
    214}
    215
    216static __exit void qlogicfas_exit(void)
    217{
    218	struct qlogicfas408_priv *priv;
    219
    220	for (priv = cards; priv != NULL; priv = priv->next)
    221		qlogicfas_release(priv->shost);
    222}
    223
    224MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
    225MODULE_DESCRIPTION("Driver for the Qlogic FAS408 based ISA card");
    226MODULE_LICENSE("GPL");
    227module_init(qlogicfas_init);
    228module_exit(qlogicfas_exit);
    229