blob: 4507a16ee1c60dcc92f016874f9a1ebbe28092a1 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07002#include <linux/init.h>
3#include <linux/interrupt.h>
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +02004#include <linux/mm.h>
5#include <linux/slab.h>
6#include <linux/spinlock.h>
7#include <linux/zorro.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <asm/page.h>
10#include <asm/pgtable.h>
11#include <asm/amigaints.h>
12#include <asm/amigahw.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013
14#include "scsi.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include "wd33c93.h"
16#include "gvp11.h"
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
Geert Uytterhoeven11ca46e2009-05-17 20:44:16 +020019#define CHECK_WD33C93
20
Geert Uytterhoeven6869b152009-05-17 12:17:28 +020021static irqreturn_t gvp11_intr(int irq, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070022{
Geert Uytterhoeven6869b152009-05-17 12:17:28 +020023 struct Scsi_Host *instance = data;
Geert Uytterhoeven349d65f2009-05-17 21:05:55 +020024 struct gvp11_scsiregs *regs = (struct gvp11_scsiregs *)(instance->base);
Geert Uytterhoeven6869b152009-05-17 12:17:28 +020025 unsigned int status = regs->CNTR;
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020026 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020028 if (!(status & GVP11_DMAC_INT_PENDING))
29 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020031 spin_lock_irqsave(instance->host_lock, flags);
32 wd33c93_intr(instance);
33 spin_unlock_irqrestore(instance->host_lock, flags);
34 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -070035}
36
37static int gvp11_xfer_mask = 0;
38
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020039void gvp11_setup(char *str, int *ints)
Linus Torvalds1da177e2005-04-16 15:20:36 -070040{
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020041 gvp11_xfer_mask = ints[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070042}
43
Henrik Kretzschmar65396412006-09-12 23:49:33 +020044static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
Linus Torvalds1da177e2005-04-16 15:20:36 -070045{
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +020046 struct Scsi_Host *instance = cmd->device->host;
47 struct WD33C93_hostdata *hdata = shost_priv(instance);
Geert Uytterhoeven349d65f2009-05-17 21:05:55 +020048 struct gvp11_scsiregs *regs = (struct gvp11_scsiregs *)(instance->base);
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020049 unsigned short cntr = GVP11_DMAC_INT_ENABLE;
50 unsigned long addr = virt_to_bus(cmd->SCp.ptr);
51 int bank_mask;
52 static int scsi_alloc_out_of_range = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020054 /* use bounce buffer if the physical address is bad */
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +020055 if (addr & hdata->dma_xfer_mask) {
56 hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020058 if (!scsi_alloc_out_of_range) {
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +020059 hdata->dma_bounce_buffer =
60 kmalloc(hdata->dma_bounce_len, GFP_KERNEL);
61 hdata->dma_buffer_pool = BUF_SCSI_ALLOCED;
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020062 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020064 if (scsi_alloc_out_of_range ||
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +020065 !hdata->dma_bounce_buffer) {
66 hdata->dma_bounce_buffer =
67 amiga_chip_alloc(hdata->dma_bounce_len,
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020068 "GVP II SCSI Bounce Buffer");
69
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +020070 if (!hdata->dma_bounce_buffer) {
71 hdata->dma_bounce_len = 0;
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020072 return 1;
73 }
74
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +020075 hdata->dma_buffer_pool = BUF_CHIP_ALLOCED;
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020076 }
77
78 /* check if the address of the bounce buffer is OK */
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +020079 addr = virt_to_bus(hdata->dma_bounce_buffer);
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020080
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +020081 if (addr & hdata->dma_xfer_mask) {
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020082 /* fall back to Chip RAM if address out of range */
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +020083 if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED) {
84 kfree(hdata->dma_bounce_buffer);
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020085 scsi_alloc_out_of_range = 1;
86 } else {
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +020087 amiga_chip_free(hdata->dma_bounce_buffer);
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020088 }
89
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +020090 hdata->dma_bounce_buffer =
91 amiga_chip_alloc(hdata->dma_bounce_len,
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020092 "GVP II SCSI Bounce Buffer");
93
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +020094 if (!hdata->dma_bounce_buffer) {
95 hdata->dma_bounce_len = 0;
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +020096 return 1;
97 }
98
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +020099 addr = virt_to_bus(hdata->dma_bounce_buffer);
100 hdata->dma_buffer_pool = BUF_CHIP_ALLOCED;
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200101 }
102
103 if (!dir_in) {
104 /* copy to bounce buffer for a write */
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +0200105 memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
106 cmd->SCp.this_residual);
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200107 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 }
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200109
110 /* setup dma direction */
111 if (!dir_in)
112 cntr |= GVP11_DMAC_DIR_WRITE;
113
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +0200114 hdata->dma_dir = dir_in;
Geert Uytterhoeven6869b152009-05-17 12:17:28 +0200115 regs->CNTR = cntr;
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200116
117 /* setup DMA *physical* address */
Geert Uytterhoeven6869b152009-05-17 12:17:28 +0200118 regs->ACR = addr;
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200119
120 if (dir_in) {
121 /* invalidate any cache */
122 cache_clear(addr, cmd->SCp.this_residual);
123 } else {
124 /* push any dirty cache */
125 cache_push(addr, cmd->SCp.this_residual);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +0200128 bank_mask = (~hdata->dma_xfer_mask >> 18) & 0x01c0;
129 if (bank_mask)
Geert Uytterhoeven6869b152009-05-17 12:17:28 +0200130 regs->BANK = bank_mask & (addr >> 18);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200132 /* start DMA */
Geert Uytterhoeven6869b152009-05-17 12:17:28 +0200133 regs->ST_DMA = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200135 /* return success */
136 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137}
138
Henrik Kretzschmar65396412006-09-12 23:49:33 +0200139static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
140 int status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141{
Geert Uytterhoeven349d65f2009-05-17 21:05:55 +0200142 struct gvp11_scsiregs *regs = (struct gvp11_scsiregs *)(instance->base);
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +0200143 struct WD33C93_hostdata *hdata = shost_priv(instance);
144
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200145 /* stop DMA */
Geert Uytterhoeven6869b152009-05-17 12:17:28 +0200146 regs->SP_DMA = 1;
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200147 /* remove write bit from CONTROL bits */
Geert Uytterhoeven6869b152009-05-17 12:17:28 +0200148 regs->CNTR = GVP11_DMAC_INT_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200150 /* copy from a bounce buffer, if necessary */
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +0200151 if (status && hdata->dma_bounce_buffer) {
152 if (hdata->dma_dir && SCpnt)
153 memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer,
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200154 SCpnt->SCp.this_residual);
155
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +0200156 if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED)
157 kfree(hdata->dma_bounce_buffer);
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200158 else
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +0200159 amiga_chip_free(hdata->dma_bounce_buffer);
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200160
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +0200161 hdata->dma_bounce_buffer = NULL;
162 hdata->dma_bounce_len = 0;
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200163 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164}
165
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +0200166static int gvp11_bus_reset(struct scsi_cmnd *cmd)
167{
168 struct Scsi_Host *instance = cmd->device->host;
169
170 /* FIXME perform bus-specific reset */
171
172 /* FIXME 2: shouldn't we no-op this function (return
173 FAILED), and fall back to host reset function,
174 wd33c93_host_reset ? */
175
176 spin_lock_irq(instance->host_lock);
177 wd33c93_host_reset(cmd);
178 spin_unlock_irq(instance->host_lock);
179
180 return SUCCESS;
181}
182
183static struct scsi_host_template gvp11_scsi_template = {
184 .module = THIS_MODULE,
185 .name = "GVP Series II SCSI",
186 .proc_info = wd33c93_proc_info,
187 .proc_name = "GVP11",
188 .queuecommand = wd33c93_queuecommand,
189 .eh_abort_handler = wd33c93_abort,
190 .eh_bus_reset_handler = gvp11_bus_reset,
191 .eh_host_reset_handler = wd33c93_host_reset,
192 .can_queue = CAN_QUEUE,
193 .this_id = 7,
194 .sg_tablesize = SG_ALL,
195 .cmd_per_lun = CMD_PER_LUN,
196 .use_clustering = DISABLE_CLUSTERING
197};
198
199static int __devinit check_wd33c93(struct gvp11_scsiregs *regs)
Geert Uytterhoeven11ca46e2009-05-17 20:44:16 +0200200{
201#ifdef CHECK_WD33C93
202 volatile unsigned char *sasr_3393, *scmd_3393;
203 unsigned char save_sasr;
204 unsigned char q, qq;
205
206 /*
207 * These darn GVP boards are a problem - it can be tough to tell
208 * whether or not they include a SCSI controller. This is the
209 * ultimate Yet-Another-GVP-Detection-Hack in that it actually
210 * probes for a WD33c93 chip: If we find one, it's extremely
211 * likely that this card supports SCSI, regardless of Product_
212 * Code, Board_Size, etc.
213 */
214
215 /* Get pointers to the presumed register locations and save contents */
216
217 sasr_3393 = &regs->SASR;
218 scmd_3393 = &regs->SCMD;
219 save_sasr = *sasr_3393;
220
221 /* First test the AuxStatus Reg */
222
223 q = *sasr_3393; /* read it */
224 if (q & 0x08) /* bit 3 should always be clear */
225 return -ENODEV;
226 *sasr_3393 = WD_AUXILIARY_STATUS; /* setup indirect address */
227 if (*sasr_3393 == WD_AUXILIARY_STATUS) { /* shouldn't retain the write */
228 *sasr_3393 = save_sasr; /* Oops - restore this byte */
229 return -ENODEV;
230 }
231 if (*sasr_3393 != q) { /* should still read the same */
232 *sasr_3393 = save_sasr; /* Oops - restore this byte */
233 return -ENODEV;
234 }
235 if (*scmd_3393 != q) /* and so should the image at 0x1f */
236 return -ENODEV;
237
238 /*
239 * Ok, we probably have a wd33c93, but let's check a few other places
240 * for good measure. Make sure that this works for both 'A and 'B
241 * chip versions.
242 */
243
244 *sasr_3393 = WD_SCSI_STATUS;
245 q = *scmd_3393;
246 *sasr_3393 = WD_SCSI_STATUS;
247 *scmd_3393 = ~q;
248 *sasr_3393 = WD_SCSI_STATUS;
249 qq = *scmd_3393;
250 *sasr_3393 = WD_SCSI_STATUS;
251 *scmd_3393 = q;
252 if (qq != q) /* should be read only */
253 return -ENODEV;
254 *sasr_3393 = 0x1e; /* this register is unimplemented */
255 q = *scmd_3393;
256 *sasr_3393 = 0x1e;
257 *scmd_3393 = ~q;
258 *sasr_3393 = 0x1e;
259 qq = *scmd_3393;
260 *sasr_3393 = 0x1e;
261 *scmd_3393 = q;
262 if (qq != q || qq != 0xff) /* should be read only, all 1's */
263 return -ENODEV;
264 *sasr_3393 = WD_TIMEOUT_PERIOD;
265 q = *scmd_3393;
266 *sasr_3393 = WD_TIMEOUT_PERIOD;
267 *scmd_3393 = ~q;
268 *sasr_3393 = WD_TIMEOUT_PERIOD;
269 qq = *scmd_3393;
270 *sasr_3393 = WD_TIMEOUT_PERIOD;
271 *scmd_3393 = q;
272 if (qq != (~q & 0xff)) /* should be read/write */
273 return -ENODEV;
274#endif /* CHECK_WD33C93 */
275
276 return 0;
277}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +0200279static int __devinit gvp11_probe(struct zorro_dev *z,
280 const struct zorro_device_id *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200282 struct Scsi_Host *instance;
283 unsigned long address;
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +0200284 int error;
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200285 unsigned int epc;
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200286 unsigned int default_dma_xfer_mask;
Geert Uytterhoeven52c3d8a2010-04-04 11:00:37 +0200287 struct WD33C93_hostdata *hdata;
Geert Uytterhoeven349d65f2009-05-17 21:05:55 +0200288 struct gvp11_scsiregs *regs;
Geert Uytterhoeven6869b152009-05-17 12:17:28 +0200289 wd33c93_regs wdregs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +0200291 default_dma_xfer_mask = ent->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +0200293 /*
294 * Rumors state that some GVP ram boards use the same product
295 * code as the SCSI controllers. Therefore if the board-size
296 * is not 64KB we asume it is a ram board and bail out.
297 */
298 if (zorro_resource_len(z) != 0x10000)
299 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +0200301 address = z->resource.start;
302 if (!request_mem_region(address, 256, "wd33c93"))
303 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +0200305 regs = (struct gvp11_scsiregs *)(ZTWO_VADDR(address));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +0200307 error = check_wd33c93(regs);
308 if (error)
309 goto fail_check_or_alloc;
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200310
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +0200311 instance = scsi_host_alloc(&gvp11_scsi_template,
312 sizeof(struct WD33C93_hostdata));
313 if (!instance) {
314 error = -ENOMEM;
315 goto fail_check_or_alloc;
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200316 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +0200318 instance->base = (unsigned long)regs;
319 instance->irq = IRQ_AMIGA_PORTS;
320 instance->unique_id = z->slotaddr;
321
322 regs->secret2 = 1;
323 regs->secret1 = 0;
324 regs->secret3 = 15;
325 while (regs->CNTR & GVP11_DMAC_BUSY)
326 ;
327 regs->CNTR = 0;
328 regs->BANK = 0;
329
330 wdregs.SASR = &regs->SASR;
331 wdregs.SCMD = &regs->SCMD;
332
333 hdata = shost_priv(instance);
334 if (gvp11_xfer_mask)
335 hdata->dma_xfer_mask = gvp11_xfer_mask;
336 else
337 hdata->dma_xfer_mask = default_dma_xfer_mask;
338
339 hdata->no_sync = 0xff;
340 hdata->fast = 0;
341 hdata->dma_mode = CTRL_DMA;
342
343 /*
344 * Check for 14MHz SCSI clock
345 */
346 epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);
347 wd33c93_init(instance, wdregs, dma_setup, dma_stop,
348 (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
349 : WD33C93_FS_12_15);
350
351 error = request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED,
352 "GVP11 SCSI", instance);
353 if (error)
354 goto fail_irq;
355
356 regs->CNTR = GVP11_DMAC_INT_ENABLE;
357
358 error = scsi_add_host(instance, NULL);
359 if (error)
360 goto fail_host;
361
362 zorro_set_drvdata(z, instance);
363 scsi_scan_host(instance);
364 return 0;
365
366fail_host:
367 free_irq(IRQ_AMIGA_PORTS, instance);
368fail_irq:
369 scsi_host_put(instance);
370fail_check_or_alloc:
371 release_mem_region(address, 256);
372 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373}
374
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +0200375static void __devexit gvp11_remove(struct zorro_dev *z)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376{
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +0200377 struct Scsi_Host *instance = zorro_get_drvdata(z);
Geert Uytterhoeven349d65f2009-05-17 21:05:55 +0200378 struct gvp11_scsiregs *regs = (struct gvp11_scsiregs *)(instance->base);
Geert Uytterhoeven6869b152009-05-17 12:17:28 +0200379
380 regs->CNTR = 0;
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +0200381 scsi_remove_host(instance);
Geert Uytterhoevenbb17b782010-04-04 11:00:33 +0200382 free_irq(IRQ_AMIGA_PORTS, instance);
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +0200383 scsi_host_put(instance);
384 release_mem_region(z->resource.start, 256);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385}
386
Geert Uytterhoevenc1d288a2009-08-16 11:17:35 +0200387 /*
388 * This should (hopefully) be the correct way to identify
389 * all the different GVP SCSI controllers (except for the
390 * SERIES I though).
391 */
392
393static struct zorro_device_id gvp11_zorro_tbl[] __devinitdata = {
394 { ZORRO_PROD_GVP_COMBO_030_R3_SCSI, ~0x00ffffff },
395 { ZORRO_PROD_GVP_SERIES_II, ~0x00ffffff },
396 { ZORRO_PROD_GVP_GFORCE_030_SCSI, ~0x01ffffff },
397 { ZORRO_PROD_GVP_A530_SCSI, ~0x01ffffff },
398 { ZORRO_PROD_GVP_COMBO_030_R4_SCSI, ~0x01ffffff },
399 { ZORRO_PROD_GVP_A1291, ~0x07ffffff },
400 { ZORRO_PROD_GVP_GFORCE_040_SCSI_1, ~0x07ffffff },
401 { 0 }
402};
403MODULE_DEVICE_TABLE(zorro, gvp11_zorro_tbl);
404
405static struct zorro_driver gvp11_driver = {
406 .name = "gvp11",
407 .id_table = gvp11_zorro_tbl,
408 .probe = gvp11_probe,
409 .remove = __devexit_p(gvp11_remove),
410};
411
412static int __init gvp11_init(void)
413{
414 return zorro_register_driver(&gvp11_driver);
415}
416module_init(gvp11_init);
417
418static void __exit gvp11_exit(void)
419{
420 zorro_unregister_driver(&gvp11_driver);
421}
422module_exit(gvp11_exit);
423
424MODULE_DESCRIPTION("GVP Series II SCSI");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425MODULE_LICENSE("GPL");