qlogicfas.c 5.7 KB

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