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/mesh.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/mesh.c')
-rw-r--r-- | drivers/scsi/mesh.c | 2062 |
1 files changed, 2062 insertions, 0 deletions
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c new file mode 100644 index 000000000000..85f3a74ac421 --- /dev/null +++ b/drivers/scsi/mesh.c | |||
@@ -0,0 +1,2062 @@ | |||
1 | /* | ||
2 | * SCSI low-level driver for the MESH (Macintosh Enhanced SCSI Hardware) | ||
3 | * bus adaptor found on Power Macintosh computers. | ||
4 | * We assume the MESH is connected to a DBDMA (descriptor-based DMA) | ||
5 | * controller. | ||
6 | * | ||
7 | * Paul Mackerras, August 1996. | ||
8 | * Copyright (C) 1996 Paul Mackerras. | ||
9 | * | ||
10 | * Apr. 21 2002 - BenH Rework bus reset code for new error handler | ||
11 | * Add delay after initial bus reset | ||
12 | * Add module parameters | ||
13 | * | ||
14 | * Sep. 27 2003 - BenH Move to new driver model, fix some write posting | ||
15 | * issues | ||
16 | * To do: | ||
17 | * - handle aborts correctly | ||
18 | * - retry arbitration if lost (unless higher levels do this for us) | ||
19 | * - power down the chip when no device is detected | ||
20 | */ | ||
21 | #include <linux/config.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/types.h> | ||
26 | #include <linux/string.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/blkdev.h> | ||
29 | #include <linux/proc_fs.h> | ||
30 | #include <linux/stat.h> | ||
31 | #include <linux/interrupt.h> | ||
32 | #include <linux/reboot.h> | ||
33 | #include <linux/spinlock.h> | ||
34 | #include <asm/dbdma.h> | ||
35 | #include <asm/io.h> | ||
36 | #include <asm/pgtable.h> | ||
37 | #include <asm/prom.h> | ||
38 | #include <asm/system.h> | ||
39 | #include <asm/irq.h> | ||
40 | #include <asm/hydra.h> | ||
41 | #include <asm/processor.h> | ||
42 | #include <asm/machdep.h> | ||
43 | #include <asm/pmac_feature.h> | ||
44 | #include <asm/pci-bridge.h> | ||
45 | #include <asm/macio.h> | ||
46 | |||
47 | #include <scsi/scsi.h> | ||
48 | #include <scsi/scsi_cmnd.h> | ||
49 | #include <scsi/scsi_device.h> | ||
50 | #include <scsi/scsi_host.h> | ||
51 | |||
52 | #include "mesh.h" | ||
53 | |||
54 | #if 1 | ||
55 | #undef KERN_DEBUG | ||
56 | #define KERN_DEBUG KERN_WARNING | ||
57 | #endif | ||
58 | |||
59 | MODULE_AUTHOR("Paul Mackerras (paulus@samba.org)"); | ||
60 | MODULE_DESCRIPTION("PowerMac MESH SCSI driver"); | ||
61 | MODULE_LICENSE("GPL"); | ||
62 | |||
63 | static int sync_rate = CONFIG_SCSI_MESH_SYNC_RATE; | ||
64 | static int sync_targets = 0xff; | ||
65 | static int resel_targets = 0xff; | ||
66 | static int debug_targets = 0; /* print debug for these targets */ | ||
67 | static int init_reset_delay = CONFIG_SCSI_MESH_RESET_DELAY_MS; | ||
68 | |||
69 | module_param(sync_rate, int, 0); | ||
70 | MODULE_PARM_DESC(sync_rate, "Synchronous rate (0..10, 0=async)"); | ||
71 | module_param(sync_targets, int, 0); | ||
72 | MODULE_PARM_DESC(sync_targets, "Bitmask of targets allowed to set synchronous"); | ||
73 | module_param(resel_targets, int, 0); | ||
74 | MODULE_PARM_DESC(resel_targets, "Bitmask of targets allowed to set disconnect"); | ||
75 | module_param(debug_targets, int, 0644); | ||
76 | MODULE_PARM_DESC(debug_targets, "Bitmask of debugged targets"); | ||
77 | module_param(init_reset_delay, int, 0); | ||
78 | MODULE_PARM_DESC(init_reset_delay, "Initial bus reset delay (0=no reset)"); | ||
79 | |||
80 | static int mesh_sync_period = 100; | ||
81 | static int mesh_sync_offset = 0; | ||
82 | static unsigned char use_active_neg = 0; /* bit mask for SEQ_ACTIVE_NEG if used */ | ||
83 | |||
84 | #define ALLOW_SYNC(tgt) ((sync_targets >> (tgt)) & 1) | ||
85 | #define ALLOW_RESEL(tgt) ((resel_targets >> (tgt)) & 1) | ||
86 | #define ALLOW_DEBUG(tgt) ((debug_targets >> (tgt)) & 1) | ||
87 | #define DEBUG_TARGET(cmd) ((cmd) && ALLOW_DEBUG((cmd)->device->id)) | ||
88 | |||
89 | #undef MESH_DBG | ||
90 | #define N_DBG_LOG 50 | ||
91 | #define N_DBG_SLOG 20 | ||
92 | #define NUM_DBG_EVENTS 13 | ||
93 | #undef DBG_USE_TB /* bombs on 601 */ | ||
94 | |||
95 | struct dbglog { | ||
96 | char *fmt; | ||
97 | u32 tb; | ||
98 | u8 phase; | ||
99 | u8 bs0; | ||
100 | u8 bs1; | ||
101 | u8 tgt; | ||
102 | int d; | ||
103 | }; | ||
104 | |||
105 | enum mesh_phase { | ||
106 | idle, | ||
107 | arbitrating, | ||
108 | selecting, | ||
109 | commanding, | ||
110 | dataing, | ||
111 | statusing, | ||
112 | busfreeing, | ||
113 | disconnecting, | ||
114 | reselecting, | ||
115 | sleeping | ||
116 | }; | ||
117 | |||
118 | enum msg_phase { | ||
119 | msg_none, | ||
120 | msg_out, | ||
121 | msg_out_xxx, | ||
122 | msg_out_last, | ||
123 | msg_in, | ||
124 | msg_in_bad, | ||
125 | }; | ||
126 | |||
127 | enum sdtr_phase { | ||
128 | do_sdtr, | ||
129 | sdtr_sent, | ||
130 | sdtr_done | ||
131 | }; | ||
132 | |||
133 | struct mesh_target { | ||
134 | enum sdtr_phase sdtr_state; | ||
135 | int sync_params; | ||
136 | int data_goes_out; /* guess as to data direction */ | ||
137 | struct scsi_cmnd *current_req; | ||
138 | u32 saved_ptr; | ||
139 | #ifdef MESH_DBG | ||
140 | int log_ix; | ||
141 | int n_log; | ||
142 | struct dbglog log[N_DBG_LOG]; | ||
143 | #endif | ||
144 | }; | ||
145 | |||
146 | struct mesh_state { | ||
147 | volatile struct mesh_regs __iomem *mesh; | ||
148 | int meshintr; | ||
149 | volatile struct dbdma_regs __iomem *dma; | ||
150 | int dmaintr; | ||
151 | struct Scsi_Host *host; | ||
152 | struct mesh_state *next; | ||
153 | struct scsi_cmnd *request_q; | ||
154 | struct scsi_cmnd *request_qtail; | ||
155 | enum mesh_phase phase; /* what we're currently trying to do */ | ||
156 | enum msg_phase msgphase; | ||
157 | int conn_tgt; /* target we're connected to */ | ||
158 | struct scsi_cmnd *current_req; /* req we're currently working on */ | ||
159 | int data_ptr; | ||
160 | int dma_started; | ||
161 | int dma_count; | ||
162 | int stat; | ||
163 | int aborting; | ||
164 | int expect_reply; | ||
165 | int n_msgin; | ||
166 | u8 msgin[16]; | ||
167 | int n_msgout; | ||
168 | int last_n_msgout; | ||
169 | u8 msgout[16]; | ||
170 | struct dbdma_cmd *dma_cmds; /* space for dbdma commands, aligned */ | ||
171 | dma_addr_t dma_cmd_bus; | ||
172 | void *dma_cmd_space; | ||
173 | int dma_cmd_size; | ||
174 | int clk_freq; | ||
175 | struct mesh_target tgts[8]; | ||
176 | struct macio_dev *mdev; | ||
177 | struct pci_dev* pdev; | ||
178 | #ifdef MESH_DBG | ||
179 | int log_ix; | ||
180 | int n_log; | ||
181 | struct dbglog log[N_DBG_SLOG]; | ||
182 | #endif | ||
183 | }; | ||
184 | |||
185 | /* | ||
186 | * Driver is too messy, we need a few prototypes... | ||
187 | */ | ||
188 | static void mesh_done(struct mesh_state *ms, int start_next); | ||
189 | static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs); | ||
190 | static void cmd_complete(struct mesh_state *ms); | ||
191 | static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd); | ||
192 | static void halt_dma(struct mesh_state *ms); | ||
193 | static void phase_mismatch(struct mesh_state *ms); | ||
194 | |||
195 | |||
196 | /* | ||
197 | * Some debugging & logging routines | ||
198 | */ | ||
199 | |||
200 | #ifdef MESH_DBG | ||
201 | |||
202 | static inline u32 readtb(void) | ||
203 | { | ||
204 | u32 tb; | ||
205 | |||
206 | #ifdef DBG_USE_TB | ||
207 | /* Beware: if you enable this, it will crash on 601s. */ | ||
208 | asm ("mftb %0" : "=r" (tb) : ); | ||
209 | #else | ||
210 | tb = 0; | ||
211 | #endif | ||
212 | return tb; | ||
213 | } | ||
214 | |||
215 | static void dlog(struct mesh_state *ms, char *fmt, int a) | ||
216 | { | ||
217 | struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; | ||
218 | struct dbglog *tlp, *slp; | ||
219 | |||
220 | tlp = &tp->log[tp->log_ix]; | ||
221 | slp = &ms->log[ms->log_ix]; | ||
222 | tlp->fmt = fmt; | ||
223 | tlp->tb = readtb(); | ||
224 | tlp->phase = (ms->msgphase << 4) + ms->phase; | ||
225 | tlp->bs0 = ms->mesh->bus_status0; | ||
226 | tlp->bs1 = ms->mesh->bus_status1; | ||
227 | tlp->tgt = ms->conn_tgt; | ||
228 | tlp->d = a; | ||
229 | *slp = *tlp; | ||
230 | if (++tp->log_ix >= N_DBG_LOG) | ||
231 | tp->log_ix = 0; | ||
232 | if (tp->n_log < N_DBG_LOG) | ||
233 | ++tp->n_log; | ||
234 | if (++ms->log_ix >= N_DBG_SLOG) | ||
235 | ms->log_ix = 0; | ||
236 | if (ms->n_log < N_DBG_SLOG) | ||
237 | ++ms->n_log; | ||
238 | } | ||
239 | |||
240 | static void dumplog(struct mesh_state *ms, int t) | ||
241 | { | ||
242 | struct mesh_target *tp = &ms->tgts[t]; | ||
243 | struct dbglog *lp; | ||
244 | int i; | ||
245 | |||
246 | if (tp->n_log == 0) | ||
247 | return; | ||
248 | i = tp->log_ix - tp->n_log; | ||
249 | if (i < 0) | ||
250 | i += N_DBG_LOG; | ||
251 | tp->n_log = 0; | ||
252 | do { | ||
253 | lp = &tp->log[i]; | ||
254 | printk(KERN_DEBUG "mesh log %d: bs=%.2x%.2x ph=%.2x ", | ||
255 | t, lp->bs1, lp->bs0, lp->phase); | ||
256 | #ifdef DBG_USE_TB | ||
257 | printk("tb=%10u ", lp->tb); | ||
258 | #endif | ||
259 | printk(lp->fmt, lp->d); | ||
260 | printk("\n"); | ||
261 | if (++i >= N_DBG_LOG) | ||
262 | i = 0; | ||
263 | } while (i != tp->log_ix); | ||
264 | } | ||
265 | |||
266 | static void dumpslog(struct mesh_state *ms) | ||
267 | { | ||
268 | struct dbglog *lp; | ||
269 | int i; | ||
270 | |||
271 | if (ms->n_log == 0) | ||
272 | return; | ||
273 | i = ms->log_ix - ms->n_log; | ||
274 | if (i < 0) | ||
275 | i += N_DBG_SLOG; | ||
276 | ms->n_log = 0; | ||
277 | do { | ||
278 | lp = &ms->log[i]; | ||
279 | printk(KERN_DEBUG "mesh log: bs=%.2x%.2x ph=%.2x t%d ", | ||
280 | lp->bs1, lp->bs0, lp->phase, lp->tgt); | ||
281 | #ifdef DBG_USE_TB | ||
282 | printk("tb=%10u ", lp->tb); | ||
283 | #endif | ||
284 | printk(lp->fmt, lp->d); | ||
285 | printk("\n"); | ||
286 | if (++i >= N_DBG_SLOG) | ||
287 | i = 0; | ||
288 | } while (i != ms->log_ix); | ||
289 | } | ||
290 | |||
291 | #else | ||
292 | |||
293 | static inline void dlog(struct mesh_state *ms, char *fmt, int a) | ||
294 | {} | ||
295 | static inline void dumplog(struct mesh_state *ms, int tgt) | ||
296 | {} | ||
297 | static inline void dumpslog(struct mesh_state *ms) | ||
298 | {} | ||
299 | |||
300 | #endif /* MESH_DBG */ | ||
301 | |||
302 | #define MKWORD(a, b, c, d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) | ||
303 | |||
304 | static void | ||
305 | mesh_dump_regs(struct mesh_state *ms) | ||
306 | { | ||
307 | volatile struct mesh_regs __iomem *mr = ms->mesh; | ||
308 | volatile struct dbdma_regs __iomem *md = ms->dma; | ||
309 | int t; | ||
310 | struct mesh_target *tp; | ||
311 | |||
312 | printk(KERN_DEBUG "mesh: state at %p, regs at %p, dma at %p\n", | ||
313 | ms, mr, md); | ||
314 | printk(KERN_DEBUG " ct=%4x seq=%2x bs=%4x fc=%2x " | ||
315 | "exc=%2x err=%2x im=%2x int=%2x sp=%2x\n", | ||
316 | (mr->count_hi << 8) + mr->count_lo, mr->sequence, | ||
317 | (mr->bus_status1 << 8) + mr->bus_status0, mr->fifo_count, | ||
318 | mr->exception, mr->error, mr->intr_mask, mr->interrupt, | ||
319 | mr->sync_params); | ||
320 | while(in_8(&mr->fifo_count)) | ||
321 | printk(KERN_DEBUG " fifo data=%.2x\n",in_8(&mr->fifo)); | ||
322 | printk(KERN_DEBUG " dma stat=%x cmdptr=%x\n", | ||
323 | in_le32(&md->status), in_le32(&md->cmdptr)); | ||
324 | printk(KERN_DEBUG " phase=%d msgphase=%d conn_tgt=%d data_ptr=%d\n", | ||
325 | ms->phase, ms->msgphase, ms->conn_tgt, ms->data_ptr); | ||
326 | printk(KERN_DEBUG " dma_st=%d dma_ct=%d n_msgout=%d\n", | ||
327 | ms->dma_started, ms->dma_count, ms->n_msgout); | ||
328 | for (t = 0; t < 8; ++t) { | ||
329 | tp = &ms->tgts[t]; | ||
330 | if (tp->current_req == NULL) | ||
331 | continue; | ||
332 | printk(KERN_DEBUG " target %d: req=%p goes_out=%d saved_ptr=%d\n", | ||
333 | t, tp->current_req, tp->data_goes_out, tp->saved_ptr); | ||
334 | } | ||
335 | } | ||
336 | |||
337 | |||
338 | /* | ||
339 | * Flush write buffers on the bus path to the mesh | ||
340 | */ | ||
341 | static inline void mesh_flush_io(volatile struct mesh_regs __iomem *mr) | ||
342 | { | ||
343 | (void)in_8(&mr->mesh_id); | ||
344 | } | ||
345 | |||
346 | |||
347 | /* | ||
348 | * Complete a SCSI command | ||
349 | */ | ||
350 | static void mesh_completed(struct mesh_state *ms, struct scsi_cmnd *cmd) | ||
351 | { | ||
352 | (*cmd->scsi_done)(cmd); | ||
353 | } | ||
354 | |||
355 | |||
356 | /* Called with meshinterrupt disabled, initialize the chipset | ||
357 | * and eventually do the initial bus reset. The lock must not be | ||
358 | * held since we can schedule. | ||
359 | */ | ||
360 | static void mesh_init(struct mesh_state *ms) | ||
361 | { | ||
362 | volatile struct mesh_regs __iomem *mr = ms->mesh; | ||
363 | volatile struct dbdma_regs __iomem *md = ms->dma; | ||
364 | |||
365 | mesh_flush_io(mr); | ||
366 | udelay(100); | ||
367 | |||
368 | /* Reset controller */ | ||
369 | out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* stop dma */ | ||
370 | out_8(&mr->exception, 0xff); /* clear all exception bits */ | ||
371 | out_8(&mr->error, 0xff); /* clear all error bits */ | ||
372 | out_8(&mr->sequence, SEQ_RESETMESH); | ||
373 | mesh_flush_io(mr); | ||
374 | udelay(10); | ||
375 | out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); | ||
376 | out_8(&mr->source_id, ms->host->this_id); | ||
377 | out_8(&mr->sel_timeout, 25); /* 250ms */ | ||
378 | out_8(&mr->sync_params, ASYNC_PARAMS); | ||
379 | |||
380 | if (init_reset_delay) { | ||
381 | printk(KERN_INFO "mesh: performing initial bus reset...\n"); | ||
382 | |||
383 | /* Reset bus */ | ||
384 | out_8(&mr->bus_status1, BS1_RST); /* assert RST */ | ||
385 | mesh_flush_io(mr); | ||
386 | udelay(30); /* leave it on for >= 25us */ | ||
387 | out_8(&mr->bus_status1, 0); /* negate RST */ | ||
388 | mesh_flush_io(mr); | ||
389 | |||
390 | /* Wait for bus to come back */ | ||
391 | msleep(init_reset_delay); | ||
392 | } | ||
393 | |||
394 | /* Reconfigure controller */ | ||
395 | out_8(&mr->interrupt, 0xff); /* clear all interrupt bits */ | ||
396 | out_8(&mr->sequence, SEQ_FLUSHFIFO); | ||
397 | mesh_flush_io(mr); | ||
398 | udelay(1); | ||
399 | out_8(&mr->sync_params, ASYNC_PARAMS); | ||
400 | out_8(&mr->sequence, SEQ_ENBRESEL); | ||
401 | |||
402 | ms->phase = idle; | ||
403 | ms->msgphase = msg_none; | ||
404 | } | ||
405 | |||
406 | |||
407 | static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd) | ||
408 | { | ||
409 | volatile struct mesh_regs __iomem *mr = ms->mesh; | ||
410 | int t, id; | ||
411 | |||
412 | id = cmd->device->id; | ||
413 | ms->current_req = cmd; | ||
414 | ms->tgts[id].data_goes_out = cmd->sc_data_direction == DMA_TO_DEVICE; | ||
415 | ms->tgts[id].current_req = cmd; | ||
416 | |||
417 | #if 1 | ||
418 | if (DEBUG_TARGET(cmd)) { | ||
419 | int i; | ||
420 | printk(KERN_DEBUG "mesh_start: %p ser=%lu tgt=%d cmd=", | ||
421 | cmd, cmd->serial_number, id); | ||
422 | for (i = 0; i < cmd->cmd_len; ++i) | ||
423 | printk(" %x", cmd->cmnd[i]); | ||
424 | printk(" use_sg=%d buffer=%p bufflen=%u\n", | ||
425 | cmd->use_sg, cmd->request_buffer, cmd->request_bufflen); | ||
426 | } | ||
427 | #endif | ||
428 | if (ms->dma_started) | ||
429 | panic("mesh: double DMA start !\n"); | ||
430 | |||
431 | ms->phase = arbitrating; | ||
432 | ms->msgphase = msg_none; | ||
433 | ms->data_ptr = 0; | ||
434 | ms->dma_started = 0; | ||
435 | ms->n_msgout = 0; | ||
436 | ms->last_n_msgout = 0; | ||
437 | ms->expect_reply = 0; | ||
438 | ms->conn_tgt = id; | ||
439 | ms->tgts[id].saved_ptr = 0; | ||
440 | ms->stat = DID_OK; | ||
441 | ms->aborting = 0; | ||
442 | #ifdef MESH_DBG | ||
443 | ms->tgts[id].n_log = 0; | ||
444 | dlog(ms, "start cmd=%x", (int) cmd); | ||
445 | #endif | ||
446 | |||
447 | /* Off we go */ | ||
448 | dlog(ms, "about to arb, intr/exc/err/fc=%.8x", | ||
449 | MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count)); | ||
450 | out_8(&mr->interrupt, INT_CMDDONE); | ||
451 | out_8(&mr->sequence, SEQ_ENBRESEL); | ||
452 | mesh_flush_io(mr); | ||
453 | udelay(1); | ||
454 | |||
455 | if (in_8(&mr->bus_status1) & (BS1_BSY | BS1_SEL)) { | ||
456 | /* | ||
457 | * Some other device has the bus or is arbitrating for it - | ||
458 | * probably a target which is about to reselect us. | ||
459 | */ | ||
460 | dlog(ms, "busy b4 arb, intr/exc/err/fc=%.8x", | ||
461 | MKWORD(mr->interrupt, mr->exception, | ||
462 | mr->error, mr->fifo_count)); | ||
463 | for (t = 100; t > 0; --t) { | ||
464 | if ((in_8(&mr->bus_status1) & (BS1_BSY | BS1_SEL)) == 0) | ||
465 | break; | ||
466 | if (in_8(&mr->interrupt) != 0) { | ||
467 | dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x", | ||
468 | MKWORD(mr->interrupt, mr->exception, | ||
469 | mr->error, mr->fifo_count)); | ||
470 | mesh_interrupt(0, (void *)ms, NULL); | ||
471 | if (ms->phase != arbitrating) | ||
472 | return; | ||
473 | } | ||
474 | udelay(1); | ||
475 | } | ||
476 | if (in_8(&mr->bus_status1) & (BS1_BSY | BS1_SEL)) { | ||
477 | /* XXX should try again in a little while */ | ||
478 | ms->stat = DID_BUS_BUSY; | ||
479 | ms->phase = idle; | ||
480 | mesh_done(ms, 0); | ||
481 | return; | ||
482 | } | ||
483 | } | ||
484 | |||
485 | /* | ||
486 | * Apparently the mesh has a bug where it will assert both its | ||
487 | * own bit and the target's bit on the bus during arbitration. | ||
488 | */ | ||
489 | out_8(&mr->dest_id, mr->source_id); | ||
490 | |||
491 | /* | ||
492 | * There appears to be a race with reselection sometimes, | ||
493 | * where a target reselects us just as we issue the | ||
494 | * arbitrate command. It seems that then the arbitrate | ||
495 | * command just hangs waiting for the bus to be free | ||
496 | * without giving us a reselection exception. | ||
497 | * The only way I have found to get it to respond correctly | ||
498 | * is this: disable reselection before issuing the arbitrate | ||
499 | * command, then after issuing it, if it looks like a target | ||
500 | * is trying to reselect us, reset the mesh and then enable | ||
501 | * reselection. | ||
502 | */ | ||
503 | out_8(&mr->sequence, SEQ_DISRESEL); | ||
504 | if (in_8(&mr->interrupt) != 0) { | ||
505 | dlog(ms, "intr after disresel, intr/exc/err/fc=%.8x", | ||
506 | MKWORD(mr->interrupt, mr->exception, | ||
507 | mr->error, mr->fifo_count)); | ||
508 | mesh_interrupt(0, (void *)ms, NULL); | ||
509 | if (ms->phase != arbitrating) | ||
510 | return; | ||
511 | dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x", | ||
512 | MKWORD(mr->interrupt, mr->exception, | ||
513 | mr->error, mr->fifo_count)); | ||
514 | } | ||
515 | |||
516 | out_8(&mr->sequence, SEQ_ARBITRATE); | ||
517 | |||
518 | for (t = 230; t > 0; --t) { | ||
519 | if (in_8(&mr->interrupt) != 0) | ||
520 | break; | ||
521 | udelay(1); | ||
522 | } | ||
523 | dlog(ms, "after arb, intr/exc/err/fc=%.8x", | ||
524 | MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count)); | ||
525 | if (in_8(&mr->interrupt) == 0 && (in_8(&mr->bus_status1) & BS1_SEL) | ||
526 | && (in_8(&mr->bus_status0) & BS0_IO)) { | ||
527 | /* looks like a reselection - try resetting the mesh */ | ||
528 | dlog(ms, "resel? after arb, intr/exc/err/fc=%.8x", | ||
529 | MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count)); | ||
530 | out_8(&mr->sequence, SEQ_RESETMESH); | ||
531 | mesh_flush_io(mr); | ||
532 | udelay(10); | ||
533 | out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); | ||
534 | out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); | ||
535 | out_8(&mr->sequence, SEQ_ENBRESEL); | ||
536 | mesh_flush_io(mr); | ||
537 | for (t = 10; t > 0 && in_8(&mr->interrupt) == 0; --t) | ||
538 | udelay(1); | ||
539 | dlog(ms, "tried reset after arb, intr/exc/err/fc=%.8x", | ||
540 | MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count)); | ||
541 | #ifndef MESH_MULTIPLE_HOSTS | ||
542 | if (in_8(&mr->interrupt) == 0 && (in_8(&mr->bus_status1) & BS1_SEL) | ||
543 | && (in_8(&mr->bus_status0) & BS0_IO)) { | ||
544 | printk(KERN_ERR "mesh: controller not responding" | ||
545 | " to reselection!\n"); | ||
546 | /* | ||
547 | * If this is a target reselecting us, and the | ||
548 | * mesh isn't responding, the higher levels of | ||
549 | * the scsi code will eventually time out and | ||
550 | * reset the bus. | ||
551 | */ | ||
552 | } | ||
553 | #endif | ||
554 | } | ||
555 | } | ||
556 | |||
557 | /* | ||
558 | * Start the next command for a MESH. | ||
559 | * Should be called with interrupts disabled. | ||
560 | */ | ||
561 | static void mesh_start(struct mesh_state *ms) | ||
562 | { | ||
563 | struct scsi_cmnd *cmd, *prev, *next; | ||
564 | |||
565 | if (ms->phase != idle || ms->current_req != NULL) { | ||
566 | printk(KERN_ERR "inappropriate mesh_start (phase=%d, ms=%p)", | ||
567 | ms->phase, ms); | ||
568 | return; | ||
569 | } | ||
570 | |||
571 | while (ms->phase == idle) { | ||
572 | prev = NULL; | ||
573 | for (cmd = ms->request_q; ; cmd = (struct scsi_cmnd *) cmd->host_scribble) { | ||
574 | if (cmd == NULL) | ||
575 | return; | ||
576 | if (ms->tgts[cmd->device->id].current_req == NULL) | ||
577 | break; | ||
578 | prev = cmd; | ||
579 | } | ||
580 | next = (struct scsi_cmnd *) cmd->host_scribble; | ||
581 | if (prev == NULL) | ||
582 | ms->request_q = next; | ||
583 | else | ||
584 | prev->host_scribble = (void *) next; | ||
585 | if (next == NULL) | ||
586 | ms->request_qtail = prev; | ||
587 | |||
588 | mesh_start_cmd(ms, cmd); | ||
589 | } | ||
590 | } | ||
591 | |||
592 | static void mesh_done(struct mesh_state *ms, int start_next) | ||
593 | { | ||
594 | struct scsi_cmnd *cmd; | ||
595 | struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; | ||
596 | |||
597 | cmd = ms->current_req; | ||
598 | ms->current_req = NULL; | ||
599 | tp->current_req = NULL; | ||
600 | if (cmd) { | ||
601 | cmd->result = (ms->stat << 16) + cmd->SCp.Status; | ||
602 | if (ms->stat == DID_OK) | ||
603 | cmd->result += (cmd->SCp.Message << 8); | ||
604 | if (DEBUG_TARGET(cmd)) { | ||
605 | printk(KERN_DEBUG "mesh_done: result = %x, data_ptr=%d, buflen=%d\n", | ||
606 | cmd->result, ms->data_ptr, cmd->request_bufflen); | ||
607 | if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12 || cmd->cmnd[0] == 3) | ||
608 | && cmd->request_buffer != 0) { | ||
609 | unsigned char *b = cmd->request_buffer; | ||
610 | printk(KERN_DEBUG "buffer = %x %x %x %x %x %x %x %x\n", | ||
611 | b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); | ||
612 | } | ||
613 | } | ||
614 | cmd->SCp.this_residual -= ms->data_ptr; | ||
615 | mesh_completed(ms, cmd); | ||
616 | } | ||
617 | if (start_next) { | ||
618 | out_8(&ms->mesh->sequence, SEQ_ENBRESEL); | ||
619 | mesh_flush_io(ms->mesh); | ||
620 | udelay(1); | ||
621 | ms->phase = idle; | ||
622 | mesh_start(ms); | ||
623 | } | ||
624 | } | ||
625 | |||
626 | static inline void add_sdtr_msg(struct mesh_state *ms) | ||
627 | { | ||
628 | int i = ms->n_msgout; | ||
629 | |||
630 | ms->msgout[i] = EXTENDED_MESSAGE; | ||
631 | ms->msgout[i+1] = 3; | ||
632 | ms->msgout[i+2] = EXTENDED_SDTR; | ||
633 | ms->msgout[i+3] = mesh_sync_period/4; | ||
634 | ms->msgout[i+4] = (ALLOW_SYNC(ms->conn_tgt)? mesh_sync_offset: 0); | ||
635 | ms->n_msgout = i + 5; | ||
636 | } | ||
637 | |||
638 | static void set_sdtr(struct mesh_state *ms, int period, int offset) | ||
639 | { | ||
640 | struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; | ||
641 | volatile struct mesh_regs __iomem *mr = ms->mesh; | ||
642 | int v, tr; | ||
643 | |||
644 | tp->sdtr_state = sdtr_done; | ||
645 | if (offset == 0) { | ||
646 | /* asynchronous */ | ||
647 | if (SYNC_OFF(tp->sync_params)) | ||
648 | printk(KERN_INFO "mesh: target %d now asynchronous\n", | ||
649 | ms->conn_tgt); | ||
650 | tp->sync_params = ASYNC_PARAMS; | ||
651 | out_8(&mr->sync_params, ASYNC_PARAMS); | ||
652 | return; | ||
653 | } | ||
654 | /* | ||
655 | * We need to compute ceil(clk_freq * period / 500e6) - 2 | ||
656 | * without incurring overflow. | ||
657 | */ | ||
658 | v = (ms->clk_freq / 5000) * period; | ||
659 | if (v <= 250000) { | ||
660 | /* special case: sync_period == 5 * clk_period */ | ||
661 | v = 0; | ||
662 | /* units of tr are 100kB/s */ | ||
663 | tr = (ms->clk_freq + 250000) / 500000; | ||
664 | } else { | ||
665 | /* sync_period == (v + 2) * 2 * clk_period */ | ||
666 | v = (v + 99999) / 100000 - 2; | ||
667 | if (v > 15) | ||
668 | v = 15; /* oops */ | ||
669 | tr = ((ms->clk_freq / (v + 2)) + 199999) / 200000; | ||
670 | } | ||
671 | if (offset > 15) | ||
672 | offset = 15; /* can't happen */ | ||
673 | tp->sync_params = SYNC_PARAMS(offset, v); | ||
674 | out_8(&mr->sync_params, tp->sync_params); | ||
675 | printk(KERN_INFO "mesh: target %d synchronous at %d.%d MB/s\n", | ||
676 | ms->conn_tgt, tr/10, tr%10); | ||
677 | } | ||
678 | |||
679 | static void start_phase(struct mesh_state *ms) | ||
680 | { | ||
681 | int i, seq, nb; | ||
682 | volatile struct mesh_regs __iomem *mr = ms->mesh; | ||
683 | volatile struct dbdma_regs __iomem *md = ms->dma; | ||
684 | struct scsi_cmnd *cmd = ms->current_req; | ||
685 | struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; | ||
686 | |||
687 | dlog(ms, "start_phase nmo/exc/fc/seq = %.8x", | ||
688 | MKWORD(ms->n_msgout, mr->exception, mr->fifo_count, mr->sequence)); | ||
689 | out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); | ||
690 | seq = use_active_neg + (ms->n_msgout? SEQ_ATN: 0); | ||
691 | switch (ms->msgphase) { | ||
692 | case msg_none: | ||
693 | break; | ||
694 | |||
695 | case msg_in: | ||
696 | out_8(&mr->count_hi, 0); | ||
697 | out_8(&mr->count_lo, 1); | ||
698 | out_8(&mr->sequence, SEQ_MSGIN + seq); | ||
699 | ms->n_msgin = 0; | ||
700 | return; | ||
701 | |||
702 | case msg_out: | ||
703 | /* | ||
704 | * To make sure ATN drops before we assert ACK for | ||
705 | * the last byte of the message, we have to do the | ||
706 | * last byte specially. | ||
707 | */ | ||
708 | if (ms->n_msgout <= 0) { | ||
709 | printk(KERN_ERR "mesh: msg_out but n_msgout=%d\n", | ||
710 | ms->n_msgout); | ||
711 | mesh_dump_regs(ms); | ||
712 | ms->msgphase = msg_none; | ||
713 | break; | ||
714 | } | ||
715 | if (ALLOW_DEBUG(ms->conn_tgt)) { | ||
716 | printk(KERN_DEBUG "mesh: sending %d msg bytes:", | ||
717 | ms->n_msgout); | ||
718 | for (i = 0; i < ms->n_msgout; ++i) | ||
719 | printk(" %x", ms->msgout[i]); | ||
720 | printk("\n"); | ||
721 | } | ||
722 | dlog(ms, "msgout msg=%.8x", MKWORD(ms->n_msgout, ms->msgout[0], | ||
723 | ms->msgout[1], ms->msgout[2])); | ||
724 | out_8(&mr->count_hi, 0); | ||
725 | out_8(&mr->sequence, SEQ_FLUSHFIFO); | ||
726 | mesh_flush_io(mr); | ||
727 | udelay(1); | ||
728 | /* | ||
729 | * If ATN is not already asserted, we assert it, then | ||
730 | * issue a SEQ_MSGOUT to get the mesh to drop ACK. | ||
731 | */ | ||
732 | if ((in_8(&mr->bus_status0) & BS0_ATN) == 0) { | ||
733 | dlog(ms, "bus0 was %.2x explictly asserting ATN", mr->bus_status0); | ||
734 | out_8(&mr->bus_status0, BS0_ATN); /* explicit ATN */ | ||
735 | mesh_flush_io(mr); | ||
736 | udelay(1); | ||
737 | out_8(&mr->count_lo, 1); | ||
738 | out_8(&mr->sequence, SEQ_MSGOUT + seq); | ||
739 | out_8(&mr->bus_status0, 0); /* release explicit ATN */ | ||
740 | dlog(ms,"hace: after explicit ATN bus0=%.2x",mr->bus_status0); | ||
741 | } | ||
742 | if (ms->n_msgout == 1) { | ||
743 | /* | ||
744 | * We can't issue the SEQ_MSGOUT without ATN | ||
745 | * until the target has asserted REQ. The logic | ||
746 | * in cmd_complete handles both situations: | ||
747 | * REQ already asserted or not. | ||
748 | */ | ||
749 | cmd_complete(ms); | ||
750 | } else { | ||
751 | out_8(&mr->count_lo, ms->n_msgout - 1); | ||
752 | out_8(&mr->sequence, SEQ_MSGOUT + seq); | ||
753 | for (i = 0; i < ms->n_msgout - 1; ++i) | ||
754 | out_8(&mr->fifo, ms->msgout[i]); | ||
755 | } | ||
756 | return; | ||
757 | |||
758 | default: | ||
759 | printk(KERN_ERR "mesh bug: start_phase msgphase=%d\n", | ||
760 | ms->msgphase); | ||
761 | } | ||
762 | |||
763 | switch (ms->phase) { | ||
764 | case selecting: | ||
765 | out_8(&mr->dest_id, ms->conn_tgt); | ||
766 | out_8(&mr->sequence, SEQ_SELECT + SEQ_ATN); | ||
767 | break; | ||
768 | case commanding: | ||
769 | out_8(&mr->sync_params, tp->sync_params); | ||
770 | out_8(&mr->count_hi, 0); | ||
771 | if (cmd) { | ||
772 | out_8(&mr->count_lo, cmd->cmd_len); | ||
773 | out_8(&mr->sequence, SEQ_COMMAND + seq); | ||
774 | for (i = 0; i < cmd->cmd_len; ++i) | ||
775 | out_8(&mr->fifo, cmd->cmnd[i]); | ||
776 | } else { | ||
777 | out_8(&mr->count_lo, 6); | ||
778 | out_8(&mr->sequence, SEQ_COMMAND + seq); | ||
779 | for (i = 0; i < 6; ++i) | ||
780 | out_8(&mr->fifo, 0); | ||
781 | } | ||
782 | break; | ||
783 | case dataing: | ||
784 | /* transfer data, if any */ | ||
785 | if (!ms->dma_started) { | ||
786 | set_dma_cmds(ms, cmd); | ||
787 | out_le32(&md->cmdptr, virt_to_phys(ms->dma_cmds)); | ||
788 | out_le32(&md->control, (RUN << 16) | RUN); | ||
789 | ms->dma_started = 1; | ||
790 | } | ||
791 | nb = ms->dma_count; | ||
792 | if (nb > 0xfff0) | ||
793 | nb = 0xfff0; | ||
794 | ms->dma_count -= nb; | ||
795 | ms->data_ptr += nb; | ||
796 | out_8(&mr->count_lo, nb); | ||
797 | out_8(&mr->count_hi, nb >> 8); | ||
798 | out_8(&mr->sequence, (tp->data_goes_out? | ||
799 | SEQ_DATAOUT: SEQ_DATAIN) + SEQ_DMA_MODE + seq); | ||
800 | break; | ||
801 | case statusing: | ||
802 | out_8(&mr->count_hi, 0); | ||
803 | out_8(&mr->count_lo, 1); | ||
804 | out_8(&mr->sequence, SEQ_STATUS + seq); | ||
805 | break; | ||
806 | case busfreeing: | ||
807 | case disconnecting: | ||
808 | out_8(&mr->sequence, SEQ_ENBRESEL); | ||
809 | mesh_flush_io(mr); | ||
810 | udelay(1); | ||
811 | dlog(ms, "enbresel intr/exc/err/fc=%.8x", | ||
812 | MKWORD(mr->interrupt, mr->exception, mr->error, | ||
813 | mr->fifo_count)); | ||
814 | out_8(&mr->sequence, SEQ_BUSFREE); | ||
815 | break; | ||
816 | default: | ||
817 | printk(KERN_ERR "mesh: start_phase called with phase=%d\n", | ||
818 | ms->phase); | ||
819 | dumpslog(ms); | ||
820 | } | ||
821 | |||
822 | } | ||
823 | |||
824 | static inline void get_msgin(struct mesh_state *ms) | ||
825 | { | ||
826 | volatile struct mesh_regs __iomem *mr = ms->mesh; | ||
827 | int i, n; | ||
828 | |||
829 | n = mr->fifo_count; | ||
830 | if (n != 0) { | ||
831 | i = ms->n_msgin; | ||
832 | ms->n_msgin = i + n; | ||
833 | for (; n > 0; --n) | ||
834 | ms->msgin[i++] = in_8(&mr->fifo); | ||
835 | } | ||
836 | } | ||
837 | |||
838 | static inline int msgin_length(struct mesh_state *ms) | ||
839 | { | ||
840 | int b, n; | ||
841 | |||
842 | n = 1; | ||
843 | if (ms->n_msgin > 0) { | ||
844 | b = ms->msgin[0]; | ||
845 | if (b == 1) { | ||
846 | /* extended message */ | ||
847 | n = ms->n_msgin < 2? 2: ms->msgin[1] + 2; | ||
848 | } else if (0x20 <= b && b <= 0x2f) { | ||
849 | /* 2-byte message */ | ||
850 | n = 2; | ||
851 | } | ||
852 | } | ||
853 | return n; | ||
854 | } | ||
855 | |||
856 | static void reselected(struct mesh_state *ms) | ||
857 | { | ||
858 | volatile struct mesh_regs __iomem *mr = ms->mesh; | ||
859 | struct scsi_cmnd *cmd; | ||
860 | struct mesh_target *tp; | ||
861 | int b, t, prev; | ||
862 | |||
863 | switch (ms->phase) { | ||
864 | case idle: | ||
865 | break; | ||
866 | case arbitrating: | ||
867 | if ((cmd = ms->current_req) != NULL) { | ||
868 | /* put the command back on the queue */ | ||
869 | cmd->host_scribble = (void *) ms->request_q; | ||
870 | if (ms->request_q == NULL) | ||
871 | ms->request_qtail = cmd; | ||
872 | ms->request_q = cmd; | ||
873 | tp = &ms->tgts[cmd->device->id]; | ||
874 | tp->current_req = NULL; | ||
875 | } | ||
876 | break; | ||
877 | case busfreeing: | ||
878 | ms->phase = reselecting; | ||
879 | mesh_done(ms, 0); | ||
880 | break; | ||
881 | case disconnecting: | ||
882 | break; | ||
883 | default: | ||
884 | printk(KERN_ERR "mesh: reselected in phase %d/%d tgt %d\n", | ||
885 | ms->msgphase, ms->phase, ms->conn_tgt); | ||
886 | dumplog(ms, ms->conn_tgt); | ||
887 | dumpslog(ms); | ||
888 | } | ||
889 | |||
890 | if (ms->dma_started) { | ||
891 | printk(KERN_ERR "mesh: reselected with DMA started !\n"); | ||
892 | halt_dma(ms); | ||
893 | } | ||
894 | ms->current_req = NULL; | ||
895 | ms->phase = dataing; | ||
896 | ms->msgphase = msg_in; | ||
897 | ms->n_msgout = 0; | ||
898 | ms->last_n_msgout = 0; | ||
899 | prev = ms->conn_tgt; | ||
900 | |||
901 | /* | ||
902 | * We seem to get abortive reselections sometimes. | ||
903 | */ | ||
904 | while ((in_8(&mr->bus_status1) & BS1_BSY) == 0) { | ||
905 | static int mesh_aborted_resels; | ||
906 | mesh_aborted_resels++; | ||
907 | out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); | ||
908 | mesh_flush_io(mr); | ||
909 | udelay(1); | ||
910 | out_8(&mr->sequence, SEQ_ENBRESEL); | ||
911 | mesh_flush_io(mr); | ||
912 | udelay(5); | ||
913 | dlog(ms, "extra resel err/exc/fc = %.6x", | ||
914 | MKWORD(0, mr->error, mr->exception, mr->fifo_count)); | ||
915 | } | ||
916 | out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); | ||
917 | mesh_flush_io(mr); | ||
918 | udelay(1); | ||
919 | out_8(&mr->sequence, SEQ_ENBRESEL); | ||
920 | mesh_flush_io(mr); | ||
921 | udelay(1); | ||
922 | out_8(&mr->sync_params, ASYNC_PARAMS); | ||
923 | |||
924 | /* | ||
925 | * Find out who reselected us. | ||
926 | */ | ||
927 | if (in_8(&mr->fifo_count) == 0) { | ||
928 | printk(KERN_ERR "mesh: reselection but nothing in fifo?\n"); | ||
929 | ms->conn_tgt = ms->host->this_id; | ||
930 | goto bogus; | ||
931 | } | ||
932 | /* get the last byte in the fifo */ | ||
933 | do { | ||
934 | b = in_8(&mr->fifo); | ||
935 | dlog(ms, "reseldata %x", b); | ||
936 | } while (in_8(&mr->fifo_count)); | ||
937 | for (t = 0; t < 8; ++t) | ||
938 | if ((b & (1 << t)) != 0 && t != ms->host->this_id) | ||
939 | break; | ||
940 | if (b != (1 << t) + (1 << ms->host->this_id)) { | ||
941 | printk(KERN_ERR "mesh: bad reselection data %x\n", b); | ||
942 | ms->conn_tgt = ms->host->this_id; | ||
943 | goto bogus; | ||
944 | } | ||
945 | |||
946 | |||
947 | /* | ||
948 | * Set up to continue with that target's transfer. | ||
949 | */ | ||
950 | ms->conn_tgt = t; | ||
951 | tp = &ms->tgts[t]; | ||
952 | out_8(&mr->sync_params, tp->sync_params); | ||
953 | if (ALLOW_DEBUG(t)) { | ||
954 | printk(KERN_DEBUG "mesh: reselected by target %d\n", t); | ||
955 | printk(KERN_DEBUG "mesh: saved_ptr=%x goes_out=%d cmd=%p\n", | ||
956 | tp->saved_ptr, tp->data_goes_out, tp->current_req); | ||
957 | } | ||
958 | ms->current_req = tp->current_req; | ||
959 | if (tp->current_req == NULL) { | ||
960 | printk(KERN_ERR "mesh: reselected by tgt %d but no cmd!\n", t); | ||
961 | goto bogus; | ||
962 | } | ||
963 | ms->data_ptr = tp->saved_ptr; | ||
964 | dlog(ms, "resel prev tgt=%d", prev); | ||
965 | dlog(ms, "resel err/exc=%.4x", MKWORD(0, 0, mr->error, mr->exception)); | ||
966 | start_phase(ms); | ||
967 | return; | ||
968 | |||
969 | bogus: | ||
970 | dumplog(ms, ms->conn_tgt); | ||
971 | dumpslog(ms); | ||
972 | ms->data_ptr = 0; | ||
973 | ms->aborting = 1; | ||
974 | start_phase(ms); | ||
975 | } | ||
976 | |||
977 | static void do_abort(struct mesh_state *ms) | ||
978 | { | ||
979 | ms->msgout[0] = ABORT; | ||
980 | ms->n_msgout = 1; | ||
981 | ms->aborting = 1; | ||
982 | ms->stat = DID_ABORT; | ||
983 | dlog(ms, "abort", 0); | ||
984 | } | ||
985 | |||
986 | static void handle_reset(struct mesh_state *ms) | ||
987 | { | ||
988 | int tgt; | ||
989 | struct mesh_target *tp; | ||
990 | struct scsi_cmnd *cmd; | ||
991 | volatile struct mesh_regs __iomem *mr = ms->mesh; | ||
992 | |||
993 | for (tgt = 0; tgt < 8; ++tgt) { | ||
994 | tp = &ms->tgts[tgt]; | ||
995 | if ((cmd = tp->current_req) != NULL) { | ||
996 | cmd->result = DID_RESET << 16; | ||
997 | tp->current_req = NULL; | ||
998 | mesh_completed(ms, cmd); | ||
999 | } | ||
1000 | ms->tgts[tgt].sdtr_state = do_sdtr; | ||
1001 | ms->tgts[tgt].sync_params = ASYNC_PARAMS; | ||
1002 | } | ||
1003 | ms->current_req = NULL; | ||
1004 | while ((cmd = ms->request_q) != NULL) { | ||
1005 | ms->request_q = (struct scsi_cmnd *) cmd->host_scribble; | ||
1006 | cmd->result = DID_RESET << 16; | ||
1007 | mesh_completed(ms, cmd); | ||
1008 | } | ||
1009 | ms->phase = idle; | ||
1010 | ms->msgphase = msg_none; | ||
1011 | out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); | ||
1012 | out_8(&mr->sequence, SEQ_FLUSHFIFO); | ||
1013 | mesh_flush_io(mr); | ||
1014 | udelay(1); | ||
1015 | out_8(&mr->sync_params, ASYNC_PARAMS); | ||
1016 | out_8(&mr->sequence, SEQ_ENBRESEL); | ||
1017 | } | ||
1018 | |||
1019 | static irqreturn_t do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) | ||
1020 | { | ||
1021 | unsigned long flags; | ||
1022 | struct Scsi_Host *dev = ((struct mesh_state *)dev_id)->host; | ||
1023 | |||
1024 | spin_lock_irqsave(dev->host_lock, flags); | ||
1025 | mesh_interrupt(irq, dev_id, ptregs); | ||
1026 | spin_unlock_irqrestore(dev->host_lock, flags); | ||
1027 | return IRQ_HANDLED; | ||
1028 | } | ||
1029 | |||
1030 | static void handle_error(struct mesh_state *ms) | ||
1031 | { | ||
1032 | int err, exc, count; | ||
1033 | volatile struct mesh_regs __iomem *mr = ms->mesh; | ||
1034 | |||
1035 | err = in_8(&mr->error); | ||
1036 | exc = in_8(&mr->exception); | ||
1037 | out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); | ||
1038 | dlog(ms, "error err/exc/fc/cl=%.8x", | ||
1039 | MKWORD(err, exc, mr->fifo_count, mr->count_lo)); | ||
1040 | if (err & ERR_SCSIRESET) { | ||
1041 | /* SCSI bus was reset */ | ||
1042 | printk(KERN_INFO "mesh: SCSI bus reset detected: " | ||
1043 | "waiting for end..."); | ||
1044 | while ((in_8(&mr->bus_status1) & BS1_RST) != 0) | ||
1045 | udelay(1); | ||
1046 | printk("done\n"); | ||
1047 | handle_reset(ms); | ||
1048 | /* request_q is empty, no point in mesh_start() */ | ||
1049 | return; | ||
1050 | } | ||
1051 | if (err & ERR_UNEXPDISC) { | ||
1052 | /* Unexpected disconnect */ | ||
1053 | if (exc & EXC_RESELECTED) { | ||
1054 | reselected(ms); | ||
1055 | return; | ||
1056 | } | ||
1057 | if (!ms->aborting) { | ||
1058 | printk(KERN_WARNING "mesh: target %d aborted\n", | ||
1059 | ms->conn_tgt); | ||
1060 | dumplog(ms, ms->conn_tgt); | ||
1061 | dumpslog(ms); | ||
1062 | } | ||
1063 | out_8(&mr->interrupt, INT_CMDDONE); | ||
1064 | ms->stat = DID_ABORT; | ||
1065 | mesh_done(ms, 1); | ||
1066 | return; | ||
1067 | } | ||
1068 | if (err & ERR_PARITY) { | ||
1069 | if (ms->msgphase == msg_in) { | ||
1070 | printk(KERN_ERR "mesh: msg parity error, target %d\n", | ||
1071 | ms->conn_tgt); | ||
1072 | ms->msgout[0] = MSG_PARITY_ERROR; | ||
1073 | ms->n_msgout = 1; | ||
1074 | ms->msgphase = msg_in_bad; | ||
1075 | cmd_complete(ms); | ||
1076 | return; | ||
1077 | } | ||
1078 | if (ms->stat == DID_OK) { | ||
1079 | printk(KERN_ERR "mesh: parity error, target %d\n", | ||
1080 | ms->conn_tgt); | ||
1081 | ms->stat = DID_PARITY; | ||
1082 | } | ||
1083 | count = (mr->count_hi << 8) + mr->count_lo; | ||
1084 | if (count == 0) { | ||
1085 | cmd_complete(ms); | ||
1086 | } else { | ||
1087 | /* reissue the data transfer command */ | ||
1088 | out_8(&mr->sequence, mr->sequence); | ||
1089 | } | ||
1090 | return; | ||
1091 | } | ||
1092 | if (err & ERR_SEQERR) { | ||
1093 | if (exc & EXC_RESELECTED) { | ||
1094 | /* This can happen if we issue a command to | ||
1095 | get the bus just after the target reselects us. */ | ||
1096 | static int mesh_resel_seqerr; | ||
1097 | mesh_resel_seqerr++; | ||
1098 | reselected(ms); | ||
1099 | return; | ||
1100 | } | ||
1101 | if (exc == EXC_PHASEMM) { | ||
1102 | static int mesh_phasemm_seqerr; | ||
1103 | mesh_phasemm_seqerr++; | ||
1104 | phase_mismatch(ms); | ||
1105 | return; | ||
1106 | } | ||
1107 | printk(KERN_ERR "mesh: sequence error (err=%x exc=%x)\n", | ||
1108 | err, exc); | ||
1109 | } else { | ||
1110 | printk(KERN_ERR "mesh: unknown error %x (exc=%x)\n", err, exc); | ||
1111 | } | ||
1112 | mesh_dump_regs(ms); | ||
1113 | dumplog(ms, ms->conn_tgt); | ||
1114 | if (ms->phase > selecting && (in_8(&mr->bus_status1) & BS1_BSY)) { | ||
1115 | /* try to do what the target wants */ | ||
1116 | do_abort(ms); | ||
1117 | phase_mismatch(ms); | ||
1118 | return; | ||
1119 | } | ||
1120 | ms->stat = DID_ERROR; | ||
1121 | mesh_done(ms, 1); | ||
1122 | } | ||
1123 | |||
1124 | static void handle_exception(struct mesh_state *ms) | ||
1125 | { | ||
1126 | int exc; | ||
1127 | volatile struct mesh_regs __iomem *mr = ms->mesh; | ||
1128 | |||
1129 | exc = in_8(&mr->exception); | ||
1130 | out_8(&mr->interrupt, INT_EXCEPTION | INT_CMDDONE); | ||
1131 | if (exc & EXC_RESELECTED) { | ||
1132 | static int mesh_resel_exc; | ||
1133 | mesh_resel_exc++; | ||
1134 | reselected(ms); | ||
1135 | } else if (exc == EXC_ARBLOST) { | ||
1136 | printk(KERN_DEBUG "mesh: lost arbitration\n"); | ||
1137 | ms->stat = DID_BUS_BUSY; | ||
1138 | mesh_done(ms, 1); | ||
1139 | } else if (exc == EXC_SELTO) { | ||
1140 | /* selection timed out */ | ||
1141 | ms->stat = DID_BAD_TARGET; | ||
1142 | mesh_done(ms, 1); | ||
1143 | } else if (exc == EXC_PHASEMM) { | ||
1144 | /* target wants to do something different: | ||
1145 | find out what it wants and do it. */ | ||
1146 | phase_mismatch(ms); | ||
1147 | } else { | ||
1148 | printk(KERN_ERR "mesh: can't cope with exception %x\n", exc); | ||
1149 | mesh_dump_regs(ms); | ||
1150 | dumplog(ms, ms->conn_tgt); | ||
1151 | do_abort(ms); | ||
1152 | phase_mismatch(ms); | ||
1153 | } | ||
1154 | } | ||
1155 | |||
1156 | static void handle_msgin(struct mesh_state *ms) | ||
1157 | { | ||
1158 | int i, code; | ||
1159 | struct scsi_cmnd *cmd = ms->current_req; | ||
1160 | struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; | ||
1161 | |||
1162 | if (ms->n_msgin == 0) | ||
1163 | return; | ||
1164 | code = ms->msgin[0]; | ||
1165 | if (ALLOW_DEBUG(ms->conn_tgt)) { | ||
1166 | printk(KERN_DEBUG "got %d message bytes:", ms->n_msgin); | ||
1167 | for (i = 0; i < ms->n_msgin; ++i) | ||
1168 | printk(" %x", ms->msgin[i]); | ||
1169 | printk("\n"); | ||
1170 | } | ||
1171 | dlog(ms, "msgin msg=%.8x", | ||
1172 | MKWORD(ms->n_msgin, code, ms->msgin[1], ms->msgin[2])); | ||
1173 | |||
1174 | ms->expect_reply = 0; | ||
1175 | ms->n_msgout = 0; | ||
1176 | if (ms->n_msgin < msgin_length(ms)) | ||
1177 | goto reject; | ||
1178 | if (cmd) | ||
1179 | cmd->SCp.Message = code; | ||
1180 | switch (code) { | ||
1181 | case COMMAND_COMPLETE: | ||
1182 | break; | ||
1183 | case EXTENDED_MESSAGE: | ||
1184 | switch (ms->msgin[2]) { | ||
1185 | case EXTENDED_MODIFY_DATA_POINTER: | ||
1186 | ms->data_ptr += (ms->msgin[3] << 24) + ms->msgin[6] | ||
1187 | + (ms->msgin[4] << 16) + (ms->msgin[5] << 8); | ||
1188 | break; | ||
1189 | case EXTENDED_SDTR: | ||
1190 | if (tp->sdtr_state != sdtr_sent) { | ||
1191 | /* reply with an SDTR */ | ||
1192 | add_sdtr_msg(ms); | ||
1193 | /* limit period to at least his value, | ||
1194 | offset to no more than his */ | ||
1195 | if (ms->msgout[3] < ms->msgin[3]) | ||
1196 | ms->msgout[3] = ms->msgin[3]; | ||
1197 | if (ms->msgout[4] > ms->msgin[4]) | ||
1198 | ms->msgout[4] = ms->msgin[4]; | ||
1199 | set_sdtr(ms, ms->msgout[3], ms->msgout[4]); | ||
1200 | ms->msgphase = msg_out; | ||
1201 | } else { | ||
1202 | set_sdtr(ms, ms->msgin[3], ms->msgin[4]); | ||
1203 | } | ||
1204 | break; | ||
1205 | default: | ||
1206 | goto reject; | ||
1207 | } | ||
1208 | break; | ||
1209 | case SAVE_POINTERS: | ||
1210 | tp->saved_ptr = ms->data_ptr; | ||
1211 | break; | ||
1212 | case RESTORE_POINTERS: | ||
1213 | ms->data_ptr = tp->saved_ptr; | ||
1214 | break; | ||
1215 | case DISCONNECT: | ||
1216 | ms->phase = disconnecting; | ||
1217 | break; | ||
1218 | case ABORT: | ||
1219 | break; | ||
1220 | case MESSAGE_REJECT: | ||
1221 | if (tp->sdtr_state == sdtr_sent) | ||
1222 | set_sdtr(ms, 0, 0); | ||
1223 | break; | ||
1224 | case NOP: | ||
1225 | break; | ||
1226 | default: | ||
1227 | if (IDENTIFY_BASE <= code && code <= IDENTIFY_BASE + 7) { | ||
1228 | if (cmd == NULL) { | ||
1229 | do_abort(ms); | ||
1230 | ms->msgphase = msg_out; | ||
1231 | } else if (code != cmd->device->lun + IDENTIFY_BASE) { | ||
1232 | printk(KERN_WARNING "mesh: lun mismatch " | ||
1233 | "(%d != %d) on reselection from " | ||
1234 | "target %d\n", code - IDENTIFY_BASE, | ||
1235 | cmd->device->lun, ms->conn_tgt); | ||
1236 | } | ||
1237 | break; | ||
1238 | } | ||
1239 | goto reject; | ||
1240 | } | ||
1241 | return; | ||
1242 | |||
1243 | reject: | ||
1244 | printk(KERN_WARNING "mesh: rejecting message from target %d:", | ||
1245 | ms->conn_tgt); | ||
1246 | for (i = 0; i < ms->n_msgin; ++i) | ||
1247 | printk(" %x", ms->msgin[i]); | ||
1248 | printk("\n"); | ||
1249 | ms->msgout[0] = MESSAGE_REJECT; | ||
1250 | ms->n_msgout = 1; | ||
1251 | ms->msgphase = msg_out; | ||
1252 | } | ||
1253 | |||
1254 | /* | ||
1255 | * Set up DMA commands for transferring data. | ||
1256 | */ | ||
1257 | static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd) | ||
1258 | { | ||
1259 | int i, dma_cmd, total, off, dtot; | ||
1260 | struct scatterlist *scl; | ||
1261 | struct dbdma_cmd *dcmds; | ||
1262 | |||
1263 | dma_cmd = ms->tgts[ms->conn_tgt].data_goes_out? | ||
1264 | OUTPUT_MORE: INPUT_MORE; | ||
1265 | dcmds = ms->dma_cmds; | ||
1266 | dtot = 0; | ||
1267 | if (cmd) { | ||
1268 | cmd->SCp.this_residual = cmd->request_bufflen; | ||
1269 | if (cmd->use_sg > 0) { | ||
1270 | int nseg; | ||
1271 | total = 0; | ||
1272 | scl = (struct scatterlist *) cmd->buffer; | ||
1273 | off = ms->data_ptr; | ||
1274 | nseg = pci_map_sg(ms->pdev, scl, cmd->use_sg, | ||
1275 | cmd->sc_data_direction); | ||
1276 | for (i = 0; i <nseg; ++i, ++scl) { | ||
1277 | u32 dma_addr = sg_dma_address(scl); | ||
1278 | u32 dma_len = sg_dma_len(scl); | ||
1279 | |||
1280 | total += scl->length; | ||
1281 | if (off >= dma_len) { | ||
1282 | off -= dma_len; | ||
1283 | continue; | ||
1284 | } | ||
1285 | if (dma_len > 0xffff) | ||
1286 | panic("mesh: scatterlist element >= 64k"); | ||
1287 | st_le16(&dcmds->req_count, dma_len - off); | ||
1288 | st_le16(&dcmds->command, dma_cmd); | ||
1289 | st_le32(&dcmds->phy_addr, dma_addr + off); | ||
1290 | dcmds->xfer_status = 0; | ||
1291 | ++dcmds; | ||
1292 | dtot += dma_len - off; | ||
1293 | off = 0; | ||
1294 | } | ||
1295 | } else if (ms->data_ptr < cmd->request_bufflen) { | ||
1296 | dtot = cmd->request_bufflen - ms->data_ptr; | ||
1297 | if (dtot > 0xffff) | ||
1298 | panic("mesh: transfer size >= 64k"); | ||
1299 | st_le16(&dcmds->req_count, dtot); | ||
1300 | /* XXX Use pci DMA API here ... */ | ||
1301 | st_le32(&dcmds->phy_addr, | ||
1302 | virt_to_phys(cmd->request_buffer) + ms->data_ptr); | ||
1303 | dcmds->xfer_status = 0; | ||
1304 | ++dcmds; | ||
1305 | } | ||
1306 | } | ||
1307 | if (dtot == 0) { | ||
1308 | /* Either the target has overrun our buffer, | ||
1309 | or the caller didn't provide a buffer. */ | ||
1310 | static char mesh_extra_buf[64]; | ||
1311 | |||
1312 | dtot = sizeof(mesh_extra_buf); | ||
1313 | st_le16(&dcmds->req_count, dtot); | ||
1314 | st_le32(&dcmds->phy_addr, virt_to_phys(mesh_extra_buf)); | ||
1315 | dcmds->xfer_status = 0; | ||
1316 | ++dcmds; | ||
1317 | } | ||
1318 | dma_cmd += OUTPUT_LAST - OUTPUT_MORE; | ||
1319 | st_le16(&dcmds[-1].command, dma_cmd); | ||
1320 | memset(dcmds, 0, sizeof(*dcmds)); | ||
1321 | st_le16(&dcmds->command, DBDMA_STOP); | ||
1322 | ms->dma_count = dtot; | ||
1323 | } | ||
1324 | |||
1325 | static void halt_dma(struct mesh_state *ms) | ||
1326 | { | ||
1327 | volatile struct dbdma_regs __iomem *md = ms->dma; | ||
1328 | volatile struct mesh_regs __iomem *mr = ms->mesh; | ||
1329 | struct scsi_cmnd *cmd = ms->current_req; | ||
1330 | int t, nb; | ||
1331 | |||
1332 | if (!ms->tgts[ms->conn_tgt].data_goes_out) { | ||
1333 | /* wait a little while until the fifo drains */ | ||
1334 | t = 50; | ||
1335 | while (t > 0 && in_8(&mr->fifo_count) != 0 | ||
1336 | && (in_le32(&md->status) & ACTIVE) != 0) { | ||
1337 | --t; | ||
1338 | udelay(1); | ||
1339 | } | ||
1340 | } | ||
1341 | out_le32(&md->control, RUN << 16); /* turn off RUN bit */ | ||
1342 | nb = (mr->count_hi << 8) + mr->count_lo; | ||
1343 | dlog(ms, "halt_dma fc/count=%.6x", | ||
1344 | MKWORD(0, mr->fifo_count, 0, nb)); | ||
1345 | if (ms->tgts[ms->conn_tgt].data_goes_out) | ||
1346 | nb += mr->fifo_count; | ||
1347 | /* nb is the number of bytes not yet transferred | ||
1348 | to/from the target. */ | ||
1349 | ms->data_ptr -= nb; | ||
1350 | dlog(ms, "data_ptr %x", ms->data_ptr); | ||
1351 | if (ms->data_ptr < 0) { | ||
1352 | printk(KERN_ERR "mesh: halt_dma: data_ptr=%d (nb=%d, ms=%p)\n", | ||
1353 | ms->data_ptr, nb, ms); | ||
1354 | ms->data_ptr = 0; | ||
1355 | #ifdef MESH_DBG | ||
1356 | dumplog(ms, ms->conn_tgt); | ||
1357 | dumpslog(ms); | ||
1358 | #endif /* MESH_DBG */ | ||
1359 | } else if (cmd && cmd->request_bufflen != 0 && | ||
1360 | ms->data_ptr > cmd->request_bufflen) { | ||
1361 | printk(KERN_DEBUG "mesh: target %d overrun, " | ||
1362 | "data_ptr=%x total=%x goes_out=%d\n", | ||
1363 | ms->conn_tgt, ms->data_ptr, cmd->request_bufflen, | ||
1364 | ms->tgts[ms->conn_tgt].data_goes_out); | ||
1365 | } | ||
1366 | if (cmd->use_sg != 0) { | ||
1367 | struct scatterlist *sg; | ||
1368 | sg = (struct scatterlist *)cmd->request_buffer; | ||
1369 | pci_unmap_sg(ms->pdev, sg, cmd->use_sg, cmd->sc_data_direction); | ||
1370 | } | ||
1371 | ms->dma_started = 0; | ||
1372 | } | ||
1373 | |||
1374 | static void phase_mismatch(struct mesh_state *ms) | ||
1375 | { | ||
1376 | volatile struct mesh_regs __iomem *mr = ms->mesh; | ||
1377 | int phase; | ||
1378 | |||
1379 | dlog(ms, "phasemm ch/cl/seq/fc=%.8x", | ||
1380 | MKWORD(mr->count_hi, mr->count_lo, mr->sequence, mr->fifo_count)); | ||
1381 | phase = in_8(&mr->bus_status0) & BS0_PHASE; | ||
1382 | if (ms->msgphase == msg_out_xxx && phase == BP_MSGOUT) { | ||
1383 | /* output the last byte of the message, without ATN */ | ||
1384 | out_8(&mr->count_lo, 1); | ||
1385 | out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg); | ||
1386 | mesh_flush_io(mr); | ||
1387 | udelay(1); | ||
1388 | out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]); | ||
1389 | ms->msgphase = msg_out_last; | ||
1390 | return; | ||
1391 | } | ||
1392 | |||
1393 | if (ms->msgphase == msg_in) { | ||
1394 | get_msgin(ms); | ||
1395 | if (ms->n_msgin) | ||
1396 | handle_msgin(ms); | ||
1397 | } | ||
1398 | |||
1399 | if (ms->dma_started) | ||
1400 | halt_dma(ms); | ||
1401 | if (mr->fifo_count) { | ||
1402 | out_8(&mr->sequence, SEQ_FLUSHFIFO); | ||
1403 | mesh_flush_io(mr); | ||
1404 | udelay(1); | ||
1405 | } | ||
1406 | |||
1407 | ms->msgphase = msg_none; | ||
1408 | switch (phase) { | ||
1409 | case BP_DATAIN: | ||
1410 | ms->tgts[ms->conn_tgt].data_goes_out = 0; | ||
1411 | ms->phase = dataing; | ||
1412 | break; | ||
1413 | case BP_DATAOUT: | ||
1414 | ms->tgts[ms->conn_tgt].data_goes_out = 1; | ||
1415 | ms->phase = dataing; | ||
1416 | break; | ||
1417 | case BP_COMMAND: | ||
1418 | ms->phase = commanding; | ||
1419 | break; | ||
1420 | case BP_STATUS: | ||
1421 | ms->phase = statusing; | ||
1422 | break; | ||
1423 | case BP_MSGIN: | ||
1424 | ms->msgphase = msg_in; | ||
1425 | ms->n_msgin = 0; | ||
1426 | break; | ||
1427 | case BP_MSGOUT: | ||
1428 | ms->msgphase = msg_out; | ||
1429 | if (ms->n_msgout == 0) { | ||
1430 | if (ms->aborting) { | ||
1431 | do_abort(ms); | ||
1432 | } else { | ||
1433 | if (ms->last_n_msgout == 0) { | ||
1434 | printk(KERN_DEBUG | ||
1435 | "mesh: no msg to repeat\n"); | ||
1436 | ms->msgout[0] = NOP; | ||
1437 | ms->last_n_msgout = 1; | ||
1438 | } | ||
1439 | ms->n_msgout = ms->last_n_msgout; | ||
1440 | } | ||
1441 | } | ||
1442 | break; | ||
1443 | default: | ||
1444 | printk(KERN_DEBUG "mesh: unknown scsi phase %x\n", phase); | ||
1445 | ms->stat = DID_ERROR; | ||
1446 | mesh_done(ms, 1); | ||
1447 | return; | ||
1448 | } | ||
1449 | |||
1450 | start_phase(ms); | ||
1451 | } | ||
1452 | |||
1453 | static void cmd_complete(struct mesh_state *ms) | ||
1454 | { | ||
1455 | volatile struct mesh_regs __iomem *mr = ms->mesh; | ||
1456 | struct scsi_cmnd *cmd = ms->current_req; | ||
1457 | struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; | ||
1458 | int seq, n, t; | ||
1459 | |||
1460 | dlog(ms, "cmd_complete fc=%x", mr->fifo_count); | ||
1461 | seq = use_active_neg + (ms->n_msgout? SEQ_ATN: 0); | ||
1462 | switch (ms->msgphase) { | ||
1463 | case msg_out_xxx: | ||
1464 | /* huh? we expected a phase mismatch */ | ||
1465 | ms->n_msgin = 0; | ||
1466 | ms->msgphase = msg_in; | ||
1467 | /* fall through */ | ||
1468 | |||
1469 | case msg_in: | ||
1470 | /* should have some message bytes in fifo */ | ||
1471 | get_msgin(ms); | ||
1472 | n = msgin_length(ms); | ||
1473 | if (ms->n_msgin < n) { | ||
1474 | out_8(&mr->count_lo, n - ms->n_msgin); | ||
1475 | out_8(&mr->sequence, SEQ_MSGIN + seq); | ||
1476 | } else { | ||
1477 | ms->msgphase = msg_none; | ||
1478 | handle_msgin(ms); | ||
1479 | start_phase(ms); | ||
1480 | } | ||
1481 | break; | ||
1482 | |||
1483 | case msg_in_bad: | ||
1484 | out_8(&mr->sequence, SEQ_FLUSHFIFO); | ||
1485 | mesh_flush_io(mr); | ||
1486 | udelay(1); | ||
1487 | out_8(&mr->count_lo, 1); | ||
1488 | out_8(&mr->sequence, SEQ_MSGIN + SEQ_ATN + use_active_neg); | ||
1489 | break; | ||
1490 | |||
1491 | case msg_out: | ||
1492 | /* | ||
1493 | * To get the right timing on ATN wrt ACK, we have | ||
1494 | * to get the MESH to drop ACK, wait until REQ gets | ||
1495 | * asserted, then drop ATN. To do this we first | ||
1496 | * issue a SEQ_MSGOUT with ATN and wait for REQ, | ||
1497 | * then change the command to a SEQ_MSGOUT w/o ATN. | ||
1498 | * If we don't see REQ in a reasonable time, we | ||
1499 | * change the command to SEQ_MSGIN with ATN, | ||
1500 | * wait for the phase mismatch interrupt, then | ||
1501 | * issue the SEQ_MSGOUT without ATN. | ||
1502 | */ | ||
1503 | out_8(&mr->count_lo, 1); | ||
1504 | out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg + SEQ_ATN); | ||
1505 | t = 30; /* wait up to 30us */ | ||
1506 | while ((in_8(&mr->bus_status0) & BS0_REQ) == 0 && --t >= 0) | ||
1507 | udelay(1); | ||
1508 | dlog(ms, "last_mbyte err/exc/fc/cl=%.8x", | ||
1509 | MKWORD(mr->error, mr->exception, | ||
1510 | mr->fifo_count, mr->count_lo)); | ||
1511 | if (in_8(&mr->interrupt) & (INT_ERROR | INT_EXCEPTION)) { | ||
1512 | /* whoops, target didn't do what we expected */ | ||
1513 | ms->last_n_msgout = ms->n_msgout; | ||
1514 | ms->n_msgout = 0; | ||
1515 | if (in_8(&mr->interrupt) & INT_ERROR) { | ||
1516 | printk(KERN_ERR "mesh: error %x in msg_out\n", | ||
1517 | in_8(&mr->error)); | ||
1518 | handle_error(ms); | ||
1519 | return; | ||
1520 | } | ||
1521 | if (in_8(&mr->exception) != EXC_PHASEMM) | ||
1522 | printk(KERN_ERR "mesh: exc %x in msg_out\n", | ||
1523 | in_8(&mr->exception)); | ||
1524 | else | ||
1525 | printk(KERN_DEBUG "mesh: bs0=%x in msg_out\n", | ||
1526 | in_8(&mr->bus_status0)); | ||
1527 | handle_exception(ms); | ||
1528 | return; | ||
1529 | } | ||
1530 | if (in_8(&mr->bus_status0) & BS0_REQ) { | ||
1531 | out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg); | ||
1532 | mesh_flush_io(mr); | ||
1533 | udelay(1); | ||
1534 | out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]); | ||
1535 | ms->msgphase = msg_out_last; | ||
1536 | } else { | ||
1537 | out_8(&mr->sequence, SEQ_MSGIN + use_active_neg + SEQ_ATN); | ||
1538 | ms->msgphase = msg_out_xxx; | ||
1539 | } | ||
1540 | break; | ||
1541 | |||
1542 | case msg_out_last: | ||
1543 | ms->last_n_msgout = ms->n_msgout; | ||
1544 | ms->n_msgout = 0; | ||
1545 | ms->msgphase = ms->expect_reply? msg_in: msg_none; | ||
1546 | start_phase(ms); | ||
1547 | break; | ||
1548 | |||
1549 | case msg_none: | ||
1550 | switch (ms->phase) { | ||
1551 | case idle: | ||
1552 | printk(KERN_ERR "mesh: interrupt in idle phase?\n"); | ||
1553 | dumpslog(ms); | ||
1554 | return; | ||
1555 | case selecting: | ||
1556 | dlog(ms, "Selecting phase at command completion",0); | ||
1557 | ms->msgout[0] = IDENTIFY(ALLOW_RESEL(ms->conn_tgt), | ||
1558 | (cmd? cmd->device->lun: 0)); | ||
1559 | ms->n_msgout = 1; | ||
1560 | ms->expect_reply = 0; | ||
1561 | if (ms->aborting) { | ||
1562 | ms->msgout[0] = ABORT; | ||
1563 | ms->n_msgout++; | ||
1564 | } else if (tp->sdtr_state == do_sdtr) { | ||
1565 | /* add SDTR message */ | ||
1566 | add_sdtr_msg(ms); | ||
1567 | ms->expect_reply = 1; | ||
1568 | tp->sdtr_state = sdtr_sent; | ||
1569 | } | ||
1570 | ms->msgphase = msg_out; | ||
1571 | /* | ||
1572 | * We need to wait for REQ before dropping ATN. | ||
1573 | * We wait for at most 30us, then fall back to | ||
1574 | * a scheme where we issue a SEQ_COMMAND with ATN, | ||
1575 | * which will give us a phase mismatch interrupt | ||
1576 | * when REQ does come, and then we send the message. | ||
1577 | */ | ||
1578 | t = 230; /* wait up to 230us */ | ||
1579 | while ((in_8(&mr->bus_status0) & BS0_REQ) == 0) { | ||
1580 | if (--t < 0) { | ||
1581 | dlog(ms, "impatient for req", ms->n_msgout); | ||
1582 | ms->msgphase = msg_none; | ||
1583 | break; | ||
1584 | } | ||
1585 | udelay(1); | ||
1586 | } | ||
1587 | break; | ||
1588 | case dataing: | ||
1589 | if (ms->dma_count != 0) { | ||
1590 | start_phase(ms); | ||
1591 | return; | ||
1592 | } | ||
1593 | /* | ||
1594 | * We can get a phase mismatch here if the target | ||
1595 | * changes to the status phase, even though we have | ||
1596 | * had a command complete interrupt. Then, if we | ||
1597 | * issue the SEQ_STATUS command, we'll get a sequence | ||
1598 | * error interrupt. Which isn't so bad except that | ||
1599 | * occasionally the mesh actually executes the | ||
1600 | * SEQ_STATUS *as well as* giving us the sequence | ||
1601 | * error and phase mismatch exception. | ||
1602 | */ | ||
1603 | out_8(&mr->sequence, 0); | ||
1604 | out_8(&mr->interrupt, | ||
1605 | INT_ERROR | INT_EXCEPTION | INT_CMDDONE); | ||
1606 | halt_dma(ms); | ||
1607 | break; | ||
1608 | case statusing: | ||
1609 | if (cmd) { | ||
1610 | cmd->SCp.Status = mr->fifo; | ||
1611 | if (DEBUG_TARGET(cmd)) | ||
1612 | printk(KERN_DEBUG "mesh: status is %x\n", | ||
1613 | cmd->SCp.Status); | ||
1614 | } | ||
1615 | ms->msgphase = msg_in; | ||
1616 | break; | ||
1617 | case busfreeing: | ||
1618 | mesh_done(ms, 1); | ||
1619 | return; | ||
1620 | case disconnecting: | ||
1621 | ms->current_req = NULL; | ||
1622 | ms->phase = idle; | ||
1623 | mesh_start(ms); | ||
1624 | return; | ||
1625 | default: | ||
1626 | break; | ||
1627 | } | ||
1628 | ++ms->phase; | ||
1629 | start_phase(ms); | ||
1630 | break; | ||
1631 | } | ||
1632 | } | ||
1633 | |||
1634 | |||
1635 | /* | ||
1636 | * Called by midlayer with host locked to queue a new | ||
1637 | * request | ||
1638 | */ | ||
1639 | static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) | ||
1640 | { | ||
1641 | struct mesh_state *ms; | ||
1642 | |||
1643 | cmd->scsi_done = done; | ||
1644 | cmd->host_scribble = NULL; | ||
1645 | |||
1646 | ms = (struct mesh_state *) cmd->device->host->hostdata; | ||
1647 | |||
1648 | if (ms->request_q == NULL) | ||
1649 | ms->request_q = cmd; | ||
1650 | else | ||
1651 | ms->request_qtail->host_scribble = (void *) cmd; | ||
1652 | ms->request_qtail = cmd; | ||
1653 | |||
1654 | if (ms->phase == idle) | ||
1655 | mesh_start(ms); | ||
1656 | |||
1657 | return 0; | ||
1658 | } | ||
1659 | |||
1660 | /* | ||
1661 | * Called to handle interrupts, either call by the interrupt | ||
1662 | * handler (do_mesh_interrupt) or by other functions in | ||
1663 | * exceptional circumstances | ||
1664 | */ | ||
1665 | static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) | ||
1666 | { | ||
1667 | struct mesh_state *ms = (struct mesh_state *) dev_id; | ||
1668 | volatile struct mesh_regs __iomem *mr = ms->mesh; | ||
1669 | int intr; | ||
1670 | |||
1671 | #if 0 | ||
1672 | if (ALLOW_DEBUG(ms->conn_tgt)) | ||
1673 | printk(KERN_DEBUG "mesh_intr, bs0=%x int=%x exc=%x err=%x " | ||
1674 | "phase=%d msgphase=%d\n", mr->bus_status0, | ||
1675 | mr->interrupt, mr->exception, mr->error, | ||
1676 | ms->phase, ms->msgphase); | ||
1677 | #endif | ||
1678 | while ((intr = in_8(&mr->interrupt)) != 0) { | ||
1679 | dlog(ms, "interrupt intr/err/exc/seq=%.8x", | ||
1680 | MKWORD(intr, mr->error, mr->exception, mr->sequence)); | ||
1681 | if (intr & INT_ERROR) { | ||
1682 | handle_error(ms); | ||
1683 | } else if (intr & INT_EXCEPTION) { | ||
1684 | handle_exception(ms); | ||
1685 | } else if (intr & INT_CMDDONE) { | ||
1686 | out_8(&mr->interrupt, INT_CMDDONE); | ||
1687 | cmd_complete(ms); | ||
1688 | } | ||
1689 | } | ||
1690 | } | ||
1691 | |||
1692 | /* Todo: here we can at least try to remove the command from the | ||
1693 | * queue if it isn't connected yet, and for pending command, assert | ||
1694 | * ATN until the bus gets freed. | ||
1695 | */ | ||
1696 | static int mesh_abort(struct scsi_cmnd *cmd) | ||
1697 | { | ||
1698 | struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata; | ||
1699 | |||
1700 | printk(KERN_DEBUG "mesh_abort(%p)\n", cmd); | ||
1701 | mesh_dump_regs(ms); | ||
1702 | dumplog(ms, cmd->device->id); | ||
1703 | dumpslog(ms); | ||
1704 | return FAILED; | ||
1705 | } | ||
1706 | |||
1707 | /* | ||
1708 | * Called by the midlayer with the lock held to reset the | ||
1709 | * SCSI host and bus. | ||
1710 | * The midlayer will wait for devices to come back, we don't need | ||
1711 | * to do that ourselves | ||
1712 | */ | ||
1713 | static int mesh_host_reset(struct scsi_cmnd *cmd) | ||
1714 | { | ||
1715 | struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata; | ||
1716 | volatile struct mesh_regs __iomem *mr = ms->mesh; | ||
1717 | volatile struct dbdma_regs __iomem *md = ms->dma; | ||
1718 | |||
1719 | printk(KERN_DEBUG "mesh_host_reset\n"); | ||
1720 | |||
1721 | /* Reset the controller & dbdma channel */ | ||
1722 | out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* stop dma */ | ||
1723 | out_8(&mr->exception, 0xff); /* clear all exception bits */ | ||
1724 | out_8(&mr->error, 0xff); /* clear all error bits */ | ||
1725 | out_8(&mr->sequence, SEQ_RESETMESH); | ||
1726 | mesh_flush_io(mr); | ||
1727 | udelay(1); | ||
1728 | out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); | ||
1729 | out_8(&mr->source_id, ms->host->this_id); | ||
1730 | out_8(&mr->sel_timeout, 25); /* 250ms */ | ||
1731 | out_8(&mr->sync_params, ASYNC_PARAMS); | ||
1732 | |||
1733 | /* Reset the bus */ | ||
1734 | out_8(&mr->bus_status1, BS1_RST); /* assert RST */ | ||
1735 | mesh_flush_io(mr); | ||
1736 | udelay(30); /* leave it on for >= 25us */ | ||
1737 | out_8(&mr->bus_status1, 0); /* negate RST */ | ||
1738 | |||
1739 | /* Complete pending commands */ | ||
1740 | handle_reset(ms); | ||
1741 | |||
1742 | return SUCCESS; | ||
1743 | } | ||
1744 | |||
1745 | static void set_mesh_power(struct mesh_state *ms, int state) | ||
1746 | { | ||
1747 | if (_machine != _MACH_Pmac) | ||
1748 | return; | ||
1749 | if (state) { | ||
1750 | pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 1); | ||
1751 | msleep(200); | ||
1752 | } else { | ||
1753 | pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 0); | ||
1754 | msleep(10); | ||
1755 | } | ||
1756 | } | ||
1757 | |||
1758 | |||
1759 | #ifdef CONFIG_PM | ||
1760 | static int mesh_suspend(struct macio_dev *mdev, u32 state) | ||
1761 | { | ||
1762 | struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev); | ||
1763 | unsigned long flags; | ||
1764 | |||
1765 | if (state == mdev->ofdev.dev.power.power_state || state < 2) | ||
1766 | return 0; | ||
1767 | |||
1768 | scsi_block_requests(ms->host); | ||
1769 | spin_lock_irqsave(ms->host->host_lock, flags); | ||
1770 | while(ms->phase != idle) { | ||
1771 | spin_unlock_irqrestore(ms->host->host_lock, flags); | ||
1772 | msleep(10); | ||
1773 | spin_lock_irqsave(ms->host->host_lock, flags); | ||
1774 | } | ||
1775 | ms->phase = sleeping; | ||
1776 | spin_unlock_irqrestore(ms->host->host_lock, flags); | ||
1777 | disable_irq(ms->meshintr); | ||
1778 | set_mesh_power(ms, 0); | ||
1779 | |||
1780 | mdev->ofdev.dev.power.power_state = state; | ||
1781 | |||
1782 | return 0; | ||
1783 | } | ||
1784 | |||
1785 | static int mesh_resume(struct macio_dev *mdev) | ||
1786 | { | ||
1787 | struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev); | ||
1788 | unsigned long flags; | ||
1789 | |||
1790 | if (mdev->ofdev.dev.power.power_state == 0) | ||
1791 | return 0; | ||
1792 | |||
1793 | set_mesh_power(ms, 1); | ||
1794 | mesh_init(ms); | ||
1795 | spin_lock_irqsave(ms->host->host_lock, flags); | ||
1796 | mesh_start(ms); | ||
1797 | spin_unlock_irqrestore(ms->host->host_lock, flags); | ||
1798 | enable_irq(ms->meshintr); | ||
1799 | scsi_unblock_requests(ms->host); | ||
1800 | |||
1801 | mdev->ofdev.dev.power.power_state = 0; | ||
1802 | |||
1803 | return 0; | ||
1804 | } | ||
1805 | |||
1806 | #endif /* CONFIG_PM */ | ||
1807 | |||
1808 | /* | ||
1809 | * If we leave drives set for synchronous transfers (especially | ||
1810 | * CDROMs), and reboot to MacOS, it gets confused, poor thing. | ||
1811 | * So, on reboot we reset the SCSI bus. | ||
1812 | */ | ||
1813 | static int mesh_shutdown(struct macio_dev *mdev) | ||
1814 | { | ||
1815 | struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev); | ||
1816 | volatile struct mesh_regs __iomem *mr; | ||
1817 | unsigned long flags; | ||
1818 | |||
1819 | printk(KERN_INFO "resetting MESH scsi bus(es)\n"); | ||
1820 | spin_lock_irqsave(ms->host->host_lock, flags); | ||
1821 | mr = ms->mesh; | ||
1822 | out_8(&mr->intr_mask, 0); | ||
1823 | out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); | ||
1824 | out_8(&mr->bus_status1, BS1_RST); | ||
1825 | mesh_flush_io(mr); | ||
1826 | udelay(30); | ||
1827 | out_8(&mr->bus_status1, 0); | ||
1828 | spin_unlock_irqrestore(ms->host->host_lock, flags); | ||
1829 | |||
1830 | return 0; | ||
1831 | } | ||
1832 | |||
1833 | static struct scsi_host_template mesh_template = { | ||
1834 | .proc_name = "mesh", | ||
1835 | .name = "MESH", | ||
1836 | .queuecommand = mesh_queue, | ||
1837 | .eh_abort_handler = mesh_abort, | ||
1838 | .eh_host_reset_handler = mesh_host_reset, | ||
1839 | .can_queue = 20, | ||
1840 | .this_id = 7, | ||
1841 | .sg_tablesize = SG_ALL, | ||
1842 | .cmd_per_lun = 2, | ||
1843 | .use_clustering = DISABLE_CLUSTERING, | ||
1844 | }; | ||
1845 | |||
1846 | static int mesh_probe(struct macio_dev *mdev, const struct of_match *match) | ||
1847 | { | ||
1848 | struct device_node *mesh = macio_get_of_node(mdev); | ||
1849 | struct pci_dev* pdev = macio_get_pci_dev(mdev); | ||
1850 | int tgt, *cfp, minper; | ||
1851 | struct mesh_state *ms; | ||
1852 | struct Scsi_Host *mesh_host; | ||
1853 | void *dma_cmd_space; | ||
1854 | dma_addr_t dma_cmd_bus; | ||
1855 | |||
1856 | switch (mdev->bus->chip->type) { | ||
1857 | case macio_heathrow: | ||
1858 | case macio_gatwick: | ||
1859 | case macio_paddington: | ||
1860 | use_active_neg = 0; | ||
1861 | break; | ||
1862 | default: | ||
1863 | use_active_neg = SEQ_ACTIVE_NEG; | ||
1864 | } | ||
1865 | |||
1866 | if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) { | ||
1867 | printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs" | ||
1868 | " (got %d,%d)\n", mesh->n_addrs, mesh->n_intrs); | ||
1869 | return -ENODEV; | ||
1870 | } | ||
1871 | |||
1872 | if (macio_request_resources(mdev, "mesh") != 0) { | ||
1873 | printk(KERN_ERR "mesh: unable to request memory resources"); | ||
1874 | return -EBUSY; | ||
1875 | } | ||
1876 | mesh_host = scsi_host_alloc(&mesh_template, sizeof(struct mesh_state)); | ||
1877 | if (mesh_host == NULL) { | ||
1878 | printk(KERN_ERR "mesh: couldn't register host"); | ||
1879 | goto out_release; | ||
1880 | } | ||
1881 | |||
1882 | /* Old junk for root discovery, that will die ultimately */ | ||
1883 | #if !defined(MODULE) | ||
1884 | note_scsi_host(mesh, mesh_host); | ||
1885 | #endif | ||
1886 | |||
1887 | mesh_host->base = macio_resource_start(mdev, 0); | ||
1888 | mesh_host->irq = macio_irq(mdev, 0); | ||
1889 | ms = (struct mesh_state *) mesh_host->hostdata; | ||
1890 | macio_set_drvdata(mdev, ms); | ||
1891 | ms->host = mesh_host; | ||
1892 | ms->mdev = mdev; | ||
1893 | ms->pdev = pdev; | ||
1894 | |||
1895 | ms->mesh = ioremap(macio_resource_start(mdev, 0), 0x1000); | ||
1896 | if (ms->mesh == NULL) { | ||
1897 | printk(KERN_ERR "mesh: can't map registers\n"); | ||
1898 | goto out_free; | ||
1899 | } | ||
1900 | ms->dma = ioremap(macio_resource_start(mdev, 1), 0x1000); | ||
1901 | if (ms->dma == NULL) { | ||
1902 | printk(KERN_ERR "mesh: can't map registers\n"); | ||
1903 | iounmap(ms->mesh); | ||
1904 | goto out_free; | ||
1905 | } | ||
1906 | |||
1907 | ms->meshintr = macio_irq(mdev, 0); | ||
1908 | ms->dmaintr = macio_irq(mdev, 1); | ||
1909 | |||
1910 | /* Space for dma command list: +1 for stop command, | ||
1911 | * +1 to allow for aligning. | ||
1912 | */ | ||
1913 | ms->dma_cmd_size = (mesh_host->sg_tablesize + 2) * sizeof(struct dbdma_cmd); | ||
1914 | |||
1915 | /* We use the PCI APIs for now until the generic one gets fixed | ||
1916 | * enough or until we get some macio-specific versions | ||
1917 | */ | ||
1918 | dma_cmd_space = pci_alloc_consistent(macio_get_pci_dev(mdev), | ||
1919 | ms->dma_cmd_size, | ||
1920 | &dma_cmd_bus); | ||
1921 | if (dma_cmd_space == NULL) { | ||
1922 | printk(KERN_ERR "mesh: can't allocate DMA table\n"); | ||
1923 | goto out_unmap; | ||
1924 | } | ||
1925 | memset(dma_cmd_space, 0, ms->dma_cmd_size); | ||
1926 | |||
1927 | ms->dma_cmds = (struct dbdma_cmd *) DBDMA_ALIGN(dma_cmd_space); | ||
1928 | ms->dma_cmd_space = dma_cmd_space; | ||
1929 | ms->dma_cmd_bus = dma_cmd_bus + ((unsigned long)ms->dma_cmds) | ||
1930 | - (unsigned long)dma_cmd_space; | ||
1931 | ms->current_req = NULL; | ||
1932 | for (tgt = 0; tgt < 8; ++tgt) { | ||
1933 | ms->tgts[tgt].sdtr_state = do_sdtr; | ||
1934 | ms->tgts[tgt].sync_params = ASYNC_PARAMS; | ||
1935 | ms->tgts[tgt].current_req = NULL; | ||
1936 | } | ||
1937 | |||
1938 | if ((cfp = (int *) get_property(mesh, "clock-frequency", NULL))) | ||
1939 | ms->clk_freq = *cfp; | ||
1940 | else { | ||
1941 | printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n"); | ||
1942 | ms->clk_freq = 50000000; | ||
1943 | } | ||
1944 | |||
1945 | /* The maximum sync rate is clock / 5; increase | ||
1946 | * mesh_sync_period if necessary. | ||
1947 | */ | ||
1948 | minper = 1000000000 / (ms->clk_freq / 5); /* ns */ | ||
1949 | if (mesh_sync_period < minper) | ||
1950 | mesh_sync_period = minper; | ||
1951 | |||
1952 | /* Power up the chip */ | ||
1953 | set_mesh_power(ms, 1); | ||
1954 | |||
1955 | /* Set it up */ | ||
1956 | mesh_init(ms); | ||
1957 | |||
1958 | /* XXX FIXME: error should be fatal */ | ||
1959 | if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) | ||
1960 | printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr); | ||
1961 | |||
1962 | /* XXX FIXME: handle failure */ | ||
1963 | scsi_add_host(mesh_host, &mdev->ofdev.dev); | ||
1964 | scsi_scan_host(mesh_host); | ||
1965 | |||
1966 | return 0; | ||
1967 | |||
1968 | out_unmap: | ||
1969 | iounmap(ms->dma); | ||
1970 | iounmap(ms->mesh); | ||
1971 | out_free: | ||
1972 | scsi_host_put(mesh_host); | ||
1973 | out_release: | ||
1974 | macio_release_resources(mdev); | ||
1975 | |||
1976 | return -ENODEV; | ||
1977 | } | ||
1978 | |||
1979 | static int mesh_remove(struct macio_dev *mdev) | ||
1980 | { | ||
1981 | struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev); | ||
1982 | struct Scsi_Host *mesh_host = ms->host; | ||
1983 | |||
1984 | scsi_remove_host(mesh_host); | ||
1985 | |||
1986 | free_irq(ms->meshintr, ms); | ||
1987 | |||
1988 | /* Reset scsi bus */ | ||
1989 | mesh_shutdown(mdev); | ||
1990 | |||
1991 | /* Shut down chip & termination */ | ||
1992 | set_mesh_power(ms, 0); | ||
1993 | |||
1994 | /* Unmap registers & dma controller */ | ||
1995 | iounmap(ms->mesh); | ||
1996 | iounmap(ms->dma); | ||
1997 | |||
1998 | /* Free DMA commands memory */ | ||
1999 | pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size, | ||
2000 | ms->dma_cmd_space, ms->dma_cmd_bus); | ||
2001 | |||
2002 | /* Release memory resources */ | ||
2003 | macio_release_resources(mdev); | ||
2004 | |||
2005 | scsi_host_put(mesh_host); | ||
2006 | |||
2007 | return 0; | ||
2008 | } | ||
2009 | |||
2010 | |||
2011 | static struct of_match mesh_match[] = | ||
2012 | { | ||
2013 | { | ||
2014 | .name = "mesh", | ||
2015 | .type = OF_ANY_MATCH, | ||
2016 | .compatible = OF_ANY_MATCH | ||
2017 | }, | ||
2018 | { | ||
2019 | .name = OF_ANY_MATCH, | ||
2020 | .type = "scsi", | ||
2021 | .compatible = "chrp,mesh0" | ||
2022 | }, | ||
2023 | {}, | ||
2024 | }; | ||
2025 | |||
2026 | static struct macio_driver mesh_driver = | ||
2027 | { | ||
2028 | .name = "mesh", | ||
2029 | .match_table = mesh_match, | ||
2030 | .probe = mesh_probe, | ||
2031 | .remove = mesh_remove, | ||
2032 | .shutdown = mesh_shutdown, | ||
2033 | #ifdef CONFIG_PM | ||
2034 | .suspend = mesh_suspend, | ||
2035 | .resume = mesh_resume, | ||
2036 | #endif | ||
2037 | }; | ||
2038 | |||
2039 | |||
2040 | static int __init init_mesh(void) | ||
2041 | { | ||
2042 | |||
2043 | /* Calculate sync rate from module parameters */ | ||
2044 | if (sync_rate > 10) | ||
2045 | sync_rate = 10; | ||
2046 | if (sync_rate > 0) { | ||
2047 | printk(KERN_INFO "mesh: configured for synchronous %d MB/s\n", sync_rate); | ||
2048 | mesh_sync_period = 1000 / sync_rate; /* ns */ | ||
2049 | mesh_sync_offset = 15; | ||
2050 | } else | ||
2051 | printk(KERN_INFO "mesh: configured for asynchronous\n"); | ||
2052 | |||
2053 | return macio_register_driver(&mesh_driver); | ||
2054 | } | ||
2055 | |||
2056 | static void __exit exit_mesh(void) | ||
2057 | { | ||
2058 | return macio_unregister_driver(&mesh_driver); | ||
2059 | } | ||
2060 | |||
2061 | module_init(init_mesh); | ||
2062 | module_exit(exit_mesh); | ||