109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * SCSI low-level driver for the MESH (Macintosh Enhanced SCSI Hardware)
41da177e4SLinus Torvalds * bus adaptor found on Power Macintosh computers.
51da177e4SLinus Torvalds * We assume the MESH is connected to a DBDMA (descriptor-based DMA)
61da177e4SLinus Torvalds * controller.
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * Paul Mackerras, August 1996.
91da177e4SLinus Torvalds * Copyright (C) 1996 Paul Mackerras.
101da177e4SLinus Torvalds *
111da177e4SLinus Torvalds * Apr. 21 2002 - BenH Rework bus reset code for new error handler
121da177e4SLinus Torvalds * Add delay after initial bus reset
131da177e4SLinus Torvalds * Add module parameters
141da177e4SLinus Torvalds *
151da177e4SLinus Torvalds * Sep. 27 2003 - BenH Move to new driver model, fix some write posting
161da177e4SLinus Torvalds * issues
171da177e4SLinus Torvalds * To do:
181da177e4SLinus Torvalds * - handle aborts correctly
191da177e4SLinus Torvalds * - retry arbitration if lost (unless higher levels do this for us)
201da177e4SLinus Torvalds * - power down the chip when no device is detected
211da177e4SLinus Torvalds */
221da177e4SLinus Torvalds #include <linux/module.h>
231da177e4SLinus Torvalds #include <linux/kernel.h>
241da177e4SLinus Torvalds #include <linux/delay.h>
251da177e4SLinus Torvalds #include <linux/types.h>
261da177e4SLinus Torvalds #include <linux/string.h>
271da177e4SLinus Torvalds #include <linux/blkdev.h>
281da177e4SLinus Torvalds #include <linux/proc_fs.h>
291da177e4SLinus Torvalds #include <linux/stat.h>
301da177e4SLinus Torvalds #include <linux/interrupt.h>
311da177e4SLinus Torvalds #include <linux/reboot.h>
321da177e4SLinus Torvalds #include <linux/spinlock.h>
33952bbcb0SBjorn Helgaas #include <linux/pci.h>
3465fddcfcSMike Rapoport #include <linux/pgtable.h>
351da177e4SLinus Torvalds #include <asm/dbdma.h>
361da177e4SLinus Torvalds #include <asm/io.h>
371da177e4SLinus Torvalds #include <asm/prom.h>
381da177e4SLinus Torvalds #include <asm/irq.h>
391da177e4SLinus Torvalds #include <asm/hydra.h>
401da177e4SLinus Torvalds #include <asm/processor.h>
41113fe88eSChristophe Leroy #include <asm/setup.h>
421da177e4SLinus Torvalds #include <asm/pmac_feature.h>
431da177e4SLinus Torvalds #include <asm/macio.h>
441da177e4SLinus Torvalds
451da177e4SLinus Torvalds #include <scsi/scsi.h>
461da177e4SLinus Torvalds #include <scsi/scsi_cmnd.h>
471da177e4SLinus Torvalds #include <scsi/scsi_device.h>
481da177e4SLinus Torvalds #include <scsi/scsi_host.h>
491da177e4SLinus Torvalds
501da177e4SLinus Torvalds #include "mesh.h"
511da177e4SLinus Torvalds
521da177e4SLinus Torvalds #if 1
531da177e4SLinus Torvalds #undef KERN_DEBUG
541da177e4SLinus Torvalds #define KERN_DEBUG KERN_WARNING
551da177e4SLinus Torvalds #endif
561da177e4SLinus Torvalds
571da177e4SLinus Torvalds MODULE_AUTHOR("Paul Mackerras (paulus@samba.org)");
581da177e4SLinus Torvalds MODULE_DESCRIPTION("PowerMac MESH SCSI driver");
591da177e4SLinus Torvalds MODULE_LICENSE("GPL");
601da177e4SLinus Torvalds
611da177e4SLinus Torvalds static int sync_rate = CONFIG_SCSI_MESH_SYNC_RATE;
621da177e4SLinus Torvalds static int sync_targets = 0xff;
631da177e4SLinus Torvalds static int resel_targets = 0xff;
641da177e4SLinus Torvalds static int debug_targets = 0; /* print debug for these targets */
651da177e4SLinus Torvalds static int init_reset_delay = CONFIG_SCSI_MESH_RESET_DELAY_MS;
661da177e4SLinus Torvalds
671da177e4SLinus Torvalds module_param(sync_rate, int, 0);
681da177e4SLinus Torvalds MODULE_PARM_DESC(sync_rate, "Synchronous rate (0..10, 0=async)");
691da177e4SLinus Torvalds module_param(sync_targets, int, 0);
701da177e4SLinus Torvalds MODULE_PARM_DESC(sync_targets, "Bitmask of targets allowed to set synchronous");
711da177e4SLinus Torvalds module_param(resel_targets, int, 0);
721da177e4SLinus Torvalds MODULE_PARM_DESC(resel_targets, "Bitmask of targets allowed to set disconnect");
731da177e4SLinus Torvalds module_param(debug_targets, int, 0644);
741da177e4SLinus Torvalds MODULE_PARM_DESC(debug_targets, "Bitmask of debugged targets");
751da177e4SLinus Torvalds module_param(init_reset_delay, int, 0);
761da177e4SLinus Torvalds MODULE_PARM_DESC(init_reset_delay, "Initial bus reset delay (0=no reset)");
771da177e4SLinus Torvalds
781da177e4SLinus Torvalds static int mesh_sync_period = 100;
791da177e4SLinus Torvalds static int mesh_sync_offset = 0;
801da177e4SLinus Torvalds static unsigned char use_active_neg = 0; /* bit mask for SEQ_ACTIVE_NEG if used */
811da177e4SLinus Torvalds
821da177e4SLinus Torvalds #define ALLOW_SYNC(tgt) ((sync_targets >> (tgt)) & 1)
831da177e4SLinus Torvalds #define ALLOW_RESEL(tgt) ((resel_targets >> (tgt)) & 1)
841da177e4SLinus Torvalds #define ALLOW_DEBUG(tgt) ((debug_targets >> (tgt)) & 1)
851da177e4SLinus Torvalds #define DEBUG_TARGET(cmd) ((cmd) && ALLOW_DEBUG((cmd)->device->id))
861da177e4SLinus Torvalds
871da177e4SLinus Torvalds #undef MESH_DBG
881da177e4SLinus Torvalds #define N_DBG_LOG 50
891da177e4SLinus Torvalds #define N_DBG_SLOG 20
901da177e4SLinus Torvalds #define NUM_DBG_EVENTS 13
911da177e4SLinus Torvalds #undef DBG_USE_TB /* bombs on 601 */
921da177e4SLinus Torvalds
931da177e4SLinus Torvalds struct dbglog {
941da177e4SLinus Torvalds char *fmt;
951da177e4SLinus Torvalds u32 tb;
961da177e4SLinus Torvalds u8 phase;
971da177e4SLinus Torvalds u8 bs0;
981da177e4SLinus Torvalds u8 bs1;
991da177e4SLinus Torvalds u8 tgt;
1001da177e4SLinus Torvalds int d;
1011da177e4SLinus Torvalds };
1021da177e4SLinus Torvalds
1031da177e4SLinus Torvalds enum mesh_phase {
1041da177e4SLinus Torvalds idle,
1051da177e4SLinus Torvalds arbitrating,
1061da177e4SLinus Torvalds selecting,
1071da177e4SLinus Torvalds commanding,
1081da177e4SLinus Torvalds dataing,
1091da177e4SLinus Torvalds statusing,
1101da177e4SLinus Torvalds busfreeing,
1111da177e4SLinus Torvalds disconnecting,
1121da177e4SLinus Torvalds reselecting,
1131da177e4SLinus Torvalds sleeping
1141da177e4SLinus Torvalds };
1151da177e4SLinus Torvalds
1161da177e4SLinus Torvalds enum msg_phase {
1171da177e4SLinus Torvalds msg_none,
1181da177e4SLinus Torvalds msg_out,
1191da177e4SLinus Torvalds msg_out_xxx,
1201da177e4SLinus Torvalds msg_out_last,
1211da177e4SLinus Torvalds msg_in,
1221da177e4SLinus Torvalds msg_in_bad,
1231da177e4SLinus Torvalds };
1241da177e4SLinus Torvalds
1251da177e4SLinus Torvalds enum sdtr_phase {
1261da177e4SLinus Torvalds do_sdtr,
1271da177e4SLinus Torvalds sdtr_sent,
1281da177e4SLinus Torvalds sdtr_done
1291da177e4SLinus Torvalds };
1301da177e4SLinus Torvalds
1311da177e4SLinus Torvalds struct mesh_target {
1321da177e4SLinus Torvalds enum sdtr_phase sdtr_state;
1331da177e4SLinus Torvalds int sync_params;
1341da177e4SLinus Torvalds int data_goes_out; /* guess as to data direction */
1351da177e4SLinus Torvalds struct scsi_cmnd *current_req;
1361da177e4SLinus Torvalds u32 saved_ptr;
1371da177e4SLinus Torvalds #ifdef MESH_DBG
1381da177e4SLinus Torvalds int log_ix;
1391da177e4SLinus Torvalds int n_log;
1401da177e4SLinus Torvalds struct dbglog log[N_DBG_LOG];
1411da177e4SLinus Torvalds #endif
1421da177e4SLinus Torvalds };
1431da177e4SLinus Torvalds
1441da177e4SLinus Torvalds struct mesh_state {
1451da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mesh;
1461da177e4SLinus Torvalds int meshintr;
1471da177e4SLinus Torvalds volatile struct dbdma_regs __iomem *dma;
1481da177e4SLinus Torvalds int dmaintr;
1491da177e4SLinus Torvalds struct Scsi_Host *host;
1501da177e4SLinus Torvalds struct mesh_state *next;
1511da177e4SLinus Torvalds struct scsi_cmnd *request_q;
1521da177e4SLinus Torvalds struct scsi_cmnd *request_qtail;
1531da177e4SLinus Torvalds enum mesh_phase phase; /* what we're currently trying to do */
1541da177e4SLinus Torvalds enum msg_phase msgphase;
1551da177e4SLinus Torvalds int conn_tgt; /* target we're connected to */
1561da177e4SLinus Torvalds struct scsi_cmnd *current_req; /* req we're currently working on */
1571da177e4SLinus Torvalds int data_ptr;
1581da177e4SLinus Torvalds int dma_started;
1591da177e4SLinus Torvalds int dma_count;
1601da177e4SLinus Torvalds int stat;
1611da177e4SLinus Torvalds int aborting;
1621da177e4SLinus Torvalds int expect_reply;
1631da177e4SLinus Torvalds int n_msgin;
1641da177e4SLinus Torvalds u8 msgin[16];
1651da177e4SLinus Torvalds int n_msgout;
1661da177e4SLinus Torvalds int last_n_msgout;
1671da177e4SLinus Torvalds u8 msgout[16];
1681da177e4SLinus Torvalds struct dbdma_cmd *dma_cmds; /* space for dbdma commands, aligned */
1691da177e4SLinus Torvalds dma_addr_t dma_cmd_bus;
1701da177e4SLinus Torvalds void *dma_cmd_space;
1711da177e4SLinus Torvalds int dma_cmd_size;
1721da177e4SLinus Torvalds int clk_freq;
1731da177e4SLinus Torvalds struct mesh_target tgts[8];
1741da177e4SLinus Torvalds struct macio_dev *mdev;
1751da177e4SLinus Torvalds struct pci_dev* pdev;
1761da177e4SLinus Torvalds #ifdef MESH_DBG
1771da177e4SLinus Torvalds int log_ix;
1781da177e4SLinus Torvalds int n_log;
1791da177e4SLinus Torvalds struct dbglog log[N_DBG_SLOG];
1801da177e4SLinus Torvalds #endif
1811da177e4SLinus Torvalds };
1821da177e4SLinus Torvalds
1831da177e4SLinus Torvalds /*
1841da177e4SLinus Torvalds * Driver is too messy, we need a few prototypes...
1851da177e4SLinus Torvalds */
1861da177e4SLinus Torvalds static void mesh_done(struct mesh_state *ms, int start_next);
1872135be5fSOlaf Hering static void mesh_interrupt(struct mesh_state *ms);
1881da177e4SLinus Torvalds static void cmd_complete(struct mesh_state *ms);
1891da177e4SLinus Torvalds static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd);
1901da177e4SLinus Torvalds static void halt_dma(struct mesh_state *ms);
1911da177e4SLinus Torvalds static void phase_mismatch(struct mesh_state *ms);
1921da177e4SLinus Torvalds
1931da177e4SLinus Torvalds
1941da177e4SLinus Torvalds /*
1951da177e4SLinus Torvalds * Some debugging & logging routines
1961da177e4SLinus Torvalds */
1971da177e4SLinus Torvalds
1981da177e4SLinus Torvalds #ifdef MESH_DBG
1991da177e4SLinus Torvalds
readtb(void)2001da177e4SLinus Torvalds static inline u32 readtb(void)
2011da177e4SLinus Torvalds {
2021da177e4SLinus Torvalds u32 tb;
2031da177e4SLinus Torvalds
2041da177e4SLinus Torvalds #ifdef DBG_USE_TB
2051da177e4SLinus Torvalds /* Beware: if you enable this, it will crash on 601s. */
2061da177e4SLinus Torvalds asm ("mftb %0" : "=r" (tb) : );
2071da177e4SLinus Torvalds #else
2081da177e4SLinus Torvalds tb = 0;
2091da177e4SLinus Torvalds #endif
2101da177e4SLinus Torvalds return tb;
2111da177e4SLinus Torvalds }
2121da177e4SLinus Torvalds
dlog(struct mesh_state * ms,char * fmt,int a)2131da177e4SLinus Torvalds static void dlog(struct mesh_state *ms, char *fmt, int a)
2141da177e4SLinus Torvalds {
2151da177e4SLinus Torvalds struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
2161da177e4SLinus Torvalds struct dbglog *tlp, *slp;
2171da177e4SLinus Torvalds
2181da177e4SLinus Torvalds tlp = &tp->log[tp->log_ix];
2191da177e4SLinus Torvalds slp = &ms->log[ms->log_ix];
2201da177e4SLinus Torvalds tlp->fmt = fmt;
2211da177e4SLinus Torvalds tlp->tb = readtb();
2221da177e4SLinus Torvalds tlp->phase = (ms->msgphase << 4) + ms->phase;
2231da177e4SLinus Torvalds tlp->bs0 = ms->mesh->bus_status0;
2241da177e4SLinus Torvalds tlp->bs1 = ms->mesh->bus_status1;
2251da177e4SLinus Torvalds tlp->tgt = ms->conn_tgt;
2261da177e4SLinus Torvalds tlp->d = a;
2271da177e4SLinus Torvalds *slp = *tlp;
2281da177e4SLinus Torvalds if (++tp->log_ix >= N_DBG_LOG)
2291da177e4SLinus Torvalds tp->log_ix = 0;
2301da177e4SLinus Torvalds if (tp->n_log < N_DBG_LOG)
2311da177e4SLinus Torvalds ++tp->n_log;
2321da177e4SLinus Torvalds if (++ms->log_ix >= N_DBG_SLOG)
2331da177e4SLinus Torvalds ms->log_ix = 0;
2341da177e4SLinus Torvalds if (ms->n_log < N_DBG_SLOG)
2351da177e4SLinus Torvalds ++ms->n_log;
2361da177e4SLinus Torvalds }
2371da177e4SLinus Torvalds
dumplog(struct mesh_state * ms,int t)2381da177e4SLinus Torvalds static void dumplog(struct mesh_state *ms, int t)
2391da177e4SLinus Torvalds {
2401da177e4SLinus Torvalds struct mesh_target *tp = &ms->tgts[t];
2411da177e4SLinus Torvalds struct dbglog *lp;
2421da177e4SLinus Torvalds int i;
2431da177e4SLinus Torvalds
2441da177e4SLinus Torvalds if (tp->n_log == 0)
2451da177e4SLinus Torvalds return;
2461da177e4SLinus Torvalds i = tp->log_ix - tp->n_log;
2471da177e4SLinus Torvalds if (i < 0)
2481da177e4SLinus Torvalds i += N_DBG_LOG;
2491da177e4SLinus Torvalds tp->n_log = 0;
2501da177e4SLinus Torvalds do {
2511da177e4SLinus Torvalds lp = &tp->log[i];
2521da177e4SLinus Torvalds printk(KERN_DEBUG "mesh log %d: bs=%.2x%.2x ph=%.2x ",
2531da177e4SLinus Torvalds t, lp->bs1, lp->bs0, lp->phase);
2541da177e4SLinus Torvalds #ifdef DBG_USE_TB
2551da177e4SLinus Torvalds printk("tb=%10u ", lp->tb);
2561da177e4SLinus Torvalds #endif
2571da177e4SLinus Torvalds printk(lp->fmt, lp->d);
2581da177e4SLinus Torvalds printk("\n");
2591da177e4SLinus Torvalds if (++i >= N_DBG_LOG)
2601da177e4SLinus Torvalds i = 0;
2611da177e4SLinus Torvalds } while (i != tp->log_ix);
2621da177e4SLinus Torvalds }
2631da177e4SLinus Torvalds
dumpslog(struct mesh_state * ms)2641da177e4SLinus Torvalds static void dumpslog(struct mesh_state *ms)
2651da177e4SLinus Torvalds {
2661da177e4SLinus Torvalds struct dbglog *lp;
2671da177e4SLinus Torvalds int i;
2681da177e4SLinus Torvalds
2691da177e4SLinus Torvalds if (ms->n_log == 0)
2701da177e4SLinus Torvalds return;
2711da177e4SLinus Torvalds i = ms->log_ix - ms->n_log;
2721da177e4SLinus Torvalds if (i < 0)
2731da177e4SLinus Torvalds i += N_DBG_SLOG;
2741da177e4SLinus Torvalds ms->n_log = 0;
2751da177e4SLinus Torvalds do {
2761da177e4SLinus Torvalds lp = &ms->log[i];
2771da177e4SLinus Torvalds printk(KERN_DEBUG "mesh log: bs=%.2x%.2x ph=%.2x t%d ",
2781da177e4SLinus Torvalds lp->bs1, lp->bs0, lp->phase, lp->tgt);
2791da177e4SLinus Torvalds #ifdef DBG_USE_TB
2801da177e4SLinus Torvalds printk("tb=%10u ", lp->tb);
2811da177e4SLinus Torvalds #endif
2821da177e4SLinus Torvalds printk(lp->fmt, lp->d);
2831da177e4SLinus Torvalds printk("\n");
2841da177e4SLinus Torvalds if (++i >= N_DBG_SLOG)
2851da177e4SLinus Torvalds i = 0;
2861da177e4SLinus Torvalds } while (i != ms->log_ix);
2871da177e4SLinus Torvalds }
2881da177e4SLinus Torvalds
2891da177e4SLinus Torvalds #else
2901da177e4SLinus Torvalds
dlog(struct mesh_state * ms,char * fmt,int a)2911da177e4SLinus Torvalds static inline void dlog(struct mesh_state *ms, char *fmt, int a)
2921da177e4SLinus Torvalds {}
dumplog(struct mesh_state * ms,int tgt)2931da177e4SLinus Torvalds static inline void dumplog(struct mesh_state *ms, int tgt)
2941da177e4SLinus Torvalds {}
dumpslog(struct mesh_state * ms)2951da177e4SLinus Torvalds static inline void dumpslog(struct mesh_state *ms)
2961da177e4SLinus Torvalds {}
2971da177e4SLinus Torvalds
2981da177e4SLinus Torvalds #endif /* MESH_DBG */
2991da177e4SLinus Torvalds
3001da177e4SLinus Torvalds #define MKWORD(a, b, c, d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
3011da177e4SLinus Torvalds
3021da177e4SLinus Torvalds static void
mesh_dump_regs(struct mesh_state * ms)3031da177e4SLinus Torvalds mesh_dump_regs(struct mesh_state *ms)
3041da177e4SLinus Torvalds {
3051da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr = ms->mesh;
3061da177e4SLinus Torvalds volatile struct dbdma_regs __iomem *md = ms->dma;
3071da177e4SLinus Torvalds int t;
3081da177e4SLinus Torvalds struct mesh_target *tp;
3091da177e4SLinus Torvalds
3101da177e4SLinus Torvalds printk(KERN_DEBUG "mesh: state at %p, regs at %p, dma at %p\n",
3111da177e4SLinus Torvalds ms, mr, md);
3121da177e4SLinus Torvalds printk(KERN_DEBUG " ct=%4x seq=%2x bs=%4x fc=%2x "
3131da177e4SLinus Torvalds "exc=%2x err=%2x im=%2x int=%2x sp=%2x\n",
3141da177e4SLinus Torvalds (mr->count_hi << 8) + mr->count_lo, mr->sequence,
3151da177e4SLinus Torvalds (mr->bus_status1 << 8) + mr->bus_status0, mr->fifo_count,
3161da177e4SLinus Torvalds mr->exception, mr->error, mr->intr_mask, mr->interrupt,
3171da177e4SLinus Torvalds mr->sync_params);
3181da177e4SLinus Torvalds while(in_8(&mr->fifo_count))
3191da177e4SLinus Torvalds printk(KERN_DEBUG " fifo data=%.2x\n",in_8(&mr->fifo));
3201da177e4SLinus Torvalds printk(KERN_DEBUG " dma stat=%x cmdptr=%x\n",
3211da177e4SLinus Torvalds in_le32(&md->status), in_le32(&md->cmdptr));
3221da177e4SLinus Torvalds printk(KERN_DEBUG " phase=%d msgphase=%d conn_tgt=%d data_ptr=%d\n",
3231da177e4SLinus Torvalds ms->phase, ms->msgphase, ms->conn_tgt, ms->data_ptr);
3241da177e4SLinus Torvalds printk(KERN_DEBUG " dma_st=%d dma_ct=%d n_msgout=%d\n",
3251da177e4SLinus Torvalds ms->dma_started, ms->dma_count, ms->n_msgout);
3261da177e4SLinus Torvalds for (t = 0; t < 8; ++t) {
3271da177e4SLinus Torvalds tp = &ms->tgts[t];
3281da177e4SLinus Torvalds if (tp->current_req == NULL)
3291da177e4SLinus Torvalds continue;
3301da177e4SLinus Torvalds printk(KERN_DEBUG " target %d: req=%p goes_out=%d saved_ptr=%d\n",
3311da177e4SLinus Torvalds t, tp->current_req, tp->data_goes_out, tp->saved_ptr);
3321da177e4SLinus Torvalds }
3331da177e4SLinus Torvalds }
3341da177e4SLinus Torvalds
3351da177e4SLinus Torvalds
3361da177e4SLinus Torvalds /*
3371da177e4SLinus Torvalds * Flush write buffers on the bus path to the mesh
3381da177e4SLinus Torvalds */
mesh_flush_io(volatile struct mesh_regs __iomem * mr)3391da177e4SLinus Torvalds static inline void mesh_flush_io(volatile struct mesh_regs __iomem *mr)
3401da177e4SLinus Torvalds {
3411da177e4SLinus Torvalds (void)in_8(&mr->mesh_id);
3421da177e4SLinus Torvalds }
3431da177e4SLinus Torvalds
3441da177e4SLinus Torvalds
3451da177e4SLinus Torvalds /* Called with meshinterrupt disabled, initialize the chipset
3461da177e4SLinus Torvalds * and eventually do the initial bus reset. The lock must not be
3471da177e4SLinus Torvalds * held since we can schedule.
3481da177e4SLinus Torvalds */
mesh_init(struct mesh_state * ms)3491da177e4SLinus Torvalds static void mesh_init(struct mesh_state *ms)
3501da177e4SLinus Torvalds {
3511da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr = ms->mesh;
3521da177e4SLinus Torvalds volatile struct dbdma_regs __iomem *md = ms->dma;
3531da177e4SLinus Torvalds
3541da177e4SLinus Torvalds mesh_flush_io(mr);
3551da177e4SLinus Torvalds udelay(100);
3561da177e4SLinus Torvalds
3571da177e4SLinus Torvalds /* Reset controller */
3581da177e4SLinus Torvalds out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* stop dma */
3591da177e4SLinus Torvalds out_8(&mr->exception, 0xff); /* clear all exception bits */
3601da177e4SLinus Torvalds out_8(&mr->error, 0xff); /* clear all error bits */
3611da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_RESETMESH);
3621da177e4SLinus Torvalds mesh_flush_io(mr);
3631da177e4SLinus Torvalds udelay(10);
3641da177e4SLinus Torvalds out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
3651da177e4SLinus Torvalds out_8(&mr->source_id, ms->host->this_id);
3661da177e4SLinus Torvalds out_8(&mr->sel_timeout, 25); /* 250ms */
3671da177e4SLinus Torvalds out_8(&mr->sync_params, ASYNC_PARAMS);
3681da177e4SLinus Torvalds
3691da177e4SLinus Torvalds if (init_reset_delay) {
3701da177e4SLinus Torvalds printk(KERN_INFO "mesh: performing initial bus reset...\n");
3711da177e4SLinus Torvalds
3721da177e4SLinus Torvalds /* Reset bus */
3731da177e4SLinus Torvalds out_8(&mr->bus_status1, BS1_RST); /* assert RST */
3741da177e4SLinus Torvalds mesh_flush_io(mr);
3751da177e4SLinus Torvalds udelay(30); /* leave it on for >= 25us */
3761da177e4SLinus Torvalds out_8(&mr->bus_status1, 0); /* negate RST */
3771da177e4SLinus Torvalds mesh_flush_io(mr);
3781da177e4SLinus Torvalds
3791da177e4SLinus Torvalds /* Wait for bus to come back */
3801da177e4SLinus Torvalds msleep(init_reset_delay);
3811da177e4SLinus Torvalds }
3821da177e4SLinus Torvalds
3831da177e4SLinus Torvalds /* Reconfigure controller */
3841da177e4SLinus Torvalds out_8(&mr->interrupt, 0xff); /* clear all interrupt bits */
3851da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_FLUSHFIFO);
3861da177e4SLinus Torvalds mesh_flush_io(mr);
3871da177e4SLinus Torvalds udelay(1);
3881da177e4SLinus Torvalds out_8(&mr->sync_params, ASYNC_PARAMS);
3891da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_ENBRESEL);
3901da177e4SLinus Torvalds
3911da177e4SLinus Torvalds ms->phase = idle;
3921da177e4SLinus Torvalds ms->msgphase = msg_none;
3931da177e4SLinus Torvalds }
3941da177e4SLinus Torvalds
3951da177e4SLinus Torvalds
mesh_start_cmd(struct mesh_state * ms,struct scsi_cmnd * cmd)3961da177e4SLinus Torvalds static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
3971da177e4SLinus Torvalds {
3981da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr = ms->mesh;
3991da177e4SLinus Torvalds int t, id;
4001da177e4SLinus Torvalds
4011da177e4SLinus Torvalds id = cmd->device->id;
4021da177e4SLinus Torvalds ms->current_req = cmd;
4031da177e4SLinus Torvalds ms->tgts[id].data_goes_out = cmd->sc_data_direction == DMA_TO_DEVICE;
4041da177e4SLinus Torvalds ms->tgts[id].current_req = cmd;
4051da177e4SLinus Torvalds
4061da177e4SLinus Torvalds #if 1
4071da177e4SLinus Torvalds if (DEBUG_TARGET(cmd)) {
4081da177e4SLinus Torvalds int i;
4095cd049a5SChristoph Hellwig printk(KERN_DEBUG "mesh_start: %p tgt=%d cmd=", cmd, id);
4101da177e4SLinus Torvalds for (i = 0; i < cmd->cmd_len; ++i)
4111da177e4SLinus Torvalds printk(" %x", cmd->cmnd[i]);
4121da177e4SLinus Torvalds printk(" use_sg=%d buffer=%p bufflen=%u\n",
413f0002c4eSFUJITA Tomonori scsi_sg_count(cmd), scsi_sglist(cmd), scsi_bufflen(cmd));
4141da177e4SLinus Torvalds }
4151da177e4SLinus Torvalds #endif
4161da177e4SLinus Torvalds if (ms->dma_started)
4171da177e4SLinus Torvalds panic("mesh: double DMA start !\n");
4181da177e4SLinus Torvalds
4191da177e4SLinus Torvalds ms->phase = arbitrating;
4201da177e4SLinus Torvalds ms->msgphase = msg_none;
4211da177e4SLinus Torvalds ms->data_ptr = 0;
4221da177e4SLinus Torvalds ms->dma_started = 0;
4231da177e4SLinus Torvalds ms->n_msgout = 0;
4241da177e4SLinus Torvalds ms->last_n_msgout = 0;
4251da177e4SLinus Torvalds ms->expect_reply = 0;
4261da177e4SLinus Torvalds ms->conn_tgt = id;
4271da177e4SLinus Torvalds ms->tgts[id].saved_ptr = 0;
4281da177e4SLinus Torvalds ms->stat = DID_OK;
4291da177e4SLinus Torvalds ms->aborting = 0;
4301da177e4SLinus Torvalds #ifdef MESH_DBG
4311da177e4SLinus Torvalds ms->tgts[id].n_log = 0;
4321da177e4SLinus Torvalds dlog(ms, "start cmd=%x", (int) cmd);
4331da177e4SLinus Torvalds #endif
4341da177e4SLinus Torvalds
4351da177e4SLinus Torvalds /* Off we go */
4361da177e4SLinus Torvalds dlog(ms, "about to arb, intr/exc/err/fc=%.8x",
4371da177e4SLinus Torvalds MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));
4381da177e4SLinus Torvalds out_8(&mr->interrupt, INT_CMDDONE);
4391da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_ENBRESEL);
4401da177e4SLinus Torvalds mesh_flush_io(mr);
4411da177e4SLinus Torvalds udelay(1);
4421da177e4SLinus Torvalds
4431da177e4SLinus Torvalds if (in_8(&mr->bus_status1) & (BS1_BSY | BS1_SEL)) {
4441da177e4SLinus Torvalds /*
4451da177e4SLinus Torvalds * Some other device has the bus or is arbitrating for it -
4461da177e4SLinus Torvalds * probably a target which is about to reselect us.
4471da177e4SLinus Torvalds */
4481da177e4SLinus Torvalds dlog(ms, "busy b4 arb, intr/exc/err/fc=%.8x",
4491da177e4SLinus Torvalds MKWORD(mr->interrupt, mr->exception,
4501da177e4SLinus Torvalds mr->error, mr->fifo_count));
4511da177e4SLinus Torvalds for (t = 100; t > 0; --t) {
4521da177e4SLinus Torvalds if ((in_8(&mr->bus_status1) & (BS1_BSY | BS1_SEL)) == 0)
4531da177e4SLinus Torvalds break;
4541da177e4SLinus Torvalds if (in_8(&mr->interrupt) != 0) {
4551da177e4SLinus Torvalds dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x",
4561da177e4SLinus Torvalds MKWORD(mr->interrupt, mr->exception,
4571da177e4SLinus Torvalds mr->error, mr->fifo_count));
4582135be5fSOlaf Hering mesh_interrupt(ms);
4591da177e4SLinus Torvalds if (ms->phase != arbitrating)
4601da177e4SLinus Torvalds return;
4611da177e4SLinus Torvalds }
4621da177e4SLinus Torvalds udelay(1);
4631da177e4SLinus Torvalds }
4641da177e4SLinus Torvalds if (in_8(&mr->bus_status1) & (BS1_BSY | BS1_SEL)) {
4651da177e4SLinus Torvalds /* XXX should try again in a little while */
4661da177e4SLinus Torvalds ms->stat = DID_BUS_BUSY;
4671da177e4SLinus Torvalds ms->phase = idle;
4681da177e4SLinus Torvalds mesh_done(ms, 0);
4691da177e4SLinus Torvalds return;
4701da177e4SLinus Torvalds }
4711da177e4SLinus Torvalds }
4721da177e4SLinus Torvalds
4731da177e4SLinus Torvalds /*
4741da177e4SLinus Torvalds * Apparently the mesh has a bug where it will assert both its
4751da177e4SLinus Torvalds * own bit and the target's bit on the bus during arbitration.
4761da177e4SLinus Torvalds */
4771da177e4SLinus Torvalds out_8(&mr->dest_id, mr->source_id);
4781da177e4SLinus Torvalds
4791da177e4SLinus Torvalds /*
4801da177e4SLinus Torvalds * There appears to be a race with reselection sometimes,
4811da177e4SLinus Torvalds * where a target reselects us just as we issue the
4821da177e4SLinus Torvalds * arbitrate command. It seems that then the arbitrate
4831da177e4SLinus Torvalds * command just hangs waiting for the bus to be free
4841da177e4SLinus Torvalds * without giving us a reselection exception.
4851da177e4SLinus Torvalds * The only way I have found to get it to respond correctly
4861da177e4SLinus Torvalds * is this: disable reselection before issuing the arbitrate
4871da177e4SLinus Torvalds * command, then after issuing it, if it looks like a target
4881da177e4SLinus Torvalds * is trying to reselect us, reset the mesh and then enable
4891da177e4SLinus Torvalds * reselection.
4901da177e4SLinus Torvalds */
4911da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_DISRESEL);
4921da177e4SLinus Torvalds if (in_8(&mr->interrupt) != 0) {
4931da177e4SLinus Torvalds dlog(ms, "intr after disresel, intr/exc/err/fc=%.8x",
4941da177e4SLinus Torvalds MKWORD(mr->interrupt, mr->exception,
4951da177e4SLinus Torvalds mr->error, mr->fifo_count));
4962135be5fSOlaf Hering mesh_interrupt(ms);
4971da177e4SLinus Torvalds if (ms->phase != arbitrating)
4981da177e4SLinus Torvalds return;
4991da177e4SLinus Torvalds dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x",
5001da177e4SLinus Torvalds MKWORD(mr->interrupt, mr->exception,
5011da177e4SLinus Torvalds mr->error, mr->fifo_count));
5021da177e4SLinus Torvalds }
5031da177e4SLinus Torvalds
5041da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_ARBITRATE);
5051da177e4SLinus Torvalds
5061da177e4SLinus Torvalds for (t = 230; t > 0; --t) {
5071da177e4SLinus Torvalds if (in_8(&mr->interrupt) != 0)
5081da177e4SLinus Torvalds break;
5091da177e4SLinus Torvalds udelay(1);
5101da177e4SLinus Torvalds }
5111da177e4SLinus Torvalds dlog(ms, "after arb, intr/exc/err/fc=%.8x",
5121da177e4SLinus Torvalds MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));
5131da177e4SLinus Torvalds if (in_8(&mr->interrupt) == 0 && (in_8(&mr->bus_status1) & BS1_SEL)
5141da177e4SLinus Torvalds && (in_8(&mr->bus_status0) & BS0_IO)) {
5151da177e4SLinus Torvalds /* looks like a reselection - try resetting the mesh */
5161da177e4SLinus Torvalds dlog(ms, "resel? after arb, intr/exc/err/fc=%.8x",
5171da177e4SLinus Torvalds MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));
5181da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_RESETMESH);
5191da177e4SLinus Torvalds mesh_flush_io(mr);
5201da177e4SLinus Torvalds udelay(10);
5211da177e4SLinus Torvalds out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
5221da177e4SLinus Torvalds out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
5231da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_ENBRESEL);
5241da177e4SLinus Torvalds mesh_flush_io(mr);
5251da177e4SLinus Torvalds for (t = 10; t > 0 && in_8(&mr->interrupt) == 0; --t)
5261da177e4SLinus Torvalds udelay(1);
5271da177e4SLinus Torvalds dlog(ms, "tried reset after arb, intr/exc/err/fc=%.8x",
5281da177e4SLinus Torvalds MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));
5291da177e4SLinus Torvalds #ifndef MESH_MULTIPLE_HOSTS
5301da177e4SLinus Torvalds if (in_8(&mr->interrupt) == 0 && (in_8(&mr->bus_status1) & BS1_SEL)
5311da177e4SLinus Torvalds && (in_8(&mr->bus_status0) & BS0_IO)) {
5321da177e4SLinus Torvalds printk(KERN_ERR "mesh: controller not responding"
5331da177e4SLinus Torvalds " to reselection!\n");
5341da177e4SLinus Torvalds /*
5351da177e4SLinus Torvalds * If this is a target reselecting us, and the
5361da177e4SLinus Torvalds * mesh isn't responding, the higher levels of
5371da177e4SLinus Torvalds * the scsi code will eventually time out and
5381da177e4SLinus Torvalds * reset the bus.
5391da177e4SLinus Torvalds */
5401da177e4SLinus Torvalds }
5411da177e4SLinus Torvalds #endif
5421da177e4SLinus Torvalds }
5431da177e4SLinus Torvalds }
5441da177e4SLinus Torvalds
5451da177e4SLinus Torvalds /*
5461da177e4SLinus Torvalds * Start the next command for a MESH.
5471da177e4SLinus Torvalds * Should be called with interrupts disabled.
5481da177e4SLinus Torvalds */
mesh_start(struct mesh_state * ms)5491da177e4SLinus Torvalds static void mesh_start(struct mesh_state *ms)
5501da177e4SLinus Torvalds {
5511da177e4SLinus Torvalds struct scsi_cmnd *cmd, *prev, *next;
5521da177e4SLinus Torvalds
5531da177e4SLinus Torvalds if (ms->phase != idle || ms->current_req != NULL) {
5541da177e4SLinus Torvalds printk(KERN_ERR "inappropriate mesh_start (phase=%d, ms=%p)",
5551da177e4SLinus Torvalds ms->phase, ms);
5561da177e4SLinus Torvalds return;
5571da177e4SLinus Torvalds }
5581da177e4SLinus Torvalds
5591da177e4SLinus Torvalds while (ms->phase == idle) {
5601da177e4SLinus Torvalds prev = NULL;
5611da177e4SLinus Torvalds for (cmd = ms->request_q; ; cmd = (struct scsi_cmnd *) cmd->host_scribble) {
5621da177e4SLinus Torvalds if (cmd == NULL)
5631da177e4SLinus Torvalds return;
5641da177e4SLinus Torvalds if (ms->tgts[cmd->device->id].current_req == NULL)
5651da177e4SLinus Torvalds break;
5661da177e4SLinus Torvalds prev = cmd;
5671da177e4SLinus Torvalds }
5681da177e4SLinus Torvalds next = (struct scsi_cmnd *) cmd->host_scribble;
5691da177e4SLinus Torvalds if (prev == NULL)
5701da177e4SLinus Torvalds ms->request_q = next;
5711da177e4SLinus Torvalds else
5721da177e4SLinus Torvalds prev->host_scribble = (void *) next;
5731da177e4SLinus Torvalds if (next == NULL)
5741da177e4SLinus Torvalds ms->request_qtail = prev;
5751da177e4SLinus Torvalds
5761da177e4SLinus Torvalds mesh_start_cmd(ms, cmd);
5771da177e4SLinus Torvalds }
5781da177e4SLinus Torvalds }
5791da177e4SLinus Torvalds
mesh_done(struct mesh_state * ms,int start_next)5801da177e4SLinus Torvalds static void mesh_done(struct mesh_state *ms, int start_next)
5811da177e4SLinus Torvalds {
5821da177e4SLinus Torvalds struct scsi_cmnd *cmd;
5831da177e4SLinus Torvalds struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
5841da177e4SLinus Torvalds
5851da177e4SLinus Torvalds cmd = ms->current_req;
5861da177e4SLinus Torvalds ms->current_req = NULL;
5871da177e4SLinus Torvalds tp->current_req = NULL;
5881da177e4SLinus Torvalds if (cmd) {
5892e1b3175SFinn Thain struct mesh_cmd_priv *mcmd = mesh_priv(cmd);
59057cbd78eSBart Van Assche
5913ff451e9SHannes Reinecke set_host_byte(cmd, ms->stat);
5922e1b3175SFinn Thain set_status_byte(cmd, mcmd->status);
5931da177e4SLinus Torvalds if (ms->stat == DID_OK)
5942e1b3175SFinn Thain scsi_msg_to_host_byte(cmd, mcmd->message);
5951da177e4SLinus Torvalds if (DEBUG_TARGET(cmd)) {
5961da177e4SLinus Torvalds printk(KERN_DEBUG "mesh_done: result = %x, data_ptr=%d, buflen=%d\n",
597f0002c4eSFUJITA Tomonori cmd->result, ms->data_ptr, scsi_bufflen(cmd));
598f0002c4eSFUJITA Tomonori #if 0
599f0002c4eSFUJITA Tomonori /* needs to use sg? */
6001da177e4SLinus Torvalds if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12 || cmd->cmnd[0] == 3)
6011da177e4SLinus Torvalds && cmd->request_buffer != 0) {
6021da177e4SLinus Torvalds unsigned char *b = cmd->request_buffer;
6031da177e4SLinus Torvalds printk(KERN_DEBUG "buffer = %x %x %x %x %x %x %x %x\n",
6041da177e4SLinus Torvalds b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
6051da177e4SLinus Torvalds }
606f0002c4eSFUJITA Tomonori #endif
6071da177e4SLinus Torvalds }
6082e1b3175SFinn Thain mcmd->this_residual -= ms->data_ptr;
609aaf2173bSBart Van Assche scsi_done(cmd);
6101da177e4SLinus Torvalds }
6111da177e4SLinus Torvalds if (start_next) {
6121da177e4SLinus Torvalds out_8(&ms->mesh->sequence, SEQ_ENBRESEL);
6131da177e4SLinus Torvalds mesh_flush_io(ms->mesh);
6141da177e4SLinus Torvalds udelay(1);
6151da177e4SLinus Torvalds ms->phase = idle;
6161da177e4SLinus Torvalds mesh_start(ms);
6171da177e4SLinus Torvalds }
6181da177e4SLinus Torvalds }
6191da177e4SLinus Torvalds
add_sdtr_msg(struct mesh_state * ms)6201da177e4SLinus Torvalds static inline void add_sdtr_msg(struct mesh_state *ms)
6211da177e4SLinus Torvalds {
6221da177e4SLinus Torvalds int i = ms->n_msgout;
6231da177e4SLinus Torvalds
6241da177e4SLinus Torvalds ms->msgout[i] = EXTENDED_MESSAGE;
6251da177e4SLinus Torvalds ms->msgout[i+1] = 3;
6261da177e4SLinus Torvalds ms->msgout[i+2] = EXTENDED_SDTR;
6271da177e4SLinus Torvalds ms->msgout[i+3] = mesh_sync_period/4;
6281da177e4SLinus Torvalds ms->msgout[i+4] = (ALLOW_SYNC(ms->conn_tgt)? mesh_sync_offset: 0);
6291da177e4SLinus Torvalds ms->n_msgout = i + 5;
6301da177e4SLinus Torvalds }
6311da177e4SLinus Torvalds
set_sdtr(struct mesh_state * ms,int period,int offset)6321da177e4SLinus Torvalds static void set_sdtr(struct mesh_state *ms, int period, int offset)
6331da177e4SLinus Torvalds {
6341da177e4SLinus Torvalds struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
6351da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr = ms->mesh;
6361da177e4SLinus Torvalds int v, tr;
6371da177e4SLinus Torvalds
6381da177e4SLinus Torvalds tp->sdtr_state = sdtr_done;
6391da177e4SLinus Torvalds if (offset == 0) {
6401da177e4SLinus Torvalds /* asynchronous */
6411da177e4SLinus Torvalds if (SYNC_OFF(tp->sync_params))
6421da177e4SLinus Torvalds printk(KERN_INFO "mesh: target %d now asynchronous\n",
6431da177e4SLinus Torvalds ms->conn_tgt);
6441da177e4SLinus Torvalds tp->sync_params = ASYNC_PARAMS;
6451da177e4SLinus Torvalds out_8(&mr->sync_params, ASYNC_PARAMS);
6461da177e4SLinus Torvalds return;
6471da177e4SLinus Torvalds }
6481da177e4SLinus Torvalds /*
6491da177e4SLinus Torvalds * We need to compute ceil(clk_freq * period / 500e6) - 2
6501da177e4SLinus Torvalds * without incurring overflow.
6511da177e4SLinus Torvalds */
6521da177e4SLinus Torvalds v = (ms->clk_freq / 5000) * period;
6531da177e4SLinus Torvalds if (v <= 250000) {
6541da177e4SLinus Torvalds /* special case: sync_period == 5 * clk_period */
6551da177e4SLinus Torvalds v = 0;
6561da177e4SLinus Torvalds /* units of tr are 100kB/s */
6571da177e4SLinus Torvalds tr = (ms->clk_freq + 250000) / 500000;
6581da177e4SLinus Torvalds } else {
6591da177e4SLinus Torvalds /* sync_period == (v + 2) * 2 * clk_period */
6601da177e4SLinus Torvalds v = (v + 99999) / 100000 - 2;
6611da177e4SLinus Torvalds if (v > 15)
6621da177e4SLinus Torvalds v = 15; /* oops */
6631da177e4SLinus Torvalds tr = ((ms->clk_freq / (v + 2)) + 199999) / 200000;
6641da177e4SLinus Torvalds }
6651da177e4SLinus Torvalds if (offset > 15)
6661da177e4SLinus Torvalds offset = 15; /* can't happen */
6671da177e4SLinus Torvalds tp->sync_params = SYNC_PARAMS(offset, v);
6681da177e4SLinus Torvalds out_8(&mr->sync_params, tp->sync_params);
6691da177e4SLinus Torvalds printk(KERN_INFO "mesh: target %d synchronous at %d.%d MB/s\n",
6701da177e4SLinus Torvalds ms->conn_tgt, tr/10, tr%10);
6711da177e4SLinus Torvalds }
6721da177e4SLinus Torvalds
start_phase(struct mesh_state * ms)6731da177e4SLinus Torvalds static void start_phase(struct mesh_state *ms)
6741da177e4SLinus Torvalds {
6751da177e4SLinus Torvalds int i, seq, nb;
6761da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr = ms->mesh;
6771da177e4SLinus Torvalds volatile struct dbdma_regs __iomem *md = ms->dma;
6781da177e4SLinus Torvalds struct scsi_cmnd *cmd = ms->current_req;
6791da177e4SLinus Torvalds struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
6801da177e4SLinus Torvalds
6811da177e4SLinus Torvalds dlog(ms, "start_phase nmo/exc/fc/seq = %.8x",
6821da177e4SLinus Torvalds MKWORD(ms->n_msgout, mr->exception, mr->fifo_count, mr->sequence));
6831da177e4SLinus Torvalds out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
6841da177e4SLinus Torvalds seq = use_active_neg + (ms->n_msgout? SEQ_ATN: 0);
6851da177e4SLinus Torvalds switch (ms->msgphase) {
6861da177e4SLinus Torvalds case msg_none:
6871da177e4SLinus Torvalds break;
6881da177e4SLinus Torvalds
6891da177e4SLinus Torvalds case msg_in:
6901da177e4SLinus Torvalds out_8(&mr->count_hi, 0);
6911da177e4SLinus Torvalds out_8(&mr->count_lo, 1);
6921da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_MSGIN + seq);
6931da177e4SLinus Torvalds ms->n_msgin = 0;
6941da177e4SLinus Torvalds return;
6951da177e4SLinus Torvalds
6961da177e4SLinus Torvalds case msg_out:
6971da177e4SLinus Torvalds /*
6981da177e4SLinus Torvalds * To make sure ATN drops before we assert ACK for
6991da177e4SLinus Torvalds * the last byte of the message, we have to do the
7001da177e4SLinus Torvalds * last byte specially.
7011da177e4SLinus Torvalds */
7021da177e4SLinus Torvalds if (ms->n_msgout <= 0) {
7031da177e4SLinus Torvalds printk(KERN_ERR "mesh: msg_out but n_msgout=%d\n",
7041da177e4SLinus Torvalds ms->n_msgout);
7051da177e4SLinus Torvalds mesh_dump_regs(ms);
7061da177e4SLinus Torvalds ms->msgphase = msg_none;
7071da177e4SLinus Torvalds break;
7081da177e4SLinus Torvalds }
7091da177e4SLinus Torvalds if (ALLOW_DEBUG(ms->conn_tgt)) {
7101da177e4SLinus Torvalds printk(KERN_DEBUG "mesh: sending %d msg bytes:",
7111da177e4SLinus Torvalds ms->n_msgout);
7121da177e4SLinus Torvalds for (i = 0; i < ms->n_msgout; ++i)
7131da177e4SLinus Torvalds printk(" %x", ms->msgout[i]);
7141da177e4SLinus Torvalds printk("\n");
7151da177e4SLinus Torvalds }
7161da177e4SLinus Torvalds dlog(ms, "msgout msg=%.8x", MKWORD(ms->n_msgout, ms->msgout[0],
7171da177e4SLinus Torvalds ms->msgout[1], ms->msgout[2]));
7181da177e4SLinus Torvalds out_8(&mr->count_hi, 0);
7191da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_FLUSHFIFO);
7201da177e4SLinus Torvalds mesh_flush_io(mr);
7211da177e4SLinus Torvalds udelay(1);
7221da177e4SLinus Torvalds /*
7231da177e4SLinus Torvalds * If ATN is not already asserted, we assert it, then
7241da177e4SLinus Torvalds * issue a SEQ_MSGOUT to get the mesh to drop ACK.
7251da177e4SLinus Torvalds */
7261da177e4SLinus Torvalds if ((in_8(&mr->bus_status0) & BS0_ATN) == 0) {
72733430dc5SJean Delvare dlog(ms, "bus0 was %.2x explicitly asserting ATN", mr->bus_status0);
7281da177e4SLinus Torvalds out_8(&mr->bus_status0, BS0_ATN); /* explicit ATN */
7291da177e4SLinus Torvalds mesh_flush_io(mr);
7301da177e4SLinus Torvalds udelay(1);
7311da177e4SLinus Torvalds out_8(&mr->count_lo, 1);
7321da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_MSGOUT + seq);
7331da177e4SLinus Torvalds out_8(&mr->bus_status0, 0); /* release explicit ATN */
7341da177e4SLinus Torvalds dlog(ms,"hace: after explicit ATN bus0=%.2x",mr->bus_status0);
7351da177e4SLinus Torvalds }
7361da177e4SLinus Torvalds if (ms->n_msgout == 1) {
7371da177e4SLinus Torvalds /*
7381da177e4SLinus Torvalds * We can't issue the SEQ_MSGOUT without ATN
7391da177e4SLinus Torvalds * until the target has asserted REQ. The logic
7401da177e4SLinus Torvalds * in cmd_complete handles both situations:
7411da177e4SLinus Torvalds * REQ already asserted or not.
7421da177e4SLinus Torvalds */
7431da177e4SLinus Torvalds cmd_complete(ms);
7441da177e4SLinus Torvalds } else {
7451da177e4SLinus Torvalds out_8(&mr->count_lo, ms->n_msgout - 1);
7461da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_MSGOUT + seq);
7471da177e4SLinus Torvalds for (i = 0; i < ms->n_msgout - 1; ++i)
7481da177e4SLinus Torvalds out_8(&mr->fifo, ms->msgout[i]);
7491da177e4SLinus Torvalds }
7501da177e4SLinus Torvalds return;
7511da177e4SLinus Torvalds
7521da177e4SLinus Torvalds default:
7531da177e4SLinus Torvalds printk(KERN_ERR "mesh bug: start_phase msgphase=%d\n",
7541da177e4SLinus Torvalds ms->msgphase);
7551da177e4SLinus Torvalds }
7561da177e4SLinus Torvalds
7571da177e4SLinus Torvalds switch (ms->phase) {
7581da177e4SLinus Torvalds case selecting:
7591da177e4SLinus Torvalds out_8(&mr->dest_id, ms->conn_tgt);
7601da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_SELECT + SEQ_ATN);
7611da177e4SLinus Torvalds break;
7621da177e4SLinus Torvalds case commanding:
7631da177e4SLinus Torvalds out_8(&mr->sync_params, tp->sync_params);
7641da177e4SLinus Torvalds out_8(&mr->count_hi, 0);
7651da177e4SLinus Torvalds if (cmd) {
7661da177e4SLinus Torvalds out_8(&mr->count_lo, cmd->cmd_len);
7671da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_COMMAND + seq);
7681da177e4SLinus Torvalds for (i = 0; i < cmd->cmd_len; ++i)
7691da177e4SLinus Torvalds out_8(&mr->fifo, cmd->cmnd[i]);
7701da177e4SLinus Torvalds } else {
7711da177e4SLinus Torvalds out_8(&mr->count_lo, 6);
7721da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_COMMAND + seq);
7731da177e4SLinus Torvalds for (i = 0; i < 6; ++i)
7741da177e4SLinus Torvalds out_8(&mr->fifo, 0);
7751da177e4SLinus Torvalds }
7761da177e4SLinus Torvalds break;
7771da177e4SLinus Torvalds case dataing:
7781da177e4SLinus Torvalds /* transfer data, if any */
7791da177e4SLinus Torvalds if (!ms->dma_started) {
7801da177e4SLinus Torvalds set_dma_cmds(ms, cmd);
7811da177e4SLinus Torvalds out_le32(&md->cmdptr, virt_to_phys(ms->dma_cmds));
7821da177e4SLinus Torvalds out_le32(&md->control, (RUN << 16) | RUN);
7831da177e4SLinus Torvalds ms->dma_started = 1;
7841da177e4SLinus Torvalds }
7851da177e4SLinus Torvalds nb = ms->dma_count;
7861da177e4SLinus Torvalds if (nb > 0xfff0)
7871da177e4SLinus Torvalds nb = 0xfff0;
7881da177e4SLinus Torvalds ms->dma_count -= nb;
7891da177e4SLinus Torvalds ms->data_ptr += nb;
7901da177e4SLinus Torvalds out_8(&mr->count_lo, nb);
7911da177e4SLinus Torvalds out_8(&mr->count_hi, nb >> 8);
7921da177e4SLinus Torvalds out_8(&mr->sequence, (tp->data_goes_out?
7931da177e4SLinus Torvalds SEQ_DATAOUT: SEQ_DATAIN) + SEQ_DMA_MODE + seq);
7941da177e4SLinus Torvalds break;
7951da177e4SLinus Torvalds case statusing:
7961da177e4SLinus Torvalds out_8(&mr->count_hi, 0);
7971da177e4SLinus Torvalds out_8(&mr->count_lo, 1);
7981da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_STATUS + seq);
7991da177e4SLinus Torvalds break;
8001da177e4SLinus Torvalds case busfreeing:
8011da177e4SLinus Torvalds case disconnecting:
8021da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_ENBRESEL);
8031da177e4SLinus Torvalds mesh_flush_io(mr);
8041da177e4SLinus Torvalds udelay(1);
8051da177e4SLinus Torvalds dlog(ms, "enbresel intr/exc/err/fc=%.8x",
8061da177e4SLinus Torvalds MKWORD(mr->interrupt, mr->exception, mr->error,
8071da177e4SLinus Torvalds mr->fifo_count));
8081da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_BUSFREE);
8091da177e4SLinus Torvalds break;
8101da177e4SLinus Torvalds default:
8111da177e4SLinus Torvalds printk(KERN_ERR "mesh: start_phase called with phase=%d\n",
8121da177e4SLinus Torvalds ms->phase);
8131da177e4SLinus Torvalds dumpslog(ms);
8141da177e4SLinus Torvalds }
8151da177e4SLinus Torvalds
8161da177e4SLinus Torvalds }
8171da177e4SLinus Torvalds
get_msgin(struct mesh_state * ms)8181da177e4SLinus Torvalds static inline void get_msgin(struct mesh_state *ms)
8191da177e4SLinus Torvalds {
8201da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr = ms->mesh;
8211da177e4SLinus Torvalds int i, n;
8221da177e4SLinus Torvalds
8231da177e4SLinus Torvalds n = mr->fifo_count;
8241da177e4SLinus Torvalds if (n != 0) {
8251da177e4SLinus Torvalds i = ms->n_msgin;
8261da177e4SLinus Torvalds ms->n_msgin = i + n;
8271da177e4SLinus Torvalds for (; n > 0; --n)
8281da177e4SLinus Torvalds ms->msgin[i++] = in_8(&mr->fifo);
8291da177e4SLinus Torvalds }
8301da177e4SLinus Torvalds }
8311da177e4SLinus Torvalds
msgin_length(struct mesh_state * ms)8321da177e4SLinus Torvalds static inline int msgin_length(struct mesh_state *ms)
8331da177e4SLinus Torvalds {
8341da177e4SLinus Torvalds int b, n;
8351da177e4SLinus Torvalds
8361da177e4SLinus Torvalds n = 1;
8371da177e4SLinus Torvalds if (ms->n_msgin > 0) {
8381da177e4SLinus Torvalds b = ms->msgin[0];
8391da177e4SLinus Torvalds if (b == 1) {
8401da177e4SLinus Torvalds /* extended message */
8411da177e4SLinus Torvalds n = ms->n_msgin < 2? 2: ms->msgin[1] + 2;
8421da177e4SLinus Torvalds } else if (0x20 <= b && b <= 0x2f) {
8431da177e4SLinus Torvalds /* 2-byte message */
8441da177e4SLinus Torvalds n = 2;
8451da177e4SLinus Torvalds }
8461da177e4SLinus Torvalds }
8471da177e4SLinus Torvalds return n;
8481da177e4SLinus Torvalds }
8491da177e4SLinus Torvalds
reselected(struct mesh_state * ms)8501da177e4SLinus Torvalds static void reselected(struct mesh_state *ms)
8511da177e4SLinus Torvalds {
8521da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr = ms->mesh;
8531da177e4SLinus Torvalds struct scsi_cmnd *cmd;
8541da177e4SLinus Torvalds struct mesh_target *tp;
8551da177e4SLinus Torvalds int b, t, prev;
8561da177e4SLinus Torvalds
8571da177e4SLinus Torvalds switch (ms->phase) {
8581da177e4SLinus Torvalds case idle:
8591da177e4SLinus Torvalds break;
8601da177e4SLinus Torvalds case arbitrating:
8611da177e4SLinus Torvalds if ((cmd = ms->current_req) != NULL) {
8621da177e4SLinus Torvalds /* put the command back on the queue */
8631da177e4SLinus Torvalds cmd->host_scribble = (void *) ms->request_q;
8641da177e4SLinus Torvalds if (ms->request_q == NULL)
8651da177e4SLinus Torvalds ms->request_qtail = cmd;
8661da177e4SLinus Torvalds ms->request_q = cmd;
8671da177e4SLinus Torvalds tp = &ms->tgts[cmd->device->id];
8681da177e4SLinus Torvalds tp->current_req = NULL;
8691da177e4SLinus Torvalds }
8701da177e4SLinus Torvalds break;
8711da177e4SLinus Torvalds case busfreeing:
8721da177e4SLinus Torvalds ms->phase = reselecting;
8731da177e4SLinus Torvalds mesh_done(ms, 0);
8741da177e4SLinus Torvalds break;
8751da177e4SLinus Torvalds case disconnecting:
8761da177e4SLinus Torvalds break;
8771da177e4SLinus Torvalds default:
8781da177e4SLinus Torvalds printk(KERN_ERR "mesh: reselected in phase %d/%d tgt %d\n",
8791da177e4SLinus Torvalds ms->msgphase, ms->phase, ms->conn_tgt);
8801da177e4SLinus Torvalds dumplog(ms, ms->conn_tgt);
8811da177e4SLinus Torvalds dumpslog(ms);
8821da177e4SLinus Torvalds }
8831da177e4SLinus Torvalds
8841da177e4SLinus Torvalds if (ms->dma_started) {
8851da177e4SLinus Torvalds printk(KERN_ERR "mesh: reselected with DMA started !\n");
8861da177e4SLinus Torvalds halt_dma(ms);
8871da177e4SLinus Torvalds }
8881da177e4SLinus Torvalds ms->current_req = NULL;
8891da177e4SLinus Torvalds ms->phase = dataing;
8901da177e4SLinus Torvalds ms->msgphase = msg_in;
8911da177e4SLinus Torvalds ms->n_msgout = 0;
8921da177e4SLinus Torvalds ms->last_n_msgout = 0;
8931da177e4SLinus Torvalds prev = ms->conn_tgt;
8941da177e4SLinus Torvalds
8951da177e4SLinus Torvalds /*
8961da177e4SLinus Torvalds * We seem to get abortive reselections sometimes.
8971da177e4SLinus Torvalds */
8981da177e4SLinus Torvalds while ((in_8(&mr->bus_status1) & BS1_BSY) == 0) {
8991da177e4SLinus Torvalds static int mesh_aborted_resels;
9001da177e4SLinus Torvalds mesh_aborted_resels++;
9011da177e4SLinus Torvalds out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
9021da177e4SLinus Torvalds mesh_flush_io(mr);
9031da177e4SLinus Torvalds udelay(1);
9041da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_ENBRESEL);
9051da177e4SLinus Torvalds mesh_flush_io(mr);
9061da177e4SLinus Torvalds udelay(5);
9071da177e4SLinus Torvalds dlog(ms, "extra resel err/exc/fc = %.6x",
9081da177e4SLinus Torvalds MKWORD(0, mr->error, mr->exception, mr->fifo_count));
9091da177e4SLinus Torvalds }
9101da177e4SLinus Torvalds out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
9111da177e4SLinus Torvalds mesh_flush_io(mr);
9121da177e4SLinus Torvalds udelay(1);
9131da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_ENBRESEL);
9141da177e4SLinus Torvalds mesh_flush_io(mr);
9151da177e4SLinus Torvalds udelay(1);
9161da177e4SLinus Torvalds out_8(&mr->sync_params, ASYNC_PARAMS);
9171da177e4SLinus Torvalds
9181da177e4SLinus Torvalds /*
9191da177e4SLinus Torvalds * Find out who reselected us.
9201da177e4SLinus Torvalds */
9211da177e4SLinus Torvalds if (in_8(&mr->fifo_count) == 0) {
9221da177e4SLinus Torvalds printk(KERN_ERR "mesh: reselection but nothing in fifo?\n");
9231da177e4SLinus Torvalds ms->conn_tgt = ms->host->this_id;
9241da177e4SLinus Torvalds goto bogus;
9251da177e4SLinus Torvalds }
9261da177e4SLinus Torvalds /* get the last byte in the fifo */
9271da177e4SLinus Torvalds do {
9281da177e4SLinus Torvalds b = in_8(&mr->fifo);
9291da177e4SLinus Torvalds dlog(ms, "reseldata %x", b);
9301da177e4SLinus Torvalds } while (in_8(&mr->fifo_count));
9311da177e4SLinus Torvalds for (t = 0; t < 8; ++t)
9321da177e4SLinus Torvalds if ((b & (1 << t)) != 0 && t != ms->host->this_id)
9331da177e4SLinus Torvalds break;
9341da177e4SLinus Torvalds if (b != (1 << t) + (1 << ms->host->this_id)) {
9351da177e4SLinus Torvalds printk(KERN_ERR "mesh: bad reselection data %x\n", b);
9361da177e4SLinus Torvalds ms->conn_tgt = ms->host->this_id;
9371da177e4SLinus Torvalds goto bogus;
9381da177e4SLinus Torvalds }
9391da177e4SLinus Torvalds
9401da177e4SLinus Torvalds
9411da177e4SLinus Torvalds /*
9421da177e4SLinus Torvalds * Set up to continue with that target's transfer.
9431da177e4SLinus Torvalds */
9441da177e4SLinus Torvalds ms->conn_tgt = t;
9451da177e4SLinus Torvalds tp = &ms->tgts[t];
9461da177e4SLinus Torvalds out_8(&mr->sync_params, tp->sync_params);
9471da177e4SLinus Torvalds if (ALLOW_DEBUG(t)) {
9481da177e4SLinus Torvalds printk(KERN_DEBUG "mesh: reselected by target %d\n", t);
9491da177e4SLinus Torvalds printk(KERN_DEBUG "mesh: saved_ptr=%x goes_out=%d cmd=%p\n",
9501da177e4SLinus Torvalds tp->saved_ptr, tp->data_goes_out, tp->current_req);
9511da177e4SLinus Torvalds }
9521da177e4SLinus Torvalds ms->current_req = tp->current_req;
9531da177e4SLinus Torvalds if (tp->current_req == NULL) {
9541da177e4SLinus Torvalds printk(KERN_ERR "mesh: reselected by tgt %d but no cmd!\n", t);
9551da177e4SLinus Torvalds goto bogus;
9561da177e4SLinus Torvalds }
9571da177e4SLinus Torvalds ms->data_ptr = tp->saved_ptr;
9581da177e4SLinus Torvalds dlog(ms, "resel prev tgt=%d", prev);
9591da177e4SLinus Torvalds dlog(ms, "resel err/exc=%.4x", MKWORD(0, 0, mr->error, mr->exception));
9601da177e4SLinus Torvalds start_phase(ms);
9611da177e4SLinus Torvalds return;
9621da177e4SLinus Torvalds
9631da177e4SLinus Torvalds bogus:
9641da177e4SLinus Torvalds dumplog(ms, ms->conn_tgt);
9651da177e4SLinus Torvalds dumpslog(ms);
9661da177e4SLinus Torvalds ms->data_ptr = 0;
9671da177e4SLinus Torvalds ms->aborting = 1;
9681da177e4SLinus Torvalds start_phase(ms);
9691da177e4SLinus Torvalds }
9701da177e4SLinus Torvalds
do_abort(struct mesh_state * ms)9711da177e4SLinus Torvalds static void do_abort(struct mesh_state *ms)
9721da177e4SLinus Torvalds {
9731da177e4SLinus Torvalds ms->msgout[0] = ABORT;
9741da177e4SLinus Torvalds ms->n_msgout = 1;
9751da177e4SLinus Torvalds ms->aborting = 1;
9761da177e4SLinus Torvalds ms->stat = DID_ABORT;
9771da177e4SLinus Torvalds dlog(ms, "abort", 0);
9781da177e4SLinus Torvalds }
9791da177e4SLinus Torvalds
handle_reset(struct mesh_state * ms)9801da177e4SLinus Torvalds static void handle_reset(struct mesh_state *ms)
9811da177e4SLinus Torvalds {
9821da177e4SLinus Torvalds int tgt;
9831da177e4SLinus Torvalds struct mesh_target *tp;
9841da177e4SLinus Torvalds struct scsi_cmnd *cmd;
9851da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr = ms->mesh;
9861da177e4SLinus Torvalds
9871da177e4SLinus Torvalds for (tgt = 0; tgt < 8; ++tgt) {
9881da177e4SLinus Torvalds tp = &ms->tgts[tgt];
9891da177e4SLinus Torvalds if ((cmd = tp->current_req) != NULL) {
9903ff451e9SHannes Reinecke set_host_byte(cmd, DID_RESET);
9911da177e4SLinus Torvalds tp->current_req = NULL;
992aaf2173bSBart Van Assche scsi_done(cmd);
9931da177e4SLinus Torvalds }
9941da177e4SLinus Torvalds ms->tgts[tgt].sdtr_state = do_sdtr;
9951da177e4SLinus Torvalds ms->tgts[tgt].sync_params = ASYNC_PARAMS;
9961da177e4SLinus Torvalds }
9971da177e4SLinus Torvalds ms->current_req = NULL;
9981da177e4SLinus Torvalds while ((cmd = ms->request_q) != NULL) {
9991da177e4SLinus Torvalds ms->request_q = (struct scsi_cmnd *) cmd->host_scribble;
10003ff451e9SHannes Reinecke set_host_byte(cmd, DID_RESET);
1001aaf2173bSBart Van Assche scsi_done(cmd);
10021da177e4SLinus Torvalds }
10031da177e4SLinus Torvalds ms->phase = idle;
10041da177e4SLinus Torvalds ms->msgphase = msg_none;
10051da177e4SLinus Torvalds out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
10061da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_FLUSHFIFO);
10071da177e4SLinus Torvalds mesh_flush_io(mr);
10081da177e4SLinus Torvalds udelay(1);
10091da177e4SLinus Torvalds out_8(&mr->sync_params, ASYNC_PARAMS);
10101da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_ENBRESEL);
10111da177e4SLinus Torvalds }
10121da177e4SLinus Torvalds
do_mesh_interrupt(int irq,void * dev_id)10137d12e780SDavid Howells static irqreturn_t do_mesh_interrupt(int irq, void *dev_id)
10141da177e4SLinus Torvalds {
10151da177e4SLinus Torvalds unsigned long flags;
10162135be5fSOlaf Hering struct mesh_state *ms = dev_id;
10172135be5fSOlaf Hering struct Scsi_Host *dev = ms->host;
10181da177e4SLinus Torvalds
10191da177e4SLinus Torvalds spin_lock_irqsave(dev->host_lock, flags);
10202135be5fSOlaf Hering mesh_interrupt(ms);
10211da177e4SLinus Torvalds spin_unlock_irqrestore(dev->host_lock, flags);
10221da177e4SLinus Torvalds return IRQ_HANDLED;
10231da177e4SLinus Torvalds }
10241da177e4SLinus Torvalds
handle_error(struct mesh_state * ms)10251da177e4SLinus Torvalds static void handle_error(struct mesh_state *ms)
10261da177e4SLinus Torvalds {
10271da177e4SLinus Torvalds int err, exc, count;
10281da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr = ms->mesh;
10291da177e4SLinus Torvalds
10301da177e4SLinus Torvalds err = in_8(&mr->error);
10311da177e4SLinus Torvalds exc = in_8(&mr->exception);
10321da177e4SLinus Torvalds out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
10331da177e4SLinus Torvalds dlog(ms, "error err/exc/fc/cl=%.8x",
10341da177e4SLinus Torvalds MKWORD(err, exc, mr->fifo_count, mr->count_lo));
10351da177e4SLinus Torvalds if (err & ERR_SCSIRESET) {
10361da177e4SLinus Torvalds /* SCSI bus was reset */
10371da177e4SLinus Torvalds printk(KERN_INFO "mesh: SCSI bus reset detected: "
10381da177e4SLinus Torvalds "waiting for end...");
10391da177e4SLinus Torvalds while ((in_8(&mr->bus_status1) & BS1_RST) != 0)
10401da177e4SLinus Torvalds udelay(1);
10411da177e4SLinus Torvalds printk("done\n");
1042edd7dd22SFinn Thain if (ms->dma_started)
1043edd7dd22SFinn Thain halt_dma(ms);
10441da177e4SLinus Torvalds handle_reset(ms);
10451da177e4SLinus Torvalds /* request_q is empty, no point in mesh_start() */
10461da177e4SLinus Torvalds return;
10471da177e4SLinus Torvalds }
10481da177e4SLinus Torvalds if (err & ERR_UNEXPDISC) {
10491da177e4SLinus Torvalds /* Unexpected disconnect */
10501da177e4SLinus Torvalds if (exc & EXC_RESELECTED) {
10511da177e4SLinus Torvalds reselected(ms);
10521da177e4SLinus Torvalds return;
10531da177e4SLinus Torvalds }
10541da177e4SLinus Torvalds if (!ms->aborting) {
10551da177e4SLinus Torvalds printk(KERN_WARNING "mesh: target %d aborted\n",
10561da177e4SLinus Torvalds ms->conn_tgt);
10571da177e4SLinus Torvalds dumplog(ms, ms->conn_tgt);
10581da177e4SLinus Torvalds dumpslog(ms);
10591da177e4SLinus Torvalds }
10601da177e4SLinus Torvalds out_8(&mr->interrupt, INT_CMDDONE);
10611da177e4SLinus Torvalds ms->stat = DID_ABORT;
10621da177e4SLinus Torvalds mesh_done(ms, 1);
10631da177e4SLinus Torvalds return;
10641da177e4SLinus Torvalds }
10651da177e4SLinus Torvalds if (err & ERR_PARITY) {
10661da177e4SLinus Torvalds if (ms->msgphase == msg_in) {
10671da177e4SLinus Torvalds printk(KERN_ERR "mesh: msg parity error, target %d\n",
10681da177e4SLinus Torvalds ms->conn_tgt);
10691da177e4SLinus Torvalds ms->msgout[0] = MSG_PARITY_ERROR;
10701da177e4SLinus Torvalds ms->n_msgout = 1;
10711da177e4SLinus Torvalds ms->msgphase = msg_in_bad;
10721da177e4SLinus Torvalds cmd_complete(ms);
10731da177e4SLinus Torvalds return;
10741da177e4SLinus Torvalds }
10751da177e4SLinus Torvalds if (ms->stat == DID_OK) {
10761da177e4SLinus Torvalds printk(KERN_ERR "mesh: parity error, target %d\n",
10771da177e4SLinus Torvalds ms->conn_tgt);
10781da177e4SLinus Torvalds ms->stat = DID_PARITY;
10791da177e4SLinus Torvalds }
10801da177e4SLinus Torvalds count = (mr->count_hi << 8) + mr->count_lo;
10811da177e4SLinus Torvalds if (count == 0) {
10821da177e4SLinus Torvalds cmd_complete(ms);
10831da177e4SLinus Torvalds } else {
10841da177e4SLinus Torvalds /* reissue the data transfer command */
10851da177e4SLinus Torvalds out_8(&mr->sequence, mr->sequence);
10861da177e4SLinus Torvalds }
10871da177e4SLinus Torvalds return;
10881da177e4SLinus Torvalds }
10891da177e4SLinus Torvalds if (err & ERR_SEQERR) {
10901da177e4SLinus Torvalds if (exc & EXC_RESELECTED) {
10911da177e4SLinus Torvalds /* This can happen if we issue a command to
10921da177e4SLinus Torvalds get the bus just after the target reselects us. */
10931da177e4SLinus Torvalds static int mesh_resel_seqerr;
10941da177e4SLinus Torvalds mesh_resel_seqerr++;
10951da177e4SLinus Torvalds reselected(ms);
10961da177e4SLinus Torvalds return;
10971da177e4SLinus Torvalds }
10981da177e4SLinus Torvalds if (exc == EXC_PHASEMM) {
10991da177e4SLinus Torvalds static int mesh_phasemm_seqerr;
11001da177e4SLinus Torvalds mesh_phasemm_seqerr++;
11011da177e4SLinus Torvalds phase_mismatch(ms);
11021da177e4SLinus Torvalds return;
11031da177e4SLinus Torvalds }
11041da177e4SLinus Torvalds printk(KERN_ERR "mesh: sequence error (err=%x exc=%x)\n",
11051da177e4SLinus Torvalds err, exc);
11061da177e4SLinus Torvalds } else {
11071da177e4SLinus Torvalds printk(KERN_ERR "mesh: unknown error %x (exc=%x)\n", err, exc);
11081da177e4SLinus Torvalds }
11091da177e4SLinus Torvalds mesh_dump_regs(ms);
11101da177e4SLinus Torvalds dumplog(ms, ms->conn_tgt);
11111da177e4SLinus Torvalds if (ms->phase > selecting && (in_8(&mr->bus_status1) & BS1_BSY)) {
11121da177e4SLinus Torvalds /* try to do what the target wants */
11131da177e4SLinus Torvalds do_abort(ms);
11141da177e4SLinus Torvalds phase_mismatch(ms);
11151da177e4SLinus Torvalds return;
11161da177e4SLinus Torvalds }
11171da177e4SLinus Torvalds ms->stat = DID_ERROR;
11181da177e4SLinus Torvalds mesh_done(ms, 1);
11191da177e4SLinus Torvalds }
11201da177e4SLinus Torvalds
handle_exception(struct mesh_state * ms)11211da177e4SLinus Torvalds static void handle_exception(struct mesh_state *ms)
11221da177e4SLinus Torvalds {
11231da177e4SLinus Torvalds int exc;
11241da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr = ms->mesh;
11251da177e4SLinus Torvalds
11261da177e4SLinus Torvalds exc = in_8(&mr->exception);
11271da177e4SLinus Torvalds out_8(&mr->interrupt, INT_EXCEPTION | INT_CMDDONE);
11281da177e4SLinus Torvalds if (exc & EXC_RESELECTED) {
11291da177e4SLinus Torvalds static int mesh_resel_exc;
11301da177e4SLinus Torvalds mesh_resel_exc++;
11311da177e4SLinus Torvalds reselected(ms);
11321da177e4SLinus Torvalds } else if (exc == EXC_ARBLOST) {
11331da177e4SLinus Torvalds printk(KERN_DEBUG "mesh: lost arbitration\n");
11341da177e4SLinus Torvalds ms->stat = DID_BUS_BUSY;
11351da177e4SLinus Torvalds mesh_done(ms, 1);
11361da177e4SLinus Torvalds } else if (exc == EXC_SELTO) {
11371da177e4SLinus Torvalds /* selection timed out */
11381da177e4SLinus Torvalds ms->stat = DID_BAD_TARGET;
11391da177e4SLinus Torvalds mesh_done(ms, 1);
11401da177e4SLinus Torvalds } else if (exc == EXC_PHASEMM) {
11411da177e4SLinus Torvalds /* target wants to do something different:
11421da177e4SLinus Torvalds find out what it wants and do it. */
11431da177e4SLinus Torvalds phase_mismatch(ms);
11441da177e4SLinus Torvalds } else {
11451da177e4SLinus Torvalds printk(KERN_ERR "mesh: can't cope with exception %x\n", exc);
11461da177e4SLinus Torvalds mesh_dump_regs(ms);
11471da177e4SLinus Torvalds dumplog(ms, ms->conn_tgt);
11481da177e4SLinus Torvalds do_abort(ms);
11491da177e4SLinus Torvalds phase_mismatch(ms);
11501da177e4SLinus Torvalds }
11511da177e4SLinus Torvalds }
11521da177e4SLinus Torvalds
handle_msgin(struct mesh_state * ms)11531da177e4SLinus Torvalds static void handle_msgin(struct mesh_state *ms)
11541da177e4SLinus Torvalds {
11551da177e4SLinus Torvalds int i, code;
11561da177e4SLinus Torvalds struct scsi_cmnd *cmd = ms->current_req;
11571da177e4SLinus Torvalds struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
11581da177e4SLinus Torvalds
11591da177e4SLinus Torvalds if (ms->n_msgin == 0)
11601da177e4SLinus Torvalds return;
11611da177e4SLinus Torvalds code = ms->msgin[0];
11621da177e4SLinus Torvalds if (ALLOW_DEBUG(ms->conn_tgt)) {
11631da177e4SLinus Torvalds printk(KERN_DEBUG "got %d message bytes:", ms->n_msgin);
11641da177e4SLinus Torvalds for (i = 0; i < ms->n_msgin; ++i)
11651da177e4SLinus Torvalds printk(" %x", ms->msgin[i]);
11661da177e4SLinus Torvalds printk("\n");
11671da177e4SLinus Torvalds }
11681da177e4SLinus Torvalds dlog(ms, "msgin msg=%.8x",
11691da177e4SLinus Torvalds MKWORD(ms->n_msgin, code, ms->msgin[1], ms->msgin[2]));
11701da177e4SLinus Torvalds
11711da177e4SLinus Torvalds ms->expect_reply = 0;
11721da177e4SLinus Torvalds ms->n_msgout = 0;
11731da177e4SLinus Torvalds if (ms->n_msgin < msgin_length(ms))
11741da177e4SLinus Torvalds goto reject;
11751da177e4SLinus Torvalds if (cmd)
11762e1b3175SFinn Thain mesh_priv(cmd)->message = code;
11771da177e4SLinus Torvalds switch (code) {
11781da177e4SLinus Torvalds case COMMAND_COMPLETE:
11791da177e4SLinus Torvalds break;
11801da177e4SLinus Torvalds case EXTENDED_MESSAGE:
11811da177e4SLinus Torvalds switch (ms->msgin[2]) {
11821da177e4SLinus Torvalds case EXTENDED_MODIFY_DATA_POINTER:
11831da177e4SLinus Torvalds ms->data_ptr += (ms->msgin[3] << 24) + ms->msgin[6]
11841da177e4SLinus Torvalds + (ms->msgin[4] << 16) + (ms->msgin[5] << 8);
11851da177e4SLinus Torvalds break;
11861da177e4SLinus Torvalds case EXTENDED_SDTR:
11871da177e4SLinus Torvalds if (tp->sdtr_state != sdtr_sent) {
11881da177e4SLinus Torvalds /* reply with an SDTR */
11891da177e4SLinus Torvalds add_sdtr_msg(ms);
11901da177e4SLinus Torvalds /* limit period to at least his value,
11911da177e4SLinus Torvalds offset to no more than his */
11921da177e4SLinus Torvalds if (ms->msgout[3] < ms->msgin[3])
11931da177e4SLinus Torvalds ms->msgout[3] = ms->msgin[3];
11941da177e4SLinus Torvalds if (ms->msgout[4] > ms->msgin[4])
11951da177e4SLinus Torvalds ms->msgout[4] = ms->msgin[4];
11961da177e4SLinus Torvalds set_sdtr(ms, ms->msgout[3], ms->msgout[4]);
11971da177e4SLinus Torvalds ms->msgphase = msg_out;
11981da177e4SLinus Torvalds } else {
11991da177e4SLinus Torvalds set_sdtr(ms, ms->msgin[3], ms->msgin[4]);
12001da177e4SLinus Torvalds }
12011da177e4SLinus Torvalds break;
12021da177e4SLinus Torvalds default:
12031da177e4SLinus Torvalds goto reject;
12041da177e4SLinus Torvalds }
12051da177e4SLinus Torvalds break;
12061da177e4SLinus Torvalds case SAVE_POINTERS:
12071da177e4SLinus Torvalds tp->saved_ptr = ms->data_ptr;
12081da177e4SLinus Torvalds break;
12091da177e4SLinus Torvalds case RESTORE_POINTERS:
12101da177e4SLinus Torvalds ms->data_ptr = tp->saved_ptr;
12111da177e4SLinus Torvalds break;
12121da177e4SLinus Torvalds case DISCONNECT:
12131da177e4SLinus Torvalds ms->phase = disconnecting;
12141da177e4SLinus Torvalds break;
12151da177e4SLinus Torvalds case ABORT:
12161da177e4SLinus Torvalds break;
12171da177e4SLinus Torvalds case MESSAGE_REJECT:
12181da177e4SLinus Torvalds if (tp->sdtr_state == sdtr_sent)
12191da177e4SLinus Torvalds set_sdtr(ms, 0, 0);
12201da177e4SLinus Torvalds break;
12211da177e4SLinus Torvalds case NOP:
12221da177e4SLinus Torvalds break;
12231da177e4SLinus Torvalds default:
12241da177e4SLinus Torvalds if (IDENTIFY_BASE <= code && code <= IDENTIFY_BASE + 7) {
12251da177e4SLinus Torvalds if (cmd == NULL) {
12261da177e4SLinus Torvalds do_abort(ms);
12271da177e4SLinus Torvalds ms->msgphase = msg_out;
12281da177e4SLinus Torvalds } else if (code != cmd->device->lun + IDENTIFY_BASE) {
12291da177e4SLinus Torvalds printk(KERN_WARNING "mesh: lun mismatch "
12309cb78c16SHannes Reinecke "(%d != %llu) on reselection from "
12311da177e4SLinus Torvalds "target %d\n", code - IDENTIFY_BASE,
12321da177e4SLinus Torvalds cmd->device->lun, ms->conn_tgt);
12331da177e4SLinus Torvalds }
12341da177e4SLinus Torvalds break;
12351da177e4SLinus Torvalds }
12361da177e4SLinus Torvalds goto reject;
12371da177e4SLinus Torvalds }
12381da177e4SLinus Torvalds return;
12391da177e4SLinus Torvalds
12401da177e4SLinus Torvalds reject:
12411da177e4SLinus Torvalds printk(KERN_WARNING "mesh: rejecting message from target %d:",
12421da177e4SLinus Torvalds ms->conn_tgt);
12431da177e4SLinus Torvalds for (i = 0; i < ms->n_msgin; ++i)
12441da177e4SLinus Torvalds printk(" %x", ms->msgin[i]);
12451da177e4SLinus Torvalds printk("\n");
12461da177e4SLinus Torvalds ms->msgout[0] = MESSAGE_REJECT;
12471da177e4SLinus Torvalds ms->n_msgout = 1;
12481da177e4SLinus Torvalds ms->msgphase = msg_out;
12491da177e4SLinus Torvalds }
12501da177e4SLinus Torvalds
12511da177e4SLinus Torvalds /*
12521da177e4SLinus Torvalds * Set up DMA commands for transferring data.
12531da177e4SLinus Torvalds */
set_dma_cmds(struct mesh_state * ms,struct scsi_cmnd * cmd)12541da177e4SLinus Torvalds static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd)
12551da177e4SLinus Torvalds {
12561da177e4SLinus Torvalds int i, dma_cmd, total, off, dtot;
12571da177e4SLinus Torvalds struct scatterlist *scl;
12581da177e4SLinus Torvalds struct dbdma_cmd *dcmds;
12591da177e4SLinus Torvalds
12601da177e4SLinus Torvalds dma_cmd = ms->tgts[ms->conn_tgt].data_goes_out?
12611da177e4SLinus Torvalds OUTPUT_MORE: INPUT_MORE;
12621da177e4SLinus Torvalds dcmds = ms->dma_cmds;
12631da177e4SLinus Torvalds dtot = 0;
12641da177e4SLinus Torvalds if (cmd) {
12651da177e4SLinus Torvalds int nseg;
1266f0002c4eSFUJITA Tomonori
12672e1b3175SFinn Thain mesh_priv(cmd)->this_residual = scsi_bufflen(cmd);
1268f0002c4eSFUJITA Tomonori
1269f0002c4eSFUJITA Tomonori nseg = scsi_dma_map(cmd);
1270f0002c4eSFUJITA Tomonori BUG_ON(nseg < 0);
1271f0002c4eSFUJITA Tomonori
1272f0002c4eSFUJITA Tomonori if (nseg) {
12731da177e4SLinus Torvalds total = 0;
12741da177e4SLinus Torvalds off = ms->data_ptr;
1275f0002c4eSFUJITA Tomonori
1276f0002c4eSFUJITA Tomonori scsi_for_each_sg(cmd, scl, nseg, i) {
12771da177e4SLinus Torvalds u32 dma_addr = sg_dma_address(scl);
12781da177e4SLinus Torvalds u32 dma_len = sg_dma_len(scl);
12791da177e4SLinus Torvalds
12801da177e4SLinus Torvalds total += scl->length;
12811da177e4SLinus Torvalds if (off >= dma_len) {
12821da177e4SLinus Torvalds off -= dma_len;
12831da177e4SLinus Torvalds continue;
12841da177e4SLinus Torvalds }
12851da177e4SLinus Torvalds if (dma_len > 0xffff)
12861da177e4SLinus Torvalds panic("mesh: scatterlist element >= 64k");
1287f5718726SDavid Gibson dcmds->req_count = cpu_to_le16(dma_len - off);
1288f5718726SDavid Gibson dcmds->command = cpu_to_le16(dma_cmd);
1289f5718726SDavid Gibson dcmds->phy_addr = cpu_to_le32(dma_addr + off);
12901da177e4SLinus Torvalds dcmds->xfer_status = 0;
12911da177e4SLinus Torvalds ++dcmds;
12921da177e4SLinus Torvalds dtot += dma_len - off;
12931da177e4SLinus Torvalds off = 0;
12941da177e4SLinus Torvalds }
12951da177e4SLinus Torvalds }
12961da177e4SLinus Torvalds }
12971da177e4SLinus Torvalds if (dtot == 0) {
12981da177e4SLinus Torvalds /* Either the target has overrun our buffer,
12991da177e4SLinus Torvalds or the caller didn't provide a buffer. */
13001da177e4SLinus Torvalds static char mesh_extra_buf[64];
13011da177e4SLinus Torvalds
13021da177e4SLinus Torvalds dtot = sizeof(mesh_extra_buf);
1303f5718726SDavid Gibson dcmds->req_count = cpu_to_le16(dtot);
1304f5718726SDavid Gibson dcmds->phy_addr = cpu_to_le32(virt_to_phys(mesh_extra_buf));
13051da177e4SLinus Torvalds dcmds->xfer_status = 0;
13061da177e4SLinus Torvalds ++dcmds;
13071da177e4SLinus Torvalds }
13081da177e4SLinus Torvalds dma_cmd += OUTPUT_LAST - OUTPUT_MORE;
1309f5718726SDavid Gibson dcmds[-1].command = cpu_to_le16(dma_cmd);
13101da177e4SLinus Torvalds memset(dcmds, 0, sizeof(*dcmds));
1311f5718726SDavid Gibson dcmds->command = cpu_to_le16(DBDMA_STOP);
13121da177e4SLinus Torvalds ms->dma_count = dtot;
13131da177e4SLinus Torvalds }
13141da177e4SLinus Torvalds
halt_dma(struct mesh_state * ms)13151da177e4SLinus Torvalds static void halt_dma(struct mesh_state *ms)
13161da177e4SLinus Torvalds {
13171da177e4SLinus Torvalds volatile struct dbdma_regs __iomem *md = ms->dma;
13181da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr = ms->mesh;
13191da177e4SLinus Torvalds struct scsi_cmnd *cmd = ms->current_req;
13201da177e4SLinus Torvalds int t, nb;
13211da177e4SLinus Torvalds
13221da177e4SLinus Torvalds if (!ms->tgts[ms->conn_tgt].data_goes_out) {
13231da177e4SLinus Torvalds /* wait a little while until the fifo drains */
13241da177e4SLinus Torvalds t = 50;
13251da177e4SLinus Torvalds while (t > 0 && in_8(&mr->fifo_count) != 0
13261da177e4SLinus Torvalds && (in_le32(&md->status) & ACTIVE) != 0) {
13271da177e4SLinus Torvalds --t;
13281da177e4SLinus Torvalds udelay(1);
13291da177e4SLinus Torvalds }
13301da177e4SLinus Torvalds }
13311da177e4SLinus Torvalds out_le32(&md->control, RUN << 16); /* turn off RUN bit */
13321da177e4SLinus Torvalds nb = (mr->count_hi << 8) + mr->count_lo;
13331da177e4SLinus Torvalds dlog(ms, "halt_dma fc/count=%.6x",
13341da177e4SLinus Torvalds MKWORD(0, mr->fifo_count, 0, nb));
13351da177e4SLinus Torvalds if (ms->tgts[ms->conn_tgt].data_goes_out)
13361da177e4SLinus Torvalds nb += mr->fifo_count;
13371da177e4SLinus Torvalds /* nb is the number of bytes not yet transferred
13381da177e4SLinus Torvalds to/from the target. */
13391da177e4SLinus Torvalds ms->data_ptr -= nb;
13401da177e4SLinus Torvalds dlog(ms, "data_ptr %x", ms->data_ptr);
13411da177e4SLinus Torvalds if (ms->data_ptr < 0) {
13421da177e4SLinus Torvalds printk(KERN_ERR "mesh: halt_dma: data_ptr=%d (nb=%d, ms=%p)\n",
13431da177e4SLinus Torvalds ms->data_ptr, nb, ms);
13441da177e4SLinus Torvalds ms->data_ptr = 0;
13451da177e4SLinus Torvalds #ifdef MESH_DBG
13461da177e4SLinus Torvalds dumplog(ms, ms->conn_tgt);
13471da177e4SLinus Torvalds dumpslog(ms);
13481da177e4SLinus Torvalds #endif /* MESH_DBG */
1349f0002c4eSFUJITA Tomonori } else if (cmd && scsi_bufflen(cmd) &&
1350f0002c4eSFUJITA Tomonori ms->data_ptr > scsi_bufflen(cmd)) {
13511da177e4SLinus Torvalds printk(KERN_DEBUG "mesh: target %d overrun, "
13521da177e4SLinus Torvalds "data_ptr=%x total=%x goes_out=%d\n",
1353f0002c4eSFUJITA Tomonori ms->conn_tgt, ms->data_ptr, scsi_bufflen(cmd),
13541da177e4SLinus Torvalds ms->tgts[ms->conn_tgt].data_goes_out);
13551da177e4SLinus Torvalds }
1356edd7dd22SFinn Thain if (cmd)
1357f0002c4eSFUJITA Tomonori scsi_dma_unmap(cmd);
13581da177e4SLinus Torvalds ms->dma_started = 0;
13591da177e4SLinus Torvalds }
13601da177e4SLinus Torvalds
phase_mismatch(struct mesh_state * ms)13611da177e4SLinus Torvalds static void phase_mismatch(struct mesh_state *ms)
13621da177e4SLinus Torvalds {
13631da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr = ms->mesh;
13641da177e4SLinus Torvalds int phase;
13651da177e4SLinus Torvalds
13661da177e4SLinus Torvalds dlog(ms, "phasemm ch/cl/seq/fc=%.8x",
13671da177e4SLinus Torvalds MKWORD(mr->count_hi, mr->count_lo, mr->sequence, mr->fifo_count));
13681da177e4SLinus Torvalds phase = in_8(&mr->bus_status0) & BS0_PHASE;
13691da177e4SLinus Torvalds if (ms->msgphase == msg_out_xxx && phase == BP_MSGOUT) {
13701da177e4SLinus Torvalds /* output the last byte of the message, without ATN */
13711da177e4SLinus Torvalds out_8(&mr->count_lo, 1);
13721da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg);
13731da177e4SLinus Torvalds mesh_flush_io(mr);
13741da177e4SLinus Torvalds udelay(1);
13751da177e4SLinus Torvalds out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]);
13761da177e4SLinus Torvalds ms->msgphase = msg_out_last;
13771da177e4SLinus Torvalds return;
13781da177e4SLinus Torvalds }
13791da177e4SLinus Torvalds
13801da177e4SLinus Torvalds if (ms->msgphase == msg_in) {
13811da177e4SLinus Torvalds get_msgin(ms);
13821da177e4SLinus Torvalds if (ms->n_msgin)
13831da177e4SLinus Torvalds handle_msgin(ms);
13841da177e4SLinus Torvalds }
13851da177e4SLinus Torvalds
13861da177e4SLinus Torvalds if (ms->dma_started)
13871da177e4SLinus Torvalds halt_dma(ms);
13881da177e4SLinus Torvalds if (mr->fifo_count) {
13891da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_FLUSHFIFO);
13901da177e4SLinus Torvalds mesh_flush_io(mr);
13911da177e4SLinus Torvalds udelay(1);
13921da177e4SLinus Torvalds }
13931da177e4SLinus Torvalds
13941da177e4SLinus Torvalds ms->msgphase = msg_none;
13951da177e4SLinus Torvalds switch (phase) {
13961da177e4SLinus Torvalds case BP_DATAIN:
13971da177e4SLinus Torvalds ms->tgts[ms->conn_tgt].data_goes_out = 0;
13981da177e4SLinus Torvalds ms->phase = dataing;
13991da177e4SLinus Torvalds break;
14001da177e4SLinus Torvalds case BP_DATAOUT:
14011da177e4SLinus Torvalds ms->tgts[ms->conn_tgt].data_goes_out = 1;
14021da177e4SLinus Torvalds ms->phase = dataing;
14031da177e4SLinus Torvalds break;
14041da177e4SLinus Torvalds case BP_COMMAND:
14051da177e4SLinus Torvalds ms->phase = commanding;
14061da177e4SLinus Torvalds break;
14071da177e4SLinus Torvalds case BP_STATUS:
14081da177e4SLinus Torvalds ms->phase = statusing;
14091da177e4SLinus Torvalds break;
14101da177e4SLinus Torvalds case BP_MSGIN:
14111da177e4SLinus Torvalds ms->msgphase = msg_in;
14121da177e4SLinus Torvalds ms->n_msgin = 0;
14131da177e4SLinus Torvalds break;
14141da177e4SLinus Torvalds case BP_MSGOUT:
14151da177e4SLinus Torvalds ms->msgphase = msg_out;
14161da177e4SLinus Torvalds if (ms->n_msgout == 0) {
14171da177e4SLinus Torvalds if (ms->aborting) {
14181da177e4SLinus Torvalds do_abort(ms);
14191da177e4SLinus Torvalds } else {
14201da177e4SLinus Torvalds if (ms->last_n_msgout == 0) {
14211da177e4SLinus Torvalds printk(KERN_DEBUG
14221da177e4SLinus Torvalds "mesh: no msg to repeat\n");
14231da177e4SLinus Torvalds ms->msgout[0] = NOP;
14241da177e4SLinus Torvalds ms->last_n_msgout = 1;
14251da177e4SLinus Torvalds }
14261da177e4SLinus Torvalds ms->n_msgout = ms->last_n_msgout;
14271da177e4SLinus Torvalds }
14281da177e4SLinus Torvalds }
14291da177e4SLinus Torvalds break;
14301da177e4SLinus Torvalds default:
14311da177e4SLinus Torvalds printk(KERN_DEBUG "mesh: unknown scsi phase %x\n", phase);
14321da177e4SLinus Torvalds ms->stat = DID_ERROR;
14331da177e4SLinus Torvalds mesh_done(ms, 1);
14341da177e4SLinus Torvalds return;
14351da177e4SLinus Torvalds }
14361da177e4SLinus Torvalds
14371da177e4SLinus Torvalds start_phase(ms);
14381da177e4SLinus Torvalds }
14391da177e4SLinus Torvalds
cmd_complete(struct mesh_state * ms)14401da177e4SLinus Torvalds static void cmd_complete(struct mesh_state *ms)
14411da177e4SLinus Torvalds {
14421da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr = ms->mesh;
14431da177e4SLinus Torvalds struct scsi_cmnd *cmd = ms->current_req;
14441da177e4SLinus Torvalds struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
14451da177e4SLinus Torvalds int seq, n, t;
14461da177e4SLinus Torvalds
14471da177e4SLinus Torvalds dlog(ms, "cmd_complete fc=%x", mr->fifo_count);
14481da177e4SLinus Torvalds seq = use_active_neg + (ms->n_msgout? SEQ_ATN: 0);
14491da177e4SLinus Torvalds switch (ms->msgphase) {
14501da177e4SLinus Torvalds case msg_out_xxx:
14511da177e4SLinus Torvalds /* huh? we expected a phase mismatch */
14521da177e4SLinus Torvalds ms->n_msgin = 0;
14531da177e4SLinus Torvalds ms->msgphase = msg_in;
1454df561f66SGustavo A. R. Silva fallthrough;
14551da177e4SLinus Torvalds
14561da177e4SLinus Torvalds case msg_in:
14571da177e4SLinus Torvalds /* should have some message bytes in fifo */
14581da177e4SLinus Torvalds get_msgin(ms);
14591da177e4SLinus Torvalds n = msgin_length(ms);
14601da177e4SLinus Torvalds if (ms->n_msgin < n) {
14611da177e4SLinus Torvalds out_8(&mr->count_lo, n - ms->n_msgin);
14621da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_MSGIN + seq);
14631da177e4SLinus Torvalds } else {
14641da177e4SLinus Torvalds ms->msgphase = msg_none;
14651da177e4SLinus Torvalds handle_msgin(ms);
14661da177e4SLinus Torvalds start_phase(ms);
14671da177e4SLinus Torvalds }
14681da177e4SLinus Torvalds break;
14691da177e4SLinus Torvalds
14701da177e4SLinus Torvalds case msg_in_bad:
14711da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_FLUSHFIFO);
14721da177e4SLinus Torvalds mesh_flush_io(mr);
14731da177e4SLinus Torvalds udelay(1);
14741da177e4SLinus Torvalds out_8(&mr->count_lo, 1);
14751da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_MSGIN + SEQ_ATN + use_active_neg);
14761da177e4SLinus Torvalds break;
14771da177e4SLinus Torvalds
14781da177e4SLinus Torvalds case msg_out:
14791da177e4SLinus Torvalds /*
14801da177e4SLinus Torvalds * To get the right timing on ATN wrt ACK, we have
14811da177e4SLinus Torvalds * to get the MESH to drop ACK, wait until REQ gets
14821da177e4SLinus Torvalds * asserted, then drop ATN. To do this we first
14831da177e4SLinus Torvalds * issue a SEQ_MSGOUT with ATN and wait for REQ,
14841da177e4SLinus Torvalds * then change the command to a SEQ_MSGOUT w/o ATN.
14851da177e4SLinus Torvalds * If we don't see REQ in a reasonable time, we
14861da177e4SLinus Torvalds * change the command to SEQ_MSGIN with ATN,
14871da177e4SLinus Torvalds * wait for the phase mismatch interrupt, then
14881da177e4SLinus Torvalds * issue the SEQ_MSGOUT without ATN.
14891da177e4SLinus Torvalds */
14901da177e4SLinus Torvalds out_8(&mr->count_lo, 1);
14911da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg + SEQ_ATN);
14921da177e4SLinus Torvalds t = 30; /* wait up to 30us */
14931da177e4SLinus Torvalds while ((in_8(&mr->bus_status0) & BS0_REQ) == 0 && --t >= 0)
14941da177e4SLinus Torvalds udelay(1);
14951da177e4SLinus Torvalds dlog(ms, "last_mbyte err/exc/fc/cl=%.8x",
14961da177e4SLinus Torvalds MKWORD(mr->error, mr->exception,
14971da177e4SLinus Torvalds mr->fifo_count, mr->count_lo));
14981da177e4SLinus Torvalds if (in_8(&mr->interrupt) & (INT_ERROR | INT_EXCEPTION)) {
14991da177e4SLinus Torvalds /* whoops, target didn't do what we expected */
15001da177e4SLinus Torvalds ms->last_n_msgout = ms->n_msgout;
15011da177e4SLinus Torvalds ms->n_msgout = 0;
15021da177e4SLinus Torvalds if (in_8(&mr->interrupt) & INT_ERROR) {
15031da177e4SLinus Torvalds printk(KERN_ERR "mesh: error %x in msg_out\n",
15041da177e4SLinus Torvalds in_8(&mr->error));
15051da177e4SLinus Torvalds handle_error(ms);
15061da177e4SLinus Torvalds return;
15071da177e4SLinus Torvalds }
15081da177e4SLinus Torvalds if (in_8(&mr->exception) != EXC_PHASEMM)
15091da177e4SLinus Torvalds printk(KERN_ERR "mesh: exc %x in msg_out\n",
15101da177e4SLinus Torvalds in_8(&mr->exception));
15111da177e4SLinus Torvalds else
15121da177e4SLinus Torvalds printk(KERN_DEBUG "mesh: bs0=%x in msg_out\n",
15131da177e4SLinus Torvalds in_8(&mr->bus_status0));
15141da177e4SLinus Torvalds handle_exception(ms);
15151da177e4SLinus Torvalds return;
15161da177e4SLinus Torvalds }
15171da177e4SLinus Torvalds if (in_8(&mr->bus_status0) & BS0_REQ) {
15181da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg);
15191da177e4SLinus Torvalds mesh_flush_io(mr);
15201da177e4SLinus Torvalds udelay(1);
15211da177e4SLinus Torvalds out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]);
15221da177e4SLinus Torvalds ms->msgphase = msg_out_last;
15231da177e4SLinus Torvalds } else {
15241da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_MSGIN + use_active_neg + SEQ_ATN);
15251da177e4SLinus Torvalds ms->msgphase = msg_out_xxx;
15261da177e4SLinus Torvalds }
15271da177e4SLinus Torvalds break;
15281da177e4SLinus Torvalds
15291da177e4SLinus Torvalds case msg_out_last:
15301da177e4SLinus Torvalds ms->last_n_msgout = ms->n_msgout;
15311da177e4SLinus Torvalds ms->n_msgout = 0;
15321da177e4SLinus Torvalds ms->msgphase = ms->expect_reply? msg_in: msg_none;
15331da177e4SLinus Torvalds start_phase(ms);
15341da177e4SLinus Torvalds break;
15351da177e4SLinus Torvalds
15361da177e4SLinus Torvalds case msg_none:
15371da177e4SLinus Torvalds switch (ms->phase) {
15381da177e4SLinus Torvalds case idle:
15391da177e4SLinus Torvalds printk(KERN_ERR "mesh: interrupt in idle phase?\n");
15401da177e4SLinus Torvalds dumpslog(ms);
15411da177e4SLinus Torvalds return;
15421da177e4SLinus Torvalds case selecting:
15431da177e4SLinus Torvalds dlog(ms, "Selecting phase at command completion",0);
15441da177e4SLinus Torvalds ms->msgout[0] = IDENTIFY(ALLOW_RESEL(ms->conn_tgt),
15451da177e4SLinus Torvalds (cmd? cmd->device->lun: 0));
15461da177e4SLinus Torvalds ms->n_msgout = 1;
15471da177e4SLinus Torvalds ms->expect_reply = 0;
15481da177e4SLinus Torvalds if (ms->aborting) {
15491da177e4SLinus Torvalds ms->msgout[0] = ABORT;
15501da177e4SLinus Torvalds ms->n_msgout++;
15511da177e4SLinus Torvalds } else if (tp->sdtr_state == do_sdtr) {
15521da177e4SLinus Torvalds /* add SDTR message */
15531da177e4SLinus Torvalds add_sdtr_msg(ms);
15541da177e4SLinus Torvalds ms->expect_reply = 1;
15551da177e4SLinus Torvalds tp->sdtr_state = sdtr_sent;
15561da177e4SLinus Torvalds }
15571da177e4SLinus Torvalds ms->msgphase = msg_out;
15581da177e4SLinus Torvalds /*
15591da177e4SLinus Torvalds * We need to wait for REQ before dropping ATN.
15601da177e4SLinus Torvalds * We wait for at most 30us, then fall back to
15611da177e4SLinus Torvalds * a scheme where we issue a SEQ_COMMAND with ATN,
15621da177e4SLinus Torvalds * which will give us a phase mismatch interrupt
15631da177e4SLinus Torvalds * when REQ does come, and then we send the message.
15641da177e4SLinus Torvalds */
15651da177e4SLinus Torvalds t = 230; /* wait up to 230us */
15661da177e4SLinus Torvalds while ((in_8(&mr->bus_status0) & BS0_REQ) == 0) {
15671da177e4SLinus Torvalds if (--t < 0) {
15681da177e4SLinus Torvalds dlog(ms, "impatient for req", ms->n_msgout);
15691da177e4SLinus Torvalds ms->msgphase = msg_none;
15701da177e4SLinus Torvalds break;
15711da177e4SLinus Torvalds }
15721da177e4SLinus Torvalds udelay(1);
15731da177e4SLinus Torvalds }
15741da177e4SLinus Torvalds break;
15751da177e4SLinus Torvalds case dataing:
15761da177e4SLinus Torvalds if (ms->dma_count != 0) {
15771da177e4SLinus Torvalds start_phase(ms);
15781da177e4SLinus Torvalds return;
15791da177e4SLinus Torvalds }
15801da177e4SLinus Torvalds /*
15811da177e4SLinus Torvalds * We can get a phase mismatch here if the target
15821da177e4SLinus Torvalds * changes to the status phase, even though we have
15831da177e4SLinus Torvalds * had a command complete interrupt. Then, if we
15841da177e4SLinus Torvalds * issue the SEQ_STATUS command, we'll get a sequence
15851da177e4SLinus Torvalds * error interrupt. Which isn't so bad except that
15861da177e4SLinus Torvalds * occasionally the mesh actually executes the
15871da177e4SLinus Torvalds * SEQ_STATUS *as well as* giving us the sequence
15881da177e4SLinus Torvalds * error and phase mismatch exception.
15891da177e4SLinus Torvalds */
15901da177e4SLinus Torvalds out_8(&mr->sequence, 0);
15911da177e4SLinus Torvalds out_8(&mr->interrupt,
15921da177e4SLinus Torvalds INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
15931da177e4SLinus Torvalds halt_dma(ms);
15941da177e4SLinus Torvalds break;
15951da177e4SLinus Torvalds case statusing:
15961da177e4SLinus Torvalds if (cmd) {
15972e1b3175SFinn Thain struct mesh_cmd_priv *mcmd = mesh_priv(cmd);
159857cbd78eSBart Van Assche
15992e1b3175SFinn Thain mcmd->status = mr->fifo;
16001da177e4SLinus Torvalds if (DEBUG_TARGET(cmd))
16011da177e4SLinus Torvalds printk(KERN_DEBUG "mesh: status is %x\n",
16022e1b3175SFinn Thain mcmd->status);
16031da177e4SLinus Torvalds }
16041da177e4SLinus Torvalds ms->msgphase = msg_in;
16051da177e4SLinus Torvalds break;
16061da177e4SLinus Torvalds case busfreeing:
16071da177e4SLinus Torvalds mesh_done(ms, 1);
16081da177e4SLinus Torvalds return;
16091da177e4SLinus Torvalds case disconnecting:
16101da177e4SLinus Torvalds ms->current_req = NULL;
16111da177e4SLinus Torvalds ms->phase = idle;
16121da177e4SLinus Torvalds mesh_start(ms);
16131da177e4SLinus Torvalds return;
16141da177e4SLinus Torvalds default:
16151da177e4SLinus Torvalds break;
16161da177e4SLinus Torvalds }
16171da177e4SLinus Torvalds ++ms->phase;
16181da177e4SLinus Torvalds start_phase(ms);
16191da177e4SLinus Torvalds break;
16201da177e4SLinus Torvalds }
16211da177e4SLinus Torvalds }
16221da177e4SLinus Torvalds
16231da177e4SLinus Torvalds
16241da177e4SLinus Torvalds /*
16251da177e4SLinus Torvalds * Called by midlayer with host locked to queue a new
16261da177e4SLinus Torvalds * request
16271da177e4SLinus Torvalds */
mesh_queue_lck(struct scsi_cmnd * cmd)1628af049dfdSBart Van Assche static int mesh_queue_lck(struct scsi_cmnd *cmd)
16291da177e4SLinus Torvalds {
16301da177e4SLinus Torvalds struct mesh_state *ms;
16311da177e4SLinus Torvalds
16321da177e4SLinus Torvalds cmd->host_scribble = NULL;
16331da177e4SLinus Torvalds
16341da177e4SLinus Torvalds ms = (struct mesh_state *) cmd->device->host->hostdata;
16351da177e4SLinus Torvalds
16361da177e4SLinus Torvalds if (ms->request_q == NULL)
16371da177e4SLinus Torvalds ms->request_q = cmd;
16381da177e4SLinus Torvalds else
16391da177e4SLinus Torvalds ms->request_qtail->host_scribble = (void *) cmd;
16401da177e4SLinus Torvalds ms->request_qtail = cmd;
16411da177e4SLinus Torvalds
16421da177e4SLinus Torvalds if (ms->phase == idle)
16431da177e4SLinus Torvalds mesh_start(ms);
16441da177e4SLinus Torvalds
16451da177e4SLinus Torvalds return 0;
16461da177e4SLinus Torvalds }
16471da177e4SLinus Torvalds
DEF_SCSI_QCMD(mesh_queue)1648f281233dSJeff Garzik static DEF_SCSI_QCMD(mesh_queue)
1649f281233dSJeff Garzik
16501da177e4SLinus Torvalds /*
16511da177e4SLinus Torvalds * Called to handle interrupts, either call by the interrupt
16521da177e4SLinus Torvalds * handler (do_mesh_interrupt) or by other functions in
16531da177e4SLinus Torvalds * exceptional circumstances
16541da177e4SLinus Torvalds */
16552135be5fSOlaf Hering static void mesh_interrupt(struct mesh_state *ms)
16561da177e4SLinus Torvalds {
16571da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr = ms->mesh;
16581da177e4SLinus Torvalds int intr;
16591da177e4SLinus Torvalds
16601da177e4SLinus Torvalds #if 0
16611da177e4SLinus Torvalds if (ALLOW_DEBUG(ms->conn_tgt))
16621da177e4SLinus Torvalds printk(KERN_DEBUG "mesh_intr, bs0=%x int=%x exc=%x err=%x "
16631da177e4SLinus Torvalds "phase=%d msgphase=%d\n", mr->bus_status0,
16641da177e4SLinus Torvalds mr->interrupt, mr->exception, mr->error,
16651da177e4SLinus Torvalds ms->phase, ms->msgphase);
16661da177e4SLinus Torvalds #endif
16671da177e4SLinus Torvalds while ((intr = in_8(&mr->interrupt)) != 0) {
16681da177e4SLinus Torvalds dlog(ms, "interrupt intr/err/exc/seq=%.8x",
16691da177e4SLinus Torvalds MKWORD(intr, mr->error, mr->exception, mr->sequence));
16701da177e4SLinus Torvalds if (intr & INT_ERROR) {
16711da177e4SLinus Torvalds handle_error(ms);
16721da177e4SLinus Torvalds } else if (intr & INT_EXCEPTION) {
16731da177e4SLinus Torvalds handle_exception(ms);
16741da177e4SLinus Torvalds } else if (intr & INT_CMDDONE) {
16751da177e4SLinus Torvalds out_8(&mr->interrupt, INT_CMDDONE);
16761da177e4SLinus Torvalds cmd_complete(ms);
16771da177e4SLinus Torvalds }
16781da177e4SLinus Torvalds }
16791da177e4SLinus Torvalds }
16801da177e4SLinus Torvalds
16811da177e4SLinus Torvalds /* Todo: here we can at least try to remove the command from the
16821da177e4SLinus Torvalds * queue if it isn't connected yet, and for pending command, assert
16831da177e4SLinus Torvalds * ATN until the bus gets freed.
16841da177e4SLinus Torvalds */
mesh_abort(struct scsi_cmnd * cmd)16851da177e4SLinus Torvalds static int mesh_abort(struct scsi_cmnd *cmd)
16861da177e4SLinus Torvalds {
16871da177e4SLinus Torvalds struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata;
16881da177e4SLinus Torvalds
16891da177e4SLinus Torvalds printk(KERN_DEBUG "mesh_abort(%p)\n", cmd);
16901da177e4SLinus Torvalds mesh_dump_regs(ms);
16911da177e4SLinus Torvalds dumplog(ms, cmd->device->id);
16921da177e4SLinus Torvalds dumpslog(ms);
16931da177e4SLinus Torvalds return FAILED;
16941da177e4SLinus Torvalds }
16951da177e4SLinus Torvalds
16961da177e4SLinus Torvalds /*
16971da177e4SLinus Torvalds * Called by the midlayer with the lock held to reset the
16981da177e4SLinus Torvalds * SCSI host and bus.
16991da177e4SLinus Torvalds * The midlayer will wait for devices to come back, we don't need
17001da177e4SLinus Torvalds * to do that ourselves
17011da177e4SLinus Torvalds */
mesh_host_reset(struct scsi_cmnd * cmd)17021da177e4SLinus Torvalds static int mesh_host_reset(struct scsi_cmnd *cmd)
17031da177e4SLinus Torvalds {
17041da177e4SLinus Torvalds struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata;
17051da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr = ms->mesh;
17061da177e4SLinus Torvalds volatile struct dbdma_regs __iomem *md = ms->dma;
1707df0ae249SJeff Garzik unsigned long flags;
17081da177e4SLinus Torvalds
17091da177e4SLinus Torvalds printk(KERN_DEBUG "mesh_host_reset\n");
17101da177e4SLinus Torvalds
1711df0ae249SJeff Garzik spin_lock_irqsave(ms->host->host_lock, flags);
1712df0ae249SJeff Garzik
1713edd7dd22SFinn Thain if (ms->dma_started)
1714edd7dd22SFinn Thain halt_dma(ms);
1715edd7dd22SFinn Thain
17161da177e4SLinus Torvalds /* Reset the controller & dbdma channel */
17171da177e4SLinus Torvalds out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* stop dma */
17181da177e4SLinus Torvalds out_8(&mr->exception, 0xff); /* clear all exception bits */
17191da177e4SLinus Torvalds out_8(&mr->error, 0xff); /* clear all error bits */
17201da177e4SLinus Torvalds out_8(&mr->sequence, SEQ_RESETMESH);
17211da177e4SLinus Torvalds mesh_flush_io(mr);
17221da177e4SLinus Torvalds udelay(1);
17231da177e4SLinus Torvalds out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
17241da177e4SLinus Torvalds out_8(&mr->source_id, ms->host->this_id);
17251da177e4SLinus Torvalds out_8(&mr->sel_timeout, 25); /* 250ms */
17261da177e4SLinus Torvalds out_8(&mr->sync_params, ASYNC_PARAMS);
17271da177e4SLinus Torvalds
17281da177e4SLinus Torvalds /* Reset the bus */
17291da177e4SLinus Torvalds out_8(&mr->bus_status1, BS1_RST); /* assert RST */
17301da177e4SLinus Torvalds mesh_flush_io(mr);
17311da177e4SLinus Torvalds udelay(30); /* leave it on for >= 25us */
17321da177e4SLinus Torvalds out_8(&mr->bus_status1, 0); /* negate RST */
17331da177e4SLinus Torvalds
17341da177e4SLinus Torvalds /* Complete pending commands */
17351da177e4SLinus Torvalds handle_reset(ms);
17361da177e4SLinus Torvalds
1737df0ae249SJeff Garzik spin_unlock_irqrestore(ms->host->host_lock, flags);
17381da177e4SLinus Torvalds return SUCCESS;
17391da177e4SLinus Torvalds }
17401da177e4SLinus Torvalds
set_mesh_power(struct mesh_state * ms,int state)17411da177e4SLinus Torvalds static void set_mesh_power(struct mesh_state *ms, int state)
17421da177e4SLinus Torvalds {
1743e8222502SBenjamin Herrenschmidt if (!machine_is(powermac))
17441da177e4SLinus Torvalds return;
17451da177e4SLinus Torvalds if (state) {
17461da177e4SLinus Torvalds pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 1);
17471da177e4SLinus Torvalds msleep(200);
17481da177e4SLinus Torvalds } else {
17491da177e4SLinus Torvalds pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 0);
17501da177e4SLinus Torvalds msleep(10);
17511da177e4SLinus Torvalds }
17521da177e4SLinus Torvalds }
17531da177e4SLinus Torvalds
17541da177e4SLinus Torvalds
17551da177e4SLinus Torvalds #ifdef CONFIG_PM
mesh_suspend(struct macio_dev * mdev,pm_message_t mesg)17568b4b8a24SDavid Brownell static int mesh_suspend(struct macio_dev *mdev, pm_message_t mesg)
17571da177e4SLinus Torvalds {
17581da177e4SLinus Torvalds struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
17591da177e4SLinus Torvalds unsigned long flags;
17601da177e4SLinus Torvalds
17618b4b8a24SDavid Brownell switch (mesg.event) {
17628b4b8a24SDavid Brownell case PM_EVENT_SUSPEND:
17633a2d5b70SRafael J. Wysocki case PM_EVENT_HIBERNATE:
17648b4b8a24SDavid Brownell case PM_EVENT_FREEZE:
17658b4b8a24SDavid Brownell break;
17668b4b8a24SDavid Brownell default:
17678b4b8a24SDavid Brownell return 0;
17688b4b8a24SDavid Brownell }
176919c4158bSAlan Stern if (ms->phase == sleeping)
17701da177e4SLinus Torvalds return 0;
17711da177e4SLinus Torvalds
17721da177e4SLinus Torvalds scsi_block_requests(ms->host);
17731da177e4SLinus Torvalds spin_lock_irqsave(ms->host->host_lock, flags);
17741da177e4SLinus Torvalds while(ms->phase != idle) {
17751da177e4SLinus Torvalds spin_unlock_irqrestore(ms->host->host_lock, flags);
17761da177e4SLinus Torvalds msleep(10);
17771da177e4SLinus Torvalds spin_lock_irqsave(ms->host->host_lock, flags);
17781da177e4SLinus Torvalds }
17791da177e4SLinus Torvalds ms->phase = sleeping;
17801da177e4SLinus Torvalds spin_unlock_irqrestore(ms->host->host_lock, flags);
17811da177e4SLinus Torvalds disable_irq(ms->meshintr);
17821da177e4SLinus Torvalds set_mesh_power(ms, 0);
17831da177e4SLinus Torvalds
17841da177e4SLinus Torvalds return 0;
17851da177e4SLinus Torvalds }
17861da177e4SLinus Torvalds
mesh_resume(struct macio_dev * mdev)17871da177e4SLinus Torvalds static int mesh_resume(struct macio_dev *mdev)
17881da177e4SLinus Torvalds {
17891da177e4SLinus Torvalds struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
17901da177e4SLinus Torvalds unsigned long flags;
17911da177e4SLinus Torvalds
179219c4158bSAlan Stern if (ms->phase != sleeping)
17931da177e4SLinus Torvalds return 0;
17941da177e4SLinus Torvalds
17951da177e4SLinus Torvalds set_mesh_power(ms, 1);
17961da177e4SLinus Torvalds mesh_init(ms);
17971da177e4SLinus Torvalds spin_lock_irqsave(ms->host->host_lock, flags);
17981da177e4SLinus Torvalds mesh_start(ms);
17991da177e4SLinus Torvalds spin_unlock_irqrestore(ms->host->host_lock, flags);
18001da177e4SLinus Torvalds enable_irq(ms->meshintr);
18011da177e4SLinus Torvalds scsi_unblock_requests(ms->host);
18021da177e4SLinus Torvalds
18031da177e4SLinus Torvalds return 0;
18041da177e4SLinus Torvalds }
18051da177e4SLinus Torvalds
18061da177e4SLinus Torvalds #endif /* CONFIG_PM */
18071da177e4SLinus Torvalds
18081da177e4SLinus Torvalds /*
18091da177e4SLinus Torvalds * If we leave drives set for synchronous transfers (especially
18101da177e4SLinus Torvalds * CDROMs), and reboot to MacOS, it gets confused, poor thing.
18111da177e4SLinus Torvalds * So, on reboot we reset the SCSI bus.
18121da177e4SLinus Torvalds */
mesh_shutdown(struct macio_dev * mdev)18131da177e4SLinus Torvalds static int mesh_shutdown(struct macio_dev *mdev)
18141da177e4SLinus Torvalds {
18151da177e4SLinus Torvalds struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
18161da177e4SLinus Torvalds volatile struct mesh_regs __iomem *mr;
18171da177e4SLinus Torvalds unsigned long flags;
18181da177e4SLinus Torvalds
18191da177e4SLinus Torvalds printk(KERN_INFO "resetting MESH scsi bus(es)\n");
18201da177e4SLinus Torvalds spin_lock_irqsave(ms->host->host_lock, flags);
18211da177e4SLinus Torvalds mr = ms->mesh;
18221da177e4SLinus Torvalds out_8(&mr->intr_mask, 0);
18231da177e4SLinus Torvalds out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
18241da177e4SLinus Torvalds out_8(&mr->bus_status1, BS1_RST);
18251da177e4SLinus Torvalds mesh_flush_io(mr);
18261da177e4SLinus Torvalds udelay(30);
18271da177e4SLinus Torvalds out_8(&mr->bus_status1, 0);
18281da177e4SLinus Torvalds spin_unlock_irqrestore(ms->host->host_lock, flags);
18291da177e4SLinus Torvalds
18301da177e4SLinus Torvalds return 0;
18311da177e4SLinus Torvalds }
18321da177e4SLinus Torvalds
1833*0fabb7fbSBart Van Assche static const struct scsi_host_template mesh_template = {
18341da177e4SLinus Torvalds .proc_name = "mesh",
18351da177e4SLinus Torvalds .name = "MESH",
18361da177e4SLinus Torvalds .queuecommand = mesh_queue,
18371da177e4SLinus Torvalds .eh_abort_handler = mesh_abort,
18381da177e4SLinus Torvalds .eh_host_reset_handler = mesh_host_reset,
18391da177e4SLinus Torvalds .can_queue = 20,
18401da177e4SLinus Torvalds .this_id = 7,
18411da177e4SLinus Torvalds .sg_tablesize = SG_ALL,
18421da177e4SLinus Torvalds .cmd_per_lun = 2,
18435bd6cd54SChristoph Hellwig .max_segment_size = 65535,
184457cbd78eSBart Van Assche .cmd_size = sizeof(struct mesh_cmd_priv),
18451da177e4SLinus Torvalds };
18461da177e4SLinus Torvalds
mesh_probe(struct macio_dev * mdev,const struct of_device_id * match)18475e655772SJeff Mahoney static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match)
18481da177e4SLinus Torvalds {
18491da177e4SLinus Torvalds struct device_node *mesh = macio_get_of_node(mdev);
18501da177e4SLinus Torvalds struct pci_dev* pdev = macio_get_pci_dev(mdev);
1851294ef16aSJeremy Kerr int tgt, minper;
1852294ef16aSJeremy Kerr const int *cfp;
18531da177e4SLinus Torvalds struct mesh_state *ms;
18541da177e4SLinus Torvalds struct Scsi_Host *mesh_host;
18551da177e4SLinus Torvalds void *dma_cmd_space;
18561da177e4SLinus Torvalds dma_addr_t dma_cmd_bus;
18571da177e4SLinus Torvalds
18581da177e4SLinus Torvalds switch (mdev->bus->chip->type) {
18591da177e4SLinus Torvalds case macio_heathrow:
18601da177e4SLinus Torvalds case macio_gatwick:
18611da177e4SLinus Torvalds case macio_paddington:
18621da177e4SLinus Torvalds use_active_neg = 0;
18631da177e4SLinus Torvalds break;
18641da177e4SLinus Torvalds default:
18651da177e4SLinus Torvalds use_active_neg = SEQ_ACTIVE_NEG;
18661da177e4SLinus Torvalds }
18671da177e4SLinus Torvalds
18681da177e4SLinus Torvalds if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
18691da177e4SLinus Torvalds printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs"
1870cc5d0189SBenjamin Herrenschmidt " (got %d,%d)\n", macio_resource_count(mdev),
1871cc5d0189SBenjamin Herrenschmidt macio_irq_count(mdev));
18721da177e4SLinus Torvalds return -ENODEV;
18731da177e4SLinus Torvalds }
18741da177e4SLinus Torvalds
18751da177e4SLinus Torvalds if (macio_request_resources(mdev, "mesh") != 0) {
18761da177e4SLinus Torvalds printk(KERN_ERR "mesh: unable to request memory resources");
18771da177e4SLinus Torvalds return -EBUSY;
18781da177e4SLinus Torvalds }
18791da177e4SLinus Torvalds mesh_host = scsi_host_alloc(&mesh_template, sizeof(struct mesh_state));
18801da177e4SLinus Torvalds if (mesh_host == NULL) {
18811da177e4SLinus Torvalds printk(KERN_ERR "mesh: couldn't register host");
18821da177e4SLinus Torvalds goto out_release;
18831da177e4SLinus Torvalds }
18841da177e4SLinus Torvalds
18851da177e4SLinus Torvalds mesh_host->base = macio_resource_start(mdev, 0);
18861da177e4SLinus Torvalds mesh_host->irq = macio_irq(mdev, 0);
18871da177e4SLinus Torvalds ms = (struct mesh_state *) mesh_host->hostdata;
18881da177e4SLinus Torvalds macio_set_drvdata(mdev, ms);
18891da177e4SLinus Torvalds ms->host = mesh_host;
18901da177e4SLinus Torvalds ms->mdev = mdev;
18911da177e4SLinus Torvalds ms->pdev = pdev;
18921da177e4SLinus Torvalds
18931da177e4SLinus Torvalds ms->mesh = ioremap(macio_resource_start(mdev, 0), 0x1000);
18941da177e4SLinus Torvalds if (ms->mesh == NULL) {
18951da177e4SLinus Torvalds printk(KERN_ERR "mesh: can't map registers\n");
18961da177e4SLinus Torvalds goto out_free;
18971da177e4SLinus Torvalds }
18981da177e4SLinus Torvalds ms->dma = ioremap(macio_resource_start(mdev, 1), 0x1000);
18991da177e4SLinus Torvalds if (ms->dma == NULL) {
19001da177e4SLinus Torvalds printk(KERN_ERR "mesh: can't map registers\n");
19011da177e4SLinus Torvalds iounmap(ms->mesh);
19021da177e4SLinus Torvalds goto out_free;
19031da177e4SLinus Torvalds }
19041da177e4SLinus Torvalds
19051da177e4SLinus Torvalds ms->meshintr = macio_irq(mdev, 0);
19061da177e4SLinus Torvalds ms->dmaintr = macio_irq(mdev, 1);
19071da177e4SLinus Torvalds
19081da177e4SLinus Torvalds /* Space for dma command list: +1 for stop command,
19091da177e4SLinus Torvalds * +1 to allow for aligning.
19101da177e4SLinus Torvalds */
19111da177e4SLinus Torvalds ms->dma_cmd_size = (mesh_host->sg_tablesize + 2) * sizeof(struct dbdma_cmd);
19121da177e4SLinus Torvalds
19131da177e4SLinus Torvalds /* We use the PCI APIs for now until the generic one gets fixed
19141da177e4SLinus Torvalds * enough or until we get some macio-specific versions
19151da177e4SLinus Torvalds */
1916750afb08SLuis Chamberlain dma_cmd_space = dma_alloc_coherent(&macio_get_pci_dev(mdev)->dev,
1917750afb08SLuis Chamberlain ms->dma_cmd_size, &dma_cmd_bus,
1918750afb08SLuis Chamberlain GFP_KERNEL);
19191da177e4SLinus Torvalds if (dma_cmd_space == NULL) {
19201da177e4SLinus Torvalds printk(KERN_ERR "mesh: can't allocate DMA table\n");
19211da177e4SLinus Torvalds goto out_unmap;
19221da177e4SLinus Torvalds }
19231da177e4SLinus Torvalds
19241da177e4SLinus Torvalds ms->dma_cmds = (struct dbdma_cmd *) DBDMA_ALIGN(dma_cmd_space);
19251da177e4SLinus Torvalds ms->dma_cmd_space = dma_cmd_space;
19261da177e4SLinus Torvalds ms->dma_cmd_bus = dma_cmd_bus + ((unsigned long)ms->dma_cmds)
19271da177e4SLinus Torvalds - (unsigned long)dma_cmd_space;
19281da177e4SLinus Torvalds ms->current_req = NULL;
19291da177e4SLinus Torvalds for (tgt = 0; tgt < 8; ++tgt) {
19301da177e4SLinus Torvalds ms->tgts[tgt].sdtr_state = do_sdtr;
19311da177e4SLinus Torvalds ms->tgts[tgt].sync_params = ASYNC_PARAMS;
19321da177e4SLinus Torvalds ms->tgts[tgt].current_req = NULL;
19331da177e4SLinus Torvalds }
19341da177e4SLinus Torvalds
193540cd3a45SStephen Rothwell if ((cfp = of_get_property(mesh, "clock-frequency", NULL)))
19361da177e4SLinus Torvalds ms->clk_freq = *cfp;
19371da177e4SLinus Torvalds else {
19381da177e4SLinus Torvalds printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n");
19391da177e4SLinus Torvalds ms->clk_freq = 50000000;
19401da177e4SLinus Torvalds }
19411da177e4SLinus Torvalds
19421da177e4SLinus Torvalds /* The maximum sync rate is clock / 5; increase
19431da177e4SLinus Torvalds * mesh_sync_period if necessary.
19441da177e4SLinus Torvalds */
19451da177e4SLinus Torvalds minper = 1000000000 / (ms->clk_freq / 5); /* ns */
19461da177e4SLinus Torvalds if (mesh_sync_period < minper)
19471da177e4SLinus Torvalds mesh_sync_period = minper;
19481da177e4SLinus Torvalds
19491da177e4SLinus Torvalds /* Power up the chip */
19501da177e4SLinus Torvalds set_mesh_power(ms, 1);
19511da177e4SLinus Torvalds
19521da177e4SLinus Torvalds /* Set it up */
19531da177e4SLinus Torvalds mesh_init(ms);
19541da177e4SLinus Torvalds
19550cdc82eeSBenjamin Herrenschmidt /* Request interrupt */
19560cdc82eeSBenjamin Herrenschmidt if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) {
19571da177e4SLinus Torvalds printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr);
19580cdc82eeSBenjamin Herrenschmidt goto out_shutdown;
19590cdc82eeSBenjamin Herrenschmidt }
19601da177e4SLinus Torvalds
19610cdc82eeSBenjamin Herrenschmidt /* Add scsi host & scan */
19620cdc82eeSBenjamin Herrenschmidt if (scsi_add_host(mesh_host, &mdev->ofdev.dev))
19630cdc82eeSBenjamin Herrenschmidt goto out_release_irq;
19641da177e4SLinus Torvalds scsi_scan_host(mesh_host);
19651da177e4SLinus Torvalds
19661da177e4SLinus Torvalds return 0;
19671da177e4SLinus Torvalds
19680cdc82eeSBenjamin Herrenschmidt out_release_irq:
19690cdc82eeSBenjamin Herrenschmidt free_irq(ms->meshintr, ms);
19700cdc82eeSBenjamin Herrenschmidt out_shutdown:
19710cdc82eeSBenjamin Herrenschmidt /* shutdown & reset bus in case of error or macos can be confused
19720cdc82eeSBenjamin Herrenschmidt * at reboot if the bus was set to synchronous mode already
19730cdc82eeSBenjamin Herrenschmidt */
19740cdc82eeSBenjamin Herrenschmidt mesh_shutdown(mdev);
19750cdc82eeSBenjamin Herrenschmidt set_mesh_power(ms, 0);
19766c714d44SChristoph Hellwig dma_free_coherent(&macio_get_pci_dev(mdev)->dev, ms->dma_cmd_size,
19770cdc82eeSBenjamin Herrenschmidt ms->dma_cmd_space, ms->dma_cmd_bus);
19781da177e4SLinus Torvalds out_unmap:
19791da177e4SLinus Torvalds iounmap(ms->dma);
19801da177e4SLinus Torvalds iounmap(ms->mesh);
19811da177e4SLinus Torvalds out_free:
19821da177e4SLinus Torvalds scsi_host_put(mesh_host);
19831da177e4SLinus Torvalds out_release:
19841da177e4SLinus Torvalds macio_release_resources(mdev);
19851da177e4SLinus Torvalds
19861da177e4SLinus Torvalds return -ENODEV;
19871da177e4SLinus Torvalds }
19881da177e4SLinus Torvalds
mesh_remove(struct macio_dev * mdev)19891da177e4SLinus Torvalds static int mesh_remove(struct macio_dev *mdev)
19901da177e4SLinus Torvalds {
19911da177e4SLinus Torvalds struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
19921da177e4SLinus Torvalds struct Scsi_Host *mesh_host = ms->host;
19931da177e4SLinus Torvalds
19941da177e4SLinus Torvalds scsi_remove_host(mesh_host);
19951da177e4SLinus Torvalds
19961da177e4SLinus Torvalds free_irq(ms->meshintr, ms);
19971da177e4SLinus Torvalds
19981da177e4SLinus Torvalds /* Reset scsi bus */
19991da177e4SLinus Torvalds mesh_shutdown(mdev);
20001da177e4SLinus Torvalds
20011da177e4SLinus Torvalds /* Shut down chip & termination */
20021da177e4SLinus Torvalds set_mesh_power(ms, 0);
20031da177e4SLinus Torvalds
20041da177e4SLinus Torvalds /* Unmap registers & dma controller */
20051da177e4SLinus Torvalds iounmap(ms->mesh);
20061da177e4SLinus Torvalds iounmap(ms->dma);
20071da177e4SLinus Torvalds
20081da177e4SLinus Torvalds /* Free DMA commands memory */
20096c714d44SChristoph Hellwig dma_free_coherent(&macio_get_pci_dev(mdev)->dev, ms->dma_cmd_size,
20101da177e4SLinus Torvalds ms->dma_cmd_space, ms->dma_cmd_bus);
20111da177e4SLinus Torvalds
20121da177e4SLinus Torvalds /* Release memory resources */
20131da177e4SLinus Torvalds macio_release_resources(mdev);
20141da177e4SLinus Torvalds
20151da177e4SLinus Torvalds scsi_host_put(mesh_host);
20161da177e4SLinus Torvalds
20171da177e4SLinus Torvalds return 0;
20181da177e4SLinus Torvalds }
20191da177e4SLinus Torvalds
20201da177e4SLinus Torvalds
20215e655772SJeff Mahoney static struct of_device_id mesh_match[] =
20221da177e4SLinus Torvalds {
20231da177e4SLinus Torvalds {
20241da177e4SLinus Torvalds .name = "mesh",
20251da177e4SLinus Torvalds },
20261da177e4SLinus Torvalds {
20271da177e4SLinus Torvalds .type = "scsi",
20281da177e4SLinus Torvalds .compatible = "chrp,mesh0"
20291da177e4SLinus Torvalds },
20301da177e4SLinus Torvalds {},
20311da177e4SLinus Torvalds };
20325e655772SJeff Mahoney MODULE_DEVICE_TABLE (of, mesh_match);
20331da177e4SLinus Torvalds
20341da177e4SLinus Torvalds static struct macio_driver mesh_driver =
20351da177e4SLinus Torvalds {
2036c2cdf6abSBenjamin Herrenschmidt .driver = {
20371da177e4SLinus Torvalds .name = "mesh",
2038c2cdf6abSBenjamin Herrenschmidt .owner = THIS_MODULE,
2039c2cdf6abSBenjamin Herrenschmidt .of_match_table = mesh_match,
2040c2cdf6abSBenjamin Herrenschmidt },
20411da177e4SLinus Torvalds .probe = mesh_probe,
20421da177e4SLinus Torvalds .remove = mesh_remove,
20431da177e4SLinus Torvalds .shutdown = mesh_shutdown,
20441da177e4SLinus Torvalds #ifdef CONFIG_PM
20451da177e4SLinus Torvalds .suspend = mesh_suspend,
20461da177e4SLinus Torvalds .resume = mesh_resume,
20471da177e4SLinus Torvalds #endif
20481da177e4SLinus Torvalds };
20491da177e4SLinus Torvalds
20501da177e4SLinus Torvalds
init_mesh(void)20511da177e4SLinus Torvalds static int __init init_mesh(void)
20521da177e4SLinus Torvalds {
20531da177e4SLinus Torvalds
20541da177e4SLinus Torvalds /* Calculate sync rate from module parameters */
20551da177e4SLinus Torvalds if (sync_rate > 10)
20561da177e4SLinus Torvalds sync_rate = 10;
20571da177e4SLinus Torvalds if (sync_rate > 0) {
20581da177e4SLinus Torvalds printk(KERN_INFO "mesh: configured for synchronous %d MB/s\n", sync_rate);
20591da177e4SLinus Torvalds mesh_sync_period = 1000 / sync_rate; /* ns */
20601da177e4SLinus Torvalds mesh_sync_offset = 15;
20611da177e4SLinus Torvalds } else
20621da177e4SLinus Torvalds printk(KERN_INFO "mesh: configured for asynchronous\n");
20631da177e4SLinus Torvalds
20641da177e4SLinus Torvalds return macio_register_driver(&mesh_driver);
20651da177e4SLinus Torvalds }
20661da177e4SLinus Torvalds
exit_mesh(void)20671da177e4SLinus Torvalds static void __exit exit_mesh(void)
20681da177e4SLinus Torvalds {
20691da177e4SLinus Torvalds return macio_unregister_driver(&mesh_driver);
20701da177e4SLinus Torvalds }
20711da177e4SLinus Torvalds
20721da177e4SLinus Torvalds module_init(init_mesh);
20731da177e4SLinus Torvalds module_exit(exit_mesh);
2074