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