Blame view
drivers/scsi/a2091.c
6.53 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
#include <linux/types.h> |
1da177e4c Linux-2.6.12-rc2 |
2 3 |
#include <linux/init.h> #include <linux/interrupt.h> |
c737e22cd m68k: amiga - A20... |
4 5 6 7 |
#include <linux/mm.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/zorro.h> |
acf3368ff scsi: Fix up file... |
8 |
#include <linux/module.h> |
1da177e4c Linux-2.6.12-rc2 |
9 |
|
1da177e4c Linux-2.6.12-rc2 |
10 11 12 13 |
#include <asm/page.h> #include <asm/pgtable.h> #include <asm/amigaints.h> #include <asm/amigahw.h> |
1da177e4c Linux-2.6.12-rc2 |
14 15 |
#include "scsi.h" |
1da177e4c Linux-2.6.12-rc2 |
16 17 |
#include "wd33c93.h" #include "a2091.h" |
5880f486e [SCSI] a2091: mak... |
18 |
|
65c2784a2 m68k/scsi: a2091 ... |
19 20 21 22 |
struct a2091_hostdata { struct WD33C93_hostdata wh; struct a2091_scsiregs *regs; }; |
b1de6ab79 [SCSI] a2091: Kil... |
23 |
static irqreturn_t a2091_intr(int irq, void *data) |
1da177e4c Linux-2.6.12-rc2 |
24 |
{ |
b1de6ab79 [SCSI] a2091: Kil... |
25 |
struct Scsi_Host *instance = data; |
65c2784a2 m68k/scsi: a2091 ... |
26 27 |
struct a2091_hostdata *hdata = shost_priv(instance); unsigned int status = hdata->regs->ISTR; |
09bc85b08 [SCSI] a2091: Rei... |
28 |
unsigned long flags; |
09bc85b08 [SCSI] a2091: Rei... |
29 |
|
09bc85b08 [SCSI] a2091: Rei... |
30 31 32 33 34 35 36 |
if (!(status & (ISTR_INT_F | ISTR_INT_P)) || !(status & ISTR_INTS)) return IRQ_NONE; spin_lock_irqsave(instance->host_lock, flags); wd33c93_intr(instance); spin_unlock_irqrestore(instance->host_lock, flags); return IRQ_HANDLED; |
1da177e4c Linux-2.6.12-rc2 |
37 |
} |
65396410a [SCSI] wd33c93: S... |
38 |
static int dma_setup(struct scsi_cmnd *cmd, int dir_in) |
1da177e4c Linux-2.6.12-rc2 |
39 |
{ |
6d1d5d43e [SCSI] a2091: Use... |
40 |
struct Scsi_Host *instance = cmd->device->host; |
65c2784a2 m68k/scsi: a2091 ... |
41 42 43 |
struct a2091_hostdata *hdata = shost_priv(instance); struct WD33C93_hostdata *wh = &hdata->wh; struct a2091_scsiregs *regs = hdata->regs; |
09bc85b08 [SCSI] a2091: Rei... |
44 45 |
unsigned short cntr = CNTR_PDMD | CNTR_INTEN; unsigned long addr = virt_to_bus(cmd->SCp.ptr); |
1da177e4c Linux-2.6.12-rc2 |
46 |
|
09bc85b08 [SCSI] a2091: Rei... |
47 |
/* don't allow DMA if the physical address is bad */ |
1da177e4c Linux-2.6.12-rc2 |
48 |
if (addr & A2091_XFER_MASK) { |
65c2784a2 m68k/scsi: a2091 ... |
49 50 51 |
wh->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len, GFP_KERNEL); |
09bc85b08 [SCSI] a2091: Rei... |
52 53 |
/* can't allocate memory; use PIO */ |
65c2784a2 m68k/scsi: a2091 ... |
54 55 |
if (!wh->dma_bounce_buffer) { wh->dma_bounce_len = 0; |
09bc85b08 [SCSI] a2091: Rei... |
56 57 58 59 |
return 1; } /* get the physical address of the bounce buffer */ |
65c2784a2 m68k/scsi: a2091 ... |
60 |
addr = virt_to_bus(wh->dma_bounce_buffer); |
09bc85b08 [SCSI] a2091: Rei... |
61 62 63 64 |
/* the bounce buffer may not be in the first 16M of physmem */ if (addr & A2091_XFER_MASK) { /* we could use chipmem... maybe later */ |
65c2784a2 m68k/scsi: a2091 ... |
65 66 67 |
kfree(wh->dma_bounce_buffer); wh->dma_bounce_buffer = NULL; wh->dma_bounce_len = 0; |
09bc85b08 [SCSI] a2091: Rei... |
68 69 70 71 72 |
return 1; } if (!dir_in) { /* copy to bounce buffer for a write */ |
65c2784a2 m68k/scsi: a2091 ... |
73 |
memcpy(wh->dma_bounce_buffer, cmd->SCp.ptr, |
6d1d5d43e [SCSI] a2091: Use... |
74 |
cmd->SCp.this_residual); |
09bc85b08 [SCSI] a2091: Rei... |
75 |
} |
1da177e4c Linux-2.6.12-rc2 |
76 |
} |
1da177e4c Linux-2.6.12-rc2 |
77 |
|
09bc85b08 [SCSI] a2091: Rei... |
78 79 80 |
/* setup dma direction */ if (!dir_in) cntr |= CNTR_DDIR; |
1da177e4c Linux-2.6.12-rc2 |
81 |
|
09bc85b08 [SCSI] a2091: Rei... |
82 |
/* remember direction */ |
65c2784a2 m68k/scsi: a2091 ... |
83 |
wh->dma_dir = dir_in; |
1da177e4c Linux-2.6.12-rc2 |
84 |
|
b1de6ab79 [SCSI] a2091: Kil... |
85 |
regs->CNTR = cntr; |
1da177e4c Linux-2.6.12-rc2 |
86 |
|
09bc85b08 [SCSI] a2091: Rei... |
87 |
/* setup DMA *physical* address */ |
b1de6ab79 [SCSI] a2091: Kil... |
88 |
regs->ACR = addr; |
1da177e4c Linux-2.6.12-rc2 |
89 |
|
09bc85b08 [SCSI] a2091: Rei... |
90 91 92 93 94 95 96 97 |
if (dir_in) { /* invalidate any cache */ cache_clear(addr, cmd->SCp.this_residual); } else { /* push any dirty cache */ cache_push(addr, cmd->SCp.this_residual); } /* start DMA */ |
b1de6ab79 [SCSI] a2091: Kil... |
98 |
regs->ST_DMA = 1; |
1da177e4c Linux-2.6.12-rc2 |
99 |
|
09bc85b08 [SCSI] a2091: Rei... |
100 101 |
/* return success */ return 0; |
1da177e4c Linux-2.6.12-rc2 |
102 |
} |
65396410a [SCSI] wd33c93: S... |
103 |
static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, |
09bc85b08 [SCSI] a2091: Rei... |
104 |
int status) |
1da177e4c Linux-2.6.12-rc2 |
105 |
{ |
65c2784a2 m68k/scsi: a2091 ... |
106 107 108 |
struct a2091_hostdata *hdata = shost_priv(instance); struct WD33C93_hostdata *wh = &hdata->wh; struct a2091_scsiregs *regs = hdata->regs; |
6d1d5d43e [SCSI] a2091: Use... |
109 |
|
09bc85b08 [SCSI] a2091: Rei... |
110 111 |
/* disable SCSI interrupts */ unsigned short cntr = CNTR_PDMD; |
65c2784a2 m68k/scsi: a2091 ... |
112 |
if (!wh->dma_dir) |
09bc85b08 [SCSI] a2091: Rei... |
113 114 115 |
cntr |= CNTR_DDIR; /* disable SCSI interrupts */ |
b1de6ab79 [SCSI] a2091: Kil... |
116 |
regs->CNTR = cntr; |
09bc85b08 [SCSI] a2091: Rei... |
117 118 |
/* flush if we were reading */ |
65c2784a2 m68k/scsi: a2091 ... |
119 |
if (wh->dma_dir) { |
b1de6ab79 [SCSI] a2091: Kil... |
120 121 |
regs->FLUSH = 1; while (!(regs->ISTR & ISTR_FE_FLG)) |
09bc85b08 [SCSI] a2091: Rei... |
122 123 124 125 |
; } /* clear a possible interrupt */ |
b1de6ab79 [SCSI] a2091: Kil... |
126 |
regs->CINT = 1; |
09bc85b08 [SCSI] a2091: Rei... |
127 128 |
/* stop DMA */ |
b1de6ab79 [SCSI] a2091: Kil... |
129 |
regs->SP_DMA = 1; |
09bc85b08 [SCSI] a2091: Rei... |
130 131 |
/* restore the CONTROL bits (minus the direction flag) */ |
b1de6ab79 [SCSI] a2091: Kil... |
132 |
regs->CNTR = CNTR_PDMD | CNTR_INTEN; |
09bc85b08 [SCSI] a2091: Rei... |
133 134 |
/* copy from a bounce buffer, if necessary */ |
65c2784a2 m68k/scsi: a2091 ... |
135 136 137 |
if (status && wh->dma_bounce_buffer) { if (wh->dma_dir) memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer, |
09bc85b08 [SCSI] a2091: Rei... |
138 |
SCpnt->SCp.this_residual); |
65c2784a2 m68k/scsi: a2091 ... |
139 140 141 |
kfree(wh->dma_bounce_buffer); wh->dma_bounce_buffer = NULL; wh->dma_bounce_len = 0; |
09bc85b08 [SCSI] a2091: Rei... |
142 |
} |
1da177e4c Linux-2.6.12-rc2 |
143 |
} |
65396410a [SCSI] wd33c93: S... |
144 |
static int a2091_bus_reset(struct scsi_cmnd *cmd) |
1da177e4c Linux-2.6.12-rc2 |
145 |
{ |
c737e22cd m68k: amiga - A20... |
146 |
struct Scsi_Host *instance = cmd->device->host; |
1da177e4c Linux-2.6.12-rc2 |
147 |
/* FIXME perform bus-specific reset */ |
68b3aa7c9 [SCSI] allow slee... |
148 |
|
df0ae2497 [SCSI] allow slee... |
149 150 |
/* FIXME 2: kill this function, and let midlayer fall back to the same action, calling wd33c93_host_reset() */ |
c737e22cd m68k: amiga - A20... |
151 |
spin_lock_irq(instance->host_lock); |
1da177e4c Linux-2.6.12-rc2 |
152 |
wd33c93_host_reset(cmd); |
c737e22cd m68k: amiga - A20... |
153 |
spin_unlock_irq(instance->host_lock); |
68b3aa7c9 [SCSI] allow slee... |
154 |
|
1da177e4c Linux-2.6.12-rc2 |
155 156 |
return SUCCESS; } |
c737e22cd m68k: amiga - A20... |
157 158 |
static struct scsi_host_template a2091_scsi_template = { .module = THIS_MODULE, |
1da177e4c Linux-2.6.12-rc2 |
159 |
.name = "Commodore A2091/A590 SCSI", |
c737e22cd m68k: amiga - A20... |
160 161 |
.proc_info = wd33c93_proc_info, .proc_name = "A2901", |
1da177e4c Linux-2.6.12-rc2 |
162 163 164 165 166 167 168 169 170 171 |
.queuecommand = wd33c93_queuecommand, .eh_abort_handler = wd33c93_abort, .eh_bus_reset_handler = a2091_bus_reset, .eh_host_reset_handler = wd33c93_host_reset, .can_queue = CAN_QUEUE, .this_id = 7, .sg_tablesize = SG_ALL, .cmd_per_lun = CMD_PER_LUN, .use_clustering = DISABLE_CLUSTERING }; |
c737e22cd m68k: amiga - A20... |
172 173 174 175 176 177 178 |
static int __devinit a2091_probe(struct zorro_dev *z, const struct zorro_device_id *ent) { struct Scsi_Host *instance; int error; struct a2091_scsiregs *regs; wd33c93_regs wdregs; |
65c2784a2 m68k/scsi: a2091 ... |
179 |
struct a2091_hostdata *hdata; |
c737e22cd m68k: amiga - A20... |
180 181 182 183 184 |
if (!request_mem_region(z->resource.start, 256, "wd33c93")) return -EBUSY; instance = scsi_host_alloc(&a2091_scsi_template, |
65c2784a2 m68k/scsi: a2091 ... |
185 |
sizeof(struct a2091_hostdata)); |
c737e22cd m68k: amiga - A20... |
186 187 188 189 |
if (!instance) { error = -ENOMEM; goto fail_alloc; } |
c737e22cd m68k: amiga - A20... |
190 191 |
instance->irq = IRQ_AMIGA_PORTS; instance->unique_id = z->slotaddr; |
65c2784a2 m68k/scsi: a2091 ... |
192 |
regs = (struct a2091_scsiregs *)ZTWO_VADDR(z->resource.start); |
c737e22cd m68k: amiga - A20... |
193 194 195 196 |
regs->DAWR = DAWR_A2091; wdregs.SASR = ®s->SASR; wdregs.SCMD = ®s->SCMD; |
1da177e4c Linux-2.6.12-rc2 |
197 |
|
c737e22cd m68k: amiga - A20... |
198 |
hdata = shost_priv(instance); |
65c2784a2 m68k/scsi: a2091 ... |
199 200 201 202 |
hdata->wh.no_sync = 0xff; hdata->wh.fast = 0; hdata->wh.dma_mode = CTRL_DMA; hdata->regs = regs; |
c737e22cd m68k: amiga - A20... |
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_8_10); error = request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, "A2091 SCSI", instance); if (error) goto fail_irq; regs->CNTR = CNTR_PDMD | CNTR_INTEN; error = scsi_add_host(instance, NULL); if (error) goto fail_host; zorro_set_drvdata(z, instance); scsi_scan_host(instance); return 0; |
1da177e4c Linux-2.6.12-rc2 |
220 |
|
c737e22cd m68k: amiga - A20... |
221 222 223 224 225 226 227 228 229 230 |
fail_host: free_irq(IRQ_AMIGA_PORTS, instance); fail_irq: scsi_host_put(instance); fail_alloc: release_mem_region(z->resource.start, 256); return error; } static void __devexit a2091_remove(struct zorro_dev *z) |
1da177e4c Linux-2.6.12-rc2 |
231 |
{ |
c737e22cd m68k: amiga - A20... |
232 |
struct Scsi_Host *instance = zorro_get_drvdata(z); |
65c2784a2 m68k/scsi: a2091 ... |
233 |
struct a2091_hostdata *hdata = shost_priv(instance); |
b1de6ab79 [SCSI] a2091: Kil... |
234 |
|
65c2784a2 m68k/scsi: a2091 ... |
235 |
hdata->regs->CNTR = 0; |
c737e22cd m68k: amiga - A20... |
236 |
scsi_remove_host(instance); |
1da177e4c Linux-2.6.12-rc2 |
237 |
free_irq(IRQ_AMIGA_PORTS, instance); |
c737e22cd m68k: amiga - A20... |
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
scsi_host_put(instance); release_mem_region(z->resource.start, 256); } static struct zorro_device_id a2091_zorro_tbl[] __devinitdata = { { ZORRO_PROD_CBM_A590_A2091_1 }, { ZORRO_PROD_CBM_A590_A2091_2 }, { 0 } }; MODULE_DEVICE_TABLE(zorro, a2091_zorro_tbl); static struct zorro_driver a2091_driver = { .name = "a2091", .id_table = a2091_zorro_tbl, .probe = a2091_probe, .remove = __devexit_p(a2091_remove), }; static int __init a2091_init(void) { return zorro_register_driver(&a2091_driver); } module_init(a2091_init); static void __exit a2091_exit(void) { zorro_unregister_driver(&a2091_driver); |
1da177e4c Linux-2.6.12-rc2 |
265 |
} |
c737e22cd m68k: amiga - A20... |
266 |
module_exit(a2091_exit); |
1da177e4c Linux-2.6.12-rc2 |
267 |
|
c737e22cd m68k: amiga - A20... |
268 |
MODULE_DESCRIPTION("Commodore A2091/A590 SCSI"); |
1da177e4c Linux-2.6.12-rc2 |
269 |
MODULE_LICENSE("GPL"); |