📄 sym_glue.c
字号:
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->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0; tp->tgoal.offset = 0; } else if (uc->data <= 9 && np->minsync_dt) { if (uc->data < np->minsync_dt) uc->data = np->minsync_dt; tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 1; tp->tgoal.width = 1; tp->tgoal.period = uc->data; tp->tgoal.offset = np->maxoffs_dt; } else { if (uc->data < np->minsync) uc->data = np->minsync; tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0; tp->tgoal.period = uc->data; tp->tgoal.offset = np->maxoffs; } tp->tgoal.check_nego = 1; break; case UC_SETWIDE: tp->tgoal.width = uc->data ? 1 : 0; tp->tgoal.check_nego = 1; break; case UC_SETTAGS: for (l = 0; l < SYM_CONF_MAX_LUN; l++) sym_tune_dev_queuing(tp, l, uc->data); break; case UC_RESETDEV: tp->to_reset = 1; np->istat_sem = SEM; OUTB(np, nc_istat, SIGP|SEM); break; case UC_CLEARDEV: for (l = 0; l < SYM_CONF_MAX_LUN; l++) { struct sym_lcb *lp = sym_lp(tp, l); if (lp) lp->to_clear = 1; } np->istat_sem = SEM; OUTB(np, nc_istat, SIGP|SEM); break; case UC_SETFLAG: tp->usrflags = uc->data; break; } } break; }}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){ char *end; *pv = simple_strtoul(ptr, &end, 10); return (end - ptr);}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(ptr, len) \ if ((arg_len = skip_spaces(ptr, len)) < 1) \ return -EINVAL; \ ptr += arg_len; len -= arg_len;#define GET_INT_ARG(ptr, len, 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(ptr, len); if ((arg_len = is_keyword(ptr, len, "all")) != 0) { ptr += arg_len; len -= arg_len; uc->target = ~0; } else { GET_INT_ARG(ptr, len, 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(ptr, len); GET_INT_ARG(ptr, len, 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(ptr, len); 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(ptr, len); 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 sym_hcb *np = sym_get_hcb(host); int retv; 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, struct pci_dev *pdev){ /* * Free O/S specific resources. */ if (np->s.irq) free_irq(np->s.irq, np); if (np->s.ioaddr) pci_iounmap(pdev, np->s.ioaddr); if (np->s.ramaddr) pci_iounmap(pdev, np->s.ramaddr); /* * 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; struct pci_dev *pdev = dev->pdev; 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(pdev), IRQ_PRM(pdev->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(&pdev->dev, sizeof(*np), "HCB"); if (!np) goto attach_failed; np->s.device = pdev; np->bus_dmat = &pdev->dev; /* Result in 1 DMA pool per HBA */ host_data->ncb = np; np->s.host = instance; pci_set_drvdata(pdev, np); /* * Copy some useful infos to the HCB. */ np->hcb_ba = vtobus(np); np->verbose = sym_driver_setup.verbose; np->s.device = 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->mmio_base; np->s.ioaddr = dev->s.ioaddr; np->s.ramaddr = dev->s.ramaddr; np->s.io_ws = (np->features & FE_IO256) ? 256 : 128; /* * Map on-chip RAM if present and supported. */ if (!(np->features & FE_RAM)) dev->ram_base = 0; if (dev->ram_base) { np->ram_ba = (u32)dev->ram_base; np->ram_ws = (np->features & FE_RAM8K) ? 8192 : 4096; } if (sym_hcb_attach(instance, fw, dev->nvram)) goto attach_failed; /* * Install the interrupt handler. * If we synchonize the C code with SCRIPTS on interrupt, * we do not want to share the INTR line at all. */ if (request_irq(pdev->irq, sym53c8xx_intr, SA_SHIRQ, NAME53C8XX, np)) { printf_err("%s: request irq %d failure\n", sym_name(np), pdev->irq); goto attach_failed; } np->s.irq = pdev->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. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -