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