📄 sym_glue.c
字号:
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; memset(uc, 0, 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; copy_info(&info, "Chip " NAME53C "%s, device id 0x%x, " "revision id 0x%x\n", np->s.chip_name, np->device_id, np->revision_id); copy_info(&info, "At PCI address %s, IRQ " IRQ_FMT "\n", pci_name(np->s.device), IRQ_PRM(np->s.irq)); copy_info(&info, "Min. period factor %d, %s SCSI BUS%s\n", (int) (np->minsync_dt ? np->minsync_dt : np->minsync), np->maxwide ? "Wide" : "Narrow", np->minsync_dt ? ", DT capable" : ""); copy_info(&info, "Max. started commands %d, " "max. commands per LUN %d\n", SYM_CONF_MAX_START, SYM_CONF_MAX_TAG); return info.pos > info.offset? info.pos - info.offset : 0;}#endif /* SYM_LINUX_USER_INFO_SUPPORT *//* * Entry point of the scsi proc fs of the driver. * - func = 0 means read (returns adapter infos) * - func = 1 means write (not yet merget from sym53c8xx) */static int sym53c8xx_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func){ struct host_data *host_data; struct sym_hcb *np = NULL; int retv; host_data = (struct host_data *) host->hostdata; np = host_data->ncb; if (!np) return -EINVAL; if (func) {#ifdef SYM_LINUX_USER_COMMAND_SUPPORT retv = sym_user_command(np, buffer, length);#else retv = -EINVAL;#endif } else { if (start) *start = buffer;#ifdef SYM_LINUX_USER_INFO_SUPPORT retv = sym_host_info(np, buffer, offset, length);#else retv = -EINVAL;#endif } return retv;}#endif /* SYM_LINUX_PROC_INFO_SUPPORT *//* * Free controller resources. */static void sym_free_resources(struct sym_hcb *np){ /* * Free O/S specific resources. */ if (np->s.irq) free_irq(np->s.irq, np);#ifndef SYM_CONF_IOMAPPED if (np->s.mmio_va) iounmap(np->s.mmio_va);#endif if (np->s.ram_va) iounmap(np->s.ram_va); /* * Free O/S independent resources. */ sym_hcb_free(np); sym_mfree_dma(np, sizeof(*np), "HCB");}/* * Ask/tell the system about DMA addressing. */static int sym_setup_bus_dma_mask(struct sym_hcb *np){#if SYM_CONF_DMA_ADDRESSING_MODE > 0#if SYM_CONF_DMA_ADDRESSING_MODE == 1#define DMA_DAC_MASK 0x000000ffffffffffULL /* 40-bit */#elif SYM_CONF_DMA_ADDRESSING_MODE == 2#define DMA_DAC_MASK DMA_64BIT_MASK#endif if ((np->features & FE_DAC) && !pci_set_dma_mask(np->s.device, DMA_DAC_MASK)) { np->use_dac = 1; return 0; }#endif if (!pci_set_dma_mask(np->s.device, DMA_32BIT_MASK)) return 0; printf_warning("%s: No suitable DMA available\n", sym_name(np)); return -1;}/* * Host attach and initialisations. * * Allocate host data and ncb structure. * Remap MMIO region. * Do chip initialization. * If all is OK, install interrupt handling and * start the timer daemon. */static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt, int unit, struct sym_device *dev){ struct host_data *host_data; struct sym_hcb *np = NULL; struct Scsi_Host *instance = NULL; unsigned long flags; struct sym_fw *fw; printk(KERN_INFO "sym%d: <%s> rev 0x%x at pci %s irq " IRQ_FMT "\n", unit, dev->chip.name, dev->chip.revision_id, pci_name(dev->pdev), IRQ_PRM(dev->s.irq)); /* * Get the firmware for this chip. */ fw = sym_find_firmware(&dev->chip); if (!fw) goto attach_failed; /* * Allocate host_data structure */ instance = scsi_host_alloc(tpnt, sizeof(*host_data)); if (!instance) goto attach_failed; host_data = (struct host_data *) instance->hostdata; /* * Allocate immediately the host control block, * since we are only expecting to succeed. :) * We keep track in the HCB of all the resources that * are to be released on error. */ np = __sym_calloc_dma(dev->pdev, sizeof(*np), "HCB"); if (!np) goto attach_failed; np->s.device = dev->pdev; np->bus_dmat = dev->pdev; /* Result in 1 DMA pool per HBA */ host_data->ncb = np; np->s.host = instance; pci_set_drvdata(dev->pdev, np); /* * Copy some useful infos to the HCB. */ np->hcb_ba = vtobus(np); np->verbose = sym_driver_setup.verbose; np->s.device = dev->pdev; np->s.unit = unit; np->device_id = dev->chip.device_id; np->revision_id = dev->chip.revision_id; np->features = dev->chip.features; np->clock_divn = dev->chip.nr_divisor; np->maxoffs = dev->chip.offset_max; np->maxburst = dev->chip.burst_max; np->myaddr = dev->host_id; /* * Edit its name. */ strlcpy(np->s.chip_name, dev->chip.name, sizeof(np->s.chip_name)); sprintf(np->s.inst_name, "sym%d", np->s.unit); if (sym_setup_bus_dma_mask(np)) goto attach_failed; /* * Try to map the controller chip to * virtual and physical memory. */ np->mmio_ba = (u32)dev->s.base; np->s.io_ws = (np->features & FE_IO256)? 256 : 128;#ifndef SYM_CONF_IOMAPPED np->s.mmio_va = ioremap(dev->s.base_c, np->s.io_ws); if (!np->s.mmio_va) { printf_err("%s: can't map PCI MMIO region\n", sym_name(np)); goto attach_failed; } else if (sym_verbose > 1) printf_info("%s: using memory mapped IO\n", sym_name(np));#endif /* !defined SYM_CONF_IOMAPPED */ np->s.io_port = dev->s.io_port; /* * Map on-chip RAM if present and supported. */ if (!(np->features & FE_RAM)) dev->s.base_2 = 0; if (dev->s.base_2) { np->ram_ba = (u32)dev->s.base_2; if (np->features & FE_RAM8K) np->ram_ws = 8192; else np->ram_ws = 4096; np->s.ram_va = ioremap(dev->s.base_2_c, np->ram_ws); if (!np->s.ram_va) { printf_err("%s: can't map PCI MEMORY region\n", sym_name(np)); goto attach_failed; } } /* * Perform O/S independent stuff. */ if (sym_hcb_attach(np, fw, dev->nvram)) goto attach_failed; /* * Install the interrupt handler. * If we synchonize the C code with SCRIPTS on interrupt, * we donnot want to share the INTR line at all. */ if (request_irq(dev->s.irq, sym53c8xx_intr, SA_SHIRQ, NAME53C8XX, np)) { printf_err("%s: request irq %d failure\n", sym_name(np), dev->s.irq); goto attach_failed; } np->s.irq = dev->s.irq; /* * After SCSI devices have been opened, we cannot * reset the bus safely, so we do it here. */ spin_lock_irqsave(instance->host_lock, flags); if (sym_reset_scsi_bus(np, 0)) goto reset_failed; /* * Start the SCRIPTS. */ sym_start_up (np, 1); /* * Start the timer daemon */ init_timer(&np->s.timer); np->s.timer.data = (unsigned long) np; np->s.timer.function = sym53c8xx_timer; np->s.lasttime=0; sym_timer (np); /* * Fill Linux host instance structure * and return success. */ instance->max_channel = 0; instance->this_id = np->myaddr; instance->max_id = np->maxwide ? 16 : 8; instance->max_lun = SYM_CONF_MAX_LUN;#ifndef SYM_CONF_IOMAPPED instance->base = (unsigned long) np->s.mmio_va;#endif instance->irq = np->s.irq; instance->unique_id = np->s.io_port; instance->io_port = np->s.io_port; instance->n_io_port = np->s.io_ws; instance->dma_channel = 0; instance->cmd_per_lun = SYM_CONF_MAX_TAG; instance->can_queue = (SYM_CONF_MAX_START-2); instance->sg_tablesize = SYM_CONF_MAX_SG; instance->max_cmd_len = 16; BUG_ON(sym2_transport_template == NULL); instance->transportt = sym2_transport_template; spin_unlock_irqrestore(instance->host_lock, flags); return instance; reset_failed: printf_err("%s: FATAL ERROR: CHECK SCSI BUS - CABLES, " "TERMINATION, DEVICE POWER etc.!\n", sym_name(np)); spin_unlock_irqrestore(instance->host_lock, flags); attach_failed: if (!instance) return NULL; printf_info("%s: giving up ...\n", sym_name(np)); if (np) sym_free_resources(np); scsi_host_put(instance); return NULL; }/* * Detect and try to read SYMBIOS and TEKRAM NVRAM. */#if SYM_CONF_NVRAM_SUPPORTstatic void __devinit sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp){ devp->nvram = nvp; devp->device_id = devp->chip.device_id; nvp->type = 0; /* * Get access to chip IO registers
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -