diff options
Diffstat (limited to 'drivers/scsi/a2091.c')
-rw-r--r-- | drivers/scsi/a2091.c | 309 |
1 files changed, 157 insertions, 152 deletions
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index d8fe5b76fee0..308541ff85cf 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c | |||
@@ -19,186 +19,190 @@ | |||
19 | #include "wd33c93.h" | 19 | #include "wd33c93.h" |
20 | #include "a2091.h" | 20 | #include "a2091.h" |
21 | 21 | ||
22 | #include<linux/stat.h> | 22 | #include <linux/stat.h> |
23 | 23 | ||
24 | #define DMA(ptr) ((a2091_scsiregs *)((ptr)->base)) | ||
25 | #define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata)) | ||
26 | 24 | ||
27 | static int a2091_release(struct Scsi_Host *instance); | 25 | static int a2091_release(struct Scsi_Host *instance); |
28 | 26 | ||
29 | static irqreturn_t a2091_intr (int irq, void *_instance) | 27 | static irqreturn_t a2091_intr(int irq, void *data) |
30 | { | 28 | { |
31 | unsigned long flags; | 29 | struct Scsi_Host *instance = data; |
32 | unsigned int status; | 30 | a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base); |
33 | struct Scsi_Host *instance = (struct Scsi_Host *)_instance; | 31 | unsigned int status = regs->ISTR; |
34 | 32 | unsigned long flags; | |
35 | status = DMA(instance)->ISTR; | 33 | |
36 | if (!(status & (ISTR_INT_F|ISTR_INT_P)) || !(status & ISTR_INTS)) | 34 | if (!(status & (ISTR_INT_F | ISTR_INT_P)) || !(status & ISTR_INTS)) |
37 | return IRQ_NONE; | 35 | return IRQ_NONE; |
38 | 36 | ||
39 | spin_lock_irqsave(instance->host_lock, flags); | 37 | spin_lock_irqsave(instance->host_lock, flags); |
40 | wd33c93_intr(instance); | 38 | wd33c93_intr(instance); |
41 | spin_unlock_irqrestore(instance->host_lock, flags); | 39 | spin_unlock_irqrestore(instance->host_lock, flags); |
42 | return IRQ_HANDLED; | 40 | return IRQ_HANDLED; |
43 | } | 41 | } |
44 | 42 | ||
45 | static int dma_setup(struct scsi_cmnd *cmd, int dir_in) | 43 | static int dma_setup(struct scsi_cmnd *cmd, int dir_in) |
46 | { | 44 | { |
47 | unsigned short cntr = CNTR_PDMD | CNTR_INTEN; | 45 | struct Scsi_Host *instance = cmd->device->host; |
48 | unsigned long addr = virt_to_bus(cmd->SCp.ptr); | 46 | struct WD33C93_hostdata *hdata = shost_priv(instance); |
49 | struct Scsi_Host *instance = cmd->device->host; | 47 | a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base); |
50 | 48 | unsigned short cntr = CNTR_PDMD | CNTR_INTEN; | |
51 | /* don't allow DMA if the physical address is bad */ | 49 | unsigned long addr = virt_to_bus(cmd->SCp.ptr); |
52 | if (addr & A2091_XFER_MASK) | ||
53 | { | ||
54 | HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511) | ||
55 | & ~0x1ff; | ||
56 | HDATA(instance)->dma_bounce_buffer = | ||
57 | kmalloc (HDATA(instance)->dma_bounce_len, GFP_KERNEL); | ||
58 | |||
59 | /* can't allocate memory; use PIO */ | ||
60 | if (!HDATA(instance)->dma_bounce_buffer) { | ||
61 | HDATA(instance)->dma_bounce_len = 0; | ||
62 | return 1; | ||
63 | } | ||
64 | |||
65 | /* get the physical address of the bounce buffer */ | ||
66 | addr = virt_to_bus(HDATA(instance)->dma_bounce_buffer); | ||
67 | 50 | ||
68 | /* the bounce buffer may not be in the first 16M of physmem */ | 51 | /* don't allow DMA if the physical address is bad */ |
69 | if (addr & A2091_XFER_MASK) { | 52 | if (addr & A2091_XFER_MASK) { |
70 | /* we could use chipmem... maybe later */ | 53 | hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; |
71 | kfree (HDATA(instance)->dma_bounce_buffer); | 54 | hdata->dma_bounce_buffer = kmalloc(hdata->dma_bounce_len, |
72 | HDATA(instance)->dma_bounce_buffer = NULL; | 55 | GFP_KERNEL); |
73 | HDATA(instance)->dma_bounce_len = 0; | 56 | |
74 | return 1; | 57 | /* can't allocate memory; use PIO */ |
58 | if (!hdata->dma_bounce_buffer) { | ||
59 | hdata->dma_bounce_len = 0; | ||
60 | return 1; | ||
61 | } | ||
62 | |||
63 | /* get the physical address of the bounce buffer */ | ||
64 | addr = virt_to_bus(hdata->dma_bounce_buffer); | ||
65 | |||
66 | /* the bounce buffer may not be in the first 16M of physmem */ | ||
67 | if (addr & A2091_XFER_MASK) { | ||
68 | /* we could use chipmem... maybe later */ | ||
69 | kfree(hdata->dma_bounce_buffer); | ||
70 | hdata->dma_bounce_buffer = NULL; | ||
71 | hdata->dma_bounce_len = 0; | ||
72 | return 1; | ||
73 | } | ||
74 | |||
75 | if (!dir_in) { | ||
76 | /* copy to bounce buffer for a write */ | ||
77 | memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr, | ||
78 | cmd->SCp.this_residual); | ||
79 | } | ||
75 | } | 80 | } |
76 | 81 | ||
77 | if (!dir_in) { | 82 | /* setup dma direction */ |
78 | /* copy to bounce buffer for a write */ | 83 | if (!dir_in) |
79 | memcpy (HDATA(instance)->dma_bounce_buffer, | 84 | cntr |= CNTR_DDIR; |
80 | cmd->SCp.ptr, cmd->SCp.this_residual); | ||
81 | } | ||
82 | } | ||
83 | 85 | ||
84 | /* setup dma direction */ | 86 | /* remember direction */ |
85 | if (!dir_in) | 87 | hdata->dma_dir = dir_in; |
86 | cntr |= CNTR_DDIR; | ||
87 | 88 | ||
88 | /* remember direction */ | 89 | regs->CNTR = cntr; |
89 | HDATA(cmd->device->host)->dma_dir = dir_in; | ||
90 | 90 | ||
91 | DMA(cmd->device->host)->CNTR = cntr; | 91 | /* setup DMA *physical* address */ |
92 | regs->ACR = addr; | ||
92 | 93 | ||
93 | /* setup DMA *physical* address */ | 94 | if (dir_in) { |
94 | DMA(cmd->device->host)->ACR = addr; | 95 | /* invalidate any cache */ |
95 | 96 | cache_clear(addr, cmd->SCp.this_residual); | |
96 | if (dir_in){ | 97 | } else { |
97 | /* invalidate any cache */ | 98 | /* push any dirty cache */ |
98 | cache_clear (addr, cmd->SCp.this_residual); | 99 | cache_push(addr, cmd->SCp.this_residual); |
99 | }else{ | 100 | } |
100 | /* push any dirty cache */ | 101 | /* start DMA */ |
101 | cache_push (addr, cmd->SCp.this_residual); | 102 | regs->ST_DMA = 1; |
102 | } | ||
103 | /* start DMA */ | ||
104 | DMA(cmd->device->host)->ST_DMA = 1; | ||
105 | 103 | ||
106 | /* return success */ | 104 | /* return success */ |
107 | return 0; | 105 | return 0; |
108 | } | 106 | } |
109 | 107 | ||
110 | static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, | 108 | static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, |
111 | int status) | 109 | int status) |
112 | { | 110 | { |
113 | /* disable SCSI interrupts */ | 111 | struct WD33C93_hostdata *hdata = shost_priv(instance); |
114 | unsigned short cntr = CNTR_PDMD; | 112 | a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base); |
115 | 113 | ||
116 | if (!HDATA(instance)->dma_dir) | 114 | /* disable SCSI interrupts */ |
117 | cntr |= CNTR_DDIR; | 115 | unsigned short cntr = CNTR_PDMD; |
118 | 116 | ||
119 | /* disable SCSI interrupts */ | 117 | if (!hdata->dma_dir) |
120 | DMA(instance)->CNTR = cntr; | 118 | cntr |= CNTR_DDIR; |
121 | 119 | ||
122 | /* flush if we were reading */ | 120 | /* disable SCSI interrupts */ |
123 | if (HDATA(instance)->dma_dir) { | 121 | regs->CNTR = cntr; |
124 | DMA(instance)->FLUSH = 1; | 122 | |
125 | while (!(DMA(instance)->ISTR & ISTR_FE_FLG)) | 123 | /* flush if we were reading */ |
126 | ; | 124 | if (hdata->dma_dir) { |
127 | } | 125 | regs->FLUSH = 1; |
128 | 126 | while (!(regs->ISTR & ISTR_FE_FLG)) | |
129 | /* clear a possible interrupt */ | 127 | ; |
130 | DMA(instance)->CINT = 1; | 128 | } |
131 | 129 | ||
132 | /* stop DMA */ | 130 | /* clear a possible interrupt */ |
133 | DMA(instance)->SP_DMA = 1; | 131 | regs->CINT = 1; |
134 | 132 | ||
135 | /* restore the CONTROL bits (minus the direction flag) */ | 133 | /* stop DMA */ |
136 | DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; | 134 | regs->SP_DMA = 1; |
137 | 135 | ||
138 | /* copy from a bounce buffer, if necessary */ | 136 | /* restore the CONTROL bits (minus the direction flag) */ |
139 | if (status && HDATA(instance)->dma_bounce_buffer) { | 137 | regs->CNTR = CNTR_PDMD | CNTR_INTEN; |
140 | if( HDATA(instance)->dma_dir ) | 138 | |
141 | memcpy (SCpnt->SCp.ptr, | 139 | /* copy from a bounce buffer, if necessary */ |
142 | HDATA(instance)->dma_bounce_buffer, | 140 | if (status && hdata->dma_bounce_buffer) { |
143 | SCpnt->SCp.this_residual); | 141 | if (hdata->dma_dir) |
144 | kfree (HDATA(instance)->dma_bounce_buffer); | 142 | memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer, |
145 | HDATA(instance)->dma_bounce_buffer = NULL; | 143 | SCpnt->SCp.this_residual); |
146 | HDATA(instance)->dma_bounce_len = 0; | 144 | kfree(hdata->dma_bounce_buffer); |
147 | } | 145 | hdata->dma_bounce_buffer = NULL; |
146 | hdata->dma_bounce_len = 0; | ||
147 | } | ||
148 | } | 148 | } |
149 | 149 | ||
150 | static int __init a2091_detect(struct scsi_host_template *tpnt) | 150 | static int __init a2091_detect(struct scsi_host_template *tpnt) |
151 | { | 151 | { |
152 | static unsigned char called = 0; | 152 | static unsigned char called = 0; |
153 | struct Scsi_Host *instance; | 153 | struct Scsi_Host *instance; |
154 | unsigned long address; | 154 | unsigned long address; |
155 | struct zorro_dev *z = NULL; | 155 | struct zorro_dev *z = NULL; |
156 | wd33c93_regs regs; | 156 | wd33c93_regs wdregs; |
157 | int num_a2091 = 0; | 157 | a2091_scsiregs *regs; |
158 | 158 | struct WD33C93_hostdata *hdata; | |
159 | if (!MACH_IS_AMIGA || called) | 159 | int num_a2091 = 0; |
160 | return 0; | 160 | |
161 | called = 1; | 161 | if (!MACH_IS_AMIGA || called) |
162 | 162 | return 0; | |
163 | tpnt->proc_name = "A2091"; | 163 | called = 1; |
164 | tpnt->proc_info = &wd33c93_proc_info; | 164 | |
165 | 165 | tpnt->proc_name = "A2091"; | |
166 | while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { | 166 | tpnt->proc_info = &wd33c93_proc_info; |
167 | if (z->id != ZORRO_PROD_CBM_A590_A2091_1 && | 167 | |
168 | z->id != ZORRO_PROD_CBM_A590_A2091_2) | 168 | while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { |
169 | continue; | 169 | if (z->id != ZORRO_PROD_CBM_A590_A2091_1 && |
170 | address = z->resource.start; | 170 | z->id != ZORRO_PROD_CBM_A590_A2091_2) |
171 | if (!request_mem_region(address, 256, "wd33c93")) | 171 | continue; |
172 | continue; | 172 | address = z->resource.start; |
173 | 173 | if (!request_mem_region(address, 256, "wd33c93")) | |
174 | instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata)); | 174 | continue; |
175 | if (instance == NULL) | 175 | |
176 | goto release; | 176 | instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata)); |
177 | instance->base = ZTWO_VADDR(address); | 177 | if (instance == NULL) |
178 | instance->irq = IRQ_AMIGA_PORTS; | 178 | goto release; |
179 | instance->unique_id = z->slotaddr; | 179 | instance->base = ZTWO_VADDR(address); |
180 | DMA(instance)->DAWR = DAWR_A2091; | 180 | instance->irq = IRQ_AMIGA_PORTS; |
181 | regs.SASR = &(DMA(instance)->SASR); | 181 | instance->unique_id = z->slotaddr; |
182 | regs.SCMD = &(DMA(instance)->SCMD); | 182 | regs = (a2091_scsiregs *)(instance->base); |
183 | HDATA(instance)->no_sync = 0xff; | 183 | regs->DAWR = DAWR_A2091; |
184 | HDATA(instance)->fast = 0; | 184 | wdregs.SASR = ®s->SASR; |
185 | HDATA(instance)->dma_mode = CTRL_DMA; | 185 | wdregs.SCMD = ®s->SCMD; |
186 | wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10); | 186 | hdata = shost_priv(instance); |
187 | if (request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, "A2091 SCSI", | 187 | hdata->no_sync = 0xff; |
188 | instance)) | 188 | hdata->fast = 0; |
189 | goto unregister; | 189 | hdata->dma_mode = CTRL_DMA; |
190 | DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; | 190 | wd33c93_init(instance, wdregs, dma_setup, dma_stop, |
191 | num_a2091++; | 191 | WD33C93_FS_8_10); |
192 | continue; | 192 | if (request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, |
193 | "A2091 SCSI", instance)) | ||
194 | goto unregister; | ||
195 | regs->CNTR = CNTR_PDMD | CNTR_INTEN; | ||
196 | num_a2091++; | ||
197 | continue; | ||
193 | 198 | ||
194 | unregister: | 199 | unregister: |
195 | scsi_unregister(instance); | 200 | scsi_unregister(instance); |
196 | wd33c93_release(); | ||
197 | release: | 201 | release: |
198 | release_mem_region(address, 256); | 202 | release_mem_region(address, 256); |
199 | } | 203 | } |
200 | 204 | ||
201 | return num_a2091; | 205 | return num_a2091; |
202 | } | 206 | } |
203 | 207 | ||
204 | static int a2091_bus_reset(struct scsi_cmnd *cmd) | 208 | static int a2091_bus_reset(struct scsi_cmnd *cmd) |
@@ -239,10 +243,11 @@ static struct scsi_host_template driver_template = { | |||
239 | static int a2091_release(struct Scsi_Host *instance) | 243 | static int a2091_release(struct Scsi_Host *instance) |
240 | { | 244 | { |
241 | #ifdef MODULE | 245 | #ifdef MODULE |
242 | DMA(instance)->CNTR = 0; | 246 | a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base); |
247 | |||
248 | regs->CNTR = 0; | ||
243 | release_mem_region(ZTWO_PADDR(instance->base), 256); | 249 | release_mem_region(ZTWO_PADDR(instance->base), 256); |
244 | free_irq(IRQ_AMIGA_PORTS, instance); | 250 | free_irq(IRQ_AMIGA_PORTS, instance); |
245 | wd33c93_release(); | ||
246 | #endif | 251 | #endif |
247 | return 1; | 252 | return 1; |
248 | } | 253 | } |