ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / scsi / pc980155.c
1 /*
2  *
3  *  drivers/scsi/pc980155.c
4  *
5  *  PC-9801-55 SCSI host adapter driver
6  *
7  *  Copyright (C) 1997-2003  Kyoto University Microcomputer Club
8  *                           (Linux/98 project)
9  *                           Tomoharu Ugawa <ohirune@kmc.gr.jp>
10  *
11  */
12
13 #include <linux/module.h>
14 #include <linux/blkdev.h>
15 #include <linux/ioport.h>
16 #include <linux/interrupt.h>
17 #include <linux/types.h>
18 #include <linux/delay.h>
19
20 #include <asm/dma.h>
21
22 #include "scsi.h"
23 #include "hosts.h"
24 #include "wd33c93.h"
25 #include "pc980155.h"
26
27 extern int pc98_bios_param(struct scsi_device *, struct block_device *,
28                                 sector_t, int *);
29 static int scsi_pc980155_detect(Scsi_Host_Template *);
30 static int scsi_pc980155_release(struct Scsi_Host *);
31
32 #ifndef CMD_PER_LUN
33 #define CMD_PER_LUN 2
34 #endif
35
36 #ifndef CAN_QUEUE
37 #define CAN_QUEUE 16
38 #endif
39
40 #undef PC_9801_55_DEBUG
41 #undef PC_9801_55_DEBUG_VERBOSE
42
43 #define NR_BASE_IOS 4
44 static int nr_base_ios = NR_BASE_IOS;
45 static unsigned int base_ios[NR_BASE_IOS] = {0xcc0, 0xcd0, 0xce0, 0xcf0};
46 static wd33c93_regs init_regs;
47 static int io;
48
49 static struct Scsi_Host *pc980155_host = NULL;
50
51 static void pc980155_intr_handle(int irq, void *dev_id, struct pt_regs *regp);
52
53 static inline void pc980155_dma_enable(unsigned int base_io)
54 {
55         outb(0x01, REG_CWRITE);
56 }
57
58 static inline void pc980155_dma_disable(unsigned int base_io)
59 {
60         outb(0x02, REG_CWRITE);
61 }
62
63
64 static void pc980155_intr_handle(int irq, void *dev_id, struct pt_regs *regp)
65 {
66         wd33c93_intr(pc980155_host);
67 }
68
69 static int dma_setup(Scsi_Cmnd *sc, int dir_in)
70 {
71   /*
72    * sc->SCp.this_residual : transfer count
73    * sc->SCp.ptr : distination address (virtual address)
74    * dir_in : data direction (DATA_OUT_DIR:0 or DATA_IN_DIR:1)
75    *
76    * if success return 0
77    */
78
79    /*
80     * DMA WRITE MODE
81     * bit 7,6 01b single mode (this mode only)
82     * bit 5   inc/dec (default:0 = inc)
83     * bit 4   auto initialize (normaly:0 = off)
84     * bit 3,2 01b memory -> io
85     *         10b io -> memory
86     *         00b verify
87     * bit 1,0 channel
88     */
89         disable_dma(sc->device->host->dma_channel);
90         set_dma_mode(sc->device->host->dma_channel,
91                         0x40 | (dir_in ? 0x04 : 0x08));
92         clear_dma_ff(sc->device->host->dma_channel);
93         set_dma_addr(sc->device->host->dma_channel, virt_to_phys(sc->SCp.ptr));
94         set_dma_count(sc->device->host->dma_channel, sc->SCp.this_residual);
95 #ifdef PC_9801_55_DEBUG
96         printk("D%d(%x)D", sc->device->host->dma_channel,
97                 sc->SCp.this_residual);
98 #endif
99         enable_dma(sc->device->host->dma_channel);
100         pc980155_dma_enable(sc->device->host->io_port);
101         return 0;
102 }
103
104 static void dma_stop(struct Scsi_Host *instance, Scsi_Cmnd *sc, int status)
105 {
106   /*
107    * instance: Hostadapter's instance
108    * sc: scsi command
109    * status: True if success
110    */
111         pc980155_dma_disable(sc->device->host->io_port);
112         disable_dma(sc->device->host->dma_channel);
113 }  
114
115 /* return non-zero on detection */
116 static inline int pc980155_test_port(wd33c93_regs regs)
117 {
118         /* Quick and dirty test for presence of the card. */
119         if (inb(regs.SASR) == 0xff)
120                 return 0;
121
122         return 1;
123 }
124
125 static inline int pc980155_getconfig(unsigned int base_io, wd33c93_regs regs,
126                                         unsigned char* irq, unsigned char* dma,
127                                         unsigned char* scsi_id)
128 {
129         static unsigned char irqs[] = {3, 5, 6, 9, 12, 13};
130         unsigned char result;
131   
132         printk(KERN_DEBUG "PC-9801-55: base_io=%x SASR=%x SCMD=%x\n",
133                 base_io, regs.SASR, regs.SCMD);
134         result = read_pc980155_resetint(regs);
135         printk(KERN_DEBUG "PC-9801-55: getting config (%x)\n", result);
136         *scsi_id = result & 0x07;
137         *irq = (result >> 3) & 0x07;
138         if (*irq > 5) {
139                 printk(KERN_ERR "PC-9801-55 (base %#x): impossible IRQ (%d)"
140                         " - other device here?\n", base_io, *irq);
141                 return 0;
142         }
143
144         *irq = irqs[*irq];
145         result = inb(REG_STATRD);
146         *dma = result & 0x03;
147         if (*dma == 1) {
148                 printk(KERN_ERR
149                         "PC-9801-55 (base %#x): impossible DMA channl (%d)"
150                         " - other device here?\n", base_io, *dma);
151                 return 0;
152         }
153 #ifdef PC_9801_55_DEBUG
154         printk("PC-9801-55: end of getconfig\n");
155 #endif
156         return 1;
157 }
158
159 /* return non-zero on detection */
160 static int scsi_pc980155_detect(Scsi_Host_Template* tpnt)
161 {
162         unsigned int base_io;
163         unsigned char irq, dma, scsi_id;
164         int i;
165 #ifdef PC_9801_55_DEBUG
166         unsigned char debug;
167 #endif
168   
169         if (io) {
170                 base_ios[0] = io;
171                 nr_base_ios = 1;
172         }
173
174         for (i = 0; i < nr_base_ios; i++) {
175                 base_io = base_ios[i];
176                 init_regs.SASR = REG_ADDRST;
177                 init_regs.SCMD = REG_CONTRL;
178 #ifdef PC_9801_55_DEBUG
179                 printk("PC-9801-55: SASR(%x = %x)\n", SASR, REG_ADDRST);
180 #endif
181                 if (!request_region(base_io, 6, "PC-9801-55"))
182                         continue;
183
184                 if (pc980155_test_port(init_regs) &&
185                     pc980155_getconfig(base_io, init_regs,
186                                         &irq, &dma, &scsi_id))
187                         goto found;
188
189                 release_region(base_io, 6);
190         }
191
192         printk("PC-9801-55: not found\n");
193         return 0;
194
195         found:
196 #ifdef PC_9801_55_DEBUG
197         printk("PC-9801-55: config: base io = %x, irq = %d, dma channel = %d, scsi id = %d\n", base_io, irq, dma, scsi_id);
198 #endif
199         if (request_irq(irq, pc980155_intr_handle, 0, "PC-9801-55", NULL)) {
200                 printk(KERN_ERR "PC-9801-55: unable to allocate IRQ %d\n", irq);
201                 goto err1;
202         }
203
204         if (request_dma(dma, "PC-9801-55")) {
205                 printk(KERN_ERR "PC-9801-55: unable to allocate DMA channel %d\n", dma);
206                 goto err2;
207         }
208
209         pc980155_host = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
210         if (pc980155_host) {
211                 pc980155_host->this_id = scsi_id;
212                 pc980155_host->io_port = base_io;
213                 pc980155_host->n_io_port = 6;
214                 pc980155_host->irq = irq;
215                 pc980155_host->dma_channel = dma;
216                 printk("PC-9801-55: scsi host found at %x irq = %d, use dma channel %d.\n", base_io, irq, dma);
217                 pc980155_int_enable(init_regs);
218                 wd33c93_init(pc980155_host, init_regs, dma_setup, dma_stop,
219                                 WD33C93_FS_12_15);
220                 return 1;
221         }
222
223         printk(KERN_ERR "PC-9801-55: failed to register device\n");
224
225 err2:
226         free_irq(irq, NULL);
227 err1:
228         release_region(base_io, 6);
229         return 0;
230 }
231
232 static int scsi_pc980155_release(struct Scsi_Host *shost)
233 {
234         struct WD33C93_hostdata *hostdata
235                 = (struct WD33C93_hostdata *)shost->hostdata;
236
237         pc980155_int_disable(hostdata->regs);
238         release_region(shost->io_port, shost->n_io_port);
239         free_irq(shost->irq, NULL);
240         free_dma(shost->dma_channel);
241         wd33c93_release();
242         return 1;
243 }
244
245 static int pc980155_bus_reset(Scsi_Cmnd *cmd)
246 {
247         struct WD33C93_hostdata *hostdata
248                 = (struct WD33C93_hostdata *)cmd->device->host->hostdata;
249
250         pc980155_int_disable(hostdata->regs);
251         pc980155_assert_bus_reset(hostdata->regs);
252         udelay(50);
253         pc980155_negate_bus_reset(hostdata->regs);
254         (void) inb(hostdata->regs.SASR);
255         (void) read_pc980155(hostdata->regs, WD_SCSI_STATUS);
256         pc980155_int_enable(hostdata->regs);
257         wd33c93_host_reset(cmd);
258         return SUCCESS;
259 }
260
261
262 #ifndef MODULE
263 static int __init pc980155_setup(char *str)
264 {
265         int ints[4];
266
267         str = get_options(str, ARRAY_SIZE(ints), ints);
268         if (ints[0] > 0)
269                 io = ints[1];
270         return 1;
271 }
272 __setup("pc980155_io=", pc980155_setup);
273 #endif
274
275 MODULE_PARM(io, "i");
276 MODULE_AUTHOR("Tomoharu Ugawa <ohirune@kmc.gr.jp>");
277 MODULE_DESCRIPTION("PC-9801-55 SCSI host adapter driver");
278 MODULE_LICENSE("GPL");
279
280 static Scsi_Host_Template driver_template = {
281         .proc_info              = wd33c93_proc_info,
282         .name                   = "SCSI PC-9801-55",
283         .detect                 = scsi_pc980155_detect,
284         .release                = scsi_pc980155_release,
285         .queuecommand           = wd33c93_queuecommand,
286         .eh_abort_handler       = wd33c93_abort,
287         .eh_bus_reset_handler   = pc980155_bus_reset,
288         .eh_host_reset_handler  = wd33c93_host_reset,
289         .bios_param             = pc98_bios_param,
290         .can_queue              = CAN_QUEUE,
291         .this_id                = 7,
292         .sg_tablesize           = SG_ALL,
293         .cmd_per_lun            = CMD_PER_LUN, /* dont use link command */
294         .unchecked_isa_dma      = 1, /* use dma **XXXX***/
295         .use_clustering         = ENABLE_CLUSTERING,
296         .proc_name              = "PC_9801_55",
297 };
298
299 #include "scsi_module.c"