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 + -
显示快捷键?