brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · 8f05e37 Raw
230 lines · c
1/*2 * Qlogic FAS408 ISA card driver3 *4 * Copyright 1994, Tom Zerucha.   5 * tz@execpc.com6 * 7 * Redistributable under terms of the GNU General Public License8 *9 * For the avoidance of doubt the "preferred form" of this code is one which10 * is in an open non patent encumbered format. Where cryptographic key signing11 * forms part of the process of creating an executable the information12 * including keys needed to generate an equivalently functional executable13 * 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, open44 * drain45 */46#define INT_TYPE	247 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 itself64	 *	decodes the address - I check 230 first since MIDI cards are65	 *	typically at 0x33066	 *67	 *	Theoretically, two Qlogic cards can coexist in the same system.68	 *	This should work by simply using this as a loadable module for69	 *	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	8141static 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 PCMCIA187 */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 230