⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 esp.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		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 + -