brintos

brintos / linux-shallow public Read only

0
0
Text · 80.7 KiB · e50a3db Raw
2921 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  linux/drivers/acorn/scsi/acornscsi.c4 *5 *  Acorn SCSI 3 driver6 *  By R.M.King.7 *8 * Abandoned using the Select and Transfer command since there were9 * some nasty races between our software and the target devices that10 * were not easy to solve, and the device errata had a lot of entries11 * for this command, some of them quite nasty...12 *13 * Changelog:14 *  26-Sep-1997	RMK	Re-jigged to use the queue module.15 *			Re-coded state machine to be based on driver16 *			state not scsi state.  Should be easier to debug.17 *			Added acornscsi_release to clean up properly.18 *			Updated proc/scsi reporting.19 *  05-Oct-1997	RMK	Implemented writing to SCSI devices.20 *  06-Oct-1997	RMK	Corrected small (non-serious) bug with the connect/21 *			reconnect race condition causing a warning message.22 *  12-Oct-1997	RMK	Added catch for re-entering interrupt routine.23 *  15-Oct-1997	RMK	Improved handling of commands.24 *  27-Jun-1998	RMK	Changed asm/delay.h to linux/delay.h.25 *  13-Dec-1998	RMK	Better abort code and command handling.  Extra state26 *			transitions added to allow dodgy devices to work.27 */28#define DEBUG_NO_WRITE	129#define DEBUG_QUEUES	230#define DEBUG_DMA	431#define DEBUG_ABORT	832#define DEBUG_DISCON	1633#define DEBUG_CONNECT	3234#define DEBUG_PHASES	6435#define DEBUG_WRITE	12836#define DEBUG_LINK	25637#define DEBUG_MESSAGES	51238#define DEBUG_RESET	102439#define DEBUG_ALL	(DEBUG_RESET|DEBUG_MESSAGES|DEBUG_LINK|DEBUG_WRITE|\40			 DEBUG_PHASES|DEBUG_CONNECT|DEBUG_DISCON|DEBUG_ABORT|\41			 DEBUG_DMA|DEBUG_QUEUES)42 43/* DRIVER CONFIGURATION44 *45 * SCSI-II Tagged queue support.46 *47 * I don't have any SCSI devices that support it, so it is totally untested48 * (except to make sure that it doesn't interfere with any non-tagging49 * devices).  It is not fully implemented either - what happens when a50 * tagging device reconnects???51 *52 * You can tell if you have a device that supports tagged queueing my53 * cating (eg) /proc/scsi/acornscsi/0 and see if the SCSI revision is reported54 * as '2 TAG'.55 */56 57/*58 * SCSI-II Synchronous transfer support.59 *60 * Tried and tested...61 *62 * SDTR_SIZE	  - maximum number of un-acknowledged bytes (0 = off, 12 = max)63 * SDTR_PERIOD	  - period of REQ signal (min=125, max=1020)64 * DEFAULT_PERIOD - default REQ period.65 */66#define SDTR_SIZE	1267#define SDTR_PERIOD	12568#define DEFAULT_PERIOD	50069 70/*71 * Debugging information72 *73 * DEBUG	  - bit mask from list above74 * DEBUG_TARGET   - is defined to the target number if you want to debug75 *		    a specific target. [only recon/write/dma].76 */77#define DEBUG (DEBUG_RESET|DEBUG_WRITE|DEBUG_NO_WRITE)78/* only allow writing to SCSI device 0 */79#define NO_WRITE 0xFE80/*#define DEBUG_TARGET 2*/81/*82 * Select timeout time (in 10ms units)83 *84 * This is the timeout used between the start of selection and the WD33C9385 * chip deciding that the device isn't responding.86 */87#define TIMEOUT_TIME 1088/*89 * Define this if you want to have verbose explanation of SCSI90 * status/messages.91 */92#undef CONFIG_ACORNSCSI_CONSTANTS93/*94 * Define this if you want to use the on board DMAC [don't remove this option]95 * If not set, then use PIO mode (not currently supported).96 */97#define USE_DMAC98 99/*100 * ====================================================================================101 */102 103#ifdef DEBUG_TARGET104#define DBG(cmd,xxx...) \105  if (cmd->device->id == DEBUG_TARGET) { \106    xxx; \107  }108#else109#define DBG(cmd,xxx...) xxx110#endif111 112#include <linux/module.h>113#include <linux/kernel.h>114#include <linux/string.h>115#include <linux/signal.h>116#include <linux/errno.h>117#include <linux/proc_fs.h>118#include <linux/ioport.h>119#include <linux/blkdev.h>120#include <linux/delay.h>121#include <linux/interrupt.h>122#include <linux/init.h>123#include <linux/bitops.h>124#include <linux/stringify.h>125#include <linux/io.h>126 127#include <asm/ecard.h>128 129#include <scsi/scsi.h>130#include <scsi/scsi_cmnd.h>131#include <scsi/scsi_dbg.h>132#include <scsi/scsi_device.h>133#include <scsi/scsi_eh.h>134#include <scsi/scsi_host.h>135#include <scsi/scsi_tcq.h>136#include <scsi/scsi_transport_spi.h>137#include "acornscsi.h"138#include "msgqueue.h"139#include "arm_scsi.h"140 141#include <scsi/scsicam.h>142 143#define VER_MAJOR 2144#define VER_MINOR 0145#define VER_PATCH 6146 147#ifdef USE_DMAC148/*149 * DMAC setup parameters150 */ 151#define INIT_DEVCON0	(DEVCON0_RQL|DEVCON0_EXW|DEVCON0_CMP)152#define INIT_DEVCON1	(DEVCON1_BHLD)153#define DMAC_READ	(MODECON_READ)154#define DMAC_WRITE	(MODECON_WRITE)155#define INIT_SBICDMA	(CTRL_DMABURST)156 157#define scsi_xferred	have_data_in158 159/*160 * Size of on-board DMA buffer161 */162#define DMAC_BUFFER_SIZE	65536163#endif164 165#define STATUS_BUFFER_TO_PRINT	24166 167unsigned int sdtr_period = SDTR_PERIOD;168unsigned int sdtr_size   = SDTR_SIZE;169 170static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp,171			   unsigned int result);172static int acornscsi_reconnect_finish(AS_Host *host);173static void acornscsi_dma_cleanup(AS_Host *host);174static void acornscsi_abortcmd(AS_Host *host);175 176/* ====================================================================================177 * Miscellaneous178 */179 180/* Offsets from MEMC base */181#define SBIC_REGIDX	0x2000182#define SBIC_REGVAL	0x2004183#define DMAC_OFFSET	0x3000184 185/* Offsets from FAST IOC base */186#define INT_REG		0x2000187#define PAGE_REG	0x3000188 189static inline void sbic_arm_write(AS_Host *host, unsigned int reg, unsigned int value)190{191    writeb(reg, host->base + SBIC_REGIDX);192    writeb(value, host->base + SBIC_REGVAL);193}194 195static inline int sbic_arm_read(AS_Host *host, unsigned int reg)196{197    if(reg == SBIC_ASR)198	   return readl(host->base + SBIC_REGIDX) & 255;199    writeb(reg, host->base + SBIC_REGIDX);200    return readl(host->base + SBIC_REGVAL) & 255;201}202 203#define sbic_arm_writenext(host, val)	writeb((val), (host)->base + SBIC_REGVAL)204#define sbic_arm_readnext(host) 	readb((host)->base + SBIC_REGVAL)205 206#ifdef USE_DMAC207#define dmac_read(host,reg) \208	readb((host)->base + DMAC_OFFSET + ((reg) << 2))209 210#define dmac_write(host,reg,value) \211	({ writeb((value), (host)->base + DMAC_OFFSET + ((reg) << 2)); })212 213#define dmac_clearintr(host) 	writeb(0, (host)->fast + INT_REG)214 215static inline unsigned int dmac_address(AS_Host *host)216{217    return dmac_read(host, DMAC_TXADRHI) << 16 |218	   dmac_read(host, DMAC_TXADRMD) << 8 |219	   dmac_read(host, DMAC_TXADRLO);220}221 222static223void acornscsi_dumpdma(AS_Host *host, char *where)224{225	unsigned int mode, addr, len;226 227	mode = dmac_read(host, DMAC_MODECON);228	addr = dmac_address(host);229	len  = dmac_read(host, DMAC_TXCNTHI) << 8 |230	       dmac_read(host, DMAC_TXCNTLO);231 232	printk("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ",233		host->host->host_no, where,234		mode, addr, (len + 1) & 0xffff,235		dmac_read(host, DMAC_MASKREG));236 237	printk("DMA @%06x, ", host->dma.start_addr);238	printk("BH @%p +%04x, ", host->scsi.SCp.ptr,239		host->scsi.SCp.this_residual);240	printk("DT @+%04x ST @+%04x", host->dma.transferred,241		host->scsi.SCp.scsi_xferred);242	printk("\n");243}244#endif245 246static247unsigned long acornscsi_sbic_xfcount(AS_Host *host)248{249    unsigned long length;250 251    length = sbic_arm_read(host, SBIC_TRANSCNTH) << 16;252    length |= sbic_arm_readnext(host) << 8;253    length |= sbic_arm_readnext(host);254 255    return length;256}257 258static int259acornscsi_sbic_wait(AS_Host *host, int stat_mask, int stat, int timeout, char *msg)260{261	int asr;262 263	do {264		asr = sbic_arm_read(host, SBIC_ASR);265 266		if ((asr & stat_mask) == stat)267			return 0;268 269		udelay(1);270	} while (--timeout);271 272	printk("scsi%d: timeout while %s\n", host->host->host_no, msg);273 274	return -1;275}276 277static278int acornscsi_sbic_issuecmd(AS_Host *host, int command)279{280    if (acornscsi_sbic_wait(host, ASR_CIP, 0, 1000, "issuing command"))281	return -1;282 283    sbic_arm_write(host, SBIC_CMND, command);284 285    return 0;286}287 288static void289acornscsi_csdelay(unsigned int cs)290{291    unsigned long target_jiffies, flags;292 293    target_jiffies = jiffies + 1 + cs * HZ / 100;294 295    local_save_flags(flags);296    local_irq_enable();297 298    while (time_before(jiffies, target_jiffies)) barrier();299 300    local_irq_restore(flags);301}302 303static304void acornscsi_resetcard(AS_Host *host)305{306    unsigned int i, timeout;307 308    /* assert reset line */309    host->card.page_reg = 0x80;310    writeb(host->card.page_reg, host->fast + PAGE_REG);311 312    /* wait 3 cs.  SCSI standard says 25ms. */313    acornscsi_csdelay(3);314 315    host->card.page_reg = 0;316    writeb(host->card.page_reg, host->fast + PAGE_REG);317 318    /*319     * Should get a reset from the card320     */321    timeout = 1000;322    do {323	if (readb(host->fast + INT_REG) & 8)324	    break;325	udelay(1);326    } while (--timeout);327 328    if (timeout == 0)329	printk("scsi%d: timeout while resetting card\n",330		host->host->host_no);331 332    sbic_arm_read(host, SBIC_ASR);333    sbic_arm_read(host, SBIC_SSR);334 335    /* setup sbic - WD33C93A */336    sbic_arm_write(host, SBIC_OWNID, OWNID_EAF | host->host->this_id);337    sbic_arm_write(host, SBIC_CMND, CMND_RESET);338 339    /*340     * Command should cause a reset interrupt341     */342    timeout = 1000;343    do {344	if (readb(host->fast + INT_REG) & 8)345	    break;346	udelay(1);347    } while (--timeout);348 349    if (timeout == 0)350	printk("scsi%d: timeout while resetting card\n",351		host->host->host_no);352 353    sbic_arm_read(host, SBIC_ASR);354    if (sbic_arm_read(host, SBIC_SSR) != 0x01)355	printk(KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n",356		host->host->host_no);357 358    sbic_arm_write(host, SBIC_CTRL, INIT_SBICDMA | CTRL_IDI);359    sbic_arm_write(host, SBIC_TIMEOUT, TIMEOUT_TIME);360    sbic_arm_write(host, SBIC_SYNCHTRANSFER, SYNCHTRANSFER_2DBA);361    sbic_arm_write(host, SBIC_SOURCEID, SOURCEID_ER | SOURCEID_DSP);362 363    host->card.page_reg = 0x40;364    writeb(host->card.page_reg, host->fast + PAGE_REG);365 366    /* setup dmac - uPC71071 */367    dmac_write(host, DMAC_INIT, 0);368#ifdef USE_DMAC369    dmac_write(host, DMAC_INIT, INIT_8BIT);370    dmac_write(host, DMAC_CHANNEL, CHANNEL_0);371    dmac_write(host, DMAC_DEVCON0, INIT_DEVCON0);372    dmac_write(host, DMAC_DEVCON1, INIT_DEVCON1);373#endif374 375    host->SCpnt = NULL;376    host->scsi.phase = PHASE_IDLE;377    host->scsi.disconnectable = 0;378 379    memset(host->busyluns, 0, sizeof(host->busyluns));380 381    for (i = 0; i < 8; i++) {382	host->device[i].sync_state = SYNC_NEGOCIATE;383	host->device[i].disconnect_ok = 1;384    }385 386    /* wait 25 cs.  SCSI standard says 250ms. */387    acornscsi_csdelay(25);388}389 390/*=============================================================================================391 * Utility routines (eg. debug)392 */393#ifdef CONFIG_ACORNSCSI_CONSTANTS394static char *acornscsi_interrupttype[] = {395  "rst",  "suc",  "p/a",  "3",396  "term", "5",	  "6",	  "7",397  "serv", "9",	  "a",	  "b",398  "c",	  "d",	  "e",	  "f"399};400 401static signed char acornscsi_map[] = {402  0,  1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,403 -1,  2, -1, -1,  -1, -1,  3, -1,   4,	5,  6,	7,   8,  9, 10, 11,404 12, 13, 14, -1,  -1, -1, -1, -1,   4,	5,  6,	7,   8,  9, 10, 11,405 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,406 15, 16, 17, 18,  19, -1, -1, 20,   4,	5,  6,	7,   8,  9, 10, 11,407 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,408 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,409 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,410 21, 22, -1, -1,  -1, 23, -1, -1,   4,	5,  6,	7,   8,  9, 10, 11,411 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,412 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,413 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,414 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,415 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,416 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,417 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1418};      419 420static char *acornscsi_interruptcode[] = {421    /* 0 */422    "reset - normal mode",	/* 00 */423    "reset - advanced mode",	/* 01 */424 425    /* 2 */426    "sel",			/* 11 */427    "sel+xfer", 		/* 16 */428    "data-out", 		/* 18 */429    "data-in",			/* 19 */430    "cmd",			/* 1A */431    "stat",			/* 1B */432    "??-out",			/* 1C */433    "??-in",			/* 1D */434    "msg-out",			/* 1E */435    "msg-in",			/* 1F */436 437    /* 12 */438    "/ACK asserted",		/* 20 */439    "save-data-ptr",		/* 21 */440    "{re}sel",			/* 22 */441 442    /* 15 */443    "inv cmd",			/* 40 */444    "unexpected disconnect",	/* 41 */445    "sel timeout",		/* 42 */446    "P err",			/* 43 */447    "P err+ATN",		/* 44 */448    "bad status byte",		/* 47 */449 450    /* 21 */451    "resel, no id",		/* 80 */452    "resel",			/* 81 */453    "discon",			/* 85 */454};455 456static457void print_scsi_status(unsigned int ssr)458{459    if (acornscsi_map[ssr] != -1)460	printk("%s:%s",461		acornscsi_interrupttype[(ssr >> 4)],462		acornscsi_interruptcode[acornscsi_map[ssr]]);463    else464	printk("%X:%X", ssr >> 4, ssr & 0x0f);    465}    466#endif467 468static469void print_sbic_status(int asr, int ssr, int cmdphase)470{471#ifdef CONFIG_ACORNSCSI_CONSTANTS472    printk("sbic: %c%c%c%c%c%c ",473	    asr & ASR_INT ? 'I' : 'i',474	    asr & ASR_LCI ? 'L' : 'l',475	    asr & ASR_BSY ? 'B' : 'b',476	    asr & ASR_CIP ? 'C' : 'c',477	    asr & ASR_PE  ? 'P' : 'p',478	    asr & ASR_DBR ? 'D' : 'd');479    printk("scsi: ");480    print_scsi_status(ssr);481    printk(" ph %02X\n", cmdphase);482#else483    printk("sbic: %02X scsi: %X:%X ph: %02X\n",484	    asr, (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase);485#endif486}487 488static void489acornscsi_dumplogline(AS_Host *host, int target, int line)490{491	unsigned long prev;492	signed int ptr;493 494	ptr = host->status_ptr[target] - STATUS_BUFFER_TO_PRINT;495	if (ptr < 0)496		ptr += STATUS_BUFFER_SIZE;497 498	printk("%c: %3s:", target == 8 ? 'H' : '0' + target,499		line == 0 ? "ph" : line == 1 ? "ssr" : "int");500 501	prev = host->status[target][ptr].when;502 503	for (; ptr != host->status_ptr[target]; ptr = (ptr + 1) & (STATUS_BUFFER_SIZE - 1)) {504		unsigned long time_diff;505 506		if (!host->status[target][ptr].when)507			continue;508 509		switch (line) {510		case 0:511			printk("%c%02X", host->status[target][ptr].irq ? '-' : ' ',512					 host->status[target][ptr].ph);513			break;514 515		case 1:516			printk(" %02X", host->status[target][ptr].ssr);517			break;518 519		case 2:520			time_diff = host->status[target][ptr].when - prev;521			prev = host->status[target][ptr].when;522			if (time_diff == 0)523				printk("==^");524			else if (time_diff >= 100)525				printk("   ");526			else527				printk(" %02ld", time_diff);528			break;529		}530	}531 532	printk("\n");533}534 535static536void acornscsi_dumplog(AS_Host *host, int target)537{538    do {539	acornscsi_dumplogline(host, target, 0);540	acornscsi_dumplogline(host, target, 1);541	acornscsi_dumplogline(host, target, 2);542 543	if (target == 8)544	    break;545 546	target = 8;547    } while (1);548}549 550static551char acornscsi_target(AS_Host *host)552{553	if (host->SCpnt)554		return '0' + host->SCpnt->device->id;555	return 'H';556}557 558/*559 * Prototype: cmdtype_t acornscsi_cmdtype(int command)560 * Purpose  : differentiate READ from WRITE from other commands561 * Params   : command - command to interpret562 * Returns  : CMD_READ	- command reads data,563 *	      CMD_WRITE - command writes data,564 *	      CMD_MISC	- everything else565 */566static inline567cmdtype_t acornscsi_cmdtype(int command)568{569    switch (command) {570    case WRITE_6:  case WRITE_10:  case WRITE_12:571	return CMD_WRITE;572    case READ_6:   case READ_10:   case READ_12:573	return CMD_READ;574    default:575	return CMD_MISC;576    }577}578 579/*580 * Prototype: int acornscsi_datadirection(int command)581 * Purpose  : differentiate between commands that have a DATA IN phase582 *	      and a DATA OUT phase583 * Params   : command - command to interpret584 * Returns  : DATADIR_OUT - data out phase expected585 *	      DATADIR_IN  - data in phase expected586 */587static588datadir_t acornscsi_datadirection(int command)589{590    switch (command) {591    case CHANGE_DEFINITION:	case COMPARE:		case COPY:592    case COPY_VERIFY:		case LOG_SELECT:	case MODE_SELECT:593    case MODE_SELECT_10:	case SEND_DIAGNOSTIC:	case WRITE_BUFFER:594    case FORMAT_UNIT:		case REASSIGN_BLOCKS:	case RESERVE:595    case SEARCH_EQUAL:		case SEARCH_HIGH:	case SEARCH_LOW:596    case WRITE_6:		case WRITE_10:		case WRITE_VERIFY:597    case UPDATE_BLOCK:		case WRITE_LONG:	case WRITE_SAME:598    case SEARCH_HIGH_12:	case SEARCH_EQUAL_12:	case SEARCH_LOW_12:599    case WRITE_12:		case WRITE_VERIFY_12:	case SET_WINDOW:600    case MEDIUM_SCAN:		case SEND_VOLUME_TAG:	case 0xea:601	return DATADIR_OUT;602    default:603	return DATADIR_IN;604    }605}606 607/*608 * Purpose  : provide values for synchronous transfers with 33C93.609 * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting610 *	Modified by Russell King for 8MHz WD33C93A611 */612static struct sync_xfer_tbl {613    unsigned int period_ns;614    unsigned char reg_value;615} sync_xfer_table[] = {616    {	1, 0x20 },    { 249, 0x20 },	{ 374, 0x30 },617    { 499, 0x40 },    { 624, 0x50 },	{ 749, 0x60 },618    { 874, 0x70 },    { 999, 0x00 },	{   0,	  0 }619};620 621/*622 * Prototype: int acornscsi_getperiod(unsigned char syncxfer)623 * Purpose  : period for the synchronous transfer setting624 * Params   : syncxfer SYNCXFER register value625 * Returns  : period in ns.626 */627static628int acornscsi_getperiod(unsigned char syncxfer)629{630    int i;631 632    syncxfer &= 0xf0;633    if (syncxfer == 0x10)634	syncxfer = 0;635 636    for (i = 1; sync_xfer_table[i].period_ns; i++)637	if (syncxfer == sync_xfer_table[i].reg_value)638	    return sync_xfer_table[i].period_ns;639    return 0;640}641 642/*643 * Prototype: int round_period(unsigned int period)644 * Purpose  : return index into above table for a required REQ period645 * Params   : period - time (ns) for REQ646 * Returns  : table index647 * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting648 */649static inline650int round_period(unsigned int period)651{652    int i;653 654    for (i = 1; sync_xfer_table[i].period_ns; i++) {655	if ((period <= sync_xfer_table[i].period_ns) &&656	    (period > sync_xfer_table[i - 1].period_ns))657	    return i;658    }659    return 7;660}661 662/*663 * Prototype: unsigned char calc_sync_xfer(unsigned int period, unsigned int offset)664 * Purpose  : calculate value for 33c93s SYNC register665 * Params   : period - time (ns) for REQ666 *	      offset - offset in bytes between REQ/ACK667 * Returns  : value for SYNC register668 * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting669 */670static671unsigned char __maybe_unused calc_sync_xfer(unsigned int period,672					    unsigned int offset)673{674    return sync_xfer_table[round_period(period)].reg_value |675		((offset < SDTR_SIZE) ? offset : SDTR_SIZE);676}677 678/* ====================================================================================679 * Command functions680 */681/*682 * Function: acornscsi_kick(AS_Host *host)683 * Purpose : kick next command to interface684 * Params  : host - host to send command to685 * Returns : INTR_IDLE if idle, otherwise INTR_PROCESSING686 * Notes   : interrupts are always disabled!687 */688static689intr_ret_t acornscsi_kick(AS_Host *host)690{691    int from_queue = 0;692    struct scsi_cmnd *SCpnt;693 694    /* first check to see if a command is waiting to be executed */695    SCpnt = host->origSCpnt;696    host->origSCpnt = NULL;697 698    /* retrieve next command */699    if (!SCpnt) {700	SCpnt = queue_remove_exclude(&host->queues.issue, host->busyluns);701	if (!SCpnt)702	    return INTR_IDLE;703 704	from_queue = 1;705    }706 707    if (host->scsi.disconnectable && host->SCpnt) {708	queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);709	host->scsi.disconnectable = 0;710#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))711	DBG(host->SCpnt, printk("scsi%d.%c: moved command to disconnected queue\n",712		host->host->host_no, acornscsi_target(host)));713#endif714	host->SCpnt = NULL;715    }716 717    /*718     * If we have an interrupt pending, then we may have been reselected.719     * In this case, we don't want to write to the registers720     */721    if (!(sbic_arm_read(host, SBIC_ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) {722	sbic_arm_write(host, SBIC_DESTID, SCpnt->device->id);723	sbic_arm_write(host, SBIC_CMND, CMND_SELWITHATN);724    }725 726    /*727     * claim host busy - all of these must happen atomically wrt728     * our interrupt routine.  Failure means command loss.729     */730    host->scsi.phase = PHASE_CONNECTING;731    host->SCpnt = SCpnt;732    host->scsi.SCp = *arm_scsi_pointer(SCpnt);733    host->dma.xfer_setup = 0;734    host->dma.xfer_required = 0;735    host->dma.xfer_done = 0;736 737#if (DEBUG & (DEBUG_ABORT|DEBUG_CONNECT))738    DBG(SCpnt,printk("scsi%d.%c: starting cmd %02X\n",739	    host->host->host_no, '0' + SCpnt->device->id,740	    SCpnt->cmnd[0]));741#endif742 743    if (from_queue) {744	    set_bit(SCpnt->device->id * 8 +745		    (u8)(SCpnt->device->lun & 0x07), host->busyluns);746 747	host->stats.removes += 1;748 749	switch (acornscsi_cmdtype(SCpnt->cmnd[0])) {750	case CMD_WRITE:751	    host->stats.writes += 1;752	    break;753	case CMD_READ:754	    host->stats.reads += 1;755	    break;756	case CMD_MISC:757	    host->stats.miscs += 1;758	    break;759	}760    }761 762    return INTR_PROCESSING;763}    764 765/*766 * Function: void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp, unsigned int result)767 * Purpose : complete processing for command768 * Params  : host   - interface that completed769 *	     result - driver byte of result770 */771static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp,772			   unsigned int result)773{774	struct scsi_cmnd *SCpnt = *SCpntp;775 776    /* clean up */777    sbic_arm_write(host, SBIC_SOURCEID, SOURCEID_ER | SOURCEID_DSP);778 779    host->stats.fins += 1;780 781    if (SCpnt) {782	*SCpntp = NULL;783 784	acornscsi_dma_cleanup(host);785 786	set_host_byte(SCpnt, result);787	if (result == DID_OK)788		scsi_msg_to_host_byte(SCpnt, host->scsi.SCp.Message);789	set_status_byte(SCpnt, host->scsi.SCp.Status);790 791	/*792	 * In theory, this should not happen.  In practice, it seems to.793	 * Only trigger an error if the device attempts to report all happy794	 * but with untransferred buffers...  If we don't do something, then795	 * data loss will occur.  Should we check SCpnt->underflow here?796	 * It doesn't appear to be set to something meaningful by the higher797	 * levels all the time.798	 */799	if (result == DID_OK) {800		int xfer_warn = 0;801 802		if (SCpnt->underflow == 0) {803			if (host->scsi.SCp.ptr &&804			    acornscsi_cmdtype(SCpnt->cmnd[0]) != CMD_MISC)805				xfer_warn = 1;806		} else {807			if (host->scsi.SCp.scsi_xferred < SCpnt->underflow ||808			    host->scsi.SCp.scsi_xferred != host->dma.transferred)809				xfer_warn = 1;810		}811 812		/* ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.6)813		 *  Targets which break data transfers into multiple814		 *  connections shall end each successful connection815		 *  (except possibly the last) with a SAVE DATA816		 *  POINTER - DISCONNECT message sequence.817		 *818		 * This makes it difficult to ensure that a transfer has819		 * completed.  If we reach the end of a transfer during820		 * the command, then we can only have finished the transfer.821		 * therefore, if we seem to have some data remaining, this822		 * is not a problem.823		 */824		if (host->dma.xfer_done)825			xfer_warn = 0;826 827		if (xfer_warn) {828		    switch (get_status_byte(SCpnt)) {829		    case SAM_STAT_CHECK_CONDITION:830		    case SAM_STAT_COMMAND_TERMINATED:831		    case SAM_STAT_BUSY:832		    case SAM_STAT_TASK_SET_FULL:833		    case SAM_STAT_RESERVATION_CONFLICT:834			break;835 836		    default:837			scmd_printk(KERN_ERR, SCpnt,838				    "incomplete data transfer detected: "839				    "result=%08X", SCpnt->result);840			scsi_print_command(SCpnt);841			acornscsi_dumpdma(host, "done");842			acornscsi_dumplog(host, SCpnt->device->id);843			set_host_byte(SCpnt, DID_ERROR);844		    }845		}846	}847 848	clear_bit(SCpnt->device->id * 8 +849		  (u8)(SCpnt->device->lun & 0x7), host->busyluns);850 851	scsi_done(SCpnt);852    } else853	printk("scsi%d: null command in acornscsi_done", host->host->host_no);854 855    host->scsi.phase = PHASE_IDLE;856}857 858/* ====================================================================================859 * DMA routines860 */861/*862 * Purpose  : update SCSI Data Pointer863 * Notes    : this will only be one SG entry or less864 */865static866void acornscsi_data_updateptr(AS_Host *host, struct scsi_pointer *SCp, unsigned int length)867{868    SCp->ptr += length;869    SCp->this_residual -= length;870 871    if (SCp->this_residual == 0 && next_SCp(SCp) == 0)872	host->dma.xfer_done = 1;873}874 875/*876 * Prototype: void acornscsi_data_read(AS_Host *host, char *ptr,877 *				unsigned int start_addr, unsigned int length)878 * Purpose  : read data from DMA RAM879 * Params   : host - host to transfer from880 *	      ptr  - DRAM address881 *	      start_addr - host mem address882 *	      length - number of bytes to transfer883 * Notes    : this will only be one SG entry or less884 */885static886void acornscsi_data_read(AS_Host *host, char *ptr,887				 unsigned int start_addr, unsigned int length)888{889    extern void __acornscsi_in(void __iomem *, char *buf, int len);890    unsigned int page, offset, len = length;891 892    page = (start_addr >> 12);893    offset = start_addr & ((1 << 12) - 1);894 895    writeb((page & 0x3f) | host->card.page_reg, host->fast + PAGE_REG);896 897    while (len > 0) {898	unsigned int this_len;899 900	if (len + offset > (1 << 12))901	    this_len = (1 << 12) - offset;902	else903	    this_len = len;904 905	__acornscsi_in(host->base + (offset << 1), ptr, this_len);906 907	offset += this_len;908	ptr += this_len;909	len -= this_len;910 911	if (offset == (1 << 12)) {912	    offset = 0;913	    page ++;914	    writeb((page & 0x3f) | host->card.page_reg, host->fast + PAGE_REG);915	}916    }917    writeb(host->card.page_reg, host->fast + PAGE_REG);918}919 920/*921 * Prototype: void acornscsi_data_write(AS_Host *host, char *ptr,922 *				unsigned int start_addr, unsigned int length)923 * Purpose  : write data to DMA RAM924 * Params   : host - host to transfer from925 *	      ptr  - DRAM address926 *	      start_addr - host mem address927 *	      length - number of bytes to transfer928 * Notes    : this will only be one SG entry or less929 */930static931void acornscsi_data_write(AS_Host *host, char *ptr,932				 unsigned int start_addr, unsigned int length)933{934    extern void __acornscsi_out(void __iomem *, char *buf, int len);935    unsigned int page, offset, len = length;936 937    page = (start_addr >> 12);938    offset = start_addr & ((1 << 12) - 1);939 940    writeb((page & 0x3f) | host->card.page_reg, host->fast + PAGE_REG);941 942    while (len > 0) {943	unsigned int this_len;944 945	if (len + offset > (1 << 12))946	    this_len = (1 << 12) - offset;947	else948	    this_len = len;949 950	__acornscsi_out(host->base + (offset << 1), ptr, this_len);951 952	offset += this_len;953	ptr += this_len;954	len -= this_len;955 956	if (offset == (1 << 12)) {957	    offset = 0;958	    page ++;959	    writeb((page & 0x3f) | host->card.page_reg, host->fast + PAGE_REG);960	}961    }962    writeb(host->card.page_reg, host->fast + PAGE_REG);963}964 965/* =========================================================================================966 * On-board DMA routines967 */968#ifdef USE_DMAC969/*970 * Prototype: void acornscsi_dmastop(AS_Host *host)971 * Purpose  : stop all DMA972 * Params   : host - host on which to stop DMA973 * Notes    : This is called when leaving DATA IN/OUT phase,974 *	      or when interface is RESET975 */976static inline977void acornscsi_dma_stop(AS_Host *host)978{979    dmac_write(host, DMAC_MASKREG, MASK_ON);980    dmac_clearintr(host);981 982#if (DEBUG & DEBUG_DMA)983    DBG(host->SCpnt, acornscsi_dumpdma(host, "stop"));984#endif985}986 987/*988 * Function: void acornscsi_dma_setup(AS_Host *host, dmadir_t direction)989 * Purpose : setup DMA controller for data transfer990 * Params  : host - host to setup991 *	     direction - data transfer direction992 * Notes   : This is called when entering DATA I/O phase, not993 *	     while we're in a DATA I/O phase994 */995static996void acornscsi_dma_setup(AS_Host *host, dmadir_t direction)997{998    unsigned int address, length, mode;999 1000    host->dma.direction = direction;1001 1002    dmac_write(host, DMAC_MASKREG, MASK_ON);1003 1004    if (direction == DMA_OUT) {1005#if (DEBUG & DEBUG_NO_WRITE)1006	if (NO_WRITE & (1 << host->SCpnt->device->id)) {1007	    printk(KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n",1008		    host->host->host_no, acornscsi_target(host));1009	    return;1010	}1011#endif1012	mode = DMAC_WRITE;1013    } else1014	mode = DMAC_READ;1015 1016    /*1017     * Allocate some buffer space, limited to half the buffer size1018     */1019    length = min_t(unsigned int, host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);1020    if (length) {1021	host->dma.start_addr = address = host->dma.free_addr;1022	host->dma.free_addr = (host->dma.free_addr + length) &1023				(DMAC_BUFFER_SIZE - 1);1024 1025	/*1026	 * Transfer data to DMA memory1027	 */1028	if (direction == DMA_OUT)1029	    acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,1030				length);1031 1032	length -= 1;1033	dmac_write(host, DMAC_TXCNTLO, length);1034	dmac_write(host, DMAC_TXCNTHI, length >> 8);1035	dmac_write(host, DMAC_TXADRLO, address);1036	dmac_write(host, DMAC_TXADRMD, address >> 8);1037	dmac_write(host, DMAC_TXADRHI, 0);1038	dmac_write(host, DMAC_MODECON, mode);1039	dmac_write(host, DMAC_MASKREG, MASK_OFF);1040 1041#if (DEBUG & DEBUG_DMA)1042	DBG(host->SCpnt, acornscsi_dumpdma(host, "strt"));1043#endif1044	host->dma.xfer_setup = 1;1045    }1046}1047 1048/*1049 * Function: void acornscsi_dma_cleanup(AS_Host *host)1050 * Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct1051 * Params  : host - host to finish1052 * Notes   : This is called when a command is:1053 *		terminating, RESTORE_POINTERS, SAVE_POINTERS, DISCONNECT1054 *	   : This must not return until all transfers are completed.1055 */1056static1057void acornscsi_dma_cleanup(AS_Host *host)1058{1059    dmac_write(host, DMAC_MASKREG, MASK_ON);1060    dmac_clearintr(host);1061 1062    /*1063     * Check for a pending transfer1064     */1065    if (host->dma.xfer_required) {1066	host->dma.xfer_required = 0;1067	if (host->dma.direction == DMA_IN)1068	    acornscsi_data_read(host, host->dma.xfer_ptr,1069				 host->dma.xfer_start, host->dma.xfer_length);1070    }1071 1072    /*1073     * Has a transfer been setup?1074     */1075    if (host->dma.xfer_setup) {1076	unsigned int transferred;1077 1078	host->dma.xfer_setup = 0;1079 1080#if (DEBUG & DEBUG_DMA)1081	DBG(host->SCpnt, acornscsi_dumpdma(host, "cupi"));1082#endif1083 1084	/*1085	 * Calculate number of bytes transferred from DMA.1086	 */1087	transferred = dmac_address(host) - host->dma.start_addr;1088	host->dma.transferred += transferred;1089 1090	if (host->dma.direction == DMA_IN)1091	    acornscsi_data_read(host, host->scsi.SCp.ptr,1092				 host->dma.start_addr, transferred);1093 1094	/*1095	 * Update SCSI pointers1096	 */1097	acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);1098#if (DEBUG & DEBUG_DMA)1099	DBG(host->SCpnt, acornscsi_dumpdma(host, "cupo"));1100#endif1101    }1102}1103 1104/*1105 * Function: void acornscsi_dmacintr(AS_Host *host)1106 * Purpose : handle interrupts from DMAC device1107 * Params  : host - host to process1108 * Notes   : If reading, we schedule the read to main memory &1109 *	     allow the transfer to continue.1110 *	   : If writing, we fill the onboard DMA memory from main1111 *	     memory.1112 *	   : Called whenever DMAC finished it's current transfer.1113 */1114static1115void acornscsi_dma_intr(AS_Host *host)1116{1117    unsigned int address, length, transferred;1118 1119#if (DEBUG & DEBUG_DMA)1120    DBG(host->SCpnt, acornscsi_dumpdma(host, "inti"));1121#endif1122 1123    dmac_write(host, DMAC_MASKREG, MASK_ON);1124    dmac_clearintr(host);1125 1126    /*1127     * Calculate amount transferred via DMA1128     */1129    transferred = dmac_address(host) - host->dma.start_addr;1130    host->dma.transferred += transferred;1131 1132    /*1133     * Schedule DMA transfer off board1134     */1135    if (host->dma.direction == DMA_IN) {1136	host->dma.xfer_start = host->dma.start_addr;1137	host->dma.xfer_length = transferred;1138	host->dma.xfer_ptr = host->scsi.SCp.ptr;1139	host->dma.xfer_required = 1;1140    }1141 1142    acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);1143 1144    /*1145     * Allocate some buffer space, limited to half the on-board RAM size1146     */1147    length = min_t(unsigned int, host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);1148    if (length) {1149	host->dma.start_addr = address = host->dma.free_addr;1150	host->dma.free_addr = (host->dma.free_addr + length) &1151				(DMAC_BUFFER_SIZE - 1);1152 1153	/*1154	 * Transfer data to DMA memory1155	 */1156	if (host->dma.direction == DMA_OUT)1157	    acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,1158				length);1159 1160	length -= 1;1161	dmac_write(host, DMAC_TXCNTLO, length);1162	dmac_write(host, DMAC_TXCNTHI, length >> 8);1163	dmac_write(host, DMAC_TXADRLO, address);1164	dmac_write(host, DMAC_TXADRMD, address >> 8);1165	dmac_write(host, DMAC_TXADRHI, 0);1166	dmac_write(host, DMAC_MASKREG, MASK_OFF);1167 1168#if (DEBUG & DEBUG_DMA)1169	DBG(host->SCpnt, acornscsi_dumpdma(host, "into"));1170#endif1171    } else {1172	host->dma.xfer_setup = 0;1173#if 01174	/*1175	 * If the interface still wants more, then this is an error.1176	 * We give it another byte, but we also attempt to raise an1177	 * attention condition.  We continue giving one byte until1178	 * the device recognises the attention.1179	 */1180	if (dmac_read(host, DMAC_STATUS) & STATUS_RQ0) {1181	    acornscsi_abortcmd(host);1182 1183	    dmac_write(host, DMAC_TXCNTLO, 0);1184	    dmac_write(host, DMAC_TXCNTHI, 0);1185	    dmac_write(host, DMAC_TXADRLO, 0);1186	    dmac_write(host, DMAC_TXADRMD, 0);1187	    dmac_write(host, DMAC_TXADRHI, 0);1188	    dmac_write(host, DMAC_MASKREG, MASK_OFF);1189	}1190#endif1191    }1192}1193 1194/*1195 * Function: void acornscsi_dma_xfer(AS_Host *host)1196 * Purpose : transfer data between AcornSCSI and memory1197 * Params  : host - host to process1198 */1199static1200void acornscsi_dma_xfer(AS_Host *host)1201{1202    host->dma.xfer_required = 0;1203 1204    if (host->dma.direction == DMA_IN)1205	acornscsi_data_read(host, host->dma.xfer_ptr,1206				host->dma.xfer_start, host->dma.xfer_length);1207}1208 1209/*1210 * Function: void acornscsi_dma_adjust(AS_Host *host)1211 * Purpose : adjust DMA pointers & count for bytes transferred to1212 *	     SBIC but not SCSI bus.1213 * Params  : host - host to adjust DMA count for1214 */1215static1216void acornscsi_dma_adjust(AS_Host *host)1217{1218    if (host->dma.xfer_setup) {1219	signed long transferred;1220#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))1221	DBG(host->SCpnt, acornscsi_dumpdma(host, "adji"));1222#endif1223	/*1224	 * Calculate correct DMA address - DMA is ahead of SCSI bus while1225	 * writing.1226	 *  host->scsi.SCp.scsi_xferred is the number of bytes1227	 *  actually transferred to/from the SCSI bus.1228	 *  host->dma.transferred is the number of bytes transferred1229	 *  over DMA since host->dma.start_addr was last set.1230	 *1231	 * real_dma_addr = host->dma.start_addr + host->scsi.SCp.scsi_xferred1232	 *		   - host->dma.transferred1233	 */1234	transferred = host->scsi.SCp.scsi_xferred - host->dma.transferred;1235	if (transferred < 0)1236	    printk("scsi%d.%c: Ack! DMA write correction %ld < 0!\n",1237		    host->host->host_no, acornscsi_target(host), transferred);1238	else if (transferred == 0)1239	    host->dma.xfer_setup = 0;1240	else {1241	    transferred += host->dma.start_addr;1242	    dmac_write(host, DMAC_TXADRLO, transferred);1243	    dmac_write(host, DMAC_TXADRMD, transferred >> 8);1244	    dmac_write(host, DMAC_TXADRHI, transferred >> 16);1245#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))1246	    DBG(host->SCpnt, acornscsi_dumpdma(host, "adjo"));1247#endif1248	}1249    }1250}1251#endif1252 1253/* =========================================================================================1254 * Data I/O1255 */1256static int1257acornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int max_timeout)1258{1259	unsigned int asr, timeout = max_timeout;1260	int my_ptr = *ptr;1261 1262	while (my_ptr < len) {1263		asr = sbic_arm_read(host, SBIC_ASR);1264 1265		if (asr & ASR_DBR) {1266			timeout = max_timeout;1267 1268			sbic_arm_write(host, SBIC_DATA, bytes[my_ptr++]);1269		} else if (asr & ASR_INT)1270			break;1271		else if (--timeout == 0)1272			break;1273		udelay(1);1274	}1275 1276	*ptr = my_ptr;1277 1278	return (timeout == 0) ? -1 : 0;1279}1280 1281/*1282 * Function: void acornscsi_sendcommand(AS_Host *host)1283 * Purpose : send a command to a target1284 * Params  : host - host which is connected to target1285 */1286static void1287acornscsi_sendcommand(AS_Host *host)1288{1289	struct scsi_cmnd *SCpnt = host->SCpnt;1290 1291    sbic_arm_write(host, SBIC_TRANSCNTH, 0);1292    sbic_arm_writenext(host, 0);1293    sbic_arm_writenext(host, SCpnt->cmd_len - host->scsi.SCp.sent_command);1294 1295    acornscsi_sbic_issuecmd(host, CMND_XFERINFO);1296 1297    if (acornscsi_write_pio(host, SCpnt->cmnd,1298	(int *)&host->scsi.SCp.sent_command, SCpnt->cmd_len, 1000000))1299	printk("scsi%d: timeout while sending command\n", host->host->host_no);1300 1301    host->scsi.phase = PHASE_COMMAND;1302}1303 1304static1305void acornscsi_sendmessage(AS_Host *host)1306{1307    unsigned int message_length = msgqueue_msglength(&host->scsi.msgs);1308    unsigned int msgnr;1309    struct message *msg;1310 1311#if (DEBUG & DEBUG_MESSAGES)1312    printk("scsi%d.%c: sending message ",1313	    host->host->host_no, acornscsi_target(host));1314#endif1315 1316    switch (message_length) {1317    case 0:1318	acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);1319 1320	acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 1");1321 1322	sbic_arm_write(host, SBIC_DATA, NOP);1323 1324	host->scsi.last_message = NOP;1325#if (DEBUG & DEBUG_MESSAGES)1326	printk("NOP");1327#endif1328	break;1329 1330    case 1:1331	acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);1332	msg = msgqueue_getmsg(&host->scsi.msgs, 0);1333 1334	acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 2");1335 1336	sbic_arm_write(host, SBIC_DATA, msg->msg[0]);1337 1338	host->scsi.last_message = msg->msg[0];1339#if (DEBUG & DEBUG_MESSAGES)1340	spi_print_msg(msg->msg);1341#endif1342	break;1343 1344    default:1345	/*1346	 * ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.14)1347	 * 'When a target sends this (MESSAGE_REJECT) message, it1348	 *  shall change to MESSAGE IN phase and send this message1349	 *  prior to requesting additional message bytes from the1350	 *  initiator.  This provides an interlock so that the1351	 *  initiator can determine which message byte is rejected.1352	 */1353	sbic_arm_write(host, SBIC_TRANSCNTH, 0);1354	sbic_arm_writenext(host, 0);1355	sbic_arm_writenext(host, message_length);1356	acornscsi_sbic_issuecmd(host, CMND_XFERINFO);1357 1358	msgnr = 0;1359	while ((msg = msgqueue_getmsg(&host->scsi.msgs, msgnr++)) != NULL) {1360	    unsigned int i;1361#if (DEBUG & DEBUG_MESSAGES)1362	    spi_print_msg(msg);1363#endif1364	    i = 0;1365	    if (acornscsi_write_pio(host, msg->msg, &i, msg->length, 1000000))1366		printk("scsi%d: timeout while sending message\n", host->host->host_no);1367 1368	    host->scsi.last_message = msg->msg[0];1369	    if (msg->msg[0] == EXTENDED_MESSAGE)1370		host->scsi.last_message |= msg->msg[2] << 8;1371 1372	    if (i != msg->length)1373		break;1374	}1375	break;1376    }1377#if (DEBUG & DEBUG_MESSAGES)1378    printk("\n");1379#endif1380}1381 1382/*1383 * Function: void acornscsi_readstatusbyte(AS_Host *host)1384 * Purpose : Read status byte from connected target1385 * Params  : host - host connected to target1386 */1387static1388void acornscsi_readstatusbyte(AS_Host *host)1389{1390    acornscsi_sbic_issuecmd(host, CMND_XFERINFO|CMND_SBT);1391    acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "reading status byte");1392    host->scsi.SCp.Status = sbic_arm_read(host, SBIC_DATA);1393}1394 1395/*1396 * Function: unsigned char acornscsi_readmessagebyte(AS_Host *host)1397 * Purpose : Read one message byte from connected target1398 * Params  : host - host connected to target1399 */1400static1401unsigned char acornscsi_readmessagebyte(AS_Host *host)1402{1403    unsigned char message;1404 1405    acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);1406 1407    acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "for message byte");1408 1409    message = sbic_arm_read(host, SBIC_DATA);1410 1411    /* wait for MSGIN-XFER-PAUSED */1412    acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after message byte");1413 1414    sbic_arm_read(host, SBIC_SSR);1415 1416    return message;1417}1418 1419/*1420 * Function: void acornscsi_message(AS_Host *host)1421 * Purpose : Read complete message from connected target & action message1422 * Params  : host - host connected to target1423 */1424static1425void acornscsi_message(AS_Host *host)1426{1427    struct scsi_pointer *scsi_pointer;1428    unsigned char message[16];1429    unsigned int msgidx = 0, msglen = 1;1430 1431    do {1432	message[msgidx] = acornscsi_readmessagebyte(host);1433 1434	switch (msgidx) {1435	case 0:1436	    if (message[0] == EXTENDED_MESSAGE ||1437		(message[0] >= 0x20 && message[0] <= 0x2f))1438		msglen = 2;1439	    break;1440 1441	case 1:1442	    if (message[0] == EXTENDED_MESSAGE)1443		msglen += message[msgidx];1444	    break;1445	}1446	msgidx += 1;1447	if (msgidx < msglen) {1448	    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);1449 1450	    /* wait for next msg-in */1451	    acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after negate ack");1452	    sbic_arm_read(host, SBIC_SSR);1453	}1454    } while (msgidx < msglen);1455 1456#if (DEBUG & DEBUG_MESSAGES)1457    printk("scsi%d.%c: message in: ",1458	    host->host->host_no, acornscsi_target(host));1459    spi_print_msg(message);1460    printk("\n");1461#endif1462 1463    if (host->scsi.phase == PHASE_RECONNECTED) {1464	/*1465	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17)1466	 * 'Whenever a target reconnects to an initiator to continue1467	 *  a tagged I/O process, the SIMPLE QUEUE TAG message shall1468	 *  be sent immediately following the IDENTIFY message...'1469	 */1470	if (message[0] == SIMPLE_QUEUE_TAG)1471	    host->scsi.reconnected.tag = message[1];1472	if (acornscsi_reconnect_finish(host))1473	    host->scsi.phase = PHASE_MSGIN;1474    }1475 1476    switch (message[0]) {1477    case ABORT_TASK_SET:1478    case ABORT_TASK:1479    case COMMAND_COMPLETE:1480	if (host->scsi.phase != PHASE_STATUSIN) {1481	    printk(KERN_ERR "scsi%d.%c: command complete following non-status in phase?\n",1482		    host->host->host_no, acornscsi_target(host));1483	    acornscsi_dumplog(host, host->SCpnt->device->id);1484	}1485	host->scsi.phase = PHASE_DONE;1486	host->scsi.SCp.Message = message[0];1487	break;1488 1489    case SAVE_POINTERS:1490	/*1491	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.20)1492	 * 'The SAVE DATA POINTER message is sent from a target to1493	 *  direct the initiator to copy the active data pointer to1494	 *  the saved data pointer for the current I/O process.1495	 */1496	acornscsi_dma_cleanup(host);1497	scsi_pointer = arm_scsi_pointer(host->SCpnt);1498	*scsi_pointer = host->scsi.SCp;1499	scsi_pointer->sent_command = 0;1500	host->scsi.phase = PHASE_MSGIN;1501	break;1502 1503    case RESTORE_POINTERS:1504	/*1505	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.19)1506	 * 'The RESTORE POINTERS message is sent from a target to1507	 *  direct the initiator to copy the most recently saved1508	 *  command, data, and status pointers for the I/O process1509	 *  to the corresponding active pointers.  The command and1510	 *  status pointers shall be restored to the beginning of1511	 *  the present command and status areas.'1512	 */1513	acornscsi_dma_cleanup(host);1514	host->scsi.SCp = *arm_scsi_pointer(host->SCpnt);1515	host->scsi.phase = PHASE_MSGIN;1516	break;1517 1518    case DISCONNECT:1519	/*1520	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 6.4.2)1521	 * 'On those occasions when an error or exception condition occurs1522	 *  and the target elects to repeat the information transfer, the1523	 *  target may repeat the transfer either issuing a RESTORE POINTERS1524	 *  message or by disconnecting without issuing a SAVE POINTERS1525	 *  message.  When reconnection is completed, the most recent1526	 *  saved pointer values are restored.'1527	 */1528	acornscsi_dma_cleanup(host);1529	host->scsi.phase = PHASE_DISCONNECT;1530	break;1531 1532    case MESSAGE_REJECT:1533#if 0 /* this isn't needed any more */1534	/*1535	 * If we were negociating sync transfer, we don't yet know if1536	 * this REJECT is for the sync transfer or for the tagged queue/wide1537	 * transfer.  Re-initiate sync transfer negotiation now, and if1538	 * we got a REJECT in response to SDTR, then it'll be set to DONE.1539	 */1540	if (host->device[host->SCpnt->device->id].sync_state == SYNC_SENT_REQUEST)1541	    host->device[host->SCpnt->device->id].sync_state = SYNC_NEGOCIATE;1542#endif1543 1544	/*1545	 * If we have any messages waiting to go out, then assert ATN now1546	 */1547	if (msgqueue_msglength(&host->scsi.msgs))1548	    acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);1549 1550	switch (host->scsi.last_message) {1551	case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8):1552	    /*1553	     * Target can't handle synchronous transfers1554	     */1555	    printk(KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n",1556		    host->host->host_no, acornscsi_target(host));1557	    host->device[host->SCpnt->device->id].sync_xfer = SYNCHTRANSFER_2DBA;1558	    host->device[host->SCpnt->device->id].sync_state = SYNC_ASYNCHRONOUS;1559	    sbic_arm_write(host, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);1560	    break;1561 1562	default:1563	    break;1564	}1565	break;1566 1567    case SIMPLE_QUEUE_TAG:1568	/* tag queue reconnect... message[1] = queue tag.  Print something to indicate something happened! */1569	printk("scsi%d.%c: reconnect queue tag %02X\n",1570		host->host->host_no, acornscsi_target(host),1571		message[1]);1572	break;1573 1574    case EXTENDED_MESSAGE:1575	switch (message[2]) {1576#ifdef CONFIG_SCSI_ACORNSCSI_SYNC1577	case EXTENDED_SDTR:1578	    if (host->device[host->SCpnt->device->id].sync_state == SYNC_SENT_REQUEST) {1579		/*1580		 * We requested synchronous transfers.  This isn't quite right...1581		 * We can only say if this succeeded if we proceed on to execute the1582		 * command from this message.  If we get a MESSAGE PARITY ERROR,1583		 * and the target retries fail, then we fallback to asynchronous mode1584		 */1585		host->device[host->SCpnt->device->id].sync_state = SYNC_COMPLETED;1586		printk(KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n",1587			host->host->host_no, acornscsi_target(host),1588			message[4], message[3] * 4);1589		host->device[host->SCpnt->device->id].sync_xfer =1590			calc_sync_xfer(message[3] * 4, message[4]);1591	    } else {1592		unsigned char period, length;1593		/*1594		 * Target requested synchronous transfers.  The agreement is only1595		 * to be in operation AFTER the target leaves message out phase.1596		 */1597		acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);1598		period = max_t(unsigned int, message[3], sdtr_period / 4);1599		length = min_t(unsigned int, message[4], sdtr_size);1600		msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3,1601				 EXTENDED_SDTR, period, length);1602		host->device[host->SCpnt->device->id].sync_xfer =1603			calc_sync_xfer(period * 4, length);1604	    }1605	    sbic_arm_write(host, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);1606	    break;1607#else1608	    /* We do not accept synchronous transfers.  Respond with a1609	     * MESSAGE_REJECT.1610	     */1611#endif1612 1613	case EXTENDED_WDTR:1614	    /* The WD33C93A is only 8-bit.  We respond with a MESSAGE_REJECT1615	     * to a wide data transfer request.1616	     */1617	default:1618	    acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);1619	    msgqueue_flush(&host->scsi.msgs);1620	    msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);1621	    break;1622	}1623	break;1624 1625    default: /* reject message */1626	printk(KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n",1627		host->host->host_no, acornscsi_target(host),1628		message[0]);1629	acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);1630	msgqueue_flush(&host->scsi.msgs);1631	msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);1632	host->scsi.phase = PHASE_MSGIN;1633	break;1634    }1635    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);1636}1637 1638/*1639 * Function: int acornscsi_buildmessages(AS_Host *host)1640 * Purpose : build the connection messages for a host1641 * Params  : host - host to add messages to1642 */1643static1644void acornscsi_buildmessages(AS_Host *host)1645{1646#if 01647    /* does the device need resetting? */1648    if (cmd_reset) {1649	msgqueue_addmsg(&host->scsi.msgs, 1, BUS_DEVICE_RESET);1650	return;1651    }1652#endif1653 1654    msgqueue_addmsg(&host->scsi.msgs, 1,1655		     IDENTIFY(host->device[host->SCpnt->device->id].disconnect_ok,1656			     host->SCpnt->device->lun));1657 1658#if 01659    /* does the device need the current command aborted */1660    if (cmd_aborted) {1661	acornscsi_abortcmd(host);1662	return;1663    }1664#endif1665 1666 1667#ifdef CONFIG_SCSI_ACORNSCSI_SYNC1668    if (host->device[host->SCpnt->device->id].sync_state == SYNC_NEGOCIATE) {1669	host->device[host->SCpnt->device->id].sync_state = SYNC_SENT_REQUEST;1670	msgqueue_addmsg(&host->scsi.msgs, 5,1671			 EXTENDED_MESSAGE, 3, EXTENDED_SDTR,1672			 sdtr_period / 4, sdtr_size);1673    }1674#endif1675}1676 1677/*1678 * Function: int acornscsi_starttransfer(AS_Host *host)1679 * Purpose : transfer data to/from connected target1680 * Params  : host - host to which target is connected1681 * Returns : 0 if failure1682 */1683static1684int acornscsi_starttransfer(AS_Host *host)1685{1686    int residual;1687 1688    if (!host->scsi.SCp.ptr /*&& host->scsi.SCp.this_residual*/) {1689	printk(KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n",1690		host->host->host_no, acornscsi_target(host));1691	return 0;1692    }1693 1694    residual = scsi_bufflen(host->SCpnt) - host->scsi.SCp.scsi_xferred;1695 1696    sbic_arm_write(host, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);1697    sbic_arm_writenext(host, residual >> 16);1698    sbic_arm_writenext(host, residual >> 8);1699    sbic_arm_writenext(host, residual);1700    acornscsi_sbic_issuecmd(host, CMND_XFERINFO);1701    return 1;1702}1703 1704/* =========================================================================================1705 * Connection & Disconnection1706 */1707/*1708 * Function : acornscsi_reconnect(AS_Host *host)1709 * Purpose  : reconnect a previously disconnected command1710 * Params   : host - host specific data1711 * Remarks  : SCSI spec says:1712 *		'The set of active pointers is restored from the set1713 *		 of saved pointers upon reconnection of the I/O process'1714 */1715static1716int acornscsi_reconnect(AS_Host *host)1717{1718    unsigned int target, lun, ok = 0;1719 1720    target = sbic_arm_read(host, SBIC_SOURCEID);1721 1722    if (!(target & 8))1723	printk(KERN_ERR "scsi%d: invalid source id after reselection "1724		"- device fault?\n",1725		host->host->host_no);1726 1727    target &= 7;1728 1729    if (host->SCpnt && !host->scsi.disconnectable) {1730	printk(KERN_ERR "scsi%d.%d: reconnected while command in "1731		"progress to target %d?\n",1732		host->host->host_no, target, host->SCpnt->device->id);1733	host->SCpnt = NULL;1734    }1735 1736    lun = sbic_arm_read(host, SBIC_DATA) & 7;1737 1738    host->scsi.reconnected.target = target;1739    host->scsi.reconnected.lun = lun;1740    host->scsi.reconnected.tag = 0;1741 1742    if (host->scsi.disconnectable && host->SCpnt &&1743	host->SCpnt->device->id == target && host->SCpnt->device->lun == lun)1744	ok = 1;1745 1746    if (!ok && queue_probetgtlun(&host->queues.disconnected, target, lun))1747	ok = 1;1748 1749    ADD_STATUS(target, 0x81, host->scsi.phase, 0);1750 1751    if (ok) {1752	host->scsi.phase = PHASE_RECONNECTED;1753    } else {1754	/* this doesn't seem to work */1755	printk(KERN_ERR "scsi%d.%c: reselected with no command "1756		"to reconnect with\n",1757		host->host->host_no, '0' + target);1758	acornscsi_dumplog(host, target);1759	acornscsi_abortcmd(host);1760	if (host->SCpnt) {1761	    queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);1762	    host->SCpnt = NULL;1763	}1764    }1765    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);1766    return !ok;1767}1768 1769/*1770 * Function: int acornscsi_reconnect_finish(AS_Host *host)1771 * Purpose : finish reconnecting a command1772 * Params  : host - host to complete1773 * Returns : 0 if failed1774 */1775static1776int acornscsi_reconnect_finish(AS_Host *host)1777{1778    if (host->scsi.disconnectable && host->SCpnt) {1779	host->scsi.disconnectable = 0;1780	if (host->SCpnt->device->id  == host->scsi.reconnected.target &&1781	    host->SCpnt->device->lun == host->scsi.reconnected.lun &&1782	    scsi_cmd_to_rq(host->SCpnt)->tag == host->scsi.reconnected.tag) {1783#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))1784	    DBG(host->SCpnt, printk("scsi%d.%c: reconnected",1785		    host->host->host_no, acornscsi_target(host)));1786#endif1787	} else {1788	    queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);1789#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))1790	    DBG(host->SCpnt, printk("scsi%d.%c: had to move command "1791		    "to disconnected queue\n",1792		    host->host->host_no, acornscsi_target(host)));1793#endif1794	    host->SCpnt = NULL;1795	}1796    }1797    if (!host->SCpnt) {1798	host->SCpnt = queue_remove_tgtluntag(&host->queues.disconnected,1799				host->scsi.reconnected.target,1800				host->scsi.reconnected.lun,1801				host->scsi.reconnected.tag);1802#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))1803	DBG(host->SCpnt, printk("scsi%d.%c: had to get command",1804		host->host->host_no, acornscsi_target(host)));1805#endif1806    }1807 1808    if (!host->SCpnt)1809	acornscsi_abortcmd(host);1810    else {1811	/*1812	 * Restore data pointer from SAVED pointers.1813	 */1814	host->scsi.SCp = *arm_scsi_pointer(host->SCpnt);1815#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))1816	printk(", data pointers: [%p, %X]",1817		host->scsi.SCp.ptr, host->scsi.SCp.this_residual);1818#endif1819    }1820#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))1821    printk("\n");1822#endif1823 1824    host->dma.transferred = host->scsi.SCp.scsi_xferred;1825 1826    return host->SCpnt != NULL;1827}1828 1829/*1830 * Function: void acornscsi_disconnect_unexpected(AS_Host *host)1831 * Purpose : handle an unexpected disconnect1832 * Params  : host - host on which disconnect occurred1833 */1834static1835void acornscsi_disconnect_unexpected(AS_Host *host)1836{1837    printk(KERN_ERR "scsi%d.%c: unexpected disconnect\n",1838	    host->host->host_no, acornscsi_target(host));1839#if (DEBUG & DEBUG_ABORT)1840    acornscsi_dumplog(host, 8);1841#endif1842 1843    acornscsi_done(host, &host->SCpnt, DID_ERROR);1844}1845 1846/*1847 * Function: void acornscsi_abortcmd(AS_host *host, unsigned char tag)1848 * Purpose : abort a currently executing command1849 * Params  : host - host with connected command to abort1850 */1851static1852void acornscsi_abortcmd(AS_Host *host)1853{1854    host->scsi.phase = PHASE_ABORTED;1855    sbic_arm_write(host, SBIC_CMND, CMND_ASSERTATN);1856 1857    msgqueue_flush(&host->scsi.msgs);1858    msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);1859}1860 1861/* ==========================================================================================1862 * Interrupt routines.1863 */1864/*1865 * Function: int acornscsi_sbicintr(AS_Host *host)1866 * Purpose : handle interrupts from SCSI device1867 * Params  : host - host to process1868 * Returns : INTR_PROCESS if expecting another SBIC interrupt1869 *	     INTR_IDLE if no interrupt1870 *	     INTR_NEXT_COMMAND if we have finished processing the command1871 */1872static1873intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq)1874{1875    unsigned int asr, ssr;1876 1877    asr = sbic_arm_read(host, SBIC_ASR);1878    if (!(asr & ASR_INT))1879	return INTR_IDLE;1880 1881    ssr = sbic_arm_read(host, SBIC_SSR);1882 1883#if (DEBUG & DEBUG_PHASES)1884    print_sbic_status(asr, ssr, host->scsi.phase);1885#endif1886 1887    ADD_STATUS(8, ssr, host->scsi.phase, in_irq);1888 1889    if (host->SCpnt && !host->scsi.disconnectable)1890	ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, in_irq);1891 1892    switch (ssr) {1893    case 0x00:				/* reset state - not advanced			*/1894	printk(KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n",1895		host->host->host_no);1896	/* setup sbic - WD33C93A */1897	sbic_arm_write(host, SBIC_OWNID, OWNID_EAF | host->host->this_id);1898	sbic_arm_write(host, SBIC_CMND, CMND_RESET);1899	return INTR_IDLE;1900 1901    case 0x01:				/* reset state - advanced			*/1902	sbic_arm_write(host, SBIC_CTRL, INIT_SBICDMA | CTRL_IDI);1903	sbic_arm_write(host, SBIC_TIMEOUT, TIMEOUT_TIME);1904	sbic_arm_write(host, SBIC_SYNCHTRANSFER, SYNCHTRANSFER_2DBA);1905	sbic_arm_write(host, SBIC_SOURCEID, SOURCEID_ER | SOURCEID_DSP);1906	msgqueue_flush(&host->scsi.msgs);1907	return INTR_IDLE;1908 1909    case 0x41:				/* unexpected disconnect aborted command	*/1910	acornscsi_disconnect_unexpected(host);1911	return INTR_NEXT_COMMAND;1912    }1913 1914    switch (host->scsi.phase) {1915    case PHASE_CONNECTING:		/* STATE: command removed from issue queue	*/1916	switch (ssr) {1917	case 0x11:			/* -> PHASE_CONNECTED				*/1918	    /* BUS FREE -> SELECTION */1919	    host->scsi.phase = PHASE_CONNECTED;1920	    msgqueue_flush(&host->scsi.msgs);1921	    host->dma.transferred = host->scsi.SCp.scsi_xferred;1922	    /* 33C93 gives next interrupt indicating bus phase */1923	    asr = sbic_arm_read(host, SBIC_ASR);1924	    if (!(asr & ASR_INT))1925		break;1926	    ssr = sbic_arm_read(host, SBIC_SSR);1927	    ADD_STATUS(8, ssr, host->scsi.phase, 1);1928	    ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, 1);1929	    goto connected;1930	    1931	case 0x42:			/* select timed out				*/1932					/* -> PHASE_IDLE				*/1933	    acornscsi_done(host, &host->SCpnt, DID_NO_CONNECT);1934	    return INTR_NEXT_COMMAND;1935 1936	case 0x81:			/* -> PHASE_RECONNECTED or PHASE_ABORTED	*/1937	    /* BUS FREE -> RESELECTION */1938	    host->origSCpnt = host->SCpnt;1939	    host->SCpnt = NULL;1940	    msgqueue_flush(&host->scsi.msgs);1941	    acornscsi_reconnect(host);1942	    break;1943 1944	default:1945	    printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n",1946		    host->host->host_no, acornscsi_target(host), ssr);1947	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);1948	    acornscsi_abortcmd(host);1949	}1950	return INTR_PROCESSING;1951 1952    connected:1953    case PHASE_CONNECTED:		/* STATE: device selected ok			*/1954	switch (ssr) {1955#ifdef NONSTANDARD1956	case 0x8a:			/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/1957	    /* SELECTION -> COMMAND */1958	    acornscsi_sendcommand(host);1959	    break;1960 1961	case 0x8b:			/* -> PHASE_STATUS				*/1962	    /* SELECTION -> STATUS */1963	    acornscsi_readstatusbyte(host);1964	    host->scsi.phase = PHASE_STATUSIN;1965	    break;1966#endif1967 1968	case 0x8e:			/* -> PHASE_MSGOUT				*/1969	    /* SELECTION ->MESSAGE OUT */1970	    host->scsi.phase = PHASE_MSGOUT;1971	    acornscsi_buildmessages(host);1972	    acornscsi_sendmessage(host);1973	    break;1974 1975	/* these should not happen */1976	case 0x85:			/* target disconnected				*/1977	    acornscsi_done(host, &host->SCpnt, DID_ERROR);1978	    break;1979 1980	default:1981	    printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n",1982		    host->host->host_no, acornscsi_target(host), ssr);1983	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);1984	    acornscsi_abortcmd(host);1985	}1986	return INTR_PROCESSING;1987 1988    case PHASE_MSGOUT:			/* STATE: connected & sent IDENTIFY message	*/1989	/*1990	 * SCSI standard says that MESSAGE OUT phases can be followed by a1991	 * DATA phase, STATUS phase, MESSAGE IN phase or COMMAND phase1992	 */1993	switch (ssr) {1994	case 0x8a:			/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/1995	case 0x1a:			/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/1996	    /* MESSAGE OUT -> COMMAND */1997	    acornscsi_sendcommand(host);1998	    break;1999 2000	case 0x8b:			/* -> PHASE_STATUS				*/2001	case 0x1b:			/* -> PHASE_STATUS				*/2002	    /* MESSAGE OUT -> STATUS */2003	    acornscsi_readstatusbyte(host);2004	    host->scsi.phase = PHASE_STATUSIN;2005	    break;2006 2007	case 0x8e:			/* -> PHASE_MSGOUT				*/2008	    /* MESSAGE_OUT(MESSAGE_IN) ->MESSAGE OUT */2009	    acornscsi_sendmessage(host);2010	    break;2011 2012	case 0x4f:			/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/2013	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/2014	    /* MESSAGE OUT -> MESSAGE IN */2015	    acornscsi_message(host);2016	    break;2017 2018	default:2019	    printk(KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n",2020		    host->host->host_no, acornscsi_target(host), ssr);2021	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);2022	}2023	return INTR_PROCESSING;2024 2025    case PHASE_COMMAND: 		/* STATE: connected & command sent		*/2026	switch (ssr) {2027	case 0x18:			/* -> PHASE_DATAOUT				*/2028	    /* COMMAND -> DATA OUT */2029	    if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)2030		acornscsi_abortcmd(host);2031	    acornscsi_dma_setup(host, DMA_OUT);2032	    if (!acornscsi_starttransfer(host))2033		acornscsi_abortcmd(host);2034	    host->scsi.phase = PHASE_DATAOUT;2035	    return INTR_IDLE;2036 2037	case 0x19:			/* -> PHASE_DATAIN				*/2038	    /* COMMAND -> DATA IN */2039	    if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)2040		acornscsi_abortcmd(host);2041	    acornscsi_dma_setup(host, DMA_IN);2042	    if (!acornscsi_starttransfer(host))2043		acornscsi_abortcmd(host);2044	    host->scsi.phase = PHASE_DATAIN;2045	    return INTR_IDLE;2046 2047	case 0x1b:			/* -> PHASE_STATUS				*/2048	    /* COMMAND -> STATUS */2049	    acornscsi_readstatusbyte(host);2050	    host->scsi.phase = PHASE_STATUSIN;2051	    break;2052 2053	case 0x1e:			/* -> PHASE_MSGOUT				*/2054	    /* COMMAND -> MESSAGE OUT */2055	    acornscsi_sendmessage(host);2056	    break;2057 2058	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/2059	    /* COMMAND -> MESSAGE IN */2060	    acornscsi_message(host);2061	    break;2062 2063	default:2064	    printk(KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n",2065		    host->host->host_no, acornscsi_target(host), ssr);2066	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);2067	}2068	return INTR_PROCESSING;2069 2070    case PHASE_DISCONNECT:		/* STATE: connected, received DISCONNECT msg	*/2071	if (ssr == 0x85) {		/* -> PHASE_IDLE				*/2072	    host->scsi.disconnectable = 1;2073	    host->scsi.reconnected.tag = 0;2074	    host->scsi.phase = PHASE_IDLE;2075	    host->stats.disconnects += 1;2076	} else {2077	    printk(KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n",2078		    host->host->host_no, acornscsi_target(host), ssr);2079	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);2080	}2081	return INTR_NEXT_COMMAND;2082 2083    case PHASE_IDLE:			/* STATE: disconnected				*/2084	if (ssr == 0x81)		/* -> PHASE_RECONNECTED or PHASE_ABORTED	*/2085	    acornscsi_reconnect(host);2086	else {2087	    printk(KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n",2088		    host->host->host_no, acornscsi_target(host), ssr);2089	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);2090	}2091	return INTR_PROCESSING;2092 2093    case PHASE_RECONNECTED:		/* STATE: device reconnected to initiator	*/2094	/*2095	 * Command reconnected - if MESGIN, get message - it may be2096	 * the tag.  If not, get command out of disconnected queue2097	 */2098	/*2099	 * If we reconnected and we're not in MESSAGE IN phase after IDENTIFY,2100	 * reconnect I_T_L command2101	 */2102	if (ssr != 0x8f && !acornscsi_reconnect_finish(host))2103	    return INTR_IDLE;2104	ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, in_irq);2105	switch (ssr) {2106	case 0x88:			/* data out phase				*/2107					/* -> PHASE_DATAOUT				*/2108	    /* MESSAGE IN -> DATA OUT */2109	    acornscsi_dma_setup(host, DMA_OUT);2110	    if (!acornscsi_starttransfer(host))2111		acornscsi_abortcmd(host);2112	    host->scsi.phase = PHASE_DATAOUT;2113	    return INTR_IDLE;2114 2115	case 0x89:			/* data in phase				*/2116					/* -> PHASE_DATAIN				*/2117	    /* MESSAGE IN -> DATA IN */2118	    acornscsi_dma_setup(host, DMA_IN);2119	    if (!acornscsi_starttransfer(host))2120		acornscsi_abortcmd(host);2121	    host->scsi.phase = PHASE_DATAIN;2122	    return INTR_IDLE;2123 2124	case 0x8a:			/* command out					*/2125	    /* MESSAGE IN -> COMMAND */2126	    acornscsi_sendcommand(host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/2127	    break;2128 2129	case 0x8b:			/* status in					*/2130					/* -> PHASE_STATUSIN				*/2131	    /* MESSAGE IN -> STATUS */2132	    acornscsi_readstatusbyte(host);2133	    host->scsi.phase = PHASE_STATUSIN;2134	    break;2135 2136	case 0x8e:			/* message out					*/2137					/* -> PHASE_MSGOUT				*/2138	    /* MESSAGE IN -> MESSAGE OUT */2139	    acornscsi_sendmessage(host);2140	    break;2141 2142	case 0x8f:			/* message in					*/2143	    acornscsi_message(host);	/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/2144	    break;2145 2146	default:2147	    printk(KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n",2148		    host->host->host_no, acornscsi_target(host), ssr);2149	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);2150	}2151	return INTR_PROCESSING;2152 2153    case PHASE_DATAIN:			/* STATE: transferred data in			*/2154	/*2155	 * This is simple - if we disconnect then the DMA address & count is2156	 * correct.2157	 */2158	switch (ssr) {2159	case 0x19:			/* -> PHASE_DATAIN				*/2160	case 0x89:			/* -> PHASE_DATAIN				*/2161	    acornscsi_abortcmd(host);2162	    return INTR_IDLE;2163 2164	case 0x1b:			/* -> PHASE_STATUSIN				*/2165	case 0x4b:			/* -> PHASE_STATUSIN				*/2166	case 0x8b:			/* -> PHASE_STATUSIN				*/2167	    /* DATA IN -> STATUS */2168	    host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -2169					  acornscsi_sbic_xfcount(host);2170	    acornscsi_dma_stop(host);2171	    acornscsi_readstatusbyte(host);2172	    host->scsi.phase = PHASE_STATUSIN;2173	    break;2174 2175	case 0x1e:			/* -> PHASE_MSGOUT				*/2176	case 0x4e:			/* -> PHASE_MSGOUT				*/2177	case 0x8e:			/* -> PHASE_MSGOUT				*/2178	    /* DATA IN -> MESSAGE OUT */2179	    host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -2180					  acornscsi_sbic_xfcount(host);2181	    acornscsi_dma_stop(host);2182	    acornscsi_sendmessage(host);2183	    break;2184 2185	case 0x1f:			/* message in					*/2186	case 0x4f:			/* message in					*/2187	case 0x8f:			/* message in					*/2188	    /* DATA IN -> MESSAGE IN */2189	    host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -2190					  acornscsi_sbic_xfcount(host);2191	    acornscsi_dma_stop(host);2192	    acornscsi_message(host);	/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/2193	    break;2194 2195	default:2196	    printk(KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n",2197		    host->host->host_no, acornscsi_target(host), ssr);2198	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);2199	}2200	return INTR_PROCESSING;2201 2202    case PHASE_DATAOUT: 		/* STATE: transferred data out			*/2203	/*2204	 * This is more complicated - if we disconnect, the DMA could be 122205	 * bytes ahead of us.  We need to correct this.2206	 */2207	switch (ssr) {2208	case 0x18:			/* -> PHASE_DATAOUT				*/2209	case 0x88:			/* -> PHASE_DATAOUT				*/2210	    acornscsi_abortcmd(host);2211	    return INTR_IDLE;2212 2213	case 0x1b:			/* -> PHASE_STATUSIN				*/2214	case 0x4b:			/* -> PHASE_STATUSIN				*/2215	case 0x8b:			/* -> PHASE_STATUSIN				*/2216	    /* DATA OUT -> STATUS */2217	    host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -2218					  acornscsi_sbic_xfcount(host);2219	    acornscsi_dma_stop(host);2220	    acornscsi_dma_adjust(host);2221	    acornscsi_readstatusbyte(host);2222	    host->scsi.phase = PHASE_STATUSIN;2223	    break;2224 2225	case 0x1e:			/* -> PHASE_MSGOUT				*/2226	case 0x4e:			/* -> PHASE_MSGOUT				*/2227	case 0x8e:			/* -> PHASE_MSGOUT				*/2228	    /* DATA OUT -> MESSAGE OUT */2229	    host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -2230					  acornscsi_sbic_xfcount(host);2231	    acornscsi_dma_stop(host);2232	    acornscsi_dma_adjust(host);2233	    acornscsi_sendmessage(host);2234	    break;2235 2236	case 0x1f:			/* message in					*/2237	case 0x4f:			/* message in					*/2238	case 0x8f:			/* message in					*/2239	    /* DATA OUT -> MESSAGE IN */2240	    host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -2241					  acornscsi_sbic_xfcount(host);2242	    acornscsi_dma_stop(host);2243	    acornscsi_dma_adjust(host);2244	    acornscsi_message(host);	/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/2245	    break;2246 2247	default:2248	    printk(KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n",2249		    host->host->host_no, acornscsi_target(host), ssr);2250	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);2251	}2252	return INTR_PROCESSING;2253 2254    case PHASE_STATUSIN:		/* STATE: status in complete			*/2255	switch (ssr) {2256	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */2257	case 0x8f:			/* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */2258	    /* STATUS -> MESSAGE IN */2259	    acornscsi_message(host);2260	    break;2261 2262	case 0x1e:			/* -> PHASE_MSGOUT				*/2263	case 0x8e:			/* -> PHASE_MSGOUT				*/2264	    /* STATUS -> MESSAGE OUT */2265	    acornscsi_sendmessage(host);2266	    break;2267 2268	default:2269	    printk(KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n",2270		    host->host->host_no, acornscsi_target(host), ssr);2271	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);2272	}2273	return INTR_PROCESSING;2274 2275    case PHASE_MSGIN:			/* STATE: message in				*/2276	switch (ssr) {2277	case 0x1e:			/* -> PHASE_MSGOUT				*/2278	case 0x4e:			/* -> PHASE_MSGOUT				*/2279	case 0x8e:			/* -> PHASE_MSGOUT				*/2280	    /* MESSAGE IN -> MESSAGE OUT */2281	    acornscsi_sendmessage(host);2282	    break;2283 2284	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */2285	case 0x2f:2286	case 0x4f:2287	case 0x8f:2288	    acornscsi_message(host);2289	    break;2290 2291	case 0x85:2292	    printk("scsi%d.%c: strange message in disconnection\n",2293		host->host->host_no, acornscsi_target(host));2294	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);2295	    acornscsi_done(host, &host->SCpnt, DID_ERROR);2296	    break;2297 2298	default:2299	    printk(KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n",2300		    host->host->host_no, acornscsi_target(host), ssr);2301	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);2302	}2303	return INTR_PROCESSING;2304 2305    case PHASE_DONE:			/* STATE: received status & message		*/2306	switch (ssr) {2307	case 0x85:			/* -> PHASE_IDLE				*/2308	    acornscsi_done(host, &host->SCpnt, DID_OK);2309	    return INTR_NEXT_COMMAND;2310 2311	case 0x1e:2312	case 0x8e:2313	    acornscsi_sendmessage(host);2314	    break;2315 2316	default:2317	    printk(KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n",2318		    host->host->host_no, acornscsi_target(host), ssr);2319	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);2320	}2321	return INTR_PROCESSING;2322 2323    case PHASE_ABORTED:2324	switch (ssr) {2325	case 0x85:2326	    if (host->SCpnt)2327		acornscsi_done(host, &host->SCpnt, DID_ABORT);2328	    else {2329		clear_bit(host->scsi.reconnected.target * 8 + host->scsi.reconnected.lun,2330			  host->busyluns);2331		host->scsi.phase = PHASE_IDLE;2332	    }2333	    return INTR_NEXT_COMMAND;2334 2335	case 0x1e:2336	case 0x2e:2337	case 0x4e:2338	case 0x8e:2339	    acornscsi_sendmessage(host);2340	    break;2341 2342	default:2343	    printk(KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n",2344		    host->host->host_no, acornscsi_target(host), ssr);2345	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);2346	}2347	return INTR_PROCESSING;2348 2349    default:2350	printk(KERN_ERR "scsi%d.%c: unknown driver phase %d\n",2351		host->host->host_no, acornscsi_target(host), ssr);2352	acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);2353    }2354    return INTR_PROCESSING;2355}2356 2357/*2358 * Prototype: void acornscsi_intr(int irq, void *dev_id)2359 * Purpose  : handle interrupts from Acorn SCSI card2360 * Params   : irq    - interrupt number2361 *	      dev_id - device specific data (AS_Host structure)2362 */2363static irqreturn_t2364acornscsi_intr(int irq, void *dev_id)2365{2366    AS_Host *host = (AS_Host *)dev_id;2367    intr_ret_t ret;2368    int iostatus;2369    int in_irq = 0;2370 2371    do {2372	ret = INTR_IDLE;2373 2374	iostatus = readb(host->fast + INT_REG);2375 2376	if (iostatus & 2) {2377	    acornscsi_dma_intr(host);2378	    iostatus = readb(host->fast + INT_REG);2379	}2380 2381	if (iostatus & 8)2382	    ret = acornscsi_sbicintr(host, in_irq);2383 2384	/*2385	 * If we have a transfer pending, start it.2386	 * Only start it if the interface has already started transferring2387	 * it's data2388	 */2389	if (host->dma.xfer_required)2390	    acornscsi_dma_xfer(host);2391 2392	if (ret == INTR_NEXT_COMMAND)2393	    ret = acornscsi_kick(host);2394 2395	in_irq = 1;2396    } while (ret != INTR_IDLE);2397 2398    return IRQ_HANDLED;2399}2400 2401/*=============================================================================================2402 * Interfaces between interrupt handler and rest of scsi code2403 */2404 2405/*2406 * Function : acornscsi_queuecmd(struct scsi_cmnd *cmd)2407 * Purpose  : queues a SCSI command2408 * Params   : cmd  - SCSI command2409 * Returns  : 0, or < 0 on error.2410 */2411static int acornscsi_queuecmd_lck(struct scsi_cmnd *SCpnt)2412{2413    struct scsi_pointer *scsi_pointer = arm_scsi_pointer(SCpnt);2414    void (*done)(struct scsi_cmnd *) = scsi_done;2415    AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;2416 2417#if (DEBUG & DEBUG_NO_WRITE)2418    if (acornscsi_cmdtype(SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->device->id))) {2419	printk(KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n",2420	    host->host->host_no, '0' + SCpnt->device->id);2421	set_host_byte(SCpnt, DID_NO_CONNECT);2422	done(SCpnt);2423	return 0;2424    }2425#endif2426 2427    SCpnt->host_scribble = NULL;2428    SCpnt->result = 0;2429    scsi_pointer->phase = (int)acornscsi_datadirection(SCpnt->cmnd[0]);2430    scsi_pointer->sent_command = 0;2431    scsi_pointer->scsi_xferred = 0;2432 2433    init_SCp(SCpnt);2434 2435    host->stats.queues += 1;2436 2437    {2438	unsigned long flags;2439 2440	if (!queue_add_cmd_ordered(&host->queues.issue, SCpnt)) {2441		set_host_byte(SCpnt, DID_ERROR);2442	    done(SCpnt);2443	    return 0;2444	}2445	local_irq_save(flags);2446	if (host->scsi.phase == PHASE_IDLE)2447	    acornscsi_kick(host);2448	local_irq_restore(flags);2449    }2450    return 0;2451}2452 2453static DEF_SCSI_QCMD(acornscsi_queuecmd)2454 2455enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };2456 2457/*2458 * Prototype: enum res acornscsi_do_abort(struct scsi_cmnd *SCpnt)2459 * Purpose  : abort a command on this host2460 * Params   : SCpnt - command to abort2461 * Returns  : our abort status2462 */2463static enum res_abort acornscsi_do_abort(AS_Host *host, struct scsi_cmnd *SCpnt)2464{2465	enum res_abort res = res_not_running;2466 2467	if (queue_remove_cmd(&host->queues.issue, SCpnt)) {2468		/*2469		 * The command was on the issue queue, and has not been2470		 * issued yet.  We can remove the command from the queue,2471		 * and acknowledge the abort.  Neither the devices nor the2472		 * interface know about the command.2473		 */2474//#if (DEBUG & DEBUG_ABORT)2475		printk("on issue queue ");2476//#endif2477		res = res_success;2478	} else if (queue_remove_cmd(&host->queues.disconnected, SCpnt)) {2479		/*2480		 * The command was on the disconnected queue.  Simply2481		 * acknowledge the abort condition, and when the target2482		 * reconnects, we will give it an ABORT message.  The2483		 * target should then disconnect, and we will clear2484		 * the busylun bit.2485		 */2486//#if (DEBUG & DEBUG_ABORT)2487		printk("on disconnected queue ");2488//#endif2489		res = res_success;2490	} else if (host->SCpnt == SCpnt) {2491		unsigned long flags;2492 2493//#if (DEBUG & DEBUG_ABORT)2494		printk("executing ");2495//#endif2496 2497		local_irq_save(flags);2498		switch (host->scsi.phase) {2499		/*2500		 * If the interface is idle, and the command is 'disconnectable',2501		 * then it is the same as on the disconnected queue.  We simply2502		 * remove all traces of the command.  When the target reconnects,2503		 * we will give it an ABORT message since the command could not2504		 * be found.  When the target finally disconnects, we will clear2505		 * the busylun bit.2506		 */2507		case PHASE_IDLE:2508			if (host->scsi.disconnectable) {2509				host->scsi.disconnectable = 0;2510				host->SCpnt = NULL;2511				res = res_success;2512			}2513			break;2514 2515		/*2516		 * If the command has connected and done nothing further,2517		 * simply force a disconnect.  We also need to clear the2518		 * busylun bit.2519		 */2520		case PHASE_CONNECTED:2521			sbic_arm_write(host, SBIC_CMND, CMND_DISCONNECT);2522			host->SCpnt = NULL;2523			res = res_success_clear;2524			break;2525 2526		default:2527			acornscsi_abortcmd(host);2528			res = res_snooze;2529		}2530		local_irq_restore(flags);2531	} else if (host->origSCpnt == SCpnt) {2532		/*2533		 * The command will be executed next, but a command2534		 * is currently using the interface.  This is similar to2535		 * being on the issue queue, except the busylun bit has2536		 * been set.2537		 */2538		host->origSCpnt = NULL;2539//#if (DEBUG & DEBUG_ABORT)2540		printk("waiting for execution ");2541//#endif2542		res = res_success_clear;2543	} else2544		printk("unknown ");2545 2546	return res;2547}2548 2549/*2550 * Prototype: int acornscsi_abort(struct scsi_cmnd *SCpnt)2551 * Purpose  : abort a command on this host2552 * Params   : SCpnt - command to abort2553 * Returns  : one of SCSI_ABORT_ macros2554 */2555static int acornscsi_abort(struct scsi_cmnd *SCpnt)2556{2557	AS_Host *host = (AS_Host *) SCpnt->device->host->hostdata;2558	int result;2559 2560	host->stats.aborts += 1;2561 2562#if (DEBUG & DEBUG_ABORT)2563	{2564		int asr, ssr;2565		asr = sbic_arm_read(host, SBIC_ASR);2566		ssr = sbic_arm_read(host, SBIC_SSR);2567 2568		printk(KERN_WARNING "acornscsi_abort: ");2569		print_sbic_status(asr, ssr, host->scsi.phase);2570		acornscsi_dumplog(host, SCpnt->device->id);2571	}2572#endif2573 2574	printk("scsi%d: ", host->host->host_no);2575 2576	switch (acornscsi_do_abort(host, SCpnt)) {2577	/*2578	 * We managed to find the command and cleared it out.2579	 * We do not expect the command to be executing on the2580	 * target, but we have set the busylun bit.2581	 */2582	case res_success_clear:2583//#if (DEBUG & DEBUG_ABORT)2584		printk("clear ");2585//#endif2586		clear_bit(SCpnt->device->id * 8 +2587			  (u8)(SCpnt->device->lun & 0x7), host->busyluns);2588		fallthrough;2589 2590	/*2591	 * We found the command, and cleared it out.  Either2592	 * the command is still known to be executing on the2593	 * target, or the busylun bit is not set.2594	 */2595	case res_success:2596//#if (DEBUG & DEBUG_ABORT)2597		printk("success\n");2598//#endif2599		result = SUCCESS;2600		break;2601 2602	/*2603	 * We did find the command, but unfortunately we couldn't2604	 * unhook it from ourselves.  Wait some more, and if it2605	 * still doesn't complete, reset the interface.2606	 */2607	case res_snooze:2608//#if (DEBUG & DEBUG_ABORT)2609		printk("snooze\n");2610//#endif2611		result = FAILED;2612		break;2613 2614	/*2615	 * The command could not be found (either because it completed,2616	 * or it got dropped.2617	 */2618	default:2619	case res_not_running:2620		acornscsi_dumplog(host, SCpnt->device->id);2621		result = FAILED;2622//#if (DEBUG & DEBUG_ABORT)2623		printk("not running\n");2624//#endif2625		break;2626	}2627 2628	return result;2629}2630 2631/*2632 * Prototype: int acornscsi_reset(struct scsi_cmnd *SCpnt)2633 * Purpose  : reset a command on this host/reset this host2634 * Params   : SCpnt  - command causing reset2635 * Returns  : one of SCSI_RESET_ macros2636 */2637static int acornscsi_host_reset(struct scsi_cmnd *SCpnt)2638{2639	AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;2640	struct scsi_cmnd *SCptr;2641    2642    host->stats.resets += 1;2643 2644#if (DEBUG & DEBUG_RESET)2645    {2646	int asr, ssr, devidx;2647 2648	asr = sbic_arm_read(host, SBIC_ASR);2649	ssr = sbic_arm_read(host, SBIC_SSR);2650 2651	printk(KERN_WARNING "acornscsi_reset: ");2652	print_sbic_status(asr, ssr, host->scsi.phase);2653	for (devidx = 0; devidx < 9; devidx++)2654	    acornscsi_dumplog(host, devidx);2655    }2656#endif2657 2658    acornscsi_dma_stop(host);2659 2660    /*2661     * do hard reset.  This resets all devices on this host, and so we2662     * must set the reset status on all commands.2663     */2664    acornscsi_resetcard(host);2665 2666    while ((SCptr = queue_remove(&host->queues.disconnected)) != NULL)2667	;2668 2669    return SUCCESS;2670}2671 2672/*==============================================================================================2673 * initialisation & miscellaneous support2674 */2675 2676/*2677 * Function: char *acornscsi_info(struct Scsi_Host *host)2678 * Purpose : return a string describing this interface2679 * Params  : host - host to give information on2680 * Returns : a constant string2681 */2682static const char *acornscsi_info(struct Scsi_Host *host)2683{2684    static char string[100], *p;2685 2686    p = string;2687    2688    p += sprintf(string, "%s at port %08lX irq %d v%d.%d.%d"2689#ifdef CONFIG_SCSI_ACORNSCSI_SYNC2690    " SYNC"2691#endif2692#if (DEBUG & DEBUG_NO_WRITE)2693    " NOWRITE (" __stringify(NO_WRITE) ")"2694#endif2695		, host->hostt->name, host->io_port, host->irq,2696		VER_MAJOR, VER_MINOR, VER_PATCH);2697    return string;2698}2699 2700static int acornscsi_show_info(struct seq_file *m, struct Scsi_Host *instance)2701{2702    int devidx;2703    struct scsi_device *scd;2704    AS_Host *host;2705 2706    host  = (AS_Host *)instance->hostdata;2707    2708    seq_printf(m, "AcornSCSI driver v%d.%d.%d"2709#ifdef CONFIG_SCSI_ACORNSCSI_SYNC2710    " SYNC"2711#endif2712#if (DEBUG & DEBUG_NO_WRITE)2713    " NOWRITE (" __stringify(NO_WRITE) ")"2714#endif2715		"\n\n", VER_MAJOR, VER_MINOR, VER_PATCH);2716 2717    seq_printf(m,	"SBIC: WD33C93A  Address: %p    IRQ : %d\n",2718			host->base + SBIC_REGIDX, host->scsi.irq);2719#ifdef USE_DMAC2720    seq_printf(m,	"DMAC: uPC71071  Address: %p  IRQ : %d\n\n",2721			host->base + DMAC_OFFSET, host->scsi.irq);2722#endif2723 2724    seq_printf(m,	"Statistics:\n"2725			"Queued commands: %-10u    Issued commands: %-10u\n"2726			"Done commands  : %-10u    Reads          : %-10u\n"2727			"Writes         : %-10u    Others         : %-10u\n"2728			"Disconnects    : %-10u    Aborts         : %-10u\n"2729			"Resets         : %-10u\n\nLast phases:",2730			host->stats.queues,		host->stats.removes,2731			host->stats.fins,		host->stats.reads,2732			host->stats.writes,		host->stats.miscs,2733			host->stats.disconnects,	host->stats.aborts,2734			host->stats.resets);2735 2736    for (devidx = 0; devidx < 9; devidx ++) {2737	unsigned int statptr, prev;2738 2739	seq_printf(m, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx));2740	statptr = host->status_ptr[devidx] - 10;2741 2742	if ((signed int)statptr < 0)2743	    statptr += STATUS_BUFFER_SIZE;2744 2745	prev = host->status[devidx][statptr].when;2746 2747	for (; statptr != host->status_ptr[devidx]; statptr = (statptr + 1) & (STATUS_BUFFER_SIZE - 1)) {2748	    if (host->status[devidx][statptr].when) {2749		seq_printf(m, "%c%02X:%02X+%2ld",2750			host->status[devidx][statptr].irq ? '-' : ' ',2751			host->status[devidx][statptr].ph,2752			host->status[devidx][statptr].ssr,2753			(host->status[devidx][statptr].when - prev) < 100 ?2754				(host->status[devidx][statptr].when - prev) : 99);2755		prev = host->status[devidx][statptr].when;2756	    }2757	}2758    }2759 2760    seq_printf(m, "\nAttached devices:\n");2761 2762    shost_for_each_device(scd, instance) {2763	seq_printf(m, "Device/Lun TaggedQ      Sync\n");2764	seq_printf(m, "     %d/%llu   ", scd->id, scd->lun);2765	if (scd->tagged_supported)2766		seq_printf(m, "%3sabled ",2767			     scd->simple_tags ? "en" : "dis");2768	else2769		seq_printf(m, "unsupported  ");2770 2771	if (host->device[scd->id].sync_xfer & 15)2772		seq_printf(m, "offset %d, %d ns\n",2773			     host->device[scd->id].sync_xfer & 15,2774			     acornscsi_getperiod(host->device[scd->id].sync_xfer));2775	else2776		seq_printf(m, "async\n");2777 2778    }2779    return 0;2780}2781 2782static const struct scsi_host_template acornscsi_template = {2783	.module			= THIS_MODULE,2784	.show_info		= acornscsi_show_info,2785	.name			= "AcornSCSI",2786	.info			= acornscsi_info,2787	.queuecommand		= acornscsi_queuecmd,2788	.eh_abort_handler	= acornscsi_abort,2789	.eh_host_reset_handler	= acornscsi_host_reset,2790	.can_queue		= 16,2791	.this_id		= 7,2792	.sg_tablesize		= SG_ALL,2793	.cmd_per_lun		= 2,2794	.dma_boundary		= PAGE_SIZE - 1,2795	.proc_name		= "acornscsi",2796	.cmd_size		= sizeof(struct arm_cmd_priv),2797};2798 2799static int acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id)2800{2801	struct Scsi_Host *host;2802	AS_Host *ashost;2803	int ret;2804 2805	ret = ecard_request_resources(ec);2806	if (ret)2807		goto out;2808 2809	host = scsi_host_alloc(&acornscsi_template, sizeof(AS_Host));2810	if (!host) {2811		ret = -ENOMEM;2812		goto out_release;2813	}2814 2815	ashost = (AS_Host *)host->hostdata;2816 2817	ashost->base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);2818	ashost->fast = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);2819	if (!ashost->base || !ashost->fast) {2820		ret = -ENOMEM;2821		goto out_put;2822	}2823 2824	host->irq = ec->irq;2825	ashost->host = host;2826	ashost->scsi.irq = host->irq;2827 2828	ec->irqaddr	= ashost->fast + INT_REG;2829	ec->irqmask	= 0x0a;2830 2831	ret = request_irq(host->irq, acornscsi_intr, 0, "acornscsi", ashost);2832	if (ret) {2833		printk(KERN_CRIT "scsi%d: IRQ%d not free: %d\n",2834			host->host_no, ashost->scsi.irq, ret);2835		goto out_put;2836	}2837 2838	memset(&ashost->stats, 0, sizeof (ashost->stats));2839	queue_initialise(&ashost->queues.issue);2840	queue_initialise(&ashost->queues.disconnected);2841	msgqueue_initialise(&ashost->scsi.msgs);2842 2843	acornscsi_resetcard(ashost);2844 2845	ret = scsi_add_host(host, &ec->dev);2846	if (ret)2847		goto out_irq;2848 2849	scsi_scan_host(host);2850	goto out;2851 2852 out_irq:2853	free_irq(host->irq, ashost);2854	msgqueue_free(&ashost->scsi.msgs);2855	queue_free(&ashost->queues.disconnected);2856	queue_free(&ashost->queues.issue);2857 out_put:2858	ecardm_iounmap(ec, ashost->fast);2859	ecardm_iounmap(ec, ashost->base);2860	scsi_host_put(host);2861 out_release:2862	ecard_release_resources(ec);2863 out:2864	return ret;2865}2866 2867static void acornscsi_remove(struct expansion_card *ec)2868{2869	struct Scsi_Host *host = ecard_get_drvdata(ec);2870	AS_Host *ashost = (AS_Host *)host->hostdata;2871 2872	ecard_set_drvdata(ec, NULL);2873	scsi_remove_host(host);2874 2875	/*2876	 * Put card into RESET state2877	 */2878	writeb(0x80, ashost->fast + PAGE_REG);2879 2880	free_irq(host->irq, ashost);2881 2882	msgqueue_free(&ashost->scsi.msgs);2883	queue_free(&ashost->queues.disconnected);2884	queue_free(&ashost->queues.issue);2885	ecardm_iounmap(ec, ashost->fast);2886	ecardm_iounmap(ec, ashost->base);2887	scsi_host_put(host);2888	ecard_release_resources(ec);2889}2890 2891static const struct ecard_id acornscsi_cids[] = {2892	{ MANU_ACORN, PROD_ACORN_SCSI },2893	{ 0xffff, 0xffff },2894};2895 2896static struct ecard_driver acornscsi_driver = {2897	.probe		= acornscsi_probe,2898	.remove		= acornscsi_remove,2899	.id_table	= acornscsi_cids,2900	.drv = {2901		.name		= "acornscsi",2902	},2903};2904 2905static int __init acornscsi_init(void)2906{2907	return ecard_register_driver(&acornscsi_driver);2908}2909 2910static void __exit acornscsi_exit(void)2911{2912	ecard_remove_driver(&acornscsi_driver);2913}2914 2915module_init(acornscsi_init);2916module_exit(acornscsi_exit);2917 2918MODULE_AUTHOR("Russell King");2919MODULE_DESCRIPTION("AcornSCSI driver");2920MODULE_LICENSE("GPL");2921