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

📄 mesh.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 4 页
字号:
	return NOTIFY_DONE;}intmesh_command(Scsi_Cmnd *cmd){	printk(KERN_WARNING "whoops... mesh_command called\n");	return -1;}static voidmesh_init(struct mesh_state *ms){	volatile struct mesh_regs *mr = ms->mesh;	volatile struct dbdma_regs *md = ms->dma;	udelay(100);	out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);	/* stop dma */	out_8(&mr->exception, 0xff);	/* clear all exception bits */	out_8(&mr->error, 0xff);	/* clear all error bits */	out_8(&mr->sequence, SEQ_RESETMESH);	udelay(10);	out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);	out_8(&mr->source_id, ms->host->this_id);	out_8(&mr->sel_timeout, 25);	/* 250ms */	out_8(&mr->sync_params, ASYNC_PARAMS);	out_8(&mr->bus_status1, BS1_RST);	/* assert RST */	udelay(30);			/* leave it on for >= 25us */	out_8(&mr->bus_status1, 0);	/* negate RST */	out_8(&mr->sequence, SEQ_FLUSHFIFO);	udelay(1);	out_8(&mr->sync_params, ASYNC_PARAMS);	out_8(&mr->sequence, SEQ_ENBRESEL);	out_8(&mr->interrupt, 0xff);	/* clear all interrupt bits */}/* * Start the next command for a MESH. * Should be called with interrupts disabled. */static voidmesh_start(struct mesh_state *ms){	Scsi_Cmnd *cmd, *prev, *next;	if (ms->phase != idle || ms->current_req != NULL) {		printk(KERN_ERR "inappropriate mesh_start (phase=%d, ms=%p)",		       ms->phase, ms);		return;	}	while (ms->phase == idle) {		prev = NULL;		for (cmd = ms->request_q; ; cmd = (Scsi_Cmnd *) cmd->host_scribble) {			if (cmd == NULL)				return;			if (ms->tgts[cmd->target].current_req == NULL)				break;			prev = cmd;		}		next = (Scsi_Cmnd *) cmd->host_scribble;		if (prev == NULL)			ms->request_q = next;		else			prev->host_scribble = (void *) next;		if (next == NULL)			ms->request_qtail = prev;		mesh_start_cmd(ms, cmd);	}}static voidmesh_start_cmd(struct mesh_state *ms, Scsi_Cmnd *cmd){	volatile struct mesh_regs *mr = ms->mesh;	int t;	ms->current_req = cmd;	ms->tgts[cmd->target].data_goes_out = data_goes_out(cmd);	ms->tgts[cmd->target].current_req = cmd;#if 1	if (DEBUG_TARGET(cmd)) {		int i;		printk(KERN_DEBUG "mesh_start: %p ser=%lu tgt=%d cmd=",		       cmd, cmd->serial_number, cmd->target);		for (i = 0; i < cmd->cmd_len; ++i)			printk(" %x", cmd->cmnd[i]);		printk(" use_sg=%d buffer=%p bufflen=%u\n",		       cmd->use_sg, cmd->request_buffer, cmd->request_bufflen);	}#endif	ms->phase = arbitrating;	ms->msgphase = msg_none;	ms->data_ptr = 0;	ms->dma_started = 0;	ms->n_msgout = 0;	ms->last_n_msgout = 0;	ms->expect_reply = 0;	ms->conn_tgt = cmd->target;	ms->tgts[cmd->target].saved_ptr = 0;	ms->stat = DID_OK;	ms->aborting = 0;#ifdef MESH_DBG	ms->tgts[cmd->target].n_log = 0;	dlog(ms, "start cmd=%x", (int) cmd);#endif	/* Off we go */	dlog(ms, "about to arb, intr/exc/err/fc=%.8x",	     MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));	out_8(&mr->interrupt, INT_CMDDONE);	out_8(&mr->sequence, SEQ_ENBRESEL);	udelay(1);	if (mr->bus_status1 & (BS1_BSY | BS1_SEL)) {		/*		 * Some other device has the bus or is arbitrating for it -		 * probably a target which is about to reselect us.		 */		dlog(ms, "busy b4 arb, intr/exc/err/fc=%.8x",		     MKWORD(mr->interrupt, mr->exception,			    mr->error, mr->fifo_count));		for (t = 100; t > 0; --t) {			if ((mr->bus_status1 & (BS1_BSY | BS1_SEL)) == 0)				break;			if (in_8(&mr->interrupt) != 0) {				dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x",				     MKWORD(mr->interrupt, mr->exception,					    mr->error, mr->fifo_count));				mesh_interrupt(0, (void *)ms, 0);				if (ms->phase != arbitrating)					return;			}			udelay(1);		}		if (mr->bus_status1 & (BS1_BSY | BS1_SEL)) {			/* XXX should try again in a little while */			ms->stat = DID_BUS_BUSY;			ms->phase = idle;			mesh_done(ms, 0);			return;		}	}	/*	 * Apparently the mesh has a bug where it will assert both its	 * own bit and the target's bit on the bus during arbitration.	 */	out_8(&mr->dest_id, mr->source_id);	/*	 * There appears to be a race with reselection sometimes,	 * where a target reselects us just as we issue the	 * arbitrate command.  It seems that then the arbitrate	 * command just hangs waiting for the bus to be free	 * without giving us a reselection exception.	 * The only way I have found to get it to respond correctly	 * is this: disable reselection before issuing the arbitrate	 * command, then after issuing it, if it looks like a target	 * is trying to reselect us, reset the mesh and then enable	 * reselection.	 */	out_8(&mr->sequence, SEQ_DISRESEL);	if (in_8(&mr->interrupt) != 0) {		dlog(ms, "intr after disresel, intr/exc/err/fc=%.8x",		     MKWORD(mr->interrupt, mr->exception,			    mr->error, mr->fifo_count));		mesh_interrupt(0, (void *)ms, 0);		if (ms->phase != arbitrating)			return;		dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x",		     MKWORD(mr->interrupt, mr->exception,			    mr->error, mr->fifo_count));	}	out_8(&mr->sequence, SEQ_ARBITRATE);	for (t = 230; t > 0; --t) {		if (in_8(&mr->interrupt) != 0)			break;		udelay(1);	}	dlog(ms, "after arb, intr/exc/err/fc=%.8x",	     MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));	if (mr->interrupt == 0 && (mr->bus_status1 & BS1_SEL)	    && (mr->bus_status0 & BS0_IO)) {		/* looks like a reselection - try resetting the mesh */		dlog(ms, "resel? after arb, intr/exc/err/fc=%.8x",		     MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));		out_8(&mr->sequence, SEQ_RESETMESH);		udelay(10);		out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);		out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);		out_8(&mr->sequence, SEQ_ENBRESEL);		for (t = 10; t > 0 && mr->interrupt == 0; --t)			udelay(1);		dlog(ms, "tried reset after arb, intr/exc/err/fc=%.8x",		     MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));#ifndef MESH_MULTIPLE_HOSTS		if (mr->interrupt == 0 && (mr->bus_status1 & BS1_SEL)		    && (mr->bus_status0 & BS0_IO)) {			printk(KERN_ERR "mesh: controller not responding"			       " to reselection!\n");			/*			 * If this is a target reselecting us, and the			 * mesh isn't responding, the higher levels of			 * the scsi code will eventually time out and			 * reset the bus.			 */		}#endif	}}#ifndef MESH_NEW_STYLE_EHstatic voidfinish_cmds(void *data){	struct mesh_state *ms = data;	Scsi_Cmnd *cmd;	unsigned long flags;	for (;;) {		spin_lock_irqsave(&io_request_lock, flags);		cmd = ms->completed_q;		if (cmd == NULL) {			spin_unlock_irqrestore(&io_request_lock, flags);			break;		}		ms->completed_q = (Scsi_Cmnd *) cmd->host_scribble;		(*cmd->scsi_done)(cmd);		spin_unlock_irqrestore(&io_request_lock, flags);	}}#endif /* MESH_NEW_STYLE_EH */static inline voidadd_sdtr_msg(struct mesh_state *ms){	int i = ms->n_msgout;	ms->msgout[i] = EXTENDED_MESSAGE;	ms->msgout[i+1] = 3;	ms->msgout[i+2] = EXTENDED_SDTR;	ms->msgout[i+3] = mesh_sync_period/4;	ms->msgout[i+4] = (ALLOW_SYNC(ms->conn_tgt)? mesh_sync_offset: 0);	ms->n_msgout = i + 5;}static voidset_sdtr(struct mesh_state *ms, int period, int offset){	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];	volatile struct mesh_regs *mr = ms->mesh;	int v, tr;	tp->sdtr_state = sdtr_done;	if (offset == 0) {		/* asynchronous */		if (SYNC_OFF(tp->sync_params))			printk(KERN_INFO "mesh: target %d now asynchronous\n",			       ms->conn_tgt);		tp->sync_params = ASYNC_PARAMS;		out_8(&mr->sync_params, ASYNC_PARAMS);		return;	}	/*	 * We need to compute ceil(clk_freq * period / 500e6) - 2	 * without incurring overflow.	 */	v = (ms->clk_freq / 5000) * period;	if (v <= 250000) {		/* special case: sync_period == 5 * clk_period */		v = 0;		/* units of tr are 100kB/s */		tr = (ms->clk_freq + 250000) / 500000;	} else {		/* sync_period == (v + 2) * 2 * clk_period */		v = (v + 99999) / 100000 - 2;		if (v > 15)			v = 15;	/* oops */		tr = ((ms->clk_freq / (v + 2)) + 199999) / 200000;	}	if (offset > 15)		offset = 15;	/* can't happen */	tp->sync_params = SYNC_PARAMS(offset, v);	out_8(&mr->sync_params, tp->sync_params);	printk(KERN_INFO "mesh: target %d synchronous at %d.%d MB/s\n",	       ms->conn_tgt, tr/10, tr%10);}static voidstart_phase(struct mesh_state *ms){	int i, seq, nb;	volatile struct mesh_regs *mr = ms->mesh;	volatile struct dbdma_regs *md = ms->dma;	Scsi_Cmnd *cmd = ms->current_req;	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];	dlog(ms, "start_phase nmo/exc/fc/seq = %.8x",	     MKWORD(ms->n_msgout, mr->exception, mr->fifo_count, mr->sequence));	out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);	seq = use_active_neg + (ms->n_msgout? SEQ_ATN: 0);	switch (ms->msgphase) {	case msg_none:		break;	case msg_in:		out_8(&mr->count_hi, 0);		out_8(&mr->count_lo, 1);		out_8(&mr->sequence, SEQ_MSGIN + seq);		ms->n_msgin = 0;		return;	case msg_out:		/*		 * To make sure ATN drops before we assert ACK for		 * the last byte of the message, we have to do the		 * last byte specially.		 */		if (ms->n_msgout <= 0) {			printk(KERN_ERR "mesh: msg_out but n_msgout=%d\n",			       ms->n_msgout);			mesh_dump_regs(ms);			ms->msgphase = msg_none;			break;		}		if (ALLOW_DEBUG(ms->conn_tgt)) {			printk(KERN_DEBUG "mesh: sending %d msg bytes:",			       ms->n_msgout);			for (i = 0; i < ms->n_msgout; ++i)				printk(" %x", ms->msgout[i]);			printk("\n");		}		dlog(ms, "msgout msg=%.8x", MKWORD(ms->n_msgout, ms->msgout[0],						ms->msgout[1], ms->msgout[2]));		out_8(&mr->count_hi, 0);		out_8(&mr->sequence, SEQ_FLUSHFIFO);		udelay(1);		/*		 * If ATN is not already asserted, we assert it, then		 * issue a SEQ_MSGOUT to get the mesh to drop ACK.		 */		if ((mr->bus_status0 & BS0_ATN) == 0) {			dlog(ms, "bus0 was %.2x explictly asserting ATN", mr->bus_status0);			out_8(&mr->bus_status0, BS0_ATN); /* explicit ATN */			udelay(1);			out_8(&mr->count_lo, 1);			out_8(&mr->sequence, SEQ_MSGOUT + seq);			out_8(&mr->bus_status0, 0); /* release explicit ATN */			dlog(ms,"hace: after explicit ATN bus0=%.2x",mr->bus_status0);		}		if (ms->n_msgout == 1) {			/*			 * We can't issue the SEQ_MSGOUT without ATN			 * until the target has asserted REQ.  The logic			 * in cmd_complete handles both situations:			 * REQ already asserted or not.			 */			cmd_complete(ms);		} else {			out_8(&mr->count_lo, ms->n_msgout - 1);			out_8(&mr->sequence, SEQ_MSGOUT + seq);			for (i = 0; i < ms->n_msgout - 1; ++i)				out_8(&mr->fifo, ms->msgout[i]);		}		return;	default:		printk(KERN_ERR "mesh bug: start_phase msgphase=%d\n",		       ms->msgphase);	}	switch (ms->phase) {	case selecting:		out_8(&mr->dest_id, ms->conn_tgt);		out_8(&mr->sequence, SEQ_SELECT + SEQ_ATN);		break;	case commanding:		out_8(&mr->sync_params, tp->sync_params);		out_8(&mr->count_hi, 0);		if (cmd) {			out_8(&mr->count_lo, cmd->cmd_len);			out_8(&mr->sequence, SEQ_COMMAND + seq);			for (i = 0; i < cmd->cmd_len; ++i)				out_8(&mr->fifo, cmd->cmnd[i]);		} else {			out_8(&mr->count_lo, 6);			out_8(&mr->sequence, SEQ_COMMAND + seq);			for (i = 0; i < 6; ++i)				out_8(&mr->fifo, 0);		}		break;	case dataing:		/* transfer data, if any */		if (!ms->dma_started) {			set_dma_cmds(ms, cmd);			out_le32(&md->cmdptr, virt_to_phys(ms->dma_cmds));			out_le32(&md->control, (RUN << 16) | RUN);			ms->dma_started = 1;		}		nb = ms->dma_count;		if (nb > 0xfff0)			nb = 0xfff0;		ms->dma_count -= nb;		ms->data_ptr += nb;		out_8(&mr->count_lo, nb);		out_8(&mr->count_hi, nb >> 8);		out_8(&mr->sequence, (tp->data_goes_out?				SEQ_DATAOUT: SEQ_DATAIN) + SEQ_DMA_MODE + seq);		break;	case statusing:		out_8(&mr->count_hi, 0);		out_8(&mr->count_lo, 1);		out_8(&mr->sequence, SEQ_STATUS + seq);		break;	case busfreeing:	case disconnecting:		out_8(&mr->sequence, SEQ_ENBRESEL);		udelay(1);		dlog(ms, "enbresel intr/exc/err/fc=%.8x",		     MKWORD(mr->interrupt, mr->exception, mr->error,			    mr->fifo_count));		out_8(&mr->sequence, SEQ_BUSFREE);		break;	default:		printk(KERN_ERR "mesh: start_phase called with phase=%d\n",		       ms->phase);		dumpslog(ms);	}}static inline voidget_msgin(struct mesh_state *ms){	volatile struct mesh_regs *mr = ms->mesh;	int i, n;	n = mr->fifo_count;	if (n != 0) {		i = ms->n_msgin;		ms->n_msgin = i + n;		for (; n > 0; --n)			ms->msgin[i++] = in_8(&mr->fifo);	}}static inline intmsgin_length(struct mesh_state *ms){	int b, n;	n = 1;	if (ms->n_msgin > 0) {		b = ms->msgin[0];		if (b == 1) {			/* extended message */			n = ms->n_msgin < 2? 2: ms->msgin[1] + 2;		} else if (0x20 <= b && b <= 0x2f) {			/* 2-byte message */			n = 2;		}	}	return n;}static voidcmd_complete(struct mesh_state *ms){	volatile struct mesh_regs *mr = ms->mesh;	Scsi_Cmnd *cmd = ms->current_req;	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];	int seq, n, t;	dlog(ms, "cmd_complete fc=%x", mr->fifo_count);	seq = use_active_neg + (ms->n_msgout? SEQ_ATN: 0);	switch (ms->msgphase) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -