📄 acornscsi.c.2
字号:
/* * linux/arch/arm/drivers/scsi/acornscsi.c * * Acorn SCSI 3 driver * By R.M.King. * * Abandoned using the Select and Transfer command since there were * some nasty races between our software and the target devices that * were not easy to solve, and the device errata had a lot of entries * for this command, some of them quite nasty... * * Changelog: * 26-Sep-1997 RMK Re-jigged to use the queue module. * Re-coded state machine to be based on driver * state not scsi state. Should be easier to debug. * Added acornscsi_release to clean up properly. * Updated proc/scsi reporting. * 05-Oct-1997 RMK Implemented writing to SCSI devices. * 06-Oct-1997 RMK Corrected small (non-serious) bug with the connect/ * reconnect race condition causing a warning message. */#define DEBUG_NO_WRITE 1#define DEBUG_QUEUES 2#define DEBUG_DMA 4#define DEBUG_ABORT 8#define DEBUG_DISCON 16#define DEBUG_CONNECT 32#define DEBUG_PHASES 64#define DEBUG_WRITE 128#define DEBUG_LINK 256#define DEBUG_MESSAGES 512#define DEBUG_RESET 1024#define DEBUG_ALL (DEBUG_RESET|DEBUG_MESSAGES|DEBUG_LINK|DEBUG_WRITE|\ DEBUG_PHASES|DEBUG_CONNECT|DEBUG_DISCON|DEBUG_ABORT|\ DEBUG_DMA|DEBUG_QUEUES|DEBUG_NO_WRITE)/* DRIVER CONFIGURATION * * SCSI-II Tagged queue support. * * I don't have any SCSI devices that support it, so it is totally untested * (except to make sure that it doesn't interfere with any non-tagging * devices). It is not fully implemented either - what happens when a * tagging device reconnects??? * * You can tell if you have a device that supports tagged queueing my * cating (eg) /proc/scsi/acornscsi/0 and see if the SCSI revision is reported * as '2 TAG'. */#define SCSI2_TAG/* * SCSI-II Linked command support. * * The higher level code doesn't support linked commands yet. */#undef SCSI2_LINK/* * SCSI-II Synchronous transfer support. * * Tried and tested... * * SDTR_SIZE - maximum number of un-acknowledged bytes (0 = off, 12 = max) * SDTR_PERIOD - period of REQ signal (min=125, max=1020) * DEFAULT_PERIOD - default REQ period. */#define SCSI2_SYNC#define SDTR_SIZE 12#define SDTR_PERIOD 125#define DEFAULT_PERIOD 500/* * Debugging information * * DEBUG - bit mask from list above * DEBUG_TARGET - is defined to the target number if you want to debug * a specific target. [only recon/write/dma]. */#define DEBUG (DEBUG_RESET|DEBUG_WRITE|DEBUG_NO_WRITE)/* only allow writing to SCSI device 0 */#define NO_WRITE 0xFE/*#define DEBUG_TARGET 2*//* * Select timeout time (in 10ms units) * * This is the timeout used between the start of selection and the WD33C93 * chip deciding that the device isn't responding. */#define TIMEOUT_TIME 10/* * Define this if you want to have verbose explaination of SCSI * status/messages. */#undef CONFIG_ACORNSCSI_CONSTANTS/* * Define this if you want to use the on board DMAC */#define USE_DMAC/* * List of devices that the driver will recognise */#define ACORNSCSI_LIST { MANU_ACORN, PROD_ACORN_SCSI }/* * ==================================================================================== */#ifdef DEBUG_TARGET#define DBG(cmd,xxx...) \ if (cmd->target == DEBUG_TARGET) { \ xxx; \ }#else#define DBG(cmd,xxx...) xxx#endif#ifndef STRINGIFY#define STRINGIFY(x) #x#endif#define STR(x) STRINGIFY(x)#define NO_WRITE_STR STR(NO_WRITE)#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <linux/ioport.h>#include <asm/bitops.h>#include <asm/delay.h>#include <asm/system.h>#include <asm/io.h>#include <asm/ecard.h>#include "../block/blk.h"#include "scsi.h"#include "hosts.h"#include "acornscsi.h"#include "constants.h"#define VER_MAJOR 2#define VER_MINOR 0#define VER_PATCH 3#ifndef ABORT_TAG#define ABORT_TAG 0xd#else#error "Yippee! ABORT TAG is now defined! Remove this error!"#endif#ifndef NO_IRQ#define NO_IRQ 255#endif/* * DMAC setup parameters */ #define INIT_DEVCON0 (DEVCON0_RQL|DEVCON0_EXW|DEVCON0_CMP)#define INIT_DEVCON1 (DEVCON1_BHLD)#define DMAC_READ (MODECON_READ)#define DMAC_WRITE (MODECON_WRITE)#define INIT_SBICDMA (CTRL_DMABURST)#ifdef SCSI2_LINK#error SCSI2 LINKed commands not supported (yet)!#endif/* * Size of on-board DMA buffer */#define DMAC_BUFFER_SIZE 65536/* * This is used to dump the previous states of the SBIC */static struct status_entry { unsigned long when; unsigned char ssr; unsigned char ph; unsigned char irq; unsigned char unused;} status[9][16];static unsigned char status_ptr[9];#define ADD_STATUS(_q,_ssr,_ph,_irq) \({ \ status[(_q)][status_ptr[(_q)]].when = jiffies; \ status[(_q)][status_ptr[(_q)]].ssr = (_ssr); \ status[(_q)][status_ptr[(_q)]].ph = (_ph); \ status[(_q)][status_ptr[(_q)]].irq = (_irq); \ status_ptr[(_q)] = (status_ptr[(_q)] + 1) & 15; \})unsigned int sdtr_period = SDTR_PERIOD;unsigned int sdtr_size = SDTR_SIZE;static struct proc_dir_entry proc_scsi_acornscsi = { PROC_SCSI_EATA, 9, "acornscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2};static void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result);static int acornscsi_reconnect_finish (AS_Host *host);static void acornscsi_dma_cleanup (AS_Host *host);static void acornscsi_abortcmd (AS_Host *host, unsigned char tag);/* ==================================================================================== * Miscellaneous */static inline voidsbic_arm_write (unsigned int io_port, int reg, int value){ arm_outb (reg, io_port); arm_outb (value, io_port + 4);}#define sbic_arm_writenext(io,val) \ arm_outb ((val), (io) + 4)static inlineint sbic_arm_read (unsigned int io_port, int reg){ if(reg == ASR) return arm_inl(io_port) & 255; arm_outb(reg, io_port); return arm_inl(io_port + 4) & 255;}#define sbic_arm_readnext(io) \ arm_inb((io) + 4)#define dmac_read(io_port,reg) \ inb ((io_port) + (reg))#define dmac_write(io_port,reg,value) \ ({ outb ((value), (io_port) + (reg)); })#define dmac_clearintr(io_port) \ ({ outb (0, (io_port)); })static inlineunsigned int dmac_address (unsigned int io_port){ return dmac_read (io_port, TXADRHI) << 16 | dmac_read (io_port, TXADRMD) << 8 | dmac_read (io_port, TXADRLO);}staticunsigned long acornscsi_sbic_xfcount (AS_Host *host){ unsigned long length; length = sbic_arm_read (host->scsi.io_port, TRANSCNTH) << 16; length |= sbic_arm_readnext (host->scsi.io_port) << 8; length |= sbic_arm_readnext (host->scsi.io_port); return length;}static voidacornscsi_csdelay (unsigned int cs){ unsigned long target_jiffies, flags; target_jiffies = jiffies + 1 + cs * HZ / 100; save_flags (flags); sti (); while (jiffies < target_jiffies) barrier(); restore_flags (flags);}staticvoid acornscsi_resetcard (AS_Host *host){ unsigned int i; /* assert reset line */ host->card.page_reg = 0x80; outb (host->card.page_reg, host->card.io_page); /* wait 3 cs. SCSI standard says 25ms. */ acornscsi_csdelay (3); host->card.page_reg = 0; outb (host->card.page_reg, host->card.io_page); /* * Should get a reset from the card */ while (!(inb (host->card.io_intr) & 8)); sbic_arm_read (host->scsi.io_port, ASR); sbic_arm_read (host->scsi.io_port, SSR); /* setup sbic - WD33C93A */ sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET); /* * Command should cause a reset interrupt */ while (!(inb (host->card.io_intr) & 8)); sbic_arm_read (host->scsi.io_port, ASR); if (sbic_arm_read (host->scsi.io_port, SSR) != 0x01) printk (KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n", host->host->host_no); sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); host->card.page_reg = 0x40; outb (host->card.page_reg, host->card.io_page); /* setup dmac - uPC71071 */ dmac_write (host->dma.io_port, INIT, 0); dmac_write (host->dma.io_port, INIT, INIT_8BIT); dmac_write (host->dma.io_port, CHANNEL, CHANNEL_0); dmac_write (host->dma.io_port, DEVCON0, INIT_DEVCON0); dmac_write (host->dma.io_port, DEVCON1, INIT_DEVCON1); host->SCpnt = NULL; host->scsi.phase = PHASE_IDLE; host->scsi.disconnectable = 0; for (i = 0; i < 8; i++) { host->busyluns[i] = 0; host->device[i].sync_state = SYNC_NEGOCIATE; host->device[i].disconnect_ok = 1; } /* wait 25 cs. SCSI standard says 250ms. */ acornscsi_csdelay (25);}/*============================================================================================= * Utility routines (eg. debug) */#ifdef CONFIG_ACORNSCSI_CONSTANTSstatic char *acornscsi_interrupttype[] = { "rst", "suc", "p/a", "3", "term", "5", "6", "7", "serv", "9", "a", "b", "c", "d", "e", "f"};static signed char acornscsi_map[] = { 0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, 3, -1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, 4, 5, 6, 7, 8, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, 16, 17, 18, 19, -1, -1, 20, 4, 5, 6, 7, 8, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21, 22, -1, -1, -1, 23, -1, -1, 4, 5, 6, 7, 8, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; static char *acornscsi_interruptcode[] = { /* 0 */ "reset - normal mode", /* 00 */ "reset - advanced mode", /* 01 */ /* 2 */ "sel", /* 11 */ "sel+xfer", /* 16 */ "data-out", /* 18 */ "data-in", /* 19 */ "cmd", /* 1A */ "stat", /* 1B */ "??-out", /* 1C */ "??-in", /* 1D */ "msg-out", /* 1E */ "msg-in", /* 1F */ /* 12 */ "/ACK asserted", /* 20 */ "save-data-ptr", /* 21 */ "{re}sel", /* 22 */ /* 15 */ "inv cmd", /* 40 */ "unexpected disconnect", /* 41 */ "sel timeout", /* 42 */ "P err", /* 43 */ "P err+ATN", /* 44 */ "bad status byte", /* 47 */ /* 21 */ "resel, no id", /* 80 */ "resel", /* 81 */ "discon", /* 85 */};staticvoid print_scsi_status (unsigned int ssr){ if (acornscsi_map[ssr] != -1) printk ("%s:%s", acornscsi_interrupttype[(ssr >> 4)], acornscsi_interruptcode[acornscsi_map[ssr]]); else printk ("%X:%X", ssr >> 4, ssr & 0x0f); } #endifstaticvoid print_sbic_status (int asr, int ssr, int cmdphase){#ifdef CONFIG_ACORNSCSI_CONSTANTS printk ("sbic: %c%c%c%c%c%c ", asr & ASR_INT ? 'I' : 'i', asr & ASR_LCI ? 'L' : 'l', asr & ASR_BSY ? 'B' : 'b', asr & ASR_CIP ? 'C' : 'c', asr & ASR_PE ? 'P' : 'p', asr & ASR_DBR ? 'D' : 'd'); printk ("scsi: "); print_scsi_status (ssr); printk (" ph %02X\n", cmdphase);#else printk ("sbic: %02X scsi: %X:%X ph: %02X\n", asr, (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase);#endif}staticvoid acornscsi_dumplog (AS_Host *host, int target)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -