nsp32.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,409 行 · 第 1/5 页

C
2,409
字号
	if (data->CurrentSC != NULL) {		nsp32_msg(KERN_ERR, "Currentsc != NULL. Cancel this command request");		data->CurrentSC = NULL;		SCpnt->result   = DID_NO_CONNECT << 16;		done(SCpnt);		return SCSI_MLQUEUE_HOST_BUSY;	}	/* check target ID is not same as this initiator ID */	if (SCpnt->device->id == SCpnt->device->host->this_id) {		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "terget==host???");		SCpnt->result = DID_BAD_TARGET << 16;		done(SCpnt);		return SCSI_MLQUEUE_DEVICE_BUSY;	}	/* check target LUN is allowable value */	if (SCpnt->device->lun >= MAX_LUN) {		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "no more lun");		SCpnt->result = DID_BAD_TARGET << 16;		done(SCpnt);		return SCSI_MLQUEUE_DEVICE_BUSY;	}	show_command(SCpnt);	SCpnt->scsi_done     = done;	data->CurrentSC      = SCpnt;	SCpnt->SCp.Status    = CHECK_CONDITION;	SCpnt->SCp.Message   = 0;	SCpnt->resid         = SCpnt->request_bufflen;	SCpnt->SCp.ptr		    = (char *) SCpnt->request_buffer;	SCpnt->SCp.this_residual    = SCpnt->request_bufflen;	SCpnt->SCp.buffer	    = NULL;	SCpnt->SCp.buffers_residual = 0;	/* initialize data */	data->msgout_len	= 0;	data->msgin_len		= 0;	cur_lunt		= &(data->lunt[SCpnt->device->id][SCpnt->device->lun]);	cur_lunt->SCpnt		= SCpnt;	cur_lunt->save_datp	= 0;	cur_lunt->msgin03	= FALSE;	data->cur_lunt		= cur_lunt;	data->cur_id		= SCpnt->device->id;	data->cur_lun		= SCpnt->device->lun;	ret = nsp32_setup_sg_table(SCpnt);	if (ret == FALSE) {		nsp32_msg(KERN_ERR, "SGT fail");		SCpnt->result = DID_ERROR << 16;		nsp32_scsi_done(SCpnt);		return SCSI_MLQUEUE_HOST_BUSY;	}	/* Build IDENTIFY */	nsp32_build_identify(SCpnt);	/* 	 * If target is the first time to transfer after the reset	 * (target don't have SDTR_DONE and SDTR_INITIATOR), sync	 * message SDTR is needed to do synchronous transfer.	 */	target = &data->target[SCpnt->device->id];	data->cur_target = target;	if (!(target->sync_flag & (SDTR_DONE | SDTR_INITIATOR | SDTR_TARGET))) {		unsigned char period, offset;		if (trans_mode != ASYNC_MODE) {			nsp32_set_max_sync(data, target, &period, &offset);			nsp32_build_sdtr(SCpnt, period, offset);			target->sync_flag |= SDTR_INITIATOR;		} else {			nsp32_set_async(data, target);			target->sync_flag |= SDTR_DONE;		}		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,			  "SDTR: entry: %d start_period: 0x%x offset: 0x%x\n",			  target->limit_entry, period, offset);	} else if (target->sync_flag & SDTR_INITIATOR) {		/*		 * It was negotiating SDTR with target, sending from the		 * initiator, but there are no chance to remove this flag.		 * Set async because we don't get proper negotiation.		 */		nsp32_set_async(data, target);		target->sync_flag &= ~SDTR_INITIATOR;		target->sync_flag |= SDTR_DONE;		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,			  "SDTR_INITIATOR: fall back to async");	} else if (target->sync_flag & SDTR_TARGET) {		/*		 * It was negotiating SDTR with target, sending from target,		 * but there are no chance to remove this flag.  Set async		 * because we don't get proper negotiation.		 */		nsp32_set_async(data, target);		target->sync_flag &= ~SDTR_TARGET;		target->sync_flag |= SDTR_DONE;		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,			  "Unknown SDTR from target is reached, fall back to async.");	}	nsp32_dbg(NSP32_DEBUG_TARGETFLAG,		  "target: %d sync_flag: 0x%x syncreg: 0x%x ackwidth: 0x%x",		  SCpnt->device->id, target->sync_flag, target->syncreg,		  target->ackwidth);	/* Selection */	if (auto_param == 0) {		ret = nsp32_selection_autopara(SCpnt);	} else {		ret = nsp32_selection_autoscsi(SCpnt);	}	if (ret != TRUE) {		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "selection fail");		nsp32_scsi_done(SCpnt);		return SCSI_MLQUEUE_DEVICE_BUSY;	}	return 0;}/* initialize asic */static int nsp32hw_init(nsp32_hw_data *data){	unsigned int   base = data->BaseAddress;	unsigned short irq_stat;	unsigned long  lc_reg;	unsigned char  power;	lc_reg = nsp32_index_read4(base, CFG_LATE_CACHE);	if ((lc_reg & 0xff00) == 0) {		lc_reg |= (0x20 << 8);		nsp32_index_write2(base, CFG_LATE_CACHE, lc_reg & 0xffff);	}	nsp32_write2(base, IRQ_CONTROL,        IRQ_CONTROL_ALL_IRQ_MASK);	nsp32_write2(base, TRANSFER_CONTROL,   0);	nsp32_write4(base, BM_CNT,             0);	nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);	do {		irq_stat = nsp32_read2(base, IRQ_STATUS);		nsp32_dbg(NSP32_DEBUG_INIT, "irq_stat 0x%x", irq_stat);	} while (irq_stat & IRQSTATUS_ANY_IRQ);	/*	 * Fill FIFO_FULL_SHLD, FIFO_EMPTY_SHLD. Below parameter is	 *  designated by specification.	 */	if ((data->trans_method & NSP32_TRANSFER_PIO) ||	    (data->trans_method & NSP32_TRANSFER_MMIO)) {		nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT,  0x40);		nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x40);	} else if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {		nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT,  0x10);		nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x60);	} else {		nsp32_dbg(NSP32_DEBUG_INIT, "unknown transfer mode");	}	nsp32_dbg(NSP32_DEBUG_INIT, "full 0x%x emp 0x%x",		  nsp32_index_read1(base, FIFO_FULL_SHLD_COUNT),		  nsp32_index_read1(base, FIFO_EMPTY_SHLD_COUNT));	nsp32_index_write1(base, CLOCK_DIV, data->clock);	nsp32_index_write1(base, BM_CYCLE,  MEMRD_CMD1 | SGT_AUTO_PARA_MEMED_CMD);	nsp32_write1(base, PARITY_CONTROL, 0);	/* parity check is disable */	/*	 * initialize MISC_WRRD register	 * 	 * Note: Designated parameters is obeyed as following:	 *	MISC_SCSI_DIRECTION_DETECTOR_SELECT: It must be set.	 *	MISC_MASTER_TERMINATION_SELECT:      It must be set.	 *	MISC_BMREQ_NEGATE_TIMING_SEL:	     It should be set.	 *	MISC_AUTOSEL_TIMING_SEL:	     It should be set.	 *	MISC_BMSTOP_CHANGE2_NONDATA_PHASE:   It should be set.	 *	MISC_DELAYED_BMSTART:		     It's selected for safety.	 *	 * Note: If MISC_BMSTOP_CHANGE2_NONDATA_PHASE is set, then	 *	we have to set TRANSFERCONTROL_BM_START as 0 and set	 *	appropriate value before restarting bus master transfer.	 */	nsp32_index_write2(base, MISC_WR,			   (SCSI_DIRECTION_DETECTOR_SELECT |			    DELAYED_BMSTART                |			    MASTER_TERMINATION_SELECT      |			    BMREQ_NEGATE_TIMING_SEL        |			    AUTOSEL_TIMING_SEL             |			    BMSTOP_CHANGE2_NONDATA_PHASE));	nsp32_index_write1(base, TERM_PWR_CONTROL, 0);	power = nsp32_index_read1(base, TERM_PWR_CONTROL);	if (!(power & SENSE)) {		nsp32_msg(KERN_INFO, "term power on");		nsp32_index_write1(base, TERM_PWR_CONTROL, BPWR);	}	nsp32_write2(base, TIMER_SET, TIMER_STOP);	nsp32_write2(base, TIMER_SET, TIMER_STOP); /* Required 2 times */	nsp32_write1(base, SYNC_REG,     0);	nsp32_write1(base, ACK_WIDTH,    0);	nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME);	/*	 * enable to select designated IRQ (except for	 * IRQSELECT_SERR, IRQSELECT_PERR, IRQSELECT_BMCNTERR)	 */	nsp32_index_write2(base, IRQ_SELECT, IRQSELECT_TIMER_IRQ         |			                     IRQSELECT_SCSIRESET_IRQ     |			                     IRQSELECT_FIFO_SHLD_IRQ     |			                     IRQSELECT_RESELECT_IRQ      |			                     IRQSELECT_PHASE_CHANGE_IRQ  |			                     IRQSELECT_AUTO_SCSI_SEQ_IRQ |			                  //   IRQSELECT_BMCNTERR_IRQ      |			                     IRQSELECT_TARGET_ABORT_IRQ  |			                     IRQSELECT_MASTER_ABORT_IRQ );	nsp32_write2(base, IRQ_CONTROL, 0);	/* PCI LED off */	nsp32_index_write1(base, EXT_PORT_DDR, LED_OFF);	nsp32_index_write1(base, EXT_PORT,     LED_OFF);	return TRUE;}/* interrupt routine */static irqreturn_t do_nsp32_isr(int irq, void *dev_id, struct pt_regs *regs){	nsp32_hw_data *data = dev_id;	unsigned int base = data->BaseAddress;	Scsi_Cmnd *SCpnt = data->CurrentSC;	unsigned short auto_stat, irq_stat, trans_stat;	unsigned char busmon, busphase;	unsigned long flags;	int ret;	int handled = 0;#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))	struct Scsi_Host *host = data->Host;	spin_lock_irqsave(host->host_lock, flags);#else	spin_lock_irqsave(&io_request_lock, flags);#endif	/*	 * IRQ check, then enable IRQ mask	 */	irq_stat = nsp32_read2(base, IRQ_STATUS);	nsp32_dbg(NSP32_DEBUG_INTR, 		  "enter IRQ: %d, IRQstatus: 0x%x", irq, irq_stat);	/* is this interrupt comes from Ninja asic? */	if ((irq_stat & IRQSTATUS_ANY_IRQ) == 0) {		nsp32_dbg(NSP32_DEBUG_INTR, "shared interrupt: irq other 0x%x", irq_stat);		goto out2;	}	handled = 1;	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);	busmon = nsp32_read1(base, SCSI_BUS_MONITOR);	busphase = busmon & BUSMON_PHASE_MASK;	trans_stat = nsp32_read2(base, TRANSFER_STATUS);	if ((irq_stat == 0xffff) && (trans_stat == 0xffff)) {		nsp32_msg(KERN_INFO, "card disconnect");		if (data->CurrentSC != NULL) {			nsp32_msg(KERN_INFO, "clean up current SCSI command");			SCpnt->result = DID_BAD_TARGET << 16;			nsp32_scsi_done(SCpnt);		}		goto out;	}	/* Timer IRQ */	if (irq_stat & IRQSTATUS_TIMER_IRQ) {		nsp32_dbg(NSP32_DEBUG_INTR, "timer stop");		nsp32_write2(base, TIMER_SET, TIMER_STOP);		goto out;	}	/* SCSI reset */	if (irq_stat & IRQSTATUS_SCSIRESET_IRQ) {		nsp32_msg(KERN_INFO, "detected someone do bus reset");		nsp32_do_bus_reset(data);		if (SCpnt != NULL) {			SCpnt->result = DID_RESET << 16;			nsp32_scsi_done(SCpnt);		}		goto out;	}	if (SCpnt == NULL) {		nsp32_msg(KERN_WARNING, "SCpnt==NULL this can't be happened");		nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat);		goto out;	}	/*	 * AutoSCSI Interrupt.	 * Note: This interrupt is occurred when AutoSCSI is finished.  Then	 * check SCSIEXECUTEPHASE, and do appropriate action.  Each phases are	 * recorded when AutoSCSI sequencer has been processed.	 */	if(irq_stat & IRQSTATUS_AUTOSCSI_IRQ) {		/* getting SCSI executed phase */		auto_stat = nsp32_read2(base, SCSI_EXECUTE_PHASE);		nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);		/* Selection Timeout, go busfree phase. */		if (auto_stat & SELECTION_TIMEOUT) {			nsp32_dbg(NSP32_DEBUG_INTR,				  "selection timeout occurred");			SCpnt->result = DID_TIME_OUT << 16;			nsp32_scsi_done(SCpnt);			goto out;		}		if (auto_stat & MSGOUT_PHASE) {			/*			 * MsgOut phase was processed.			 * If MSG_IN_OCCUER is not set, then MsgOut phase is			 * completed. Thus, msgout_len must reset.  Otherwise,			 * nothing to do here. If MSG_OUT_OCCUER is occurred,			 * then we will encounter the condition and check.			 */			if (!(auto_stat & MSG_IN_OCCUER) &&			     (data->msgout_len <= 3)) {				/*				 * !MSG_IN_OCCUER && msgout_len <=3				 *   ---> AutoSCSI with MSGOUTreg is processed.				 */				data->msgout_len = 0;			};			nsp32_dbg(NSP32_DEBUG_INTR, "MsgOut phase processed");		}		if ((auto_stat & DATA_IN_PHASE) &&		    (SCpnt->resid > 0) &&		    ((nsp32_read2(base, FIFO_REST_CNT) & FIFO_REST_MASK) != 0)) {			printk( "auto+fifo\n");			//nsp32_pio_read(SCpnt);		}		if (auto_stat & (DATA_IN_PHASE | DATA_OUT_PHASE)) {			/* DATA_IN_PHASE/DATA_OUT_PHASE was processed. */			nsp32_dbg(NSP32_DEBUG_INTR,				  "Data in/out phase processed");			/* read BMCNT, SGT pointer addr */			nsp32_dbg(NSP32_DEBUG_INTR, "BMCNT=0x%lx", 				    nsp32_read4(base, BM_CNT));			nsp32_dbg(NSP32_DEBUG_INTR, "addr=0x%lx", 				    nsp32_read4(base, SGT_ADR));			nsp32_dbg(NSP32_DEBUG_INTR, "SACK=0x%lx", 				    nsp32_read4(base, SACK_CNT));			nsp32_dbg(NSP32_DEBUG_INTR, "SSACK=0x%lx", 				    nsp32_read4(base, SAVED_SACK_CNT));			SCpnt->resid = 0; /* all data transfered! */		}		/*		 * MsgIn Occur		 */		if (auto_stat & MSG_IN_OCCUER) {			nsp32_msgin_occur(SCpnt, irq_stat, auto_stat);		}		/*		 * MsgOut Occur		 */		if (auto_stat & MSG_OUT_OCCUER) {			nsp32_msgout_occur(SCpnt);		}		/*		 * Bus Free Occur		 */		if (auto_stat & BUS_FREE_OCCUER) {			ret = nsp32_busfree_occur(SCpnt, auto_stat);			if (ret == TRUE) {				goto out;			}		}		if (auto_stat & STATUS_PHASE) {			/*			 * Read CSB and substitute CSB for SCpnt->result			 * to save status phase stutas byte.			 * scsi error handler checks host_byte (DID_*:			 * low level driver to indicate status), then checks 			 * status_byte (SCSI status byte).			 */			SCpnt->result =	(int)nsp32_read1(base, SCSI_CSB_IN);		}		if (auto_stat & ILLEGAL_PHASE) {			/* Illegal phase is detected. SACK is not back. */			nsp32_msg(KERN_WARNING, 				  "AUTO SCSI ILLEGAL PHASE OCCUR!!!!");			/* TODO: currently we don't have any action... bus reset? */			/*			 * To send back SACK, assert, wait, and negate.			 */			nsp32_sack_assert(data);			nsp32_wait_req(data, NEGATE);			nsp32_sack_negate(data);		}		if (auto_stat & COMMAND_PHASE) {			/* nothing to do */			nsp32_dbg(NSP32_DEBUG_INTR, "Command phase processed");		}		if (auto_stat & AUTOSCSI_BUSY) {			/* AutoSCSI is running */		}		show_autophase(auto_stat);	}	/* FIFO_SHLD_IRQ */	if (irq_stat & IRQSTATUS_FIFO_SHLD_IRQ) {		nsp32_dbg(NSP32_DEBUG_INTR, "FIFO IRQ");		switch(busphase) {		case BUSPHASE_DATA_OUT:			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/write");			//nsp32_pio_write(SCpnt);			break;		case BUSPHASE_DATA_IN:			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/read");			//nsp32_pio_read(SCpnt);			break;		case BUSPHASE_STATUS:			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/status");			SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN);			break;		default:			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/other phase");			nsp32_dbg(NSP32_DEBUG_INTR, "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat);			show_busphase(busphase);			break;		}		goto out;	}	/* Phase Change IRQ */	if (irq_stat & IRQSTATUS_PHASE_CHANGE_IRQ) {		nsp32_dbg(NSP32_DEBUG_INTR, "phase change IRQ");		switch(busphase) {		case BUSPHASE_MESSAGE_IN:			nsp32_dbg(NSP32_DEBUG_INTR, "phase chg/msg in");			nsp32_msgin_occur(SCpnt, irq_stat, 0);			break;

⌨️ 快捷键说明

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