nsp32.c

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

C
2,409
字号
		default:			nsp32_msg(KERN_WARNING, "phase chg/other phase?");			nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x\n",				  irq_stat, trans_stat);			show_busphase(busphase);			break;		}		goto out;	}	/* PCI_IRQ */	if (irq_stat & IRQSTATUS_PCI_IRQ) {		nsp32_dbg(NSP32_DEBUG_INTR, "PCI IRQ occurred");		/* Do nothing */	}	/* BMCNTERR_IRQ */	if (irq_stat & IRQSTATUS_BMCNTERR_IRQ) {		nsp32_msg(KERN_ERR, "Received unexpected BMCNTERR IRQ! ");		/*		 * TODO: To be implemented improving bus master		 * transfer reliablity when BMCNTERR is occurred in		 * AutoSCSI phase described in specification.		 */	}#if 0	nsp32_dbg(NSP32_DEBUG_INTR,		  "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat);	show_busphase(busphase);#endif out:	/* disable IRQ mask */	nsp32_write2(base, IRQ_CONTROL, 0); out2:#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))	spin_unlock_irqrestore(host->host_lock, flags);#else	spin_unlock_irqrestore(&io_request_lock, flags);#endif	nsp32_dbg(NSP32_DEBUG_INTR, "exit");	return IRQ_RETVAL(handled);}#undef SPRINTF#define SPRINTF(args...) \	do { \		if(length > (pos - buffer)) { \			pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \			nsp32_dbg(NSP32_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length,  length - (pos - buffer));\		} \	} while(0)static int nsp32_proc_info(#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) 	struct Scsi_Host *host,#endif	char             *buffer,	char            **start,	off_t             offset,	int               length,#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) 	int               hostno,#endif	int               inout){	char             *pos = buffer;	int               thislength;	unsigned long     flags;	nsp32_hw_data    *data;#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) 	int               hostno;#else	struct Scsi_Host *host;#endif	unsigned int      base;	unsigned char     mode_reg;	int               id, speed;	long              model;	/* Write is not supported, just return. */	if (inout == TRUE) {		return -EINVAL;	}#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) 	hostno = host->host_no;#else	/* search this HBA host */	host = scsi_host_hn_get(hostno);	if (host == NULL) {		return -ESRCH;	}#endif	data = (nsp32_hw_data *)host->hostdata;	base = host->io_port;	SPRINTF("NinjaSCSI-32 status\n\n");	SPRINTF("Driver version:        %s, $Revision: 1.33 $\n", nsp32_release_version);	SPRINTF("SCSI host No.:         %d\n",		hostno);	SPRINTF("IRQ:                   %d\n",		host->irq);	SPRINTF("IO:                    0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);	SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n",	host->base, host->base + data->MmioLength - 1);	SPRINTF("sg_tablesize:          %d\n",		host->sg_tablesize);	SPRINTF("Chip revision:         0x%x\n",       	(nsp32_read2(base, INDEX_REG) >> 8) & 0xff);	mode_reg = nsp32_index_read1(base, CHIP_MODE);	model    = data->pci_devid->driver_data;#ifdef CONFIG_PM	SPRINTF("Power Management:      %s\n",          (mode_reg & OPTF) ? "yes" : "no");#endif	SPRINTF("OEM:                   %ld, %s\n",     (mode_reg & (OEM0|OEM1)), nsp32_model[model]);	spin_lock_irqsave(&(data->Lock), flags);	SPRINTF("CurrentSC:             0x%p\n\n",      data->CurrentSC);	spin_unlock_irqrestore(&(data->Lock), flags);	SPRINTF("SDTR status\n");	for (id = 0; id < ARRAY_SIZE(data->target); id++) {                SPRINTF("id %d: ", id);		if (id == host->this_id) {			SPRINTF("----- NinjaSCSI-32 host adapter\n");			continue;		}		if (data->target[id].sync_flag == SDTR_DONE) {			if (data->target[id].period == 0            &&			    data->target[id].offset == ASYNC_OFFSET ) {				SPRINTF("async");			} else {				SPRINTF(" sync");			}		} else {			SPRINTF(" none");		}		if (data->target[id].period != 0) {			speed = 1000000 / (data->target[id].period * 4);			SPRINTF(" transfer %d.%dMB/s, offset %d",				speed / 1000,				speed % 1000,				data->target[id].offset				);		}		SPRINTF("\n");	}	thislength = pos - (buffer + offset);	if(thislength < 0) {		*start = NULL;                return 0;        }	thislength = min(thislength, length);	*start = buffer + offset;	return thislength;}#undef SPRINTF/* * Reset parameters and call scsi_done for data->cur_lunt. * Be careful setting SCpnt->result = DID_* before calling this function. */static void nsp32_scsi_done(Scsi_Cmnd *SCpnt){	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;	unsigned int   base = SCpnt->device->host->io_port;	/*	 * unmap pci	 */	if (SCpnt->request_bufflen == 0) {		goto skip;	}	if (SCpnt->use_sg) {		pci_unmap_sg(data->Pci,			     (struct scatterlist *)SCpnt->buffer,			     SCpnt->use_sg,			     scsi_to_pci_dma_dir(SCpnt->sc_data_direction));	} else {		pci_unmap_single(data->Pci,				 (u32)SCpnt->SCp.have_data_in,				 SCpnt->request_bufflen,				 scsi_to_pci_dma_dir(SCpnt->sc_data_direction));	} skip:	/*	 * clear TRANSFERCONTROL_BM_START	 */	nsp32_write2(base, TRANSFER_CONTROL, 0);	nsp32_write4(base, BM_CNT,           0);	/*	 * call scsi_done	 */	(*SCpnt->scsi_done)(SCpnt);	/*	 * reset parameters	 */	data->cur_lunt->SCpnt = NULL;	data->cur_lunt        = NULL;	data->cur_target      = NULL;	data->CurrentSC      = NULL;}/* * Bus Free Occur * * Current Phase is BUSFREE. AutoSCSI is automatically execute BUSFREE phase * with ACK reply when below condition is matched: *	MsgIn 00: Command Complete. *	MsgIn 02: Save Data Pointer. *	MsgIn 04: Diconnect. * In other case, unexpected BUSFREE is detected. */static int nsp32_busfree_occur(Scsi_Cmnd *SCpnt, unsigned short execph){	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;	unsigned int base   = SCpnt->device->host->io_port;	nsp32_dbg(NSP32_DEBUG_BUSFREE, "enter execph=0x%x", execph);	show_autophase(execph);	nsp32_write4(base, BM_CNT,           0);	nsp32_write2(base, TRANSFER_CONTROL, 0);	/*	 * MsgIn 02: Save Data Pointer	 *	 * VALID:	 *   Save Data Pointer is received. Adjust pointer.	 *   	 * NO-VALID:	 *   SCSI-3 says if Save Data Pointer is not received, then we restart	 *   processing and we can't adjust any SCSI data pointer in next data	 *   phase.	 */	if (execph & MSGIN_02_VALID) {		nsp32_dbg(NSP32_DEBUG_BUSFREE, "MsgIn02_Valid");		/*		 * Check sack_cnt/saved_sack_cnt, then adjust sg table if		 * needed.		 */		if (!(execph & MSGIN_00_VALID) && 		    ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE))) {			unsigned int sacklen, s_sacklen;			/*			 * Read SACK count and SAVEDSACK count, then compare.			 */			sacklen   = nsp32_read4(base, SACK_CNT      );			s_sacklen = nsp32_read4(base, SAVED_SACK_CNT);			/*			 * If SAVEDSACKCNT == 0, it means SavedDataPointer is			 * come after data transfering.			 */			if (s_sacklen > 0) {				/*				 * Comparing between sack and savedsack to				 * check the condition of AutoMsgIn03.				 *				 * If they are same, set msgin03 == TRUE,				 * COMMANDCONTROL_AUTO_MSGIN_03 is enabled at				 * reselection.  On the other hand, if they				 * aren't same, set msgin03 == FALSE, and				 * COMMANDCONTROL_AUTO_MSGIN_03 is disabled at				 * reselection.				 */				if (sacklen != s_sacklen) {					data->cur_lunt->msgin03 = FALSE;				} else {					data->cur_lunt->msgin03 = TRUE;				}				nsp32_adjust_busfree(SCpnt, s_sacklen);			}		}		/* This value has not substitude with valid value yet... */		//data->cur_lunt->save_datp = data->cur_datp;	} else {		/*		 * no processing.		 */	}		if (execph & MSGIN_03_VALID) {		/* MsgIn03 was valid to be processed. No need processing. */	}	/*	 * target SDTR check	 */	if (data->cur_target->sync_flag & SDTR_INITIATOR) {		/*		 * SDTR negotiation pulled by the initiator has not		 * finished yet. Fall back to ASYNC mode.		 */		nsp32_set_async(data, data->cur_target);		data->cur_target->sync_flag &= ~SDTR_INITIATOR;		data->cur_target->sync_flag |= SDTR_DONE;	} else if (data->cur_target->sync_flag & SDTR_TARGET) {		/*		 * SDTR negotiation pulled by the target has been		 * negotiating.		 */		if (execph & (MSGIN_00_VALID | MSGIN_04_VALID)) {			/* 			 * If valid message is received, then			 * negotiation is succeeded.			 */		} else {			/*			 * On the contrary, if unexpected bus free is			 * occurred, then negotiation is failed. Fall			 * back to ASYNC mode.			 */			nsp32_set_async(data, data->cur_target);		}		data->cur_target->sync_flag &= ~SDTR_TARGET;		data->cur_target->sync_flag |= SDTR_DONE;	}	/*	 * It is always ensured by SCSI standard that initiator	 * switches into Bus Free Phase after	 * receiving message 00 (Command Complete), 04 (Disconnect).	 * It's the reason that processing here is valid.	 */	if (execph & MSGIN_00_VALID) {		/* MsgIn 00: Command Complete */		nsp32_dbg(NSP32_DEBUG_BUSFREE, "command complete");		SCpnt->SCp.Status  = nsp32_read1(base, SCSI_CSB_IN);		SCpnt->SCp.Message = 0;		nsp32_dbg(NSP32_DEBUG_BUSFREE, 			  "normal end stat=0x%x resid=0x%x\n",			  SCpnt->SCp.Status, SCpnt->resid);		SCpnt->result = (DID_OK             << 16) |			        (SCpnt->SCp.Message <<  8) |			        (SCpnt->SCp.Status  <<  0);		nsp32_scsi_done(SCpnt);		/* All operation is done */		return TRUE;	} else if (execph & MSGIN_04_VALID) {		/* MsgIn 04: Disconnect */		SCpnt->SCp.Status  = nsp32_read1(base, SCSI_CSB_IN);		SCpnt->SCp.Message = 4;				nsp32_dbg(NSP32_DEBUG_BUSFREE, "disconnect");		return TRUE;	} else {		/* Unexpected bus free */		nsp32_msg(KERN_WARNING, "unexpected bus free occurred");		/* DID_ERROR? */		//SCpnt->result   = (DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0);		SCpnt->result = DID_ERROR << 16;		nsp32_scsi_done(SCpnt);		return TRUE;	}	return FALSE;}/* * nsp32_adjust_busfree - adjusting SG table * * Note: This driver adjust the SG table using SCSI ACK *       counter instead of BMCNT counter! */static void nsp32_adjust_busfree(Scsi_Cmnd *SCpnt, unsigned int s_sacklen){	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;	int                   old_entry = data->cur_entry;	int                   new_entry;	int                   sg_num = data->cur_lunt->sg_num;	nsp32_sgtable *sgt    = data->cur_lunt->sglun->sgt;	unsigned int          restlen, sentlen;	u32_le                len, addr;	nsp32_dbg(NSP32_DEBUG_SGLIST, "old resid=0x%x", SCpnt->resid);	/* adjust saved SACK count with 4 byte start address boundary */	s_sacklen -= le32_to_cpu(sgt[old_entry].addr) & 3;	/*	 * calculate new_entry from sack count and each sgt[].len 	 * calculate the byte which is intent to send	 */	sentlen = 0;	for (new_entry = old_entry; new_entry < sg_num; new_entry++) {		sentlen += (le32_to_cpu(sgt[new_entry].len) & ~SGTEND);		if (sentlen > s_sacklen) {			break;		}	}	/* all sgt is processed */	if (new_entry == sg_num) {		goto last;	}	if (sentlen == s_sacklen) {		/* XXX: confirm it's ok or not */		/* In this case, it's ok because we are at 		   the head element of the sg. restlen is correctly calculated. */	}	/* calculate the rest length for transfering */	restlen = sentlen - s_sacklen;	/* update adjusting current SG table entry */	len  = le32_to_cpu(sgt[new_entry].len);	addr = le32_to_cpu(sgt[new_entry].addr);	addr += (len - restlen);	sgt[new_entry].addr = cpu_to_le32(addr);	sgt[new_entry].len  = cpu_to_le32(restlen);	/* set cur_entry with new_entry */	data->cur_entry = new_entry; 	return; last:	if (SCpnt->resid < sentlen) {		nsp32_msg(KERN_ERR, "resid underflow");	}	SCpnt->resid -= sentlen;	nsp32_dbg(NSP32_DEBUG_SGLIST, "new resid=0x%x", SCpnt->resid);	/* update hostdata and lun */	return;}/* * It's called MsgOut phase occur. * NinjaSCSI-32Bi/UDE automatically processes up to 3 messages in * message out phase. It, however, has more than 3 messages, * HBA creates the interrupt and we have to process by hand. */static void nsp32_msgout_occur(Scsi_Cmnd *SCpnt){	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;	unsigned int base   = SCpnt->device->host->io_port;	//unsigned short command;	long new_sgtp;	int i;		nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR,		  "enter: msgout_len: 0x%x", data->msgout_len);	/*	 * If MsgOut phase is occurred without having any	 * message, then No_Operation is sent (SCSI-2).	 */	if (data->msgout_len == 0) {		nsp32_build_nop(SCpnt);

⌨️ 快捷键说明

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