📄 esp.c
字号:
sbus_writel(tmp | DMA_RST_SCSI, esp->dregs + DMA_CSR); sbus_writel(tmp & ~DMA_RST_SCSI, esp->dregs + DMA_CSR); } switch (esp->dma->revision) { case dvmahme: /* This is the HME DVMA gate array. */ save_flags(flags); cli(); /* I really hate this chip. */ sbus_writel(DMA_RESET_FAS366, esp->dregs + DMA_CSR); sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR); esp->prev_hme_dmacsr = (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB); esp->prev_hme_dmacsr &= ~(DMA_ENABLE|DMA_ST_WRITE|DMA_BRST_SZ); if (can_do_burst64) esp->prev_hme_dmacsr |= DMA_BRST64; else if (can_do_burst32) esp->prev_hme_dmacsr |= DMA_BRST32; if (can_do_sbus64) { esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64; sbus_set_sbus64(esp->sdev, esp->bursts); } /* This chip is horrible. */ while (sbus_readl(esp->dregs + DMA_CSR) & DMA_PEND_READ) udelay(1); sbus_writel(0, esp->dregs + DMA_CSR); sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR); /* This is necessary to avoid having the SCSI channel * engine lock up on us. */ sbus_writel(0, esp->dregs + DMA_ADDR); restore_flags(flags); break; case dvmarev2: /* This is the gate array found in the sun4m * NCR SBUS I/O subsystem. */ if (esp->erev != esp100) { tmp = sbus_readl(esp->dregs + DMA_CSR); sbus_writel(tmp | DMA_3CLKS, esp->dregs + DMA_CSR); } break; case dvmarev3: tmp = sbus_readl(esp->dregs + DMA_CSR); tmp &= ~DMA_3CLKS; tmp |= DMA_2CLKS; if (can_do_burst32) { tmp &= ~DMA_BRST_SZ; tmp |= DMA_BRST32; } sbus_writel(tmp, esp->dregs + DMA_CSR); break; case dvmaesc1: /* This is the DMA unit found on SCSI/Ether cards. */ tmp = sbus_readl(esp->dregs + DMA_CSR); tmp |= DMA_ADD_ENABLE; tmp &= ~DMA_BCNT_ENAB; if (!can_do_burst32 && can_do_burst16) { tmp |= DMA_ESC_BURST; } else { tmp &= ~(DMA_ESC_BURST); } sbus_writel(tmp, esp->dregs + DMA_CSR); break; default: break; }; ESP_INTSON(esp->dregs);}/* Reset the ESP chip, _not_ the SCSI bus. */static void __init esp_reset_esp(struct esp *esp){ u8 family_code, version; int i; /* Now reset the ESP chip */ esp_cmd(esp, ESP_CMD_RC); esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); /* Reload the configuration registers */ sbus_writeb(esp->cfact, esp->eregs + ESP_CFACT); esp->prev_stp = 0; sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP); esp->prev_soff = 0; sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF); sbus_writeb(esp->neg_defp, esp->eregs + ESP_TIMEO); /* This is the only point at which it is reliable to read * the ID-code for a fast ESP chip variants. */ esp->max_period = ((35 * esp->ccycle) / 1000); if (esp->erev == fast) { version = sbus_readb(esp->eregs + ESP_UID); family_code = (version & 0xf8) >> 3; if (family_code == 0x02) esp->erev = fas236; else if (family_code == 0x0a) esp->erev = fashme; /* Version is usually '5'. */ else esp->erev = fas100a; ESPMISC(("esp%d: FAST chip is %s (family=%d, version=%d)\n", esp->esp_id, (esp->erev == fas236) ? "fas236" : ((esp->erev == fas100a) ? "fas100a" : "fasHME"), family_code, (version & 7))); esp->min_period = ((4 * esp->ccycle) / 1000); } else { esp->min_period = ((5 * esp->ccycle) / 1000); } esp->max_period = (esp->max_period + 3)>>2; esp->min_period = (esp->min_period + 3)>>2; sbus_writeb(esp->config1, esp->eregs + ESP_CFG1); switch (esp->erev) { case esp100: /* nothing to do */ break; case esp100a: sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); break; case esp236: /* Slow 236 */ sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); esp->prev_cfg3 = esp->config3[0]; sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); break; case fashme: esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB); /* fallthrough... */ case fas236: /* Fast 236 or HME */ sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); for (i = 0; i < 16; i++) { if (esp->erev == fashme) { u8 cfg3; cfg3 = ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH; if (esp->scsi_id >= 8) cfg3 |= ESP_CONFIG3_IDBIT3; esp->config3[i] |= cfg3; } else { esp->config3[i] |= ESP_CONFIG3_FCLK; } } esp->prev_cfg3 = esp->config3[0]; sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); if (esp->erev == fashme) { esp->radelay = 80; } else { if (esp->diff) esp->radelay = 0; else esp->radelay = 96; } break; case fas100a: /* Fast 100a */ sbus_writeb(esp->config2, esp->eregs + ESP_CFG2); for (i = 0; i < 16; i++) esp->config3[i] |= ESP_CONFIG3_FCLOCK; esp->prev_cfg3 = esp->config3[0]; sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3); esp->radelay = 32; break; default: panic("esp: what could it be... I wonder..."); break; }; /* Eat any bitrot in the chip */ sbus_readb(esp->eregs + ESP_INTRPT); udelay(100);}/* This places the ESP into a known state at boot time. */static void __init esp_bootup_reset(struct esp *esp){ u8 tmp; /* Reset the DMA */ esp_reset_dma(esp); /* Reset the ESP */ esp_reset_esp(esp); /* Reset the SCSI bus, but tell ESP not to generate an irq */ tmp = sbus_readb(esp->eregs + ESP_CFG1); tmp |= ESP_CONFIG1_SRRDISAB; sbus_writeb(tmp, esp->eregs + ESP_CFG1); esp_cmd(esp, ESP_CMD_RS); udelay(400); sbus_writeb(esp->config1, esp->eregs + ESP_CFG1); /* Eat any bitrot in the chip and we are done... */ sbus_readb(esp->eregs + ESP_INTRPT);}static void esp_chain_add(struct esp *esp){ spin_lock_irq(&espchain_lock); if (espchain) { struct esp *elink = espchain; while (elink->next) elink = elink->next; elink->next = esp; } else { espchain = esp; } esp->next = NULL; spin_unlock_irq(&espchain_lock);}static void esp_chain_del(struct esp *esp){ spin_lock_irq(&espchain_lock); if (espchain == esp) { espchain = esp->next; } else { struct esp *elink = espchain; while (elink->next != esp) elink = elink->next; elink->next = esp->next; } esp->next = NULL; spin_unlock_irq(&espchain_lock);}static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev){ struct sbus_dev *sdev = esp->sdev; struct sbus_dma *dma; if (dma_sdev != NULL) { for_each_dvma(dma) { if (dma->sdev == dma_sdev) break; } } else { for_each_dvma(dma) { /* If allocated already, can't use it. */ if (dma->allocated) continue; if (dma->sdev == NULL) break; /* If bus + slot are the same and it has the * correct OBP name, it's ours. */ if (sdev->bus == dma->sdev->bus && sdev->slot == dma->sdev->slot && (!strcmp(dma->sdev->prom_name, "dma") || !strcmp(dma->sdev->prom_name, "espdma"))) break; } } /* If we don't know how to handle the dvma, * do not use this device. */ if (dma == NULL) { printk("Cannot find dvma for ESP%d's SCSI\n", esp->esp_id); return -1; } if (dma->allocated) { printk("esp%d: can't use my espdma\n", esp->esp_id); return -1; } dma->allocated = 1; esp->dma = dma; esp->dregs = dma->regs; return 0;}static int __init esp_map_regs(struct esp *esp, int hme){ struct sbus_dev *sdev = esp->sdev; struct resource *res; /* On HME, two reg sets exist, first is DVMA, * second is ESP registers. */ if (hme) res = &sdev->resource[1]; else res = &sdev->resource[0]; esp->eregs = sbus_ioremap(res, 0, ESP_REG_SIZE, "ESP Registers"); if (esp->eregs == 0) return -1; return 0;}static int __init esp_map_cmdarea(struct esp *esp){ struct sbus_dev *sdev = esp->sdev; esp->esp_command = sbus_alloc_consistent(sdev, 16, &esp->esp_command_dvma); if (esp->esp_command == NULL || esp->esp_command_dvma == 0) return -1; return 0;}static int __init esp_register_irq(struct esp *esp){ esp->ehost->irq = esp->irq = esp->sdev->irqs[0]; /* We used to try various overly-clever things to * reduce the interrupt processing overhead on * sun4c/sun4m when multiple ESP's shared the * same IRQ. It was too complex and messy to * sanely maintain. */ if (request_irq(esp->ehost->irq, esp_intr, SA_SHIRQ, "ESP SCSI", esp)) { printk("esp%d: Cannot acquire irq line\n", esp->esp_id); return -1; } printk("esp%d: IRQ %s ", esp->esp_id, __irq_itoa(esp->ehost->irq)); return 0;}static void __init esp_get_scsi_id(struct esp *esp){ struct sbus_dev *sdev = esp->sdev; esp->scsi_id = prom_getintdefault(esp->prom_node, "initiator-id", -1); if (esp->scsi_id == -1) esp->scsi_id = prom_getintdefault(esp->prom_node, "scsi-initiator-id", -1); if (esp->scsi_id == -1) esp->scsi_id = (sdev->bus == NULL) ? 7 : prom_getintdefault(sdev->bus->prom_node, "scsi-initiator-id", 7); esp->ehost->this_id = esp->scsi_id; esp->scsi_id_mask = (1 << esp->scsi_id);}static void __init esp_get_clock_params(struct esp *esp){ struct sbus_dev *sdev = esp->sdev; int prom_node = esp->prom_node; int sbus_prom_node; unsigned int fmhz; u8 ccf; if (sdev != NULL && sdev->bus != NULL) sbus_prom_node = sdev->bus->prom_node; else sbus_prom_node = 0; /* This is getting messy but it has to be done * correctly or else you get weird behavior all * over the place. We are trying to basically * figure out three pieces of information. * * a) Clock Conversion Factor * * This is a representation of the input * crystal clock frequency going into the * ESP on this machine. Any operation whose * timing is longer than 400ns depends on this * value being correct. For example, you'll * get blips for arbitration/selection during * high load or with multiple targets if this * is not set correctly. * * b) Selection Time-Out * * The ESP isn't very bright and will arbitrate * for the bus and try to select a target * forever if you let it. This value tells * the ESP when it has taken too long to * negotiate and that it should interrupt * the CPU so we can see what happened. * The value is computed as follows (from * NCR/Symbios chip docs). * * (Time Out Period) * (Input Clock) * STO = ---------------------------------- * (8192) * (Clock Conversion Factor) * * You usually want the time out period to be * around 250ms, I think we'll set it a little * bit higher to account for fully loaded SCSI * bus's and slow devices that don't respond so * quickly to selection attempts. (yeah, I know * this is out of spec. but there is a lot of * buggy pieces of firmware out there so bite me) * * c) Imperical constants for synchronous offset * and transfer period register values * * This entails the smallest and largest sync * period we could ever handle on this ESP. */ fmhz = prom_getintdefault(prom_node, "clock-frequency", -1); if (fmhz == -1) fmhz = (!sbus_prom_node) ? 0 : prom_getintdefault(sbus_prom_node, "clock-frequency", -1); if (fmhz <= (5000000)) ccf = 0; else ccf = (((5000000 - 1) + (fmhz))/(5000000)); if (!ccf || ccf > 8) { /* If we can't find anything reasonable, * just assume 20MHZ. This is the clock * frequency of the older sun4c's where I've * been unable to find the clock-frequency * PROM property. All other machines provide * useful values it seems. */ ccf = ESP_CCF_F4; fmhz = (20000000); } if (ccf == (ESP_CCF_F7 + 1)) esp->cfact = ESP_CCF_F0; else if (ccf == ESP_CCF_NEVER) esp->cfact = ESP_CCF_F2; else esp->cfact = ccf; esp->raw_cfact = ccf; esp->cfreq = fmhz; esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz); esp->ctick = ESP_TICK(ccf, esp->ccycle); esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf); esp->sync_defp = SYNC_DEFP_SLOW; printk("SCSI ID %d Clk %dMHz CCYC=%d CCF=%d TOut %d ", esp->scsi_id, (fmhz / 1000000), (int)esp->ccycle, (int)ccf, (int) esp->neg_defp);}static void __init esp_get_bursts(struct esp *esp, struct sbus_dev *dma){ struct sbus_dev *sdev = esp->sdev; u8 bursts; bursts = prom_getintdefault(esp->prom_node, "burst-sizes", 0xff); if (dma) { u8 tmp = prom_getintdefault(dma->prom_node, "burst-sizes", 0xff); if (tmp != 0xff) bursts &= tmp; } if (sdev->bus) { u8 tmp = prom_getintdefault(sdev->bus->prom_node, "burst-sizes", 0xff); if (tmp != 0xff) bursts &= tmp; } if (bursts == 0xff || (bursts & DMA_BURST16) == 0 || (bursts & DMA_BURST32) == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -