⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sym_glue.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (!ep)		return;	/* Try to avoid a race here (not 100% safe) */	if (!timed_out) {		ep->timed_out = 0;		if (ep->to_do == SYM_EH_DO_WAIT && !del_timer(&ep->timer))			return;	}	/* Revert everything */	SYM_UCMD_PTR(cmd)->eh_wait = 0;	cmd->scsi_done = ep->old_done;	/* Wake up the eh thread if it wants to sleep */	if (ep->to_do == SYM_EH_DO_WAIT)		up(&ep->sem);}/* *  scsi_done() alias when error recovery is in progress.  */static void sym_eh_done(Scsi_Cmnd *cmd) { __sym_eh_done(cmd, 0); }/* *  Some timeout handler to avoid waiting too long. */static void sym_eh_timeout(u_long p) { __sym_eh_done((Scsi_Cmnd *)p, 1); }/* *  Generic method for our eh processing. *  The 'op' argument tells what we have to do. */static int sym_eh_handler(int op, char *opname, Scsi_Cmnd *cmd){	hcb_p np = SYM_SOFTC_PTR(cmd);	unsigned long flags;	SYM_QUEHEAD *qp;	int to_do = SYM_EH_DO_IGNORE;	int sts = -1;	struct sym_eh_wait eh, *ep = &eh;	char devname[20];	sprintf(devname, "%s:%d:%d", sym_name(np), cmd->target, cmd->lun);	printf_warning("%s: %s operation started.\n", devname, opname);	SYM_LOCK_HCB(np, flags);#if 0	/* This one should be the result of some race, thus to ignore */	if (cmd->serial_number != cmd->serial_number_at_timeout)		goto prepare;#endif	/* This one is not queued to the core driver -> to complete here */ 	FOR_EACH_QUEUED_ELEMENT(&np->s.wait_cmdq, qp) {		if (SYM_SCMD_PTR(qp) == cmd) {			to_do = SYM_EH_DO_COMPLETE;			goto prepare;		}	}	/* This one is queued in some place -> to wait for completion */	FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {		ccb_p cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);		if (cp->cam_ccb == cmd) {			to_do = SYM_EH_DO_WAIT;			goto prepare;		}	}prepare:	/* Prepare stuff to either ignore, complete or wait for completion */	switch(to_do) {	default:	case SYM_EH_DO_IGNORE:		goto finish;		break;	case SYM_EH_DO_WAIT:#if LINUX_VERSION_CODE > LinuxVersionCode(2,3,0)		init_MUTEX_LOCKED(&ep->sem);#else		ep->sem = MUTEX_LOCKED;#endif		/* fall through */	case SYM_EH_DO_COMPLETE:		ep->old_done = cmd->scsi_done;		cmd->scsi_done = sym_eh_done;		SYM_UCMD_PTR(cmd)->eh_wait = ep;	}	/* Try to proceed the operation we have been asked for */	sts = -1;	switch(op) {	case SYM_EH_ABORT:		sts = sym_abort_scsiio(np, cmd, 1);		break;	case SYM_EH_DEVICE_RESET:		sts = sym_reset_scsi_target(np, cmd->target);		break;	case SYM_EH_BUS_RESET:		sym_reset_scsi_bus(np, 1);		sts = 0;		break;	case SYM_EH_HOST_RESET:		sym_reset_scsi_bus(np, 0);		sym_start_up (np, 1);		sts = 0;		break;	default:		break;	}	/* On error, restore everything and cross fingers :) */	if (sts) {		SYM_UCMD_PTR(cmd)->eh_wait = 0;		cmd->scsi_done = ep->old_done;		to_do = SYM_EH_DO_IGNORE;	}finish:	ep->to_do = to_do;	/* Complete the command with locks held as required by the driver */	if (to_do == SYM_EH_DO_COMPLETE)		sym_xpt_done2(np, cmd, CAM_REQ_ABORTED);	SYM_UNLOCK_HCB(np, flags);	/* Wait for completion with locks released, as required by kernel */	if (to_do == SYM_EH_DO_WAIT) {		init_timer(&ep->timer);		ep->timer.expires = jiffies + (5*HZ);		ep->timer.function = sym_eh_timeout;		ep->timer.data = (u_long)cmd;		ep->timed_out = 1;	/* Be pessimistic for once :) */		add_timer(&ep->timer);		SYM_UNLOCK_SCSI_NORESTORE(np);		down(&ep->sem);		SYM_LOCK_SCSI_NOSAVE(np);		if (ep->timed_out)			sts = -2;	}	printf_warning("%s: %s operation %s.\n", devname, opname,			sts==0?"complete":sts==-2?"timed-out":"failed");	return sts? SCSI_FAILED : SCSI_SUCCESS;}/* * Error handlers called from the eh thread (one thread per HBA). */int sym53c8xx_eh_abort_handler(Scsi_Cmnd *cmd){	return sym_eh_handler(SYM_EH_ABORT, "ABORT", cmd);}int sym53c8xx_eh_device_reset_handler(Scsi_Cmnd *cmd){	return sym_eh_handler(SYM_EH_DEVICE_RESET, "DEVICE RESET", cmd);}int sym53c8xx_eh_bus_reset_handler(Scsi_Cmnd *cmd){	return sym_eh_handler(SYM_EH_BUS_RESET, "BUS RESET", cmd);}int sym53c8xx_eh_host_reset_handler(Scsi_Cmnd *cmd){	return sym_eh_handler(SYM_EH_HOST_RESET, "HOST RESET", cmd);}/* *  Tune device queuing depth, according to various limits. */static void sym_tune_dev_queuing(hcb_p np, int target, int lun, u_short reqtags){	tcb_p	tp = &np->target[target];	lcb_p	lp = sym_lp(np, tp, lun);	u_short	oldtags;	if (!lp)		return;	oldtags = lp->s.reqtags;	if (reqtags > lp->s.scdev_depth)		reqtags = lp->s.scdev_depth;	lp->started_limit = reqtags ? reqtags : 2;	lp->started_max   = 1;	lp->s.reqtags     = reqtags;	if (reqtags != oldtags) {		printf_info("%s:%d:%d: "		         "tagged command queuing %s, command queue depth %d.\n",		          sym_name(np), target, lun,		          lp->s.reqtags ? "enabled" : "disabled", 		          lp->started_limit);	}}#ifdef	SYM_LINUX_BOOT_COMMAND_LINE_SUPPORT/* *  Linux select queue depths function */#define DEF_DEPTH	(sym_driver_setup.max_tag)#define ALL_TARGETS	-2#define NO_TARGET	-1#define ALL_LUNS	-2#define NO_LUN		-1static int device_queue_depth(hcb_p np, int target, int lun){	int c, h, t, u, v;	char *p = sym_driver_setup.tag_ctrl;	char *ep;	h = -1;	t = NO_TARGET;	u = NO_LUN;	while ((c = *p++) != 0) {		v = simple_strtoul(p, &ep, 0);		switch(c) {		case '/':			++h;			t = ALL_TARGETS;			u = ALL_LUNS;			break;		case 't':			if (t != target)				t = (target == v) ? v : NO_TARGET;			u = ALL_LUNS;			break;		case 'u':			if (u != lun)				u = (lun == v) ? v : NO_LUN;			break;		case 'q':			if (h == np->s.unit &&				(t == ALL_TARGETS || t == target) &&				(u == ALL_LUNS    || u == lun))				return v;			break;		case '-':			t = ALL_TARGETS;			u = ALL_LUNS;			break;		default:			break;		}		p = ep;	}	return DEF_DEPTH;}#else#define device_queue_depth(np, t, l)	(sym_driver_setup.max_tag)#endif	/* SYM_LINUX_BOOT_COMMAND_LINE_SUPPORT *//* * Linux entry point for device queue sizing. */static void sym53c8xx_select_queue_depths(struct Scsi_Host *host,                               struct scsi_device *devlist){	struct scsi_device *device;	for (device = devlist; device; device = device->next) {		hcb_p np;		tcb_p tp;		lcb_p lp;		int reqtags;		if (device->host != host)			continue;		np = ((struct host_data *) host->hostdata)->ncb;		tp = &np->target[device->id];		/*		 *  Get user settings for transfer parameters.		 */		tp->inq_byte7_valid = (INQ7_SYNC|INQ7_WIDE16);		sym_update_trans_settings(np, tp);		/*		 *  Allocate the LCB if not yet.		 *  If it fail, we may well be in the sh*t. :)		 */		lp = sym_alloc_lcb(np, device->id, device->lun);		if (!lp) {			device->queue_depth = 1;			continue;		}		/*		 *  Get user flags.		 */		lp->curr_flags = lp->user_flags;		/*		 *  Select queue depth from driver setup.		 *  Donnot use more than configured by user.		 *  Use at least 2.		 *  Donnot use more than our maximum.		 */		reqtags = device_queue_depth(np, device->id, device->lun);		if (reqtags > tp->usrtags)			reqtags = tp->usrtags;		if (!device->tagged_supported)			reqtags = 0;#if 1 /* Avoid to locally queue commands for no good reasons */		if (reqtags > SYM_CONF_MAX_TAG)			reqtags = SYM_CONF_MAX_TAG;		device->queue_depth = reqtags ? reqtags : 2;#else		device->queue_depth = reqtags ? SYM_CONF_MAX_TAG : 2;#endif		lp->s.scdev_depth = device->queue_depth;		sym_tune_dev_queuing(np, device->id, device->lun, reqtags);	}}/* *  Linux entry point for info() function */const char *sym53c8xx_info (struct Scsi_Host *host){	return sym_driver_name();}#ifdef SYM_LINUX_PROC_INFO_SUPPORT/* *  Proc file system stuff * *  A read operation returns adapter information. *  A write operation is a control command. *  The string is parsed in the driver code and the command is passed  *  to the sym_usercmd() function. */#ifdef SYM_LINUX_USER_COMMAND_SUPPORTstruct	sym_usrcmd {	u_long	target;	u_long	lun;	u_long	data;	u_long	cmd;};#define UC_SETSYNC      10#define UC_SETTAGS	11#define UC_SETDEBUG	12#define UC_SETWIDE	14#define UC_SETFLAG	15#define UC_SETVERBOSE	17#define UC_RESETDEV	18#define UC_CLEARDEV	19static void sym_exec_user_command (hcb_p np, struct sym_usrcmd *uc){	tcb_p tp;	int t, l;	switch (uc->cmd) {	case 0: return;#ifdef SYM_LINUX_DEBUG_CONTROL_SUPPORT	case UC_SETDEBUG:		sym_debug_flags = uc->data;		break;#endif	case UC_SETVERBOSE:		np->verbose = uc->data;		break;	default:		/*		 * We assume that other commands apply to targets.		 * This should always be the case and avoid the below 		 * 4 lines to be repeated 6 times.		 */		for (t = 0; t < SYM_CONF_MAX_TARGET; t++) {			if (!((uc->target >> t) & 1))				continue;			tp = &np->target[t];			switch (uc->cmd) {			case UC_SETSYNC:				if (!uc->data || uc->data >= 255) {					tp->tinfo.goal.options = 0;					tp->tinfo.goal.offset  = 0;					break;				}				if (uc->data <= 9 && np->minsync_dt) {					if (uc->data < np->minsync_dt)						uc->data = np->minsync_dt;					tp->tinfo.goal.options = PPR_OPT_DT;					tp->tinfo.goal.width   = 1;					tp->tinfo.goal.period = uc->data;					tp->tinfo.goal.offset = np->maxoffs_dt;				}				else {					if (uc->data < np->minsync)						uc->data = np->minsync;					tp->tinfo.goal.options = 0;					tp->tinfo.goal.period = uc->data;					tp->tinfo.goal.offset = np->maxoffs;				}				break;			case UC_SETWIDE:				tp->tinfo.goal.width = uc->data ? 1 : 0;				break;			case UC_SETTAGS:				for (l = 0; l < SYM_CONF_MAX_LUN; l++)					sym_tune_dev_queuing(np, t,l, uc->data);				break;			case UC_RESETDEV:				tp->to_reset = 1;				np->istat_sem = SEM;				OUTB (nc_istat, SIGP|SEM);				break;			case UC_CLEARDEV:				for (l = 0; l < SYM_CONF_MAX_LUN; l++) {					lcb_p lp = sym_lp(np, tp, l);					if (lp) lp->to_clear = 1;				}				np->istat_sem = SEM;				OUTB (nc_istat, SIGP|SEM);				break;			case UC_SETFLAG:				tp->usrflags = uc->data;				break;			}		}		break;	}}#define is_digit(c)	((c) >= '0' && (c) <= '9')#define digit_to_bin(c)	((c) - '0')#define is_space(c)	((c) == ' ' || (c) == '\t')static int skip_spaces(char *ptr, int len){	int cnt, c;	for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt--);	return (len - cnt);}static int get_int_arg(char *ptr, int len, u_long *pv){	int	cnt, c;	u_long	v;	for (v = 0, cnt = len; cnt > 0 && (c = *ptr++) && is_digit(c); cnt--) {		v = (v * 10) + digit_to_bin(c);	}	if (pv)		*pv = v;	return (len - cnt);}static int is_keyword(char *ptr, int len, char *verb){	int verb_len = strlen(verb);	if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len))		return verb_len;	else		return 0;}#define SKIP_SPACES(min_spaces)						\	if ((arg_len = skip_spaces(ptr, len)) < (min_spaces))		\		return -EINVAL;						\	ptr += arg_len; len -= arg_len;#define GET_INT_ARG(v)							\	if (!(arg_len = get_int_arg(ptr, len, &(v))))			\		return -EINVAL;						\	ptr += arg_len; len -= arg_len;/* * Parse a control command */static int sym_user_command(hcb_p np, char *buffer, int length){	char *ptr	= buffer;	int len		= length;	struct sym_usrcmd cmd, *uc = &cmd;	int		arg_len;	u_long 		target;	bzero(uc, sizeof(*uc));	if (len > 0 && ptr[len-1] == '\n')		--len;	if	((arg_len = is_keyword(ptr, len, "setsync")) != 0)		uc->cmd = UC_SETSYNC;	else if	((arg_len = is_keyword(ptr, len, "settags")) != 0)		uc->cmd = UC_SETTAGS;	else if	((arg_len = is_keyword(ptr, len, "setverbose")) != 0)		uc->cmd = UC_SETVERBOSE;	else if	((arg_len = is_keyword(ptr, len, "setwide")) != 0)		uc->cmd = UC_SETWIDE;#ifdef SYM_LINUX_DEBUG_CONTROL_SUPPORT	else if	((arg_len = is_keyword(ptr, len, "setdebug")) != 0)		uc->cmd = UC_SETDEBUG;#endif	else if	((arg_len = is_keyword(ptr, len, "setflag")) != 0)		uc->cmd = UC_SETFLAG;	else if	((arg_len = is_keyword(ptr, len, "resetdev")) != 0)		uc->cmd = UC_RESETDEV;	else if	((arg_len = is_keyword(ptr, len, "cleardev")) != 0)		uc->cmd = UC_CLEARDEV;	else		arg_len = 0;#ifdef DEBUG_PROC_INFOprintk("sym_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd);#endif	if (!arg_len)		return -EINVAL;	ptr += arg_len; len -= arg_len;

⌨️ 快捷键说明

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