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