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