]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1da177e4 LT |
2 | #include <linux/types.h> |
3 | #include <linux/mm.h> | |
4 | #include <linux/blkdev.h> | |
1da177e4 LT |
5 | #include <linux/interrupt.h> |
6 | ||
7 | #include <asm/page.h> | |
8 | #include <asm/pgtable.h> | |
9 | #include <asm/mvme147hw.h> | |
10 | #include <asm/irq.h> | |
11 | ||
12 | #include "scsi.h" | |
13 | #include <scsi/scsi_host.h> | |
14 | #include "wd33c93.h" | |
15 | #include "mvme147.h" | |
16 | ||
be4540db | 17 | #include <linux/stat.h> |
1da177e4 | 18 | |
be4540db | 19 | |
4616ac7e | 20 | static irqreturn_t mvme147_intr(int irq, void *data) |
1da177e4 | 21 | { |
4616ac7e GU |
22 | struct Scsi_Host *instance = data; |
23 | ||
be4540db | 24 | if (irq == MVME147_IRQ_SCSI_PORT) |
4616ac7e | 25 | wd33c93_intr(instance); |
be4540db GU |
26 | else |
27 | m147_pcc->dma_intr = 0x89; /* Ack and enable ints */ | |
28 | return IRQ_HANDLED; | |
1da177e4 LT |
29 | } |
30 | ||
65396410 | 31 | static int dma_setup(struct scsi_cmnd *cmd, int dir_in) |
1da177e4 | 32 | { |
4616ac7e GU |
33 | struct Scsi_Host *instance = cmd->device->host; |
34 | struct WD33C93_hostdata *hdata = shost_priv(instance); | |
be4540db GU |
35 | unsigned char flags = 0x01; |
36 | unsigned long addr = virt_to_bus(cmd->SCp.ptr); | |
37 | ||
38 | /* setup dma direction */ | |
39 | if (!dir_in) | |
40 | flags |= 0x04; | |
41 | ||
42 | /* remember direction */ | |
ce195662 | 43 | hdata->dma_dir = dir_in; |
be4540db GU |
44 | |
45 | if (dir_in) { | |
46 | /* invalidate any cache */ | |
47 | cache_clear(addr, cmd->SCp.this_residual); | |
48 | } else { | |
49 | /* push any dirty cache */ | |
50 | cache_push(addr, cmd->SCp.this_residual); | |
51 | } | |
52 | ||
53 | /* start DMA */ | |
54 | m147_pcc->dma_bcr = cmd->SCp.this_residual | (1 << 24); | |
55 | m147_pcc->dma_dadr = addr; | |
56 | m147_pcc->dma_cntrl = flags; | |
57 | ||
58 | /* return success */ | |
59 | return 0; | |
1da177e4 LT |
60 | } |
61 | ||
65396410 | 62 | static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, |
be4540db | 63 | int status) |
1da177e4 | 64 | { |
be4540db | 65 | m147_pcc->dma_cntrl = 0; |
1da177e4 LT |
66 | } |
67 | ||
d0be4a7d | 68 | int mvme147_detect(struct scsi_host_template *tpnt) |
1da177e4 | 69 | { |
be4540db | 70 | static unsigned char called = 0; |
4616ac7e | 71 | struct Scsi_Host *instance; |
be4540db | 72 | wd33c93_regs regs; |
ce195662 | 73 | struct WD33C93_hostdata *hdata; |
be4540db GU |
74 | |
75 | if (!MACH_IS_MVME147 || called) | |
76 | return 0; | |
77 | called++; | |
78 | ||
79 | tpnt->proc_name = "MVME147"; | |
408bb25b AV |
80 | tpnt->show_info = wd33c93_show_info, |
81 | tpnt->write_info = wd33c93_write_info, | |
be4540db | 82 | |
4616ac7e GU |
83 | instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata)); |
84 | if (!instance) | |
be4540db GU |
85 | goto err_out; |
86 | ||
4616ac7e GU |
87 | instance->base = 0xfffe4000; |
88 | instance->irq = MVME147_IRQ_SCSI_PORT; | |
be4540db GU |
89 | regs.SASR = (volatile unsigned char *)0xfffe4000; |
90 | regs.SCMD = (volatile unsigned char *)0xfffe4001; | |
4616ac7e | 91 | hdata = shost_priv(instance); |
ce195662 GU |
92 | hdata->no_sync = 0xff; |
93 | hdata->fast = 0; | |
94 | hdata->dma_mode = CTRL_DMA; | |
4616ac7e | 95 | wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10); |
be4540db GU |
96 | |
97 | if (request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0, | |
4616ac7e | 98 | "MVME147 SCSI PORT", instance)) |
be4540db GU |
99 | goto err_unregister; |
100 | if (request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0, | |
4616ac7e | 101 | "MVME147 SCSI DMA", instance)) |
be4540db | 102 | goto err_free_irq; |
1da177e4 | 103 | #if 0 /* Disabled; causes problems booting */ |
be4540db GU |
104 | m147_pcc->scsi_interrupt = 0x10; /* Assert SCSI bus reset */ |
105 | udelay(100); | |
106 | m147_pcc->scsi_interrupt = 0x00; /* Negate SCSI bus reset */ | |
107 | udelay(2000); | |
108 | m147_pcc->scsi_interrupt = 0x40; /* Clear bus reset interrupt */ | |
1da177e4 | 109 | #endif |
be4540db | 110 | m147_pcc->scsi_interrupt = 0x09; /* Enable interrupt */ |
1da177e4 | 111 | |
be4540db GU |
112 | m147_pcc->dma_cntrl = 0x00; /* ensure DMA is stopped */ |
113 | m147_pcc->dma_intr = 0x89; /* Ack and enable ints */ | |
1da177e4 | 114 | |
be4540db | 115 | return 1; |
1da177e4 | 116 | |
be4540db GU |
117 | err_free_irq: |
118 | free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr); | |
119 | err_unregister: | |
4616ac7e | 120 | scsi_unregister(instance); |
be4540db GU |
121 | err_out: |
122 | return 0; | |
1da177e4 LT |
123 | } |
124 | ||
d0be4a7d | 125 | static struct scsi_host_template driver_template = { |
1da177e4 LT |
126 | .proc_name = "MVME147", |
127 | .name = "MVME147 built-in SCSI", | |
128 | .detect = mvme147_detect, | |
129 | .release = mvme147_release, | |
130 | .queuecommand = wd33c93_queuecommand, | |
131 | .eh_abort_handler = wd33c93_abort, | |
1da177e4 LT |
132 | .eh_host_reset_handler = wd33c93_host_reset, |
133 | .can_queue = CAN_QUEUE, | |
134 | .this_id = 7, | |
135 | .sg_tablesize = SG_ALL, | |
136 | .cmd_per_lun = CMD_PER_LUN, | |
137 | .use_clustering = ENABLE_CLUSTERING | |
138 | }; | |
139 | ||
140 | ||
141 | #include "scsi_module.c" | |
142 | ||
143 | int mvme147_release(struct Scsi_Host *instance) | |
144 | { | |
145 | #ifdef MODULE | |
be4540db GU |
146 | /* XXX Make sure DMA is stopped! */ |
147 | free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr); | |
148 | free_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr); | |
1da177e4 | 149 | #endif |
be4540db | 150 | return 1; |
1da177e4 | 151 | } |