ips.c

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

C
1,776
字号
	IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n");	ips_sh[i] = NULL;	ips_ha[i] = NULL;	/* free extra memory */	ips_free(ha);	/* Free I/O Region */	if (ha->io_addr)		release_region(ha->io_addr, ha->io_len);	/* free IRQ */	free_irq(ha->irq, ha);	IPS_REMOVE_HOST(sh);	scsi_host_put(sh);	ips_released_controllers++;	return (FALSE);}/****************************************************************************//*                                                                          *//* Routine Name: ips_halt                                                   *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Perform cleanup when the system reboots                                *//*                                                                          *//****************************************************************************/static intips_halt(struct notifier_block *nb, ulong event, void *buf){	ips_scb_t *scb;	ips_ha_t *ha;	int i;	if ((event != SYS_RESTART) && (event != SYS_HALT) &&	    (event != SYS_POWER_OFF))		return (NOTIFY_DONE);	for (i = 0; i < ips_next_controller; i++) {		ha = (ips_ha_t *) ips_ha[i];		if (!ha)			continue;		if (!ha->active)			continue;		/* flush the cache on the controller */		scb = &ha->scbs[ha->max_cmds - 1];		ips_init_scb(ha, scb);		scb->timeout = ips_cmd_timeout;		scb->cdb[0] = IPS_CMD_FLUSH;		scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;		scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);		scb->cmd.flush_cache.state = IPS_NORM_STATE;		scb->cmd.flush_cache.reserved = 0;		scb->cmd.flush_cache.reserved2 = 0;		scb->cmd.flush_cache.reserved3 = 0;		scb->cmd.flush_cache.reserved4 = 0;		IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n");		/* send command */		if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) ==		    IPS_FAILURE)			IPS_PRINTK(KERN_WARNING, ha->pcidev,				   "Incomplete Flush.\n");		else			IPS_PRINTK(KERN_WARNING, ha->pcidev,				   "Flushing Complete.\n");	}	return (NOTIFY_OK);}/****************************************************************************//*                                                                          *//* Routine Name: ips_eh_abort                                               *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Abort a command (using the new error code stuff)                       *//* Note: this routine is called under the io_request_lock                   *//****************************************************************************/intips_eh_abort(Scsi_Cmnd * SC){	ips_ha_t *ha;	ips_copp_wait_item_t *item;	int ret;	METHOD_TRACE("ips_eh_abort", 1);	if (!SC)		return (FAILED);	ha = (ips_ha_t *) SC->device->host->hostdata;	if (!ha)		return (FAILED);	if (!ha->active)		return (FAILED);	if (SC->serial_number != SC->serial_number_at_timeout) {		/* HMM, looks like a bogus command */		DEBUG(1, "Abort called with bogus scsi command");		return (FAILED);	}	/* See if the command is on the copp queue */	item = ha->copp_waitlist.head;	while ((item) && (item->scsi_cmd != SC))		item = item->next;	if (item) {		/* Found it */		ips_removeq_copp(&ha->copp_waitlist, item);		ret = (SUCCESS);		/* See if the command is on the wait queue */	} else if (ips_removeq_wait(&ha->scb_waitlist, SC)) {		/* command not sent yet */		ret = (SUCCESS);	} else {		/* command must have already been sent */		ret = (FAILED);	}	return ret;}/****************************************************************************//*                                                                          *//* Routine Name: ips_eh_reset                                               *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Reset the controller (with new eh error code)                          *//*                                                                          *//* NOTE: this routine is called under the io_request_lock spinlock          *//*                                                                          *//****************************************************************************/intips_eh_reset(Scsi_Cmnd * SC){	int ret;	int i;	ips_ha_t *ha;	ips_scb_t *scb;	ips_copp_wait_item_t *item;	METHOD_TRACE("ips_eh_reset", 1);#ifdef NO_IPS_RESET	return (FAILED);#else	if (!SC) {		DEBUG(1, "Reset called with NULL scsi command");		return (FAILED);	}	ha = (ips_ha_t *) SC->device->host->hostdata;	if (!ha) {		DEBUG(1, "Reset called with NULL ha struct");		return (FAILED);	}	if (!ha->active)		return (FAILED);	/* See if the command is on the copp queue */	item = ha->copp_waitlist.head;	while ((item) && (item->scsi_cmd != SC))		item = item->next;	if (item) {		/* Found it */		ips_removeq_copp(&ha->copp_waitlist, item);		return (SUCCESS);	}	/* See if the command is on the wait queue */	if (ips_removeq_wait(&ha->scb_waitlist, SC)) {		/* command not sent yet */		return (SUCCESS);	}	/* An explanation for the casual observer:                              */	/* Part of the function of a RAID controller is automatic error         */	/* detection and recovery.  As such, the only problem that physically   */	/* resetting an adapter will ever fix is when, for some reason,         */	/* the driver is not successfully communicating with the adapter.       */	/* Therefore, we will attempt to flush this adapter.  If that succeeds, */	/* then there's no real purpose in a physical reset. This will complete */	/* much faster and avoids any problems that might be caused by a        */	/* physical reset ( such as having to fail all the outstanding I/O's ). */	if (ha->ioctl_reset == 0) {	/* IF Not an IOCTL Requested Reset */		scb = &ha->scbs[ha->max_cmds - 1];		ips_init_scb(ha, scb);		scb->timeout = ips_cmd_timeout;		scb->cdb[0] = IPS_CMD_FLUSH;		scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;		scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);		scb->cmd.flush_cache.state = IPS_NORM_STATE;		scb->cmd.flush_cache.reserved = 0;		scb->cmd.flush_cache.reserved2 = 0;		scb->cmd.flush_cache.reserved3 = 0;		scb->cmd.flush_cache.reserved4 = 0;		/* Attempt the flush command */		ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL);		if (ret == IPS_SUCCESS) {			IPS_PRINTK(KERN_NOTICE, ha->pcidev,				   "Reset Request - Flushed Cache\n");			return (SUCCESS);		}	}	/* Either we can't communicate with the adapter or it's an IOCTL request */	/* from a utility.  A physical reset is needed at this point.            */	ha->ioctl_reset = 0;	/* Reset the IOCTL Requested Reset Flag */	/*	 * command must have already been sent	 * reset the controller	 */	IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Resetting controller.\n");	ret = (*ha->func.reset) (ha);	if (!ret) {		Scsi_Cmnd *scsi_cmd;		IPS_PRINTK(KERN_NOTICE, ha->pcidev,			   "Controller reset failed - controller now offline.\n");		/* Now fail all of the active commands */		DEBUG_VAR(1, "(%s%d) Failing active commands",			  ips_name, ha->host_num);		while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {			scb->scsi_cmd->result = DID_ERROR << 16;			scb->scsi_cmd->scsi_done(scb->scsi_cmd);			ips_freescb(ha, scb);		}		/* Now fail all of the pending commands */		DEBUG_VAR(1, "(%s%d) Failing pending commands",			  ips_name, ha->host_num);		while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {			scsi_cmd->result = DID_ERROR;			scsi_cmd->scsi_done(scsi_cmd);		}		ha->active = FALSE;		return (FAILED);	}	if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {		Scsi_Cmnd *scsi_cmd;		IPS_PRINTK(KERN_NOTICE, ha->pcidev,			   "Controller reset failed - controller now offline.\n");		/* Now fail all of the active commands */		DEBUG_VAR(1, "(%s%d) Failing active commands",			  ips_name, ha->host_num);		while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {			scb->scsi_cmd->result = DID_ERROR << 16;			scb->scsi_cmd->scsi_done(scb->scsi_cmd);			ips_freescb(ha, scb);		}		/* Now fail all of the pending commands */		DEBUG_VAR(1, "(%s%d) Failing pending commands",			  ips_name, ha->host_num);		while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {			scsi_cmd->result = DID_ERROR << 16;			scsi_cmd->scsi_done(scsi_cmd);		}		ha->active = FALSE;		return (FAILED);	}	/* FFDC */	if (le32_to_cpu(ha->subsys->param[3]) & 0x300000) {		struct timeval tv;		do_gettimeofday(&tv);		ha->last_ffdc = tv.tv_sec;		ha->reset_count++;		ips_ffdc_reset(ha, IPS_INTR_IORL);	}	/* Now fail all of the active commands */	DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num);	while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {		scb->scsi_cmd->result =		    (DID_RESET << 16) | (SUGGEST_RETRY << 24);		scb->scsi_cmd->scsi_done(scb->scsi_cmd);		ips_freescb(ha, scb);	}	/* Reset DCDB active command bits */	for (i = 1; i < ha->nbus; i++)		ha->dcdb_active[i - 1] = 0;	/* Reset the number of active IOCTLs */	ha->num_ioctl = 0;	ips_next(ha, IPS_INTR_IORL);	return (SUCCESS);#endif				/* NO_IPS_RESET */}/****************************************************************************//*                                                                          *//* Routine Name: ips_queue                                                  *//*                                                                          *//* Routine Description:                                                     *//*                                                                          *//*   Send a command to the controller                                       *//*                                                                          *//* NOTE:                                                                    *//*    Linux obtains io_request_lock before calling this function            *//*                                                                          *//****************************************************************************/intips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *)){	ips_ha_t *ha;	ips_passthru_t *pt;

⌨️ 快捷键说明

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