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