Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
qlogic_stub.c
Go to the documentation of this file.
1 /*======================================================================
2 
3  A driver for the Qlogic SCSI card
4 
5  qlogic_cs.c 1.79 2000/06/12 21:27:26
6 
7  The contents of this file are subject to the Mozilla Public
8  License Version 1.1 (the "License"); you may not use this file
9  except in compliance with the License. You may obtain a copy of
10  the License at http://www.mozilla.org/MPL/
11 
12  Software distributed under the License is distributed on an "AS
13  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14  implied. See the License for the specific language governing
15  rights and limitations under the License.
16 
17  The initial developer of the original code is David A. Hinds
18  <[email protected]>. Portions created by David A. Hinds
19  are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
20 
21  Alternatively, the contents of this file may be used under the
22  terms of the GNU General Public License version 2 (the "GPL"), in which
23  case the provisions of the GPL are applicable instead of the
24  above. If you wish to allow the use of your version of this file
25  only under the terms of the GPL and not to allow others to use
26  your version of this file under the MPL, indicate your decision
27  by deleting the provisions above and replace them with the notice
28  and other provisions required by the GPL. If you do not delete
29  the provisions above, a recipient may use your version of this
30  file under either the MPL or the GPL.
31 
32 ======================================================================*/
33 
34 #include <linux/module.h>
35 #include <linux/init.h>
36 #include <linux/kernel.h>
37 #include <linux/slab.h>
38 #include <linux/string.h>
39 #include <linux/ioport.h>
40 #include <asm/io.h>
41 #include <scsi/scsi.h>
42 #include <linux/major.h>
43 #include <linux/blkdev.h>
44 #include <scsi/scsi_ioctl.h>
45 #include <linux/interrupt.h>
46 
47 #include "scsi.h"
48 #include <scsi/scsi_host.h>
49 #include "../qlogicfas408.h"
50 
51 #include <pcmcia/cistpl.h>
52 #include <pcmcia/ds.h>
53 #include <pcmcia/ciscode.h>
54 
55 /* Set the following to 2 to use normal interrupt (active high/totempole-
56  * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
57  * drain
58  */
59 #define INT_TYPE 0
60 
61 static char qlogic_name[] = "qlogic_cs";
62 
63 static struct scsi_host_template qlogicfas_driver_template = {
64  .module = THIS_MODULE,
65  .name = qlogic_name,
66  .proc_name = qlogic_name,
67  .info = qlogicfas408_info,
68  .queuecommand = qlogicfas408_queuecommand,
69  .eh_abort_handler = qlogicfas408_abort,
70  .eh_bus_reset_handler = qlogicfas408_bus_reset,
71  .bios_param = qlogicfas408_biosparam,
72  .can_queue = 1,
73  .this_id = -1,
74  .sg_tablesize = SG_ALL,
75  .cmd_per_lun = 1,
76  .use_clustering = DISABLE_CLUSTERING,
77 };
78 
79 /*====================================================================*/
80 
81 typedef struct scsi_info_t {
82  struct pcmcia_device *p_dev;
83  struct Scsi_Host *host;
84  unsigned short manf_id;
85 } scsi_info_t;
86 
87 static void qlogic_release(struct pcmcia_device *link);
88 static void qlogic_detach(struct pcmcia_device *p_dev);
89 static int qlogic_config(struct pcmcia_device * link);
90 
91 static struct Scsi_Host *qlogic_detect(struct scsi_host_template *host,
92  struct pcmcia_device *link, int qbase, int qlirq)
93 {
94  int qltyp; /* type of chip */
95  int qinitid;
96  struct Scsi_Host *shost; /* registered host structure */
97  struct qlogicfas408_priv *priv;
98 
99  qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE);
100  qinitid = host->this_id;
101  if (qinitid < 0)
102  qinitid = 7; /* if no ID, use 7 */
103 
104  qlogicfas408_setup(qbase, qinitid, INT_TYPE);
105 
106  host->name = qlogic_name;
107  shost = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv));
108  if (!shost)
109  goto err;
110  shost->io_port = qbase;
111  shost->n_io_port = 16;
112  shost->dma_channel = -1;
113  if (qlirq != -1)
114  shost->irq = qlirq;
115 
116  priv = get_priv_by_host(shost);
117  priv->qlirq = qlirq;
118  priv->qbase = qbase;
119  priv->qinitid = qinitid;
120  priv->shost = shost;
121  priv->int_type = INT_TYPE;
122 
123  if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogic_name, shost))
124  goto free_scsi_host;
125 
126  sprintf(priv->qinfo,
127  "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
128  qltyp, qbase, qlirq, QL_TURBO_PDMA);
129 
130  if (scsi_add_host(shost, NULL))
131  goto free_interrupt;
132 
133  scsi_scan_host(shost);
134 
135  return shost;
136 
137 free_interrupt:
138  free_irq(qlirq, shost);
139 
140 free_scsi_host:
141  scsi_host_put(shost);
142 
143 err:
144  return NULL;
145 }
146 static int qlogic_probe(struct pcmcia_device *link)
147 {
148  scsi_info_t *info;
149 
150  dev_dbg(&link->dev, "qlogic_attach()\n");
151 
152  /* Create new SCSI device */
153  info = kzalloc(sizeof(*info), GFP_KERNEL);
154  if (!info)
155  return -ENOMEM;
156  info->p_dev = link;
157  link->priv = info;
158  link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
159  link->config_regs = PRESENT_OPTION;
160 
161  return qlogic_config(link);
162 } /* qlogic_attach */
163 
164 /*====================================================================*/
165 
166 static void qlogic_detach(struct pcmcia_device *link)
167 {
168  dev_dbg(&link->dev, "qlogic_detach\n");
169 
170  qlogic_release(link);
171  kfree(link->priv);
172 
173 } /* qlogic_detach */
174 
175 /*====================================================================*/
176 
177 static int qlogic_config_check(struct pcmcia_device *p_dev, void *priv_data)
178 {
179  p_dev->io_lines = 10;
180  p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
181  p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
182 
183  if (p_dev->resource[0]->start == 0)
184  return -ENODEV;
185 
186  return pcmcia_request_io(p_dev);
187 }
188 
189 static int qlogic_config(struct pcmcia_device * link)
190 {
191  scsi_info_t *info = link->priv;
192  int ret;
193  struct Scsi_Host *host;
194 
195  dev_dbg(&link->dev, "qlogic_config\n");
196 
197  ret = pcmcia_loop_config(link, qlogic_config_check, NULL);
198  if (ret)
199  goto failed;
200 
201  if (!link->irq)
202  goto failed;
203 
204  ret = pcmcia_enable_device(link);
205  if (ret)
206  goto failed;
207 
208  if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) {
209  /* set ATAcmd */
210  outb(0xb4, link->resource[0]->start + 0xd);
211  outb(0x24, link->resource[0]->start + 0x9);
212  outb(0x04, link->resource[0]->start + 0xd);
213  }
214 
215  /* The KXL-810AN has a bigger IO port window */
216  if (resource_size(link->resource[0]) == 32)
217  host = qlogic_detect(&qlogicfas_driver_template, link,
218  link->resource[0]->start + 16, link->irq);
219  else
220  host = qlogic_detect(&qlogicfas_driver_template, link,
221  link->resource[0]->start, link->irq);
222 
223  if (!host) {
224  printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name);
225  goto failed;
226  }
227 
228  info->host = host;
229 
230  return 0;
231 
232 failed:
233  pcmcia_disable_device(link);
234  return -ENODEV;
235 } /* qlogic_config */
236 
237 /*====================================================================*/
238 
239 static void qlogic_release(struct pcmcia_device *link)
240 {
241  scsi_info_t *info = link->priv;
242 
243  dev_dbg(&link->dev, "qlogic_release\n");
244 
245  scsi_remove_host(info->host);
246 
247  free_irq(link->irq, info->host);
248  pcmcia_disable_device(link);
249 
250  scsi_host_put(info->host);
251 }
252 
253 /*====================================================================*/
254 
255 static int qlogic_resume(struct pcmcia_device *link)
256 {
257  scsi_info_t *info = link->priv;
258 
259  pcmcia_enable_device(link);
260  if ((info->manf_id == MANFID_MACNICA) ||
261  (info->manf_id == MANFID_PIONEER) ||
262  (info->manf_id == 0x0098)) {
263  outb(0x80, link->resource[0]->start + 0xd);
264  outb(0x24, link->resource[0]->start + 0x9);
265  outb(0x04, link->resource[0]->start + 0xd);
266  }
267  /* Ugggglllyyyy!!! */
269 
270  return 0;
271 }
272 
273 static const struct pcmcia_device_id qlogic_ids[] = {
274  PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6),
275  PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751),
276  PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d),
277  PCMCIA_DEVICE_PROD_ID12("MIDORI ELECTRONICS ", "CN-SC43", 0x6534382a, 0xd67eee79),
278  PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J03R", 0x18df0ba0, 0x24662e8a),
279  PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC003", 0x82375a27, 0xf68e5bf7),
280  PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC004", 0x82375a27, 0x68eace54),
281  PCMCIA_DEVICE_PROD_ID12("KME", "KXLC101", 0x3faee676, 0x194250ec),
282  PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05", 0xd77b2930, 0xa85b2735),
283  PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05 rev 1.10", 0xd77b2930, 0x70f8b5f8),
284  PCMCIA_DEVICE_PROD_ID123("KME", "KXLC002", "00", 0x3faee676, 0x81896b61, 0xf99f065f),
285  PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "SCSI2 CARD 37", 0x85c10e17, 0x1a2640c1),
286  PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200A PC CARD SCSI", 0xb4585a1a, 0xa6f06ebe),
287  PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200B PC CARD SCSI-10", 0xb4585a1a, 0x0a88dea0),
288  /* these conflict with other cards! */
289  /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
290  /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
291  PCMCIA_DEVICE_NULL,
292 };
293 MODULE_DEVICE_TABLE(pcmcia, qlogic_ids);
294 
295 static struct pcmcia_driver qlogic_cs_driver = {
296  .owner = THIS_MODULE,
297  .name = "qlogic_cs",
298  .probe = qlogic_probe,
299  .remove = qlogic_detach,
300  .id_table = qlogic_ids,
301  .resume = qlogic_resume,
302 };
303 
304 static int __init init_qlogic_cs(void)
305 {
306  return pcmcia_register_driver(&qlogic_cs_driver);
307 }
308 
309 static void __exit exit_qlogic_cs(void)
310 {
311  pcmcia_unregister_driver(&qlogic_cs_driver);
312 }
313 
314 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
315 MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers");
316 MODULE_LICENSE("GPL");
317 module_init(init_qlogic_cs);
318 module_exit(exit_qlogic_cs);