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

📄 nsp_cs.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
 * expect Ninja Irq */static int nsp_expect_signal(Scsi_Cmnd	   *SCpnt,			     unsigned char  current_phase,			     unsigned char  mask){	unsigned int  base	 = SCpnt->device->host->io_port;	int	      time_out;	unsigned char phase, i_src;	//nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask);	time_out = 100;	do {		phase = nsp_index_read(base, SCSIBUSMON);		if (phase == 0xff) {			//nsp_dbg(NSP_DEBUG_INTR, "ret -1");			return -1;		}		i_src = nsp_read(base, IRQSTATUS);		if (i_src & IRQSTATUS_SCSI) {			//nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal");			return 0;		}		if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) {			//nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase);			return 1;		}	} while(time_out-- != 0);	//nsp_dbg(NSP_DEBUG_INTR, "timeout");	return -1;}/* * transfer SCSI message */static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase){	unsigned int  base = SCpnt->device->host->io_port;	nsp_hw_data  *data = (nsp_hw_data *)SCpnt->device->host->hostdata;	char	     *buf  = data->MsgBuffer;	int	      len  = min(MSGBUF_SIZE, data->MsgLen);	int	      ptr;	int	      ret;	//nsp_dbg(NSP_DEBUG_DATA_IO, "in");	for (ptr = 0; len > 0; len--, ptr++) {		ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);		if (ret <= 0) {			nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit");			return 0;		}		/* if last byte, negate ATN */		if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) {			nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB);		}		/* read & write message */		if (phase & BUSMON_IO) {			nsp_dbg(NSP_DEBUG_DATA_IO, "read msg");			buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);		} else {			nsp_dbg(NSP_DEBUG_DATA_IO, "write msg");			nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);		}		nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");	}	return len;}/* * get extra SCSI data from fifo */static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt){	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;	unsigned int count;	//nsp_dbg(NSP_DEBUG_DATA_IO, "in");	if (SCpnt->SCp.have_data_in != IO_IN) {		return 0;	}	count = nsp_fifo_count(SCpnt);	if (data->FifoCount == count) {		//nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk");		return 0;	}	/*	 * XXX: NSP_QUIRK	 * data phase skip only occures in case of SCSI_LOW_READ	 */	nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk");	SCpnt->SCp.phase = PH_DATA;	nsp_pio_read(SCpnt);	nsp_setup_fifo(data, FALSE);	return 0;}/* * accept reselection */static int nsp_reselected(Scsi_Cmnd *SCpnt){	unsigned int  base    = SCpnt->device->host->io_port;	unsigned int  host_id = SCpnt->device->host->this_id;	//nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;	unsigned char bus_reg;	unsigned char id_reg, tmp;	int target;	nsp_dbg(NSP_DEBUG_RESELECTION, "in");	id_reg = nsp_index_read(base, RESELECTID);	tmp    = id_reg & (~BIT(host_id));	target = 0;	while(tmp != 0) {		if (tmp & BIT(0)) {			break;		}		tmp >>= 1;		target++;	}	if (scmd_id(SCpnt) != target) {		nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target);	}	nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");	nsp_nexus(SCpnt);	bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);	nsp_index_write(base, SCSIBUSCTRL, bus_reg);	nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB);	return TRUE;}/* * count how many data transferd */static int nsp_fifo_count(Scsi_Cmnd *SCpnt){	unsigned int base = SCpnt->device->host->io_port;	unsigned int count;	unsigned int l, m, h, dummy;	nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER);	l     = nsp_index_read(base, TRANSFERCOUNT);	m     = nsp_index_read(base, TRANSFERCOUNT);	h     = nsp_index_read(base, TRANSFERCOUNT);	dummy = nsp_index_read(base, TRANSFERCOUNT); /* required this! */	count = (h << 16) | (m << 8) | (l << 0);	//nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count);	return count;}/* fifo size */#define RFIFO_CRIT 64#define WFIFO_CRIT 64/* * read data in DATA IN phase */static void nsp_pio_read(Scsi_Cmnd *SCpnt){	unsigned int  base      = SCpnt->device->host->io_port;	unsigned long mmio_base = SCpnt->device->host->base;	nsp_hw_data  *data      = (nsp_hw_data *)SCpnt->device->host->hostdata;	long	      time_out;	int	      ocount, res;	unsigned char stat, fifo_stat;	ocount = data->FifoCount;	nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d",		SCpnt, SCpnt->resid, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual);	time_out = 1000;	while ((time_out-- != 0) &&	       (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) {		stat = nsp_index_read(base, SCSIBUSMON);		stat &= BUSMON_PHASE_MASK;		res = nsp_fifo_count(SCpnt) - ocount;		//nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x ocount=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res);		if (res == 0) { /* if some data avilable ? */			if (stat == BUSPHASE_DATA_IN) { /* phase changed? */				//nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", SCpnt->SCp.this_residual);				continue;			} else {				nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat);				break;			}		}		fifo_stat = nsp_read(base, FIFOSTATUS);		if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 &&		    stat                                == BUSPHASE_DATA_IN) {			continue;		}		res = min(res, SCpnt->SCp.this_residual);		switch (data->TransferMode) {		case MODE_IO32:			res &= ~(BIT(1)|BIT(0)); /* align 4 */			nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2);			break;		case MODE_IO8:			nsp_fifo8_read (base, SCpnt->SCp.ptr, res     );			break;		case MODE_MEM32:			res &= ~(BIT(1)|BIT(0)); /* align 4 */			nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2);			break;		default:			nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode");			return;		}		SCpnt->resid	       	 -= res;		SCpnt->SCp.ptr		 += res;		SCpnt->SCp.this_residual -= res;		ocount			 += res;		//nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this_residual=0x%x ocount=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount);		/* go to next scatter list if available */		if (SCpnt->SCp.this_residual	== 0 &&		    SCpnt->SCp.buffers_residual != 0 ) {			//nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out);			SCpnt->SCp.buffers_residual--;			SCpnt->SCp.buffer++;			SCpnt->SCp.ptr		 = BUFFER_ADDR;			SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;			time_out = 1000;			//nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset);		}	}	data->FifoCount = ocount;	if (time_out == 0) {		nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",			SCpnt->resid, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual);	}	nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);	nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);}/* * write data in DATA OUT phase */static void nsp_pio_write(Scsi_Cmnd *SCpnt){	unsigned int  base      = SCpnt->device->host->io_port;	unsigned long mmio_base = SCpnt->device->host->base;	nsp_hw_data  *data      = (nsp_hw_data *)SCpnt->device->host->hostdata;	int	      time_out;	int           ocount, res;	unsigned char stat;	ocount	 = data->FifoCount;	nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x",		data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid);	time_out = 1000;	while ((time_out-- != 0) &&	       (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) {		stat = nsp_index_read(base, SCSIBUSMON);		stat &= BUSMON_PHASE_MASK;		if (stat != BUSPHASE_DATA_OUT) {			res = ocount - nsp_fifo_count(SCpnt);			nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);			/* Put back pointer */			SCpnt->resid	       	 += res;			SCpnt->SCp.ptr		 -= res;			SCpnt->SCp.this_residual += res;			ocount			 -= res;			break;		}		res = ocount - nsp_fifo_count(SCpnt);		if (res > 0) { /* write all data? */			nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res);			continue;		}		res = min(SCpnt->SCp.this_residual, WFIFO_CRIT);		//nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res);		switch (data->TransferMode) {		case MODE_IO32:			res &= ~(BIT(1)|BIT(0)); /* align 4 */			nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2);			break;		case MODE_IO8:			nsp_fifo8_write (base, SCpnt->SCp.ptr, res     );			break;		case MODE_MEM32:			res &= ~(BIT(1)|BIT(0)); /* align 4 */			nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2);			break;		default:			nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode");			break;		}		SCpnt->resid	       	 -= res;		SCpnt->SCp.ptr		 += res;		SCpnt->SCp.this_residual -= res;		ocount			 += res;		/* go to next scatter list if available */		if (SCpnt->SCp.this_residual	== 0 &&		    SCpnt->SCp.buffers_residual != 0 ) {			//nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next");			SCpnt->SCp.buffers_residual--;			SCpnt->SCp.buffer++;			SCpnt->SCp.ptr		 = BUFFER_ADDR;			SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;			time_out = 1000;		}	}	data->FifoCount = ocount;	if (time_out == 0) {		nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", SCpnt->resid);	}	nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);	nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);}#undef RFIFO_CRIT#undef WFIFO_CRIT/* * setup synchronous/asynchronous data transfer mode */static int nsp_nexus(Scsi_Cmnd *SCpnt){	unsigned int   base   = SCpnt->device->host->io_port;	unsigned char  target = scmd_id(SCpnt);//	unsigned char  lun    = SCpnt->device->lun;	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;	sync_data     *sync   = &(data->Sync[target]);	//nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt);	/* setup synch transfer registers */	nsp_index_write(base, SYNCREG,	sync->SyncRegister);	nsp_index_write(base, ACKWIDTH, sync->AckWidth);	if (SCpnt->use_sg    == 0        ||	    SCpnt->resid % 4 != 0        ||	    SCpnt->resid     <= PAGE_SIZE ) {		data->TransferMode = MODE_IO8;	} else if (nsp_burst_mode == BURST_MEM32) {		data->TransferMode = MODE_MEM32;	} else if (nsp_burst_mode == BURST_IO32) {		data->TransferMode = MODE_IO32;	} else {		data->TransferMode = MODE_IO8;	}	/* setup pdma fifo */	nsp_setup_fifo(data, TRUE);	/* clear ack counter */ 	data->FifoCount = 0;	nsp_index_write(base, POINTERCLR, POINTER_CLEAR	    |					  ACK_COUNTER_CLEAR |					  REQ_COUNTER_CLEAR |					  HOST_COUNTER_CLEAR);	return 0;}#include "nsp_message.c"/* * interrupt handler */static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs){	unsigned int   base;	unsigned char  irq_status, irq_phase, phase;	Scsi_Cmnd     *tmpSC;	unsigned char  target, lun;	unsigned int  *sync_neg;	int            i, tmp;	nsp_hw_data   *data;	//nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id);	//nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host);	if (                dev_id        != NULL &&	    ((scsi_info_t *)dev_id)->host != NULL  ) {		scsi_info_t *info = (scsi_info_t *)dev_id;		data = (nsp_hw_data *)info->host->hostdata;	} else {		nsp_dbg(NSP_DEBUG_INTR, "host data wrong");		return IRQ_NONE;	}	//nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id);	base = data->BaseAddress;	//nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base);	/*	 * interrupt check	 */	nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE);	irq_status = nsp_read(base, IRQSTATUS);	//nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status);	if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) {		nsp_write(base, IRQCONTROL, 0);		//nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq");		return IRQ_NONE;	}	/* XXX: IMPORTANT	 * Do not read an irq_phase register if no scsi phase interrupt.	 * Unless, you should lose a scsi phase interrupt.	 */	phase = nsp_index_read(base, SCSIBUSMON);	if((irq_status & IRQSTATUS_SCSI) != 0) {		irq_phase = nsp_index_read(base, IRQPHASESENCE);	} else {		irq_phase = 0;	}	//nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase);	/*	 * timer interrupt handler (scsi vs timer interrupts)	 */	//nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount);	if (data->TimerCount != 0) {		//nsp_dbg(NSP_DEBUG_INTR, "stop timer");		nsp_index_write(base, TIMERCOUNT, 0);		nsp_index_write(base, TIMERCOUNT, 0);		data->TimerCount = 0;	}	if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&	    data->SelectionTimeOut == 0) {		//nsp_dbg(NSP_DEBUG_INTR, "timer start");		nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR);		return IRQ_HANDLED;	}	nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);	if ((irq_status & IRQSTATUS_SCSI) &&	    (irq_phase  & SCSI_RESET_IRQ)) {		nsp_msg(KERN_ERR, "bus reset (power off?)");		nsphw_init(data);		nsp_bus_reset(data);		if(data->CurrentSC != NULL) {			tmpSC = data->CurrentSC;			tmpSC->result  = (DID_RESET                   << 16) |				         ((tmpSC->SCp.Message & 0xff) <<  8) |				         ((tmpSC->SCp.Status  & 0xff) <<  0);			nsp_scsi_done(tmpSC);		}		return IRQ_HANDLED;	}	if (data->CurrentSC == NULL) {		nsp_msg(KERN_ERR, "CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen. reset everything", irq_status, phase, irq_phase);		nsphw_init(data);		nsp_bus_reset(data);		return IRQ_HANDLED;	}	tmpSC    = data->CurrentSC;	target   = tmpSC->device->id;	lun      = tmpSC->device->lun;	sync_neg = &(data->Sync[target].SyncNegotiation);	/*	 * parse hardware SCSI irq reasons register	 */	if (irq_status & IRQSTATUS_SCSI) {		if (irq_phase & RESELECT_IRQ) {			nsp_dbg(NSP_DEBUG_INTR, "reselect");			nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR);			if (nsp_reselected(tmpSC) != FALSE) {				return IRQ_HANDLED;			}		}		if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) {			return IRQ_HANDLED;		}	}	//show_phase(tmpSC);	switch(tmpSC->SCp.phase) {	case PH_SELSTART:		// *sync_neg = SYNC_NOT_YET;		if ((phase & BUSMON_BSY) == 0) {			//nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut);			if (data->SelectionTimeOut >= NSP_SELTIMEOUT) {				nsp_dbg(NSP_DEBUG_INTR, "selection time out");				data->SelectionTimeOut = 0;				nsp_index_write(base, SCSIBUSCTRL, 0);				tmpSC->result   = DID_TIME_OUT << 16;				nsp_scsi_done(tmpSC);				return IRQ_HANDLED;			}			data->SelectionTimeOut += 1;			nsp_start_timer(tmpSC, 1000/51);			return IRQ_HANDLED;		}

⌨️ 快捷键说明

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