diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/scsi/mac53c94.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/scsi/mac53c94.c')
-rw-r--r-- | drivers/scsi/mac53c94.c | 582 |
1 files changed, 582 insertions, 0 deletions
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c new file mode 100644 index 000000000000..3ef2a1443996 --- /dev/null +++ b/drivers/scsi/mac53c94.c | |||
@@ -0,0 +1,582 @@ | |||
1 | /* | ||
2 | * SCSI low-level driver for the 53c94 SCSI bus adaptor found | ||
3 | * on Power Macintosh computers, controlling the external SCSI chain. | ||
4 | * We assume the 53c94 is connected to a DBDMA (descriptor-based DMA) | ||
5 | * controller. | ||
6 | * | ||
7 | * Paul Mackerras, August 1996. | ||
8 | * Copyright (C) 1996 Paul Mackerras. | ||
9 | */ | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/string.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/blkdev.h> | ||
16 | #include <linux/proc_fs.h> | ||
17 | #include <linux/stat.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <asm/dbdma.h> | ||
21 | #include <asm/io.h> | ||
22 | #include <asm/pgtable.h> | ||
23 | #include <asm/prom.h> | ||
24 | #include <asm/system.h> | ||
25 | #include <asm/pci-bridge.h> | ||
26 | #include <asm/macio.h> | ||
27 | |||
28 | #include <scsi/scsi.h> | ||
29 | #include <scsi/scsi_cmnd.h> | ||
30 | #include <scsi/scsi_device.h> | ||
31 | #include <scsi/scsi_host.h> | ||
32 | |||
33 | #include "mac53c94.h" | ||
34 | |||
35 | enum fsc_phase { | ||
36 | idle, | ||
37 | selecting, | ||
38 | dataing, | ||
39 | completing, | ||
40 | busfreeing, | ||
41 | }; | ||
42 | |||
43 | struct fsc_state { | ||
44 | struct mac53c94_regs __iomem *regs; | ||
45 | int intr; | ||
46 | struct dbdma_regs __iomem *dma; | ||
47 | int dmaintr; | ||
48 | int clk_freq; | ||
49 | struct Scsi_Host *host; | ||
50 | struct scsi_cmnd *request_q; | ||
51 | struct scsi_cmnd *request_qtail; | ||
52 | struct scsi_cmnd *current_req; /* req we're currently working on */ | ||
53 | enum fsc_phase phase; /* what we're currently trying to do */ | ||
54 | struct dbdma_cmd *dma_cmds; /* space for dbdma commands, aligned */ | ||
55 | void *dma_cmd_space; | ||
56 | struct pci_dev *pdev; | ||
57 | dma_addr_t dma_addr; | ||
58 | struct macio_dev *mdev; | ||
59 | }; | ||
60 | |||
61 | static void mac53c94_init(struct fsc_state *); | ||
62 | static void mac53c94_start(struct fsc_state *); | ||
63 | static void mac53c94_interrupt(int, void *, struct pt_regs *); | ||
64 | static irqreturn_t do_mac53c94_interrupt(int, void *, struct pt_regs *); | ||
65 | static void cmd_done(struct fsc_state *, int result); | ||
66 | static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *); | ||
67 | |||
68 | |||
69 | static int mac53c94_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) | ||
70 | { | ||
71 | struct fsc_state *state; | ||
72 | |||
73 | #if 0 | ||
74 | if (cmd->sc_data_direction == DMA_TO_DEVICE) { | ||
75 | int i; | ||
76 | printk(KERN_DEBUG "mac53c94_queue %p: command is", cmd); | ||
77 | for (i = 0; i < cmd->cmd_len; ++i) | ||
78 | printk(" %.2x", cmd->cmnd[i]); | ||
79 | printk("\n" KERN_DEBUG "use_sg=%d request_bufflen=%d request_buffer=%p\n", | ||
80 | cmd->use_sg, cmd->request_bufflen, cmd->request_buffer); | ||
81 | } | ||
82 | #endif | ||
83 | |||
84 | cmd->scsi_done = done; | ||
85 | cmd->host_scribble = NULL; | ||
86 | |||
87 | state = (struct fsc_state *) cmd->device->host->hostdata; | ||
88 | |||
89 | if (state->request_q == NULL) | ||
90 | state->request_q = cmd; | ||
91 | else | ||
92 | state->request_qtail->host_scribble = (void *) cmd; | ||
93 | state->request_qtail = cmd; | ||
94 | |||
95 | if (state->phase == idle) | ||
96 | mac53c94_start(state); | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static int mac53c94_abort(struct scsi_cmnd *cmd) | ||
102 | { | ||
103 | return FAILED; | ||
104 | } | ||
105 | |||
106 | static int mac53c94_host_reset(struct scsi_cmnd *cmd) | ||
107 | { | ||
108 | struct fsc_state *state = (struct fsc_state *) cmd->device->host->hostdata; | ||
109 | struct mac53c94_regs __iomem *regs = state->regs; | ||
110 | struct dbdma_regs __iomem *dma = state->dma; | ||
111 | |||
112 | writel((RUN|PAUSE|FLUSH|WAKE) << 16, &dma->control); | ||
113 | writeb(CMD_SCSI_RESET, ®s->command); /* assert RST */ | ||
114 | udelay(100); /* leave it on for a while (>= 25us) */ | ||
115 | writeb(CMD_RESET, ®s->command); | ||
116 | udelay(20); | ||
117 | mac53c94_init(state); | ||
118 | writeb(CMD_NOP, ®s->command); | ||
119 | return SUCCESS; | ||
120 | } | ||
121 | |||
122 | static void mac53c94_init(struct fsc_state *state) | ||
123 | { | ||
124 | struct mac53c94_regs __iomem *regs = state->regs; | ||
125 | struct dbdma_regs __iomem *dma = state->dma; | ||
126 | int x; | ||
127 | |||
128 | writeb(state->host->this_id | CF1_PAR_ENABLE, ®s->config1); | ||
129 | writeb(TIMO_VAL(250), ®s->sel_timeout); /* 250ms */ | ||
130 | writeb(CLKF_VAL(state->clk_freq), ®s->clk_factor); | ||
131 | writeb(CF2_FEATURE_EN, ®s->config2); | ||
132 | writeb(0, ®s->config3); | ||
133 | writeb(0, ®s->sync_period); | ||
134 | writeb(0, ®s->sync_offset); | ||
135 | x = readb(®s->interrupt); | ||
136 | writel((RUN|PAUSE|FLUSH|WAKE) << 16, &dma->control); | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * Start the next command for a 53C94. | ||
141 | * Should be called with interrupts disabled. | ||
142 | */ | ||
143 | static void mac53c94_start(struct fsc_state *state) | ||
144 | { | ||
145 | struct scsi_cmnd *cmd; | ||
146 | struct mac53c94_regs __iomem *regs = state->regs; | ||
147 | int i; | ||
148 | |||
149 | if (state->phase != idle || state->current_req != NULL) | ||
150 | panic("inappropriate mac53c94_start (state=%p)", state); | ||
151 | if (state->request_q == NULL) | ||
152 | return; | ||
153 | state->current_req = cmd = state->request_q; | ||
154 | state->request_q = (struct scsi_cmnd *) cmd->host_scribble; | ||
155 | |||
156 | /* Off we go */ | ||
157 | writeb(0, ®s->count_lo); | ||
158 | writeb(0, ®s->count_mid); | ||
159 | writeb(0, ®s->count_hi); | ||
160 | writeb(CMD_NOP + CMD_DMA_MODE, ®s->command); | ||
161 | udelay(1); | ||
162 | writeb(CMD_FLUSH, ®s->command); | ||
163 | udelay(1); | ||
164 | writeb(cmd->device->id, ®s->dest_id); | ||
165 | writeb(0, ®s->sync_period); | ||
166 | writeb(0, ®s->sync_offset); | ||
167 | |||
168 | /* load the command into the FIFO */ | ||
169 | for (i = 0; i < cmd->cmd_len; ++i) | ||
170 | writeb(cmd->cmnd[i], ®s->fifo); | ||
171 | |||
172 | /* do select without ATN XXX */ | ||
173 | writeb(CMD_SELECT, ®s->command); | ||
174 | state->phase = selecting; | ||
175 | |||
176 | if (cmd->use_sg > 0 || cmd->request_bufflen != 0) | ||
177 | set_dma_cmds(state, cmd); | ||
178 | } | ||
179 | |||
180 | static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) | ||
181 | { | ||
182 | unsigned long flags; | ||
183 | struct Scsi_Host *dev = ((struct fsc_state *) dev_id)->current_req->device->host; | ||
184 | |||
185 | spin_lock_irqsave(dev->host_lock, flags); | ||
186 | mac53c94_interrupt(irq, dev_id, ptregs); | ||
187 | spin_unlock_irqrestore(dev->host_lock, flags); | ||
188 | return IRQ_HANDLED; | ||
189 | } | ||
190 | |||
191 | static void mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) | ||
192 | { | ||
193 | struct fsc_state *state = (struct fsc_state *) dev_id; | ||
194 | struct mac53c94_regs __iomem *regs = state->regs; | ||
195 | struct dbdma_regs __iomem *dma = state->dma; | ||
196 | struct scsi_cmnd *cmd = state->current_req; | ||
197 | int nb, stat, seq, intr; | ||
198 | static int mac53c94_errors; | ||
199 | |||
200 | /* | ||
201 | * Apparently, reading the interrupt register unlatches | ||
202 | * the status and sequence step registers. | ||
203 | */ | ||
204 | seq = readb(®s->seqstep); | ||
205 | stat = readb(®s->status); | ||
206 | intr = readb(®s->interrupt); | ||
207 | |||
208 | #if 0 | ||
209 | printk(KERN_DEBUG "mac53c94_intr, intr=%x stat=%x seq=%x phase=%d\n", | ||
210 | intr, stat, seq, state->phase); | ||
211 | #endif | ||
212 | |||
213 | if (intr & INTR_RESET) { | ||
214 | /* SCSI bus was reset */ | ||
215 | printk(KERN_INFO "external SCSI bus reset detected\n"); | ||
216 | writeb(CMD_NOP, ®s->command); | ||
217 | writel(RUN << 16, &dma->control); /* stop dma */ | ||
218 | cmd_done(state, DID_RESET << 16); | ||
219 | return; | ||
220 | } | ||
221 | if (intr & INTR_ILL_CMD) { | ||
222 | printk(KERN_ERR "53c94: invalid cmd, intr=%x stat=%x seq=%x phase=%d\n", | ||
223 | intr, stat, seq, state->phase); | ||
224 | cmd_done(state, DID_ERROR << 16); | ||
225 | return; | ||
226 | } | ||
227 | if (stat & STAT_ERROR) { | ||
228 | #if 0 | ||
229 | /* XXX these seem to be harmless? */ | ||
230 | printk("53c94: bad error, intr=%x stat=%x seq=%x phase=%d\n", | ||
231 | intr, stat, seq, state->phase); | ||
232 | #endif | ||
233 | ++mac53c94_errors; | ||
234 | writeb(CMD_NOP + CMD_DMA_MODE, ®s->command); | ||
235 | } | ||
236 | if (cmd == 0) { | ||
237 | printk(KERN_DEBUG "53c94: interrupt with no command active?\n"); | ||
238 | return; | ||
239 | } | ||
240 | if (stat & STAT_PARITY) { | ||
241 | printk(KERN_ERR "mac53c94: parity error\n"); | ||
242 | cmd_done(state, DID_PARITY << 16); | ||
243 | return; | ||
244 | } | ||
245 | switch (state->phase) { | ||
246 | case selecting: | ||
247 | if (intr & INTR_DISCONNECT) { | ||
248 | /* selection timed out */ | ||
249 | cmd_done(state, DID_BAD_TARGET << 16); | ||
250 | return; | ||
251 | } | ||
252 | if (intr != INTR_BUS_SERV + INTR_DONE) { | ||
253 | printk(KERN_DEBUG "got intr %x during selection\n", intr); | ||
254 | cmd_done(state, DID_ERROR << 16); | ||
255 | return; | ||
256 | } | ||
257 | if ((seq & SS_MASK) != SS_DONE) { | ||
258 | printk(KERN_DEBUG "seq step %x after command\n", seq); | ||
259 | cmd_done(state, DID_ERROR << 16); | ||
260 | return; | ||
261 | } | ||
262 | writeb(CMD_NOP, ®s->command); | ||
263 | /* set DMA controller going if any data to transfer */ | ||
264 | if ((stat & (STAT_MSG|STAT_CD)) == 0 | ||
265 | && (cmd->use_sg > 0 || cmd->request_bufflen != 0)) { | ||
266 | nb = cmd->SCp.this_residual; | ||
267 | if (nb > 0xfff0) | ||
268 | nb = 0xfff0; | ||
269 | cmd->SCp.this_residual -= nb; | ||
270 | writeb(nb, ®s->count_lo); | ||
271 | writeb(nb >> 8, ®s->count_mid); | ||
272 | writeb(CMD_DMA_MODE + CMD_NOP, ®s->command); | ||
273 | writel(virt_to_phys(state->dma_cmds), &dma->cmdptr); | ||
274 | writel((RUN << 16) | RUN, &dma->control); | ||
275 | writeb(CMD_DMA_MODE + CMD_XFER_DATA, ®s->command); | ||
276 | state->phase = dataing; | ||
277 | break; | ||
278 | } else if ((stat & STAT_PHASE) == STAT_CD + STAT_IO) { | ||
279 | /* up to status phase already */ | ||
280 | writeb(CMD_I_COMPLETE, ®s->command); | ||
281 | state->phase = completing; | ||
282 | } else { | ||
283 | printk(KERN_DEBUG "in unexpected phase %x after cmd\n", | ||
284 | stat & STAT_PHASE); | ||
285 | cmd_done(state, DID_ERROR << 16); | ||
286 | return; | ||
287 | } | ||
288 | break; | ||
289 | |||
290 | case dataing: | ||
291 | if (intr != INTR_BUS_SERV) { | ||
292 | printk(KERN_DEBUG "got intr %x before status\n", intr); | ||
293 | cmd_done(state, DID_ERROR << 16); | ||
294 | return; | ||
295 | } | ||
296 | if (cmd->SCp.this_residual != 0 | ||
297 | && (stat & (STAT_MSG|STAT_CD)) == 0) { | ||
298 | /* Set up the count regs to transfer more */ | ||
299 | nb = cmd->SCp.this_residual; | ||
300 | if (nb > 0xfff0) | ||
301 | nb = 0xfff0; | ||
302 | cmd->SCp.this_residual -= nb; | ||
303 | writeb(nb, ®s->count_lo); | ||
304 | writeb(nb >> 8, ®s->count_mid); | ||
305 | writeb(CMD_DMA_MODE + CMD_NOP, ®s->command); | ||
306 | writeb(CMD_DMA_MODE + CMD_XFER_DATA, ®s->command); | ||
307 | break; | ||
308 | } | ||
309 | if ((stat & STAT_PHASE) != STAT_CD + STAT_IO) { | ||
310 | printk(KERN_DEBUG "intr %x before data xfer complete\n", intr); | ||
311 | } | ||
312 | writel(RUN << 16, &dma->control); /* stop dma */ | ||
313 | if (cmd->use_sg != 0) { | ||
314 | pci_unmap_sg(state->pdev, | ||
315 | (struct scatterlist *)cmd->request_buffer, | ||
316 | cmd->use_sg, cmd->sc_data_direction); | ||
317 | } else { | ||
318 | pci_unmap_single(state->pdev, state->dma_addr, | ||
319 | cmd->request_bufflen, cmd->sc_data_direction); | ||
320 | } | ||
321 | /* should check dma status */ | ||
322 | writeb(CMD_I_COMPLETE, ®s->command); | ||
323 | state->phase = completing; | ||
324 | break; | ||
325 | case completing: | ||
326 | if (intr != INTR_DONE) { | ||
327 | printk(KERN_DEBUG "got intr %x on completion\n", intr); | ||
328 | cmd_done(state, DID_ERROR << 16); | ||
329 | return; | ||
330 | } | ||
331 | cmd->SCp.Status = readb(®s->fifo); | ||
332 | cmd->SCp.Message = readb(®s->fifo); | ||
333 | cmd->result = CMD_ACCEPT_MSG; | ||
334 | writeb(CMD_ACCEPT_MSG, ®s->command); | ||
335 | state->phase = busfreeing; | ||
336 | break; | ||
337 | case busfreeing: | ||
338 | if (intr != INTR_DISCONNECT) { | ||
339 | printk(KERN_DEBUG "got intr %x when expected disconnect\n", intr); | ||
340 | } | ||
341 | cmd_done(state, (DID_OK << 16) + (cmd->SCp.Message << 8) | ||
342 | + cmd->SCp.Status); | ||
343 | break; | ||
344 | default: | ||
345 | printk(KERN_DEBUG "don't know about phase %d\n", state->phase); | ||
346 | } | ||
347 | } | ||
348 | |||
349 | static void cmd_done(struct fsc_state *state, int result) | ||
350 | { | ||
351 | struct scsi_cmnd *cmd; | ||
352 | |||
353 | cmd = state->current_req; | ||
354 | if (cmd != 0) { | ||
355 | cmd->result = result; | ||
356 | (*cmd->scsi_done)(cmd); | ||
357 | state->current_req = NULL; | ||
358 | } | ||
359 | state->phase = idle; | ||
360 | mac53c94_start(state); | ||
361 | } | ||
362 | |||
363 | /* | ||
364 | * Set up DMA commands for transferring data. | ||
365 | */ | ||
366 | static void set_dma_cmds(struct fsc_state *state, struct scsi_cmnd *cmd) | ||
367 | { | ||
368 | int i, dma_cmd, total; | ||
369 | struct scatterlist *scl; | ||
370 | struct dbdma_cmd *dcmds; | ||
371 | dma_addr_t dma_addr; | ||
372 | u32 dma_len; | ||
373 | |||
374 | dma_cmd = cmd->sc_data_direction == DMA_TO_DEVICE ? | ||
375 | OUTPUT_MORE : INPUT_MORE; | ||
376 | dcmds = state->dma_cmds; | ||
377 | if (cmd->use_sg > 0) { | ||
378 | int nseg; | ||
379 | |||
380 | total = 0; | ||
381 | scl = (struct scatterlist *) cmd->buffer; | ||
382 | nseg = pci_map_sg(state->pdev, scl, cmd->use_sg, | ||
383 | cmd->sc_data_direction); | ||
384 | for (i = 0; i < nseg; ++i) { | ||
385 | dma_addr = sg_dma_address(scl); | ||
386 | dma_len = sg_dma_len(scl); | ||
387 | if (dma_len > 0xffff) | ||
388 | panic("mac53c94: scatterlist element >= 64k"); | ||
389 | total += dma_len; | ||
390 | st_le16(&dcmds->req_count, dma_len); | ||
391 | st_le16(&dcmds->command, dma_cmd); | ||
392 | st_le32(&dcmds->phy_addr, dma_addr); | ||
393 | dcmds->xfer_status = 0; | ||
394 | ++scl; | ||
395 | ++dcmds; | ||
396 | } | ||
397 | } else { | ||
398 | total = cmd->request_bufflen; | ||
399 | if (total > 0xffff) | ||
400 | panic("mac53c94: transfer size >= 64k"); | ||
401 | dma_addr = pci_map_single(state->pdev, cmd->request_buffer, | ||
402 | total, cmd->sc_data_direction); | ||
403 | state->dma_addr = dma_addr; | ||
404 | st_le16(&dcmds->req_count, total); | ||
405 | st_le32(&dcmds->phy_addr, dma_addr); | ||
406 | dcmds->xfer_status = 0; | ||
407 | ++dcmds; | ||
408 | } | ||
409 | dma_cmd += OUTPUT_LAST - OUTPUT_MORE; | ||
410 | st_le16(&dcmds[-1].command, dma_cmd); | ||
411 | st_le16(&dcmds->command, DBDMA_STOP); | ||
412 | cmd->SCp.this_residual = total; | ||
413 | } | ||
414 | |||
415 | static struct scsi_host_template mac53c94_template = { | ||
416 | .proc_name = "53c94", | ||
417 | .name = "53C94", | ||
418 | .queuecommand = mac53c94_queue, | ||
419 | .eh_abort_handler = mac53c94_abort, | ||
420 | .eh_host_reset_handler = mac53c94_host_reset, | ||
421 | .can_queue = 1, | ||
422 | .this_id = 7, | ||
423 | .sg_tablesize = SG_ALL, | ||
424 | .cmd_per_lun = 1, | ||
425 | .use_clustering = DISABLE_CLUSTERING, | ||
426 | }; | ||
427 | |||
428 | static int mac53c94_probe(struct macio_dev *mdev, const struct of_match *match) | ||
429 | { | ||
430 | struct device_node *node = macio_get_of_node(mdev); | ||
431 | struct pci_dev *pdev = macio_get_pci_dev(mdev); | ||
432 | struct fsc_state *state; | ||
433 | struct Scsi_Host *host; | ||
434 | void *dma_cmd_space; | ||
435 | unsigned char *clkprop; | ||
436 | int proplen; | ||
437 | |||
438 | if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) { | ||
439 | printk(KERN_ERR "mac53c94: expected 2 addrs and intrs (got %d/%d)\n", | ||
440 | node->n_addrs, node->n_intrs); | ||
441 | return -ENODEV; | ||
442 | } | ||
443 | |||
444 | if (macio_request_resources(mdev, "mac53c94") != 0) { | ||
445 | printk(KERN_ERR "mac53c94: unable to request memory resources"); | ||
446 | return -EBUSY; | ||
447 | } | ||
448 | |||
449 | host = scsi_host_alloc(&mac53c94_template, sizeof(struct fsc_state)); | ||
450 | if (host == NULL) { | ||
451 | printk(KERN_ERR "mac53c94: couldn't register host"); | ||
452 | goto out_release; | ||
453 | } | ||
454 | |||
455 | state = (struct fsc_state *) host->hostdata; | ||
456 | macio_set_drvdata(mdev, state); | ||
457 | state->host = host; | ||
458 | state->pdev = pdev; | ||
459 | state->mdev = mdev; | ||
460 | |||
461 | state->regs = (struct mac53c94_regs __iomem *) | ||
462 | ioremap(macio_resource_start(mdev, 0), 0x1000); | ||
463 | state->intr = macio_irq(mdev, 0); | ||
464 | state->dma = (struct dbdma_regs __iomem *) | ||
465 | ioremap(macio_resource_start(mdev, 1), 0x1000); | ||
466 | state->dmaintr = macio_irq(mdev, 1); | ||
467 | if (state->regs == NULL || state->dma == NULL) { | ||
468 | printk(KERN_ERR "mac53c94: ioremap failed for %s\n", | ||
469 | node->full_name); | ||
470 | goto out_free; | ||
471 | } | ||
472 | |||
473 | clkprop = get_property(node, "clock-frequency", &proplen); | ||
474 | if (clkprop == NULL || proplen != sizeof(int)) { | ||
475 | printk(KERN_ERR "%s: can't get clock frequency, " | ||
476 | "assuming 25MHz\n", node->full_name); | ||
477 | state->clk_freq = 25000000; | ||
478 | } else | ||
479 | state->clk_freq = *(int *)clkprop; | ||
480 | |||
481 | /* Space for dma command list: +1 for stop command, | ||
482 | * +1 to allow for aligning. | ||
483 | * XXX FIXME: Use DMA consistent routines | ||
484 | */ | ||
485 | dma_cmd_space = kmalloc((host->sg_tablesize + 2) * | ||
486 | sizeof(struct dbdma_cmd), GFP_KERNEL); | ||
487 | if (dma_cmd_space == 0) { | ||
488 | printk(KERN_ERR "mac53c94: couldn't allocate dma " | ||
489 | "command space for %s\n", node->full_name); | ||
490 | goto out_free; | ||
491 | } | ||
492 | state->dma_cmds = (struct dbdma_cmd *)DBDMA_ALIGN(dma_cmd_space); | ||
493 | memset(state->dma_cmds, 0, (host->sg_tablesize + 1) | ||
494 | * sizeof(struct dbdma_cmd)); | ||
495 | state->dma_cmd_space = dma_cmd_space; | ||
496 | |||
497 | mac53c94_init(state); | ||
498 | |||
499 | if (request_irq(state->intr, do_mac53c94_interrupt, 0, "53C94", state)) { | ||
500 | printk(KERN_ERR "mac53C94: can't get irq %d for %s\n", | ||
501 | state->intr, node->full_name); | ||
502 | goto out_free_dma; | ||
503 | } | ||
504 | |||
505 | /* XXX FIXME: handle failure */ | ||
506 | scsi_add_host(host, &mdev->ofdev.dev); | ||
507 | scsi_scan_host(host); | ||
508 | |||
509 | return 0; | ||
510 | |||
511 | out_free_dma: | ||
512 | kfree(state->dma_cmd_space); | ||
513 | out_free: | ||
514 | if (state->dma != NULL) | ||
515 | iounmap(state->dma); | ||
516 | if (state->regs != NULL) | ||
517 | iounmap(state->regs); | ||
518 | scsi_host_put(host); | ||
519 | out_release: | ||
520 | macio_release_resources(mdev); | ||
521 | |||
522 | return -ENODEV; | ||
523 | } | ||
524 | |||
525 | static int mac53c94_remove(struct macio_dev *mdev) | ||
526 | { | ||
527 | struct fsc_state *fp = (struct fsc_state *)macio_get_drvdata(mdev); | ||
528 | struct Scsi_Host *host = fp->host; | ||
529 | |||
530 | scsi_remove_host(host); | ||
531 | |||
532 | free_irq(fp->intr, fp); | ||
533 | |||
534 | if (fp->regs) | ||
535 | iounmap((void *) fp->regs); | ||
536 | if (fp->dma) | ||
537 | iounmap((void *) fp->dma); | ||
538 | kfree(fp->dma_cmd_space); | ||
539 | |||
540 | scsi_host_put(host); | ||
541 | |||
542 | macio_release_resources(mdev); | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | |||
548 | static struct of_match mac53c94_match[] = | ||
549 | { | ||
550 | { | ||
551 | .name = "53c94", | ||
552 | .type = OF_ANY_MATCH, | ||
553 | .compatible = OF_ANY_MATCH | ||
554 | }, | ||
555 | {}, | ||
556 | }; | ||
557 | |||
558 | static struct macio_driver mac53c94_driver = | ||
559 | { | ||
560 | .name = "mac53c94", | ||
561 | .match_table = mac53c94_match, | ||
562 | .probe = mac53c94_probe, | ||
563 | .remove = mac53c94_remove, | ||
564 | }; | ||
565 | |||
566 | |||
567 | static int __init init_mac53c94(void) | ||
568 | { | ||
569 | return macio_register_driver(&mac53c94_driver); | ||
570 | } | ||
571 | |||
572 | static void __exit exit_mac53c94(void) | ||
573 | { | ||
574 | return macio_unregister_driver(&mac53c94_driver); | ||
575 | } | ||
576 | |||
577 | module_init(init_mac53c94); | ||
578 | module_exit(exit_mac53c94); | ||
579 | |||
580 | MODULE_DESCRIPTION("PowerMac 53c94 SCSI driver"); | ||
581 | MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>"); | ||
582 | MODULE_LICENSE("GPL"); | ||