qlogicfas.c 5.5 KB

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