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 | 5 | #include <linux/interrupt.h> |
6937d732 CH |
6 | #include <linux/init.h> |
7 | #include <linux/kernel.h> | |
8 | #include <linux/module.h> | |
1da177e4 LT |
9 | |
10 | #include <asm/page.h> | |
11 | #include <asm/pgtable.h> | |
12 | #include <asm/mvme147hw.h> | |
13 | #include <asm/irq.h> | |
14 | ||
15 | #include "scsi.h" | |
16 | #include <scsi/scsi_host.h> | |
17 | #include "wd33c93.h" | |
18 | #include "mvme147.h" | |
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 | ||
6937d732 CH |
68 | static struct scsi_host_template mvme147_host_template = { |
69 | .module = THIS_MODULE, | |
70 | .proc_name = "MVME147", | |
71 | .name = "MVME147 built-in SCSI", | |
72 | .queuecommand = wd33c93_queuecommand, | |
73 | .eh_abort_handler = wd33c93_abort, | |
74 | .eh_host_reset_handler = wd33c93_host_reset, | |
75 | .show_info = wd33c93_show_info, | |
76 | .write_info = wd33c93_write_info, | |
77 | .can_queue = CAN_QUEUE, | |
78 | .this_id = 7, | |
79 | .sg_tablesize = SG_ALL, | |
80 | .cmd_per_lun = CMD_PER_LUN, | |
6937d732 CH |
81 | }; |
82 | ||
83 | static struct Scsi_Host *mvme147_shost; | |
84 | ||
85 | static int __init mvme147_init(void) | |
1da177e4 | 86 | { |
be4540db | 87 | wd33c93_regs regs; |
ce195662 | 88 | struct WD33C93_hostdata *hdata; |
6937d732 | 89 | int error = -ENOMEM; |
be4540db | 90 | |
6937d732 | 91 | if (!MACH_IS_MVME147) |
be4540db | 92 | return 0; |
be4540db | 93 | |
6937d732 CH |
94 | mvme147_shost = scsi_host_alloc(&mvme147_host_template, |
95 | sizeof(struct WD33C93_hostdata)); | |
96 | if (!mvme147_shost) | |
be4540db | 97 | goto err_out; |
6937d732 CH |
98 | mvme147_shost->base = 0xfffe4000; |
99 | mvme147_shost->irq = MVME147_IRQ_SCSI_PORT; | |
be4540db | 100 | |
be4540db GU |
101 | regs.SASR = (volatile unsigned char *)0xfffe4000; |
102 | regs.SCMD = (volatile unsigned char *)0xfffe4001; | |
6937d732 CH |
103 | |
104 | hdata = shost_priv(mvme147_shost); | |
ce195662 GU |
105 | hdata->no_sync = 0xff; |
106 | hdata->fast = 0; | |
107 | hdata->dma_mode = CTRL_DMA; | |
be4540db | 108 | |
6937d732 CH |
109 | wd33c93_init(mvme147_shost, regs, dma_setup, dma_stop, WD33C93_FS_8_10); |
110 | ||
111 | error = request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0, | |
112 | "MVME147 SCSI PORT", mvme147_shost); | |
113 | if (error) | |
be4540db | 114 | goto err_unregister; |
6937d732 CH |
115 | error = request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0, |
116 | "MVME147 SCSI DMA", mvme147_shost); | |
117 | if (error) | |
be4540db | 118 | goto err_free_irq; |
1da177e4 | 119 | #if 0 /* Disabled; causes problems booting */ |
be4540db GU |
120 | m147_pcc->scsi_interrupt = 0x10; /* Assert SCSI bus reset */ |
121 | udelay(100); | |
122 | m147_pcc->scsi_interrupt = 0x00; /* Negate SCSI bus reset */ | |
123 | udelay(2000); | |
124 | m147_pcc->scsi_interrupt = 0x40; /* Clear bus reset interrupt */ | |
1da177e4 | 125 | #endif |
be4540db | 126 | m147_pcc->scsi_interrupt = 0x09; /* Enable interrupt */ |
1da177e4 | 127 | |
be4540db GU |
128 | m147_pcc->dma_cntrl = 0x00; /* ensure DMA is stopped */ |
129 | m147_pcc->dma_intr = 0x89; /* Ack and enable ints */ | |
1da177e4 | 130 | |
6937d732 CH |
131 | error = scsi_add_host(mvme147_shost, NULL); |
132 | if (error) | |
133 | goto err_free_irq; | |
134 | scsi_scan_host(mvme147_shost); | |
135 | return 0; | |
1da177e4 | 136 | |
be4540db | 137 | err_free_irq: |
6937d732 | 138 | free_irq(MVME147_IRQ_SCSI_PORT, mvme147_shost); |
be4540db | 139 | err_unregister: |
6937d732 | 140 | scsi_host_put(mvme147_shost); |
be4540db | 141 | err_out: |
6937d732 | 142 | return error; |
1da177e4 LT |
143 | } |
144 | ||
6937d732 | 145 | static void __exit mvme147_exit(void) |
1da177e4 | 146 | { |
6937d732 CH |
147 | scsi_remove_host(mvme147_shost); |
148 | ||
be4540db | 149 | /* XXX Make sure DMA is stopped! */ |
6937d732 CH |
150 | free_irq(MVME147_IRQ_SCSI_PORT, mvme147_shost); |
151 | free_irq(MVME147_IRQ_SCSI_DMA, mvme147_shost); | |
152 | ||
153 | scsi_host_put(mvme147_shost); | |
1da177e4 | 154 | } |
6937d732 CH |
155 | |
156 | module_init(mvme147_init); | |
157 | module_exit(mvme147_exit); |