sym_glue.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,552 行 · 第 1/5 页

C
2,552
字号
 */static void sym_tune_dev_queuing(struct sym_hcb *np, int target, int lun, u_short reqtags){	struct sym_tcb *tp = &np->target[target];	struct sym_lcb *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(struct sym_hcb *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 int sym53c8xx_slave_configure(struct scsi_device *device){	struct Scsi_Host *host = device->host;	struct sym_hcb *np;	struct sym_tcb *tp;	struct sym_lcb *lp;	int reqtags, depth_to_use;	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)		return -ENOMEM;	/*	 *  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;	depth_to_use = (reqtags ? reqtags : 2);#else	depth_to_use = (reqtags ? SYM_CONF_MAX_TAG : 2);#endif	scsi_adjust_queue_depth(device,				(device->tagged_supported ?				 MSG_SIMPLE_TAG : 0),				depth_to_use);	lp->s.scdev_depth = depth_to_use;	sym_tune_dev_queuing(np, device->id, device->lun, reqtags);	spi_dv_device(device);	return 0;}/* *  Linux entry point for info() function */static 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 (struct sym_hcb *np, struct sym_usrcmd *uc){	struct sym_tcb *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++) {					struct sym_lcb *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 digit_to_bin(c)	((c) - '0')static int skip_spaces(char *ptr, int len){	int cnt, c;	for (cnt = len; cnt > 0 && (c = *ptr++) && isspace(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++) && isdigit(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 >= verb_len && !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(struct sym_hcb *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;	switch(uc->cmd) {	case UC_SETSYNC:	case UC_SETTAGS:	case UC_SETWIDE:	case UC_SETFLAG:	case UC_RESETDEV:	case UC_CLEARDEV:		SKIP_SPACES(1);		if ((arg_len = is_keyword(ptr, len, "all")) != 0) {			ptr += arg_len; len -= arg_len;			uc->target = ~0;		} else {			GET_INT_ARG(target);			uc->target = (1<<target);#ifdef DEBUG_PROC_INFOprintk("sym_user_command: target=%ld\n", target);#endif		}		break;	}	switch(uc->cmd) {	case UC_SETVERBOSE:	case UC_SETSYNC:	case UC_SETTAGS:	case UC_SETWIDE:		SKIP_SPACES(1);		GET_INT_ARG(uc->data);#ifdef DEBUG_PROC_INFOprintk("sym_user_command: data=%ld\n", uc->data);#endif		break;#ifdef SYM_LINUX_DEBUG_CONTROL_SUPPORT	case UC_SETDEBUG:		while (len > 0) {			SKIP_SPACES(1);			if	((arg_len = is_keyword(ptr, len, "alloc")))				uc->data |= DEBUG_ALLOC;			else if	((arg_len = is_keyword(ptr, len, "phase")))				uc->data |= DEBUG_PHASE;			else if	((arg_len = is_keyword(ptr, len, "queue")))				uc->data |= DEBUG_QUEUE;			else if	((arg_len = is_keyword(ptr, len, "result")))				uc->data |= DEBUG_RESULT;			else if	((arg_len = is_keyword(ptr, len, "scatter")))				uc->data |= DEBUG_SCATTER;			else if	((arg_len = is_keyword(ptr, len, "script")))				uc->data |= DEBUG_SCRIPT;			else if	((arg_len = is_keyword(ptr, len, "tiny")))				uc->data |= DEBUG_TINY;			else if	((arg_len = is_keyword(ptr, len, "timing")))				uc->data |= DEBUG_TIMING;			else if	((arg_len = is_keyword(ptr, len, "nego")))				uc->data |= DEBUG_NEGO;			else if	((arg_len = is_keyword(ptr, len, "tags")))				uc->data |= DEBUG_TAGS;			else if	((arg_len = is_keyword(ptr, len, "pointer")))				uc->data |= DEBUG_POINTER;			else				return -EINVAL;			ptr += arg_len; len -= arg_len;		}#ifdef DEBUG_PROC_INFOprintk("sym_user_command: data=%ld\n", uc->data);#endif		break;#endif /* SYM_LINUX_DEBUG_CONTROL_SUPPORT */	case UC_SETFLAG:		while (len > 0) {			SKIP_SPACES(1);			if	((arg_len = is_keyword(ptr, len, "no_disc")))				uc->data &= ~SYM_DISC_ENABLED;			else				return -EINVAL;			ptr += arg_len; len -= arg_len;		}		break;	default:		break;	}	if (len)		return -EINVAL;	else {		unsigned long flags;		spin_lock_irqsave(np->s.host->host_lock, flags);		sym_exec_user_command (np, uc);		spin_unlock_irqrestore(np->s.host->host_lock, flags);	}	return length;}#endif	/* SYM_LINUX_USER_COMMAND_SUPPORT */#ifdef SYM_LINUX_USER_INFO_SUPPORT/* *  Informations through the proc file system. */struct info_str {	char *buffer;	int length;	int offset;	int pos;};static void copy_mem_info(struct info_str *info, char *data, int len){	if (info->pos + len > info->length)		len = info->length - info->pos;	if (info->pos + len < info->offset) {		info->pos += len;		return;	}	if (info->pos < info->offset) {		data += (info->offset - info->pos);		len  -= (info->offset - info->pos);	}	if (len > 0) {		memcpy(info->buffer + info->pos, data, len);		info->pos += len;	}}static int copy_info(struct info_str *info, char *fmt, ...){	va_list args;	char buf[81];	int len;	va_start(args, fmt);	len = vsprintf(buf, fmt, args);	va_end(args);	copy_mem_info(info, buf, len);	return len;}/* *  Copy formatted information into the input buffer. */static int sym_host_info(struct sym_hcb *np, char *ptr, off_t offset, int len){	struct info_str info;	info.buffer	= ptr;	info.length	= len;	info.offset	= offset;	info.pos	= 0;

⌨️ 快捷键说明

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