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

📄 mesh.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	}	dlog(ms, "after arb, intr/exc/err/fc=%.8x",	     MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));	if (in_8(&mr->interrupt) == 0 && (in_8(&mr->bus_status1) & BS1_SEL)	    && (in_8(&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);		mesh_flush_io(mr);		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);		mesh_flush_io(mr);		for (t = 10; t > 0 && in_8(&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 (in_8(&mr->interrupt) == 0 && (in_8(&mr->bus_status1) & BS1_SEL)		    && (in_8(&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	}}/* * Start the next command for a MESH. * Should be called with interrupts disabled. */static void mesh_start(struct mesh_state *ms){	struct 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 = (struct scsi_cmnd *) cmd->host_scribble) {			if (cmd == NULL)				return;			if (ms->tgts[cmd->device->id].current_req == NULL)				break;			prev = cmd;		}		next = (struct 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 void mesh_done(struct mesh_state *ms, int start_next){	struct scsi_cmnd *cmd;	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];	cmd = ms->current_req;	ms->current_req = NULL;	tp->current_req = NULL;	if (cmd) {		cmd->result = (ms->stat << 16) + cmd->SCp.Status;		if (ms->stat == DID_OK)			cmd->result += (cmd->SCp.Message << 8);		if (DEBUG_TARGET(cmd)) {			printk(KERN_DEBUG "mesh_done: result = %x, data_ptr=%d, buflen=%d\n",			       cmd->result, ms->data_ptr, scsi_bufflen(cmd));#if 0			/* needs to use sg? */			if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12 || cmd->cmnd[0] == 3)			    && cmd->request_buffer != 0) {				unsigned char *b = cmd->request_buffer;				printk(KERN_DEBUG "buffer = %x %x %x %x %x %x %x %x\n",				       b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);			}#endif		}		cmd->SCp.this_residual -= ms->data_ptr;		mesh_completed(ms, cmd);	}	if (start_next) {		out_8(&ms->mesh->sequence, SEQ_ENBRESEL);		mesh_flush_io(ms->mesh);		udelay(1);		ms->phase = idle;		mesh_start(ms);	}}static inline void add_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 void set_sdtr(struct mesh_state *ms, int period, int offset){	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];	volatile struct mesh_regs __iomem *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 void start_phase(struct mesh_state *ms){	int i, seq, nb;	volatile struct mesh_regs __iomem *mr = ms->mesh;	volatile struct dbdma_regs __iomem *md = ms->dma;	struct 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);		mesh_flush_io(mr);		udelay(1);		/*		 * If ATN is not already asserted, we assert it, then		 * issue a SEQ_MSGOUT to get the mesh to drop ACK.		 */		if ((in_8(&mr->bus_status0) & BS0_ATN) == 0) {			dlog(ms, "bus0 was %.2x explicitly asserting ATN", mr->bus_status0);			out_8(&mr->bus_status0, BS0_ATN); /* explicit ATN */			mesh_flush_io(mr);			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);		mesh_flush_io(mr);		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 void get_msgin(struct mesh_state *ms){	volatile struct mesh_regs __iomem *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 int msgin_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 void reselected(struct mesh_state *ms){	volatile struct mesh_regs __iomem *mr = ms->mesh;	struct scsi_cmnd *cmd;	struct mesh_target *tp;	int b, t, prev;	switch (ms->phase) {	case idle:		break;	case arbitrating:		if ((cmd = ms->current_req) != NULL) {			/* put the command back on the queue */			cmd->host_scribble = (void *) ms->request_q;			if (ms->request_q == NULL)				ms->request_qtail = cmd;			ms->request_q = cmd;			tp = &ms->tgts[cmd->device->id];			tp->current_req = NULL;		}		break;	case busfreeing:		ms->phase = reselecting;		mesh_done(ms, 0);		break;	case disconnecting:		break;	default:		printk(KERN_ERR "mesh: reselected in phase %d/%d tgt %d\n",		       ms->msgphase, ms->phase, ms->conn_tgt);		dumplog(ms, ms->conn_tgt);		dumpslog(ms);	}	if (ms->dma_started) {		printk(KERN_ERR "mesh: reselected with DMA started !\n");		halt_dma(ms);	}	ms->current_req = NULL;	ms->phase = dataing;	ms->msgphase = msg_in;	ms->n_msgout = 0;	ms->last_n_msgout = 0;	prev = ms->conn_tgt;	/*	 * We seem to get abortive reselections sometimes.	 */	while ((in_8(&mr->bus_status1) & BS1_BSY) == 0) {		static int mesh_aborted_resels;		mesh_aborted_resels++;		out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);		mesh_flush_io(mr);		udelay(1);		out_8(&mr->sequence, SEQ_ENBRESEL);		mesh_flush_io(mr);		udelay(5);		dlog(ms, "extra resel err/exc/fc = %.6x",		     MKWORD(0, mr->error, mr->exception, mr->fifo_count));	}	out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);       	mesh_flush_io(mr);	udelay(1);	out_8(&mr->sequence, SEQ_ENBRESEL);       	mesh_flush_io(mr);	udelay(1);	out_8(&mr->sync_params, ASYNC_PARAMS);	/*	 * Find out who reselected us.	 */	if (in_8(&mr->fifo_count) == 0) {		printk(KERN_ERR "mesh: reselection but nothing in fifo?\n");		ms->conn_tgt = ms->host->this_id;		goto bogus;	}	/* get the last byte in the fifo */	do {		b = in_8(&mr->fifo);		dlog(ms, "reseldata %x", b);	} while (in_8(&mr->fifo_count));	for (t = 0; t < 8; ++t)		if ((b & (1 << t)) != 0 && t != ms->host->this_id)			break;	if (b != (1 << t) + (1 << ms->host->this_id)) {		printk(KERN_ERR "mesh: bad reselection data %x\n", b);		ms->conn_tgt = ms->host->this_id;		goto bogus;	}	/*	 * Set up to continue with that target's transfer.	 */	ms->conn_tgt = t;	tp = &ms->tgts[t];	out_8(&mr->sync_params, tp->sync_params);	if (ALLOW_DEBUG(t)) {		printk(KERN_DEBUG "mesh: reselected by target %d\n", t);		printk(KERN_DEBUG "mesh: saved_ptr=%x goes_out=%d cmd=%p\n",		       tp->saved_ptr, tp->data_goes_out, tp->current_req);	}	ms->current_req = tp->current_req;	if (tp->current_req == NULL) {		printk(KERN_ERR "mesh: reselected by tgt %d but no cmd!\n", t);		goto bogus;	}	ms->data_ptr = tp->saved_ptr;	dlog(ms, "resel prev tgt=%d", prev);	dlog(ms, "resel err/exc=%.4x", MKWORD(0, 0, mr->error, mr->exception));	start_phase(ms);	return;bogus:	dumplog(ms, ms->conn_tgt);	dumpslog(ms);	ms->data_ptr = 0;	ms->aborting = 1;	start_phase(ms);}static void do_abort(struct mesh_state *ms){	ms->msgout[0] = ABORT;	ms->n_msgout = 1;	ms->aborting = 1;	ms->stat = DID_ABORT;	dlog(ms, "abort", 0);}static void handle_reset(struct mesh_state *ms){	int tgt;	struct mesh_target *tp;	struct scsi_cmnd *cmd;	volatile struct mesh_regs __iomem *mr = ms->mesh;	for (tgt = 0; tgt < 8; ++tgt) {		tp = &ms->tgts[tgt];		if ((cmd = tp->current_req) != NULL) {			cmd->result = DID_RESET << 16;			tp->current_req = NULL;			mesh_completed(ms, cmd);		}		ms->tgts[tgt].sdtr_state = do_sdtr;		ms->tgts[tgt].sync_params = ASYNC_PARAMS;	}	ms->current_req = NULL;	while ((cmd = ms->request_q) != NULL) {		ms->request_q = (struct scsi_cmnd *) cmd->host_scribble;		cmd->result = DID_RESET << 16;		mesh_completed(ms, cmd);	}	ms->phase = idle;	ms->msgphase = msg_none;	out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);	out_8(&mr->sequence, SEQ_FLUSHFIFO);       	mesh_flush_io(mr);	udelay(1);	out_8(&mr->sync_params, ASYNC_PARAMS);	out_8(&mr->sequence, SEQ_ENBRESEL);}static irqreturn_t do_mesh_interrupt(int irq, void *dev_id){	unsigned long flags;	struct mesh_state *ms = dev_id;	struct Scsi_Host *dev = ms->host;		spin_lock_irqsave(dev->host_lock, flags);	mesh_interrupt(ms);	spin_unlock_irqrestore(dev->host_lock, flags);	return IRQ_HANDLED;}static void handle_error(struct mesh_state *ms){	int err, exc, count;	volatile struct mesh_regs __iomem *mr = ms->mesh;	err = in_8(&mr->error);	exc = in_8(&mr->exception);	out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);

⌨️ 快捷键说明

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