ibmmca.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,680 行 · 第 1/5 页

C
1,680
字号
/* Low Level Linux Driver for the IBM Microchannel SCSI Subsystem for Linux Kernel >= 2.4.0. Copyright (c) 1995 Strom Systems, Inc. under the terms of the GNU General Public License. Written by Martin Kolinek, December 1995. Further development by: Chris Beauregard, Klaus Kudielka, Michael Lang See the file Documentation/scsi/ibmmca.txt for a detailed description of this driver, the commandline arguments and the history of its development. See the WWW-page: http://www.uni-mainz.de/~langm000/linux.html for latest updates, info and ADF-files for adapters supported by this driver. Alan Cox <alan@redhat.com> Updated for Linux 2.5.45 to use the new error handler, cleaned up the lock macros and did a few unavoidable locking tweaks, plus one locking fix in the irq and completion path.  */#include <linux/config.h>#ifndef LINUX_VERSION_CODE#include <linux/version.h>#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45)#error "This driver works only with kernel 2.5.45 or higher!"#endif#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/ctype.h>#include <linux/string.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/blkdev.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <linux/mca.h>#include <linux/string.h>#include <linux/spinlock.h>#include <linux/init.h>#include <linux/mca-legacy.h>#include <asm/system.h>#include <asm/io.h>#include "scsi.h"#include <scsi/scsi_host.h>#include "ibmmca.h"/* current version of this driver-source: */#define IBMMCA_SCSI_DRIVER_VERSION "4.0b-ac"/* driver configuration */#define IM_MAX_HOSTS     8	/* maximum number of host adapters */#define IM_RESET_DELAY	60	/* seconds allowed for a reset *//* driver debugging - #undef all for normal operation *//* if defined: count interrupts and ignore this special one: */#undef	IM_DEBUG_TIMEOUT	//50#define TIMEOUT_PUN	0#define TIMEOUT_LUN	0/* verbose interrupt: */#undef IM_DEBUG_INT/* verbose queuecommand: */#undef IM_DEBUG_CMD/* verbose queucommand for specific SCSI-device type: */#undef IM_DEBUG_CMD_SPEC_DEV/* verbose device probing */#undef IM_DEBUG_PROBE/* device type that shall be displayed on syslog (only during debugging): */#define IM_DEBUG_CMD_DEVICE	TYPE_TAPE/* relative addresses of hardware registers on a subsystem */#define IM_CMD_REG(hi)	(hosts[(hi)]->io_port)	/*Command Interface, (4 bytes long) */#define IM_ATTN_REG(hi)	(hosts[(hi)]->io_port+4)	/*Attention (1 byte) */#define IM_CTR_REG(hi)	(hosts[(hi)]->io_port+5)	/*Basic Control (1 byte) */#define IM_INTR_REG(hi)	(hosts[(hi)]->io_port+6)	/*Interrupt Status (1 byte, r/o) */#define IM_STAT_REG(hi)	(hosts[(hi)]->io_port+7)	/*Basic Status (1 byte, read only) *//* basic I/O-port of first adapter */#define IM_IO_PORT	0x3540/* maximum number of hosts that can be found */#define IM_N_IO_PORT	8/*requests going into the upper nibble of the Attention register *//*note: the lower nibble specifies the device(0-14), or subsystem(15) */#define IM_IMM_CMD	0x10	/*immediate command */#define IM_SCB		0x30	/*Subsystem Control Block command */#define IM_LONG_SCB	0x40	/*long Subsystem Control Block command */#define IM_EOI		0xe0	/*end-of-interrupt request *//*values for bits 7,1,0 of Basic Control reg. (bits 6-2 reserved) */#define IM_HW_RESET	0x80	/*hardware reset */#define IM_ENABLE_DMA	0x02	/*enable subsystem's busmaster DMA */#define IM_ENABLE_INTR	0x01	/*enable interrupts to the system *//*to interpret the upper nibble of Interrupt Status register *//*note: the lower nibble specifies the device(0-14), or subsystem(15) */#define IM_SCB_CMD_COMPLETED			0x10#define IM_SCB_CMD_COMPLETED_WITH_RETRIES	0x50#define IM_LOOP_SCATTER_BUFFER_FULL		0x60#define IM_ADAPTER_HW_FAILURE			0x70#define IM_IMMEDIATE_CMD_COMPLETED		0xa0#define IM_CMD_COMPLETED_WITH_FAILURE		0xc0#define IM_CMD_ERROR				0xe0#define IM_SOFTWARE_SEQUENCING_ERROR		0xf0/*to interpret bits 3-0 of Basic Status register (bits 7-4 reserved) */#define IM_CMD_REG_FULL		0x08#define IM_CMD_REG_EMPTY	0x04#define IM_INTR_REQUEST		0x02#define IM_BUSY			0x01/*immediate commands (word written into low 2 bytes of command reg) */#define IM_RESET_IMM_CMD	0x0400#define IM_FEATURE_CTR_IMM_CMD	0x040c#define IM_DMA_PACING_IMM_CMD	0x040d#define IM_ASSIGN_IMM_CMD	0x040e#define IM_ABORT_IMM_CMD	0x040f#define IM_FORMAT_PREP_IMM_CMD	0x0417/*SCB (Subsystem Control Block) structure */struct im_scb {	unsigned short command;	/*command word (read, etc.) */	unsigned short enable;	/*enable word, modifies cmd */	union {		unsigned long log_blk_adr;	/*block address on SCSI device */		unsigned char scsi_cmd_length;	/*6,10,12, for other scsi cmd */	} u1;	unsigned long sys_buf_adr;	/*physical system memory adr */	unsigned long sys_buf_length;	/*size of sys mem buffer */	unsigned long tsb_adr;	/*Termination Status Block adr */	unsigned long scb_chain_adr;	/*optional SCB chain address */	union {		struct {			unsigned short count;	/*block count, on SCSI device */			unsigned short length;	/*block length, on SCSI device */		} blk;		unsigned char scsi_command[12];	/*other scsi command */	} u2;};/*structure scatter-gather element (for list of system memory areas) */struct im_sge {	void *address;	unsigned long byte_length;};/*structure returned by a get_pos_info command: */struct im_pos_info {	unsigned short pos_id;	/* adapter id */	unsigned char pos_3a;	/* pos 3 (if pos 6 = 0) */	unsigned char pos_2;	/* pos 2 */	unsigned char int_level;	/* interrupt level IRQ 11 or 14 */	unsigned char pos_4a;	/* pos 4 (if pos 6 = 0) */	unsigned short connector_size;	/* MCA connector size: 16 or 32 Bit */	unsigned char num_luns;	/* number of supported luns per device */	unsigned char num_puns;	/* number of supported puns */	unsigned char pacing_factor;	/* pacing factor */	unsigned char num_ldns;	/* number of ldns available */	unsigned char eoi_off;	/* time EOI and interrupt inactive */	unsigned char max_busy;	/* time between reset and busy on */	unsigned short cache_stat;	/* ldn cachestat. Bit=1 = not cached */	unsigned short retry_stat;	/* retry status of ldns. Bit=1=disabled */	unsigned char pos_4b;	/* pos 4 (if pos 6 = 1) */	unsigned char pos_3b;	/* pos 3 (if pos 6 = 1) */	unsigned char pos_6;	/* pos 6 */	unsigned char pos_5;	/* pos 5 */	unsigned short max_overlap;	/* maximum overlapping requests */	unsigned short num_bus;	/* number of SCSI-busses */};/*values for SCB command word */#define IM_NO_SYNCHRONOUS      0x0040	/*flag for any command */#define IM_NO_DISCONNECT       0x0080	/*flag for any command */#define IM_READ_DATA_CMD       0x1c01#define IM_WRITE_DATA_CMD      0x1c02#define IM_READ_VERIFY_CMD     0x1c03#define IM_WRITE_VERIFY_CMD    0x1c04#define IM_REQUEST_SENSE_CMD   0x1c08#define IM_READ_CAPACITY_CMD   0x1c09#define IM_DEVICE_INQUIRY_CMD  0x1c0b#define IM_READ_LOGICAL_CMD    0x1c2a#define IM_OTHER_SCSI_CMD_CMD  0x241f/* unused, but supported, SCB commands */#define IM_GET_COMMAND_COMPLETE_STATUS_CMD   0x1c07	/* command status */#define IM_GET_POS_INFO_CMD                  0x1c0a	/* returns neat stuff */#define IM_READ_PREFETCH_CMD                 0x1c31	/* caching controller only */#define IM_FOMAT_UNIT_CMD                    0x1c16	/* format unit */#define IM_REASSIGN_BLOCK_CMD                0x1c18	/* in case of error *//*values to set bits in the enable word of SCB */#define IM_READ_CONTROL              0x8000#define IM_REPORT_TSB_ONLY_ON_ERROR  0x4000#define IM_RETRY_ENABLE              0x2000#define IM_POINTER_TO_LIST           0x1000#define IM_SUPRESS_EXCEPTION_SHORT   0x0400#define IM_BYPASS_BUFFER             0x0200#define IM_CHAIN_ON_NO_ERROR         0x0001/*TSB (Termination Status Block) structure */struct im_tsb {	unsigned short end_status;	unsigned short reserved1;	unsigned long residual_byte_count;	unsigned long sg_list_element_adr;	unsigned short status_length;	unsigned char dev_status;	unsigned char cmd_status;	unsigned char dev_error;	unsigned char cmd_error;	unsigned short reserved2;	unsigned short reserved3;	unsigned short low_of_last_scb_adr;	unsigned short high_of_last_scb_adr;};/*subsystem uses interrupt request level 14 */#define IM_IRQ     14/*SCSI-2 F/W may evade to interrupt 11 */#define IM_IRQ_FW  11/* Model 95 has an additional alphanumeric display, which can be used   to display SCSI-activities. 8595 models do not have any disk led, which   makes this feature quite useful.   The regular PS/2 disk led is turned on/off by bits 6,7 of system   control port. *//* LED display-port (actually, last LED on display) */#define MOD95_LED_PORT	   0x108/* system-control-register of PS/2s with diskindicator */#define PS2_SYS_CTR        0x92/* activity displaying methods */#define LED_DISP           1#define LED_ADISP          2#define LED_ACTIVITY       4/* failed intr */#define CMD_FAIL           255/* The SCSI-ID(!) of the accessed SCSI-device is shown on PS/2-95 machines' LED   displays. ldn is no longer displayed here, because the ldn mapping is now    done dynamically and the ldn <-> pun,lun maps can be looked-up at boottime    or during uptime in /proc/scsi/ibmmca/<host_no> in case of trouble,    interest, debugging or just for having fun. The left number gives the   host-adapter number and the right shows the accessed SCSI-ID. *//* display_mode is set by the ibmmcascsi= command line arg */static int display_mode = 0;/* set default adapter timeout */static unsigned int adapter_timeout = 45;/* for probing on feature-command: */static unsigned int global_command_error_excuse = 0;/* global setting by command line for adapter_speed */static int global_adapter_speed = 0;	/* full speed by default *//* Panel / LED on, do it right for F/W addressin, too. adisplay will * just ignore ids>7, as the panel has only 7 digits available */#define PS2_DISK_LED_ON(ad,id) { if (display_mode & LED_DISP) { if (id>9) \    outw((ad+48)|((id+55)<<8), MOD95_LED_PORT ); else \    outw((ad+48)|((id+48)<<8), MOD95_LED_PORT ); } else \    if (display_mode & LED_ADISP) { if (id<7) outb((char)(id+48),MOD95_LED_PORT+1+id); \    outb((char)(ad+48), MOD95_LED_PORT); } \    if ((display_mode & LED_ACTIVITY)||(!display_mode)) \    outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); }/* Panel / LED off *//* bug fixed, Dec 15, 1997, where | was replaced by & here */#define PS2_DISK_LED_OFF() { if (display_mode & LED_DISP) \    outw(0x2020, MOD95_LED_PORT ); else if (display_mode & LED_ADISP) { \    outl(0x20202020,MOD95_LED_PORT); outl(0x20202020,MOD95_LED_PORT+4); } \    if ((display_mode & LED_ACTIVITY)||(!display_mode)) \    outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); }/*list of supported subsystems */struct subsys_list_struct {	unsigned short mca_id;	char *description;};/* types of different supported hardware that goes to hostdata special */#define IBM_SCSI2_FW     0#define IBM_7568_WCACHE  1#define IBM_EXP_UNIT     2#define IBM_SCSI_WCACHE  3#define IBM_SCSI         4/* other special flags for hostdata structure */#define FORCED_DETECTION         100#define INTEGRATED_SCSI          101/* List of possible IBM-SCSI-adapters */struct subsys_list_struct subsys_list[] = {	{0x8efc, "IBM SCSI-2 F/W Adapter"},	/* special = 0 */	{0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/Cache"},	/* special = 1 */	{0x8ef8, "IBM Expansion Unit SCSI Controller"},	/* special = 2 */	{0x8eff, "IBM SCSI Adapter w/Cache"},	/* special = 3 */	{0x8efe, "IBM SCSI Adapter"},	/* special = 4 */};/* Max number of logical devices (can be up from 0 to 14).  15 is the addressof the adapter itself. */#define MAX_LOG_DEV  15/*local data for a logical device */struct logical_device {	struct im_scb scb;	/* SCSI-subsystem-control-block structure */	struct im_tsb tsb;	/* SCSI command complete status block structure */	struct im_sge sge[16];	/* scatter gather list structure */	unsigned char buf[256];	/* SCSI command return data buffer */	Scsi_Cmnd *cmd;		/* SCSI-command that is currently in progress */	int device_type;	/* type of the SCSI-device. See include/scsi/scsi.h				   for interpretation of the possible values */	int block_length;	/* blocksize of a particular logical SCSI-device */	int cache_flag;		/* 1 if this is uncached, 0 if cache is present for ldn */	int retry_flag;		/* 1 if adapter retry is disabled, 0 if enabled */};/* statistics of the driver during operations (for proc_info) */struct Driver_Statistics {	/* SCSI statistics on the adapter */	int ldn_access[MAX_LOG_DEV + 1];	/* total accesses on a ldn */	int ldn_read_access[MAX_LOG_DEV + 1];	/* total read-access on a ldn */	int ldn_write_access[MAX_LOG_DEV + 1];	/* total write-access on a ldn */	int ldn_inquiry_access[MAX_LOG_DEV + 1];	/* total inquiries on a ldn */	int ldn_modeselect_access[MAX_LOG_DEV + 1];	/* total mode selects on ldn */	int scbs;		/* short SCBs queued */	int long_scbs;		/* long SCBs queued */	int total_accesses;	/* total accesses on all ldns */	int total_interrupts;	/* total interrupts (should be				   same as total_accesses) */	int total_errors;	/* command completed with error */	/* dynamical assignment statistics */	int total_scsi_devices;	/* number of physical pun,lun */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?