2 * linux/drivers/acorn/scsi/eesox.c
4 * Copyright (C) 1997-2000 Russell King
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * This driver is based on experimentation. Hence, it may have made
11 * assumptions about the particular card that I have available, and
12 * may not be reliable!
15 * 01-10-1997 RMK Created, READONLY version
16 * 15-02-1998 RMK READ/WRITE version
17 * added DMA support and hardware definitions
18 * 14-03-1998 RMK Updated DMA support
19 * Added terminator control
20 * 15-04-1998 RMK Only do PIO if FAS216 will allow it.
21 * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h
22 * 02-04-2000 RMK 0.0.3 Fixed NO_IRQ/NO_DMA problem, updated for new
23 * error handling code.
25 #include <linux/module.h>
26 #include <linux/blk.h>
27 #include <linux/kernel.h>
28 #include <linux/string.h>
29 #include <linux/ioport.h>
30 #include <linux/sched.h>
31 #include <linux/proc_fs.h>
32 #include <linux/unistd.h>
33 #include <linux/stat.h>
34 #include <linux/delay.h>
35 #include <linux/pci.h>
36 #include <linux/init.h>
41 #include <asm/ecard.h>
42 #include <asm/pgtable.h>
44 #include "../../scsi/sd.h"
45 #include "../../scsi/hosts.h"
48 #include <scsi/scsicam.h>
51 #define EESOX_XTALFREQ 40
52 #define EESOX_ASYNC_PERIOD 200
53 #define EESOX_SYNC_DEPTH 7
56 * List of devices that the driver will recognise
58 #define EESOXSCSI_LIST { MANU_EESOX, PROD_EESOX_SCSI2 }
60 #define EESOX_FAS216_OFFSET 0xc00
61 #define EESOX_FAS216_SHIFT 3
63 #define EESOX_STATUS 0xa00
64 #define EESOX_STAT_INTR 0x01
65 #define EESOX_STAT_DMA 0x02
67 #define EESOX_CONTROL 0xa00
68 #define EESOX_INTR_ENABLE 0x04
69 #define EESOX_TERM_ENABLE 0x02
70 #define EESOX_RESET 0x01
72 #define EESOX_DMA_OFFSET 0xe00
81 static struct expansion_card *ecs[MAX_ECARDS];
84 * Use term=0,1,0,0,0 to turn terminators on/off
86 static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
98 struct control control;
100 unsigned int dmaarea; /* Pseudo DMA area */
101 struct scatterlist sg[NR_SG]; /* Scatter DMA list */
104 /* Prototype: void eesoxscsi_irqenable(ec, irqnr)
105 * Purpose : Enable interrupts on EESOX SCSI card
106 * Params : ec - expansion card structure
107 * : irqnr - interrupt number
110 eesoxscsi_irqenable(struct expansion_card *ec, int irqnr)
112 struct control *control = (struct control *)ec->irq_data;
114 control->control |= EESOX_INTR_ENABLE;
116 outb(control->control, control->io_port);
119 /* Prototype: void eesoxscsi_irqdisable(ec, irqnr)
120 * Purpose : Disable interrupts on EESOX SCSI card
121 * Params : ec - expansion card structure
122 * : irqnr - interrupt number
125 eesoxscsi_irqdisable(struct expansion_card *ec, int irqnr)
127 struct control *control = (struct control *)ec->irq_data;
129 control->control &= ~EESOX_INTR_ENABLE;
131 outb(control->control, control->io_port);
134 static const expansioncard_ops_t eesoxscsi_ops = {
136 eesoxscsi_irqdisable,
143 /* Prototype: void eesoxscsi_terminator_ctl(*host, on_off)
144 * Purpose : Turn the EESOX SCSI terminators on or off
145 * Params : host - card to turn on/off
146 * : on_off - !0 to turn on, 0 to turn off
149 eesoxscsi_terminator_ctl(struct Scsi_Host *host, int on_off)
151 EESOXScsi_Info *info = (EESOXScsi_Info *)host->hostdata;
154 save_flags_cli(flags);
156 info->control.control |= EESOX_TERM_ENABLE;
158 info->control.control &= ~EESOX_TERM_ENABLE;
159 restore_flags(flags);
161 outb(info->control.control, info->control.io_port);
164 /* Prototype: void eesoxscsi_intr(irq, *dev_id, *regs)
165 * Purpose : handle interrupts from EESOX SCSI card
166 * Params : irq - interrupt number
167 * dev_id - user-defined (Scsi_Host structure)
168 * regs - processor registers at interrupt
171 eesoxscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
173 struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
178 /* Prototype: fasdmatype_t eesoxscsi_dma_setup(host, SCpnt, direction, min_type)
179 * Purpose : initialises DMA/PIO
180 * Params : host - host
182 * direction - DMA on to/off of card
183 * min_type - minimum DMA support that we must have for this transfer
184 * Returns : type of transfer to be performed
187 eesoxscsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
188 fasdmadir_t direction, fasdmatype_t min_type)
190 EESOXScsi_Info *info = (EESOXScsi_Info *)host->hostdata;
191 int dmach = host->dma_channel;
193 if (dmach != NO_DMA &&
194 (min_type == fasdma_real_all || SCp->this_residual >= 512)) {
195 int bufs = SCp->buffers_residual;
196 int pci_dir, dma_dir;
199 memcpy(info->sg + 1, SCp->buffer + 1,
200 sizeof(struct scatterlist) * bufs);
201 info->sg[0].address = SCp->ptr;
202 info->sg[0].page = NULL;
203 info->sg[0].length = SCp->this_residual;
205 if (direction == DMA_OUT)
206 pci_dir = PCI_DMA_TODEVICE,
207 dma_dir = DMA_MODE_WRITE;
209 pci_dir = PCI_DMA_FROMDEVICE,
210 dma_dir = DMA_MODE_READ;
212 pci_map_sg(NULL, info->sg, bufs + 1, pci_dir);
215 set_dma_sg(dmach, info->sg, bufs + 1);
216 set_dma_mode(dmach, dma_dir);
218 return fasdma_real_all;
221 * We don't do DMA, we only do slow PIO
223 * Some day, we will do Pseudo DMA
225 return fasdma_pseudo;
229 eesoxscsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
230 fasdmadir_t dir, int transfer_size)
232 EESOXScsi_Info *info = (EESOXScsi_Info *)host->hostdata;
234 unsigned int length = SCp->this_residual;
243 status = inb(host->io_port + EESOX_STATUS);
246 if (status & EESOX_STAT_DMA) {
247 unsigned long l1, l2;
249 l1 = inw(info->dmaarea);
250 l1 |= inw(info->dmaarea) << 16;
251 l2 = inw(info->dmaarea);
252 l2 |= inw(info->dmaarea) << 16;
256 } else if (status & EESOX_STAT_INTR)
258 status = inb(host->io_port + EESOX_STATUS);
262 if (status & EESOX_STAT_DMA) {
263 *buffer.s++ = inw(info->dmaarea);
265 } else if (status & EESOX_STAT_INTR)
267 status = inb(host->io_port + EESOX_STATUS);
271 if (status & EESOX_STAT_DMA) {
272 *buffer.c++ = inw(info->dmaarea);
274 } else if (status & EESOX_STAT_INTR)
276 status = inb(host->io_port + EESOX_STATUS);
280 if (status & EESOX_STAT_DMA) {
281 unsigned long l1, l2;
286 outw(l1, info->dmaarea);
287 outw(l1 >> 16, info->dmaarea);
288 outw(l2, info->dmaarea);
289 outw(l2 >> 16, info->dmaarea);
291 } else if (status & EESOX_STAT_INTR)
293 status = inb(host->io_port + EESOX_STATUS);
297 if (status & EESOX_STAT_DMA) {
298 outw(*buffer.s++, info->dmaarea);
300 } else if (status & EESOX_STAT_INTR)
302 status = inb(host->io_port + EESOX_STATUS);
306 if (status & EESOX_STAT_DMA) {
307 outw(*buffer.c++, info->dmaarea);
309 } else if (status & EESOX_STAT_INTR)
311 status = inb(host->io_port + EESOX_STATUS);
317 /* Prototype: int eesoxscsi_dma_stop(host, SCpnt)
318 * Purpose : stops DMA/PIO
319 * Params : host - host
323 eesoxscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
325 if (host->dma_channel != NO_DMA)
326 disable_dma(host->dma_channel);
329 /* Prototype: int eesoxscsi_detect(Scsi_Host_Template * tpnt)
330 * Purpose : initialises EESOX SCSI driver
331 * Params : tpnt - template for this SCSI adapter
332 * Returns : >0 if host found, 0 otherwise.
335 eesoxscsi_detect(Scsi_Host_Template *tpnt)
337 static const card_ids eesoxscsi_cids[] =
338 { EESOXSCSI_LIST, { 0xffff, 0xffff} };
340 struct Scsi_Host *host;
342 tpnt->proc_name = "eesox";
343 memset(ecs, 0, sizeof (ecs));
348 EESOXScsi_Info *info;
350 ecs[count] = ecard_find(0, eesoxscsi_cids);
354 ecard_claim(ecs[count]);
356 host = scsi_register(tpnt, sizeof (EESOXScsi_Info));
358 ecard_release(ecs[count]);
362 host->io_port = ecard_address(ecs[count], ECARD_IOC, ECARD_FAST);
363 host->irq = ecs[count]->irq;
364 host->dma_channel = ecs[count]->dma;
365 info = (EESOXScsi_Info *)host->hostdata;
367 info->control.io_port = host->io_port + EESOX_CONTROL;
368 info->control.control = term[count] ? EESOX_TERM_ENABLE : 0;
369 outb(info->control.control, info->control.io_port);
371 ecs[count]->irqaddr = (unsigned char *)
372 ioaddr(host->io_port + EESOX_STATUS);
373 ecs[count]->irqmask = EESOX_STAT_INTR;
374 ecs[count]->irq_data = &info->control;
375 ecs[count]->ops = (expansioncard_ops_t *)&eesoxscsi_ops;
377 info->info.scsi.io_port = host->io_port + EESOX_FAS216_OFFSET;
378 info->info.scsi.io_shift = EESOX_FAS216_SHIFT;
379 info->info.scsi.irq = host->irq;
380 info->info.ifcfg.clockrate = EESOX_XTALFREQ;
381 info->info.ifcfg.select_timeout = 255;
382 info->info.ifcfg.asyncperiod = EESOX_ASYNC_PERIOD;
383 info->info.ifcfg.sync_max_depth = EESOX_SYNC_DEPTH;
384 info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK;
385 info->info.ifcfg.disconnect_ok = 1;
386 info->info.ifcfg.wide_max_size = 0;
387 info->info.dma.setup = eesoxscsi_dma_setup;
388 info->info.dma.pseudo = eesoxscsi_dma_pseudo;
389 info->info.dma.stop = eesoxscsi_dma_stop;
390 info->dmaarea = host->io_port + EESOX_DMA_OFFSET;
392 request_region(host->io_port + EESOX_FAS216_OFFSET,
393 16 << EESOX_FAS216_SHIFT, "eesox2-fas");
395 if (host->irq != NO_IRQ &&
396 request_irq(host->irq, eesoxscsi_intr,
397 SA_INTERRUPT, "eesox", host)) {
398 printk("scsi%d: IRQ%d not free, interrupts disabled\n",
399 host->host_no, host->irq);
403 if (host->dma_channel != NO_DMA &&
404 request_dma(host->dma_channel, "eesox")) {
405 printk("scsi%d: DMA%d not free, DMA disabled\n",
406 host->host_no, host->dma_channel);
407 host->dma_channel = NO_DMA;
416 /* Prototype: int eesoxscsi_release(struct Scsi_Host * host)
417 * Purpose : releases all resources used by this adapter
418 * Params : host - driver host structure to return info for.
420 int eesoxscsi_release(struct Scsi_Host *host)
424 fas216_release(host);
426 if (host->irq != NO_IRQ)
427 free_irq(host->irq, host);
428 if (host->dma_channel != NO_DMA)
429 free_dma(host->dma_channel);
430 release_region(host->io_port + EESOX_FAS216_OFFSET, 16 << EESOX_FAS216_SHIFT);
432 for (i = 0; i < MAX_ECARDS; i++)
434 host->io_port == ecard_address(ecs[i], ECARD_IOC, ECARD_FAST))
435 ecard_release(ecs[i]);
439 /* Prototype: const char *eesoxscsi_info(struct Scsi_Host * host)
440 * Purpose : returns a descriptive string about this interface,
441 * Params : host - driver host structure to return info for.
442 * Returns : pointer to a static buffer containing null terminated string.
444 const char *eesoxscsi_info(struct Scsi_Host *host)
446 EESOXScsi_Info *info = (EESOXScsi_Info *)host->hostdata;
447 static char string[100], *p;
450 p += sprintf(p, "%s ", host->hostt->name);
451 p += fas216_info(&info->info, p);
452 p += sprintf(p, "v%d.%d.%d terminators o%s",
453 VER_MAJOR, VER_MINOR, VER_PATCH,
454 info->control.control & EESOX_TERM_ENABLE ? "n" : "ff");
459 /* Prototype: int eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
460 * Purpose : Set a driver specific function
461 * Params : host - host to setup
462 * : buffer - buffer containing string describing operation
463 * : length - length of string
464 * Returns : -EINVAL, or 0
467 eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
471 if (length >= 9 && strncmp(buffer, "EESOXSCSI", 9) == 0) {
475 if (length >= 5 && strncmp(buffer, "term=", 5) == 0) {
476 if (buffer[5] == '1')
477 eesoxscsi_terminator_ctl(host, 1);
478 else if (buffer[5] == '0')
479 eesoxscsi_terminator_ctl(host, 0);
490 /* Prototype: int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
491 * int length, int host_no, int inout)
492 * Purpose : Return information about the driver to a user process accessing
493 * the /proc filesystem.
494 * Params : buffer - a buffer to write information to
495 * start - a pointer into this buffer set by this routine to the start
496 * of the required information.
497 * offset - offset into information that we have read upto.
498 * length - length of buffer
499 * host_no - host number to return information for
500 * inout - 0 for reading, 1 for writing.
501 * Returns : length of data written to buffer.
503 int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
504 int length, int host_no, int inout)
507 struct Scsi_Host *host = scsi_hostlist;
508 EESOXScsi_Info *info;
512 if (host->host_no == host_no)
520 return eesoxscsi_set_proc_info(host, buffer, length);
522 info = (EESOXScsi_Info *)host->hostdata;
525 pos = sprintf(buffer,
526 "EESOX SCSI driver version %d.%d.%d\n",
527 VER_MAJOR, VER_MINOR, VER_PATCH);
528 pos += fas216_print_host(&info->info, buffer + pos);
529 pos += sprintf(buffer + pos, "Term : o%s\n",
530 info->control.control & EESOX_TERM_ENABLE ? "n" : "ff");
532 pos += fas216_print_stats(&info->info, buffer + pos);
534 pos += sprintf (buffer+pos, "\nAttached devices:\n");
536 for (scd = host->host_queue; scd; scd = scd->next) {
539 proc_print_scsidevice (scd, buffer, &len, pos);
541 pos += sprintf (buffer+pos, "Extensions: ");
542 if (scd->tagged_supported)
543 pos += sprintf (buffer+pos, "TAG %sabled [%d] ",
544 scd->tagged_queue ? "en" : "dis",
546 pos += sprintf (buffer+pos, "\n");
548 if (pos + begin < offset) {
553 *start = buffer + (offset - begin);
554 pos -= offset - begin;
561 static Scsi_Host_Template eesox_template = {
563 proc_info: eesoxscsi_proc_info,
565 detect: eesoxscsi_detect,
566 release: eesoxscsi_release,
567 info: eesoxscsi_info,
568 bios_param: scsicam_bios_param,
571 sg_tablesize: SG_ALL,
573 use_clustering: DISABLE_CLUSTERING,
574 command: fas216_command,
575 queuecommand: fas216_queue_command,
576 eh_host_reset_handler: fas216_eh_host_reset,
577 eh_bus_reset_handler: fas216_eh_bus_reset,
578 eh_device_reset_handler: fas216_eh_device_reset,
579 eh_abort_handler: fas216_eh_abort,
583 static int __init eesox_init(void)
585 scsi_register_module(MODULE_SCSI_HA, &eesox_template);
586 if (eesox_template.present)
589 scsi_unregister_module(MODULE_SCSI_HA, &eesox_template);
593 static void __exit eesox_exit(void)
595 scsi_unregister_module(MODULE_SCSI_HA, &eesox_template);
598 module_init(eesox_init);
599 module_exit(eesox_exit);
601 MODULE_AUTHOR("Russell King");
602 MODULE_DESCRIPTION("EESOX 'Fast' SCSI driver for Acorn machines");
603 MODULE_PARM(term, "1-8i");
604 MODULE_PARM_DESC(term, "SCSI bus termination");
605 MODULE_LICENSE("GPL");