ibmmca.c

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

C
1,680
字号
	int dyn_flag;		/* flag showing dynamical mode */	int dynamical_assignments;	/* number of remappings of ldns */	int ldn_assignments[MAX_LOG_DEV + 1];	/* number of remappings of each						   ldn */};/* data structure for each host adapter */struct ibmmca_hostdata {	/* array of logical devices: */	struct logical_device _ld[MAX_LOG_DEV + 1];	/* array to convert (pun, lun) into logical device number: */	unsigned char _get_ldn[16][8];	/*array that contains the information about the physical SCSI-devices	   attached to this host adapter: */	unsigned char _get_scsi[16][8];	/* used only when checking logical devices: */	int _local_checking_phase_flag;	/* report received interrupt: */	int _got_interrupt;	/* report termination-status of SCSI-command: */	int _stat_result;	/* reset status (used only when doing reset): */	int _reset_status;	/* code of the last SCSI command (needed for panic info): */	int _last_scsi_command[MAX_LOG_DEV + 1];	/* identifier of the last SCSI-command type */	int _last_scsi_type[MAX_LOG_DEV + 1];	/* last blockcount */	int _last_scsi_blockcount[MAX_LOG_DEV + 1];	/* last locgical block address */	unsigned long _last_scsi_logical_block[MAX_LOG_DEV + 1];	/* Counter that points on the next reassignable ldn for dynamical	   remapping. The default value is 7, that is the first reassignable	   number in the list at boottime: */	int _next_ldn;	/* Statistics-structure for this IBM-SCSI-host: */	struct Driver_Statistics _IBM_DS;	/* This hostadapters pos-registers pos2 until pos6 */	unsigned int _pos[8];	/* assign a special variable, that contains dedicated info about the	   adaptertype */	int _special;	/* connector size on the MCA bus */	int _connector_size;	/* synchronous SCSI transfer rate bitpattern */	int _adapter_speed;};/* macros to access host data structure */#define subsystem_pun(hi) (hosts[(hi)]->this_id)#define subsystem_maxid(hi) (hosts[(hi)]->max_id)#define ld(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_ld)#define get_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_ldn)#define get_scsi(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_scsi)#define local_checking_phase_flag(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_local_checking_phase_flag)#define got_interrupt(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_got_interrupt)#define stat_result(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_stat_result)#define reset_status(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_reset_status)#define last_scsi_command(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_command)#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)#define last_scsi_blockcount(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_blockcount)#define last_scsi_logical_block(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_logical_block)#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)#define next_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_next_ldn)#define IBM_DS(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_IBM_DS)#define special(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_special)#define subsystem_connector_size(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_connector_size)#define adapter_speed(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_adapter_speed)#define pos2(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[2])#define pos3(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[3])#define pos4(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[4])#define pos5(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[5])#define pos6(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[6])/* Define a arbitrary number as subsystem-marker-type. This number is, as   described in the ANSI-SCSI-standard, not occupied by other device-types. */#define TYPE_IBM_SCSI_ADAPTER   0x2F/* Define 0xFF for no device type, because this type is not defined within   the ANSI-SCSI-standard, therefore, it can be used and should not cause any   harm. */#define TYPE_NO_DEVICE          0xFF/* define medium-changer. If this is not defined previously, e.g. Linux   2.0.x, define this type here. */#ifndef TYPE_MEDIUM_CHANGER#define TYPE_MEDIUM_CHANGER     0x08#endif/* define possible operations for the immediate_assign command */#define SET_LDN        0#define REMOVE_LDN     1/* ldn which is used to probe the SCSI devices */#define PROBE_LDN      0/* reset status flag contents */#define IM_RESET_NOT_IN_PROGRESS         0#define IM_RESET_IN_PROGRESS             1#define IM_RESET_FINISHED_OK             2#define IM_RESET_FINISHED_FAIL           3#define IM_RESET_NOT_IN_PROGRESS_NO_INT  4#define IM_RESET_FINISHED_OK_NO_INT      5/* define undefined SCSI-command */#define NO_SCSI                  0xffff/*-----------------------------------------------------------------------*//* if this is nonzero, ibmmcascsi option has been passed to the kernel */static int io_port[IM_MAX_HOSTS] = { 0, 0, 0, 0, 0, 0, 0, 0 };static int scsi_id[IM_MAX_HOSTS] = { 7, 7, 7, 7, 7, 7, 7, 7 };/* fill module-parameters only, when this define is present.   (that is kernel version 2.1.x) */#if defined(MODULE)static char *boot_options = NULL;MODULE_PARM(boot_options, "s");MODULE_PARM(io_port, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i");MODULE_PARM(scsi_id, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i");MODULE_PARM(display, "1i");MODULE_PARM(adisplay, "1i");MODULE_PARM(normal, "1i");MODULE_PARM(ansi, "1i");#endif/*counter of concurrent disk read/writes, to turn on/off disk led */static int disk_rw_in_progress = 0;/* host information */static int found = 0;static struct Scsi_Host *hosts[IM_MAX_HOSTS + 1] = {	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};static unsigned int pos[8];	/* whole pos register-line for diagnosis *//* Taking into account the additions, made by ZP Gu. * This selects now the preset value from the configfile and * offers the 'normal' commandline option to be accepted */#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARDstatic char ibm_ansi_order = 1;#elsestatic char ibm_ansi_order = 0;#endifstatic void issue_cmd(int, unsigned long, unsigned char);static void internal_done(Scsi_Cmnd * cmd);static void check_devices(int, int);static int immediate_assign(int, unsigned int, unsigned int, unsigned int, unsigned int);static int immediate_feature(int, unsigned int, unsigned int);#ifdef CONFIG_IBMMCA_SCSI_DEV_RESETstatic int immediate_reset(int, unsigned int);#endifstatic int device_inquiry(int, int);static int read_capacity(int, int);static int get_pos_info(int);static char *ti_p(int);static char *ti_l(int);static char *ibmrate(unsigned int, int);static int probe_display(int);static int probe_bus_mode(int);static int device_exists(int, int, int *, int *);static struct Scsi_Host *ibmmca_register(Scsi_Host_Template *, int, int, int, char *);static int option_setup(char *);/* local functions needed for proc_info */static int ldn_access_load(int, int);static int ldn_access_total_read_write(int);static irqreturn_t interrupt_handler(int irq, void *dev_id,					struct pt_regs *regs){	int host_index, ihost_index;	unsigned int intr_reg;	unsigned int cmd_result;	unsigned int ldn;	Scsi_Cmnd *cmd;	int lastSCSI;	struct Scsi_Host *dev = dev_id;	spin_lock(dev->host_lock);	    /* search for one adapter-response on shared interrupt */	    for (host_index = 0; hosts[host_index] && !(inb(IM_STAT_REG(host_index)) & IM_INTR_REQUEST); host_index++);	/* return if some other device on this IRQ caused the interrupt */	if (!hosts[host_index]) {		spin_unlock(dev->host_lock);		return IRQ_NONE;	}	/* the reset-function already did all the job, even ints got	   renabled on the subsystem, so just return */	if ((reset_status(host_index) == IM_RESET_NOT_IN_PROGRESS_NO_INT) || (reset_status(host_index) == IM_RESET_FINISHED_OK_NO_INT)) {		reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS;		spin_unlock(dev->host_lock);		return IRQ_HANDLED;	}	/*must wait for attention reg not busy, then send EOI to subsystem */	while (1) {		if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))			break;		cpu_relax();	}	ihost_index = host_index;	/*get command result and logical device */	intr_reg = (unsigned char) (inb(IM_INTR_REG(ihost_index)));	cmd_result = intr_reg & 0xf0;	ldn = intr_reg & 0x0f;	/* get the last_scsi_command here */	lastSCSI = last_scsi_command(ihost_index)[ldn];	outb(IM_EOI | ldn, IM_ATTN_REG(ihost_index));		/*these should never happen (hw fails, or a local programming bug) */	if (!global_command_error_excuse) {		switch (cmd_result) {			/* Prevent from Ooopsing on error to show the real reason */		case IM_ADAPTER_HW_FAILURE:		case IM_SOFTWARE_SEQUENCING_ERROR:		case IM_CMD_ERROR:			printk(KERN_ERR "IBM MCA SCSI: Fatal Subsystem ERROR!\n");			printk(KERN_ERR "              Last cmd=0x%x, ena=%x, len=", lastSCSI, ld(ihost_index)[ldn].scb.enable);			if (ld(ihost_index)[ldn].cmd)				printk("%ld/%ld,", (long) (ld(ihost_index)[ldn].cmd->request_bufflen), (long) (ld(ihost_index)[ldn].scb.sys_buf_length));			else				printk("none,");			if (ld(ihost_index)[ldn].cmd)				printk("Blocksize=%d", ld(ihost_index)[ldn].scb.u2.blk.length);			else				printk("Blocksize=none");			printk(", host=0x%x, ldn=0x%x\n", ihost_index, ldn);			if (ld(ihost_index)[ldn].cmd) {				printk(KERN_ERR "Blockcount=%d/%d\n", last_scsi_blockcount(ihost_index)[ldn], ld(ihost_index)[ldn].scb.u2.blk.count);				printk(KERN_ERR "Logical block=%lx/%lx\n", last_scsi_logical_block(ihost_index)[ldn], ld(ihost_index)[ldn].scb.u1.log_blk_adr);			}			printk(KERN_ERR "Reason given: %s\n", (cmd_result == IM_ADAPTER_HW_FAILURE) ? "HARDWARE FAILURE" : (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR) ? "SOFTWARE SEQUENCING ERROR" : (cmd_result == IM_CMD_ERROR) ? "COMMAND ERROR" : "UNKNOWN");			/* if errors appear, enter this section to give detailed info */			printk(KERN_ERR "IBM MCA SCSI: Subsystem Error-Status follows:\n");			printk(KERN_ERR "              Command Type................: %x\n", last_scsi_type(ihost_index)[ldn]);			printk(KERN_ERR "              Attention Register..........: %x\n", inb(IM_ATTN_REG(ihost_index)));			printk(KERN_ERR "              Basic Control Register......: %x\n", inb(IM_CTR_REG(ihost_index)));			printk(KERN_ERR "              Interrupt Status Register...: %x\n", intr_reg);			printk(KERN_ERR "              Basic Status Register.......: %x\n", inb(IM_STAT_REG(ihost_index)));			if ((last_scsi_type(ihost_index)[ldn] == IM_SCB) || (last_scsi_type(ihost_index)[ldn] == IM_LONG_SCB)) {				printk(KERN_ERR "              SCB-Command.................: %x\n", ld(ihost_index)[ldn].scb.command);				printk(KERN_ERR "              SCB-Enable..................: %x\n", ld(ihost_index)[ldn].scb.enable);				printk(KERN_ERR "              SCB-logical block address...: %lx\n", ld(ihost_index)[ldn].scb.u1.log_blk_adr);				printk(KERN_ERR "              SCB-system buffer address...: %lx\n", ld(ihost_index)[ldn].scb.sys_buf_adr);				printk(KERN_ERR "              SCB-system buffer length....: %lx\n", ld(ihost_index)[ldn].scb.sys_buf_length);				printk(KERN_ERR "              SCB-tsb address.............: %lx\n", ld(ihost_index)[ldn].scb.tsb_adr);				printk(KERN_ERR "              SCB-Chain address...........: %lx\n", ld(ihost_index)[ldn].scb.scb_chain_adr);				printk(KERN_ERR "              SCB-block count.............: %x\n", ld(ihost_index)[ldn].scb.u2.blk.count);				printk(KERN_ERR "              SCB-block length............: %x\n", ld(ihost_index)[ldn].scb.u2.blk.length);			}			printk(KERN_ERR "              Send this report to the maintainer.\n");			panic("IBM MCA SCSI: Fatal error message from the subsystem (0x%X,0x%X)!\n", lastSCSI, cmd_result);			break;		}	} else {		/* The command error handling is made silent, but we tell the		 * calling function, that there is a reported error from the		 * adapter. */		switch (cmd_result) {		case IM_ADAPTER_HW_FAILURE:		case IM_SOFTWARE_SEQUENCING_ERROR:		case IM_CMD_ERROR:			global_command_error_excuse = CMD_FAIL;			break;		default:			global_command_error_excuse = 0;			break;		}	}	/* if no panic appeared, increase the interrupt-counter */	IBM_DS(ihost_index).total_interrupts++;	/*only for local checking phase */	if (local_checking_phase_flag(ihost_index)) {		stat_result(ihost_index) = cmd_result;		got_interrupt(ihost_index) = 1;		reset_status(ihost_index) = IM_RESET_FINISHED_OK;		last_scsi_command(ihost_index)[ldn] = NO_SCSI;		spin_unlock(dev->host_lock);		return IRQ_HANDLED;	}	/* handling of commands coming from upper level of scsi driver */	if (last_scsi_type(ihost_index)[ldn] == IM_IMM_CMD) {		/* verify ldn, and may handle rare reset immediate command */		if ((reset_status(ihost_index) == IM_RESET_IN_PROGRESS) && (last_scsi_command(ihost_index)[ldn] == IM_RESET_IMM_CMD)) {			if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) {				disk_rw_in_progress = 0;				PS2_DISK_LED_OFF();				reset_status(ihost_index) = IM_RESET_FINISHED_FAIL;			} else {				/*reset disk led counter, turn off disk led */				disk_rw_in_progress = 0;				PS2_DISK_LED_OFF();				reset_status(ihost_index) = IM_RESET_FINISHED_OK;			}			stat_result(ihost_index) = cmd_result;			last_scsi_command(ihost_index)[ldn] = NO_SCSI;			last_scsi_type(ihost_index)[ldn] = 0;			spin_unlock(dev->host_lock);			return IRQ_HANDLED;		} else if (last_scsi_command(ihost_index)[ldn] == IM_ABORT_IMM_CMD) {			/* react on SCSI abort command */#ifdef IM_DEBUG_PROBE			printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n");#endif			disk_rw_in_progress = 0;			PS2_DISK_LED_OFF();			cmd = ld(ihost_index)[ldn].cmd;			ld(ihost_index)[ldn].cmd = NULL;			if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)				cmd->result = DID_NO_CONNECT << 16;			else				cmd->result = DID_ABORT << 16;			stat_result(ihost_index) = cmd_result;			last_scsi_command(ihost_index)[ldn] = NO_SCSI;			last_scsi_type(ihost_index)[ldn] = 0;			if (cmd->scsi_done)				(cmd->scsi_done) (cmd);	/* should be the internal_done */			spin_unlock(dev->host_lock);			return IRQ_HANDLED;		} else {			disk_rw_in_progress = 0;			PS2_DISK_LED_OFF();			reset_status(ihost_index) = IM_RESET_FINISHED_OK;			stat_result(ihost_index) = cmd_result;			last_scsi_command(ihost_index)[ldn] = NO_SCSI;			spin_unlock(dev->host_lock);			return IRQ_HANDLED;		}	}	last_scsi_command(ihost_index)[ldn] = NO_SCSI;	last_scsi_type(ihost_index)[ldn] = 0;	cmd = ld(ihost_index)[ldn].cmd;	ld(ihost_index)[ldn].cmd = NULL;#ifdef IM_DEBUG_TIMEOUT	if (cmd) {		if ((cmd->target == TIMEOUT_PUN) && (cmd->device->lun == TIMEOUT_LUN)) {

⌨️ 快捷键说明

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