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