nsp32.c

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

C
2,409
字号
	}	/*	 * Set SGTP ADDR current entry for restarting AUTOSCSI, 	 * because SGTP is incremented next point.	 * There is few statement in the specification...	 */ 	new_sgtp = data->cur_lunt->sglun_paddr + 		   (data->cur_lunt->cur_entry * sizeof(nsp32_sgtable));	/*	 * send messages	 */	for (i = 0; i < data->msgout_len; i++) {		nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR,			  "%d : 0x%x", i, data->msgoutbuf[i]);		/*		 * Check REQ is asserted.		 */		nsp32_wait_req(data, ASSERT);		if (i == (data->msgout_len - 1)) {			/*			 * If the last message, set the AutoSCSI restart			 * before send back the ack message. AutoSCSI			 * restart automatically negate ATN signal.			 */			//command = (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02);			//nsp32_restart_autoscsi(SCpnt, command);			nsp32_write2(base, COMMAND_CONTROL,					 (CLEAR_CDB_FIFO_POINTER |					  AUTO_COMMAND_PHASE     |					  AUTOSCSI_RESTART       |					  AUTO_MSGIN_00_OR_04    |					  AUTO_MSGIN_02          ));		}		/*		 * Write data with SACK, then wait sack is		 * automatically negated.		 */		nsp32_write1(base, SCSI_DATA_WITH_ACK, data->msgoutbuf[i]);		nsp32_wait_sack(data, NEGATE);		nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "bus: 0x%x\n",			  nsp32_read1(base, SCSI_BUS_MONITOR));	};	data->msgout_len = 0;	nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "exit");}/* * Restart AutoSCSI * * Note: Restarting AutoSCSI needs set: *		SYNC_REG, ACK_WIDTH, SGT_ADR, TRANSFER_CONTROL */static void nsp32_restart_autoscsi(Scsi_Cmnd *SCpnt, unsigned short command){	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;	unsigned int   base = data->BaseAddress;	unsigned short transfer = 0;	nsp32_dbg(NSP32_DEBUG_RESTART, "enter");	if (data->cur_target == NULL || data->cur_lunt == NULL) {		nsp32_msg(KERN_ERR, "Target or Lun is invalid");	}	/*	 * set SYNC_REG	 * Don't set BM_START_ADR before setting this register.	 */	nsp32_write1(base, SYNC_REG, data->cur_target->syncreg);	/*	 * set ACKWIDTH	 */	nsp32_write1(base, ACK_WIDTH, data->cur_target->ackwidth);	/*	 * set SREQ hazard killer sampling rate	 */	nsp32_write1(base, SREQ_SMPL_RATE, data->cur_target->sample_reg);	/*	 * set SGT ADDR (physical address)	 */	nsp32_write4(base, SGT_ADR, data->cur_lunt->sglun_paddr);	/*	 * set TRANSFER CONTROL REG	 */	transfer = 0;	transfer |= (TRANSFER_GO | ALL_COUNTER_CLR);	if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {		if (SCpnt->request_bufflen > 0) {			transfer |= BM_START;		}	} else if (data->trans_method & NSP32_TRANSFER_MMIO) {		transfer |= CB_MMIO_MODE;	} else if (data->trans_method & NSP32_TRANSFER_PIO) {		transfer |= CB_IO_MODE;	}	nsp32_write2(base, TRANSFER_CONTROL, transfer);	/*	 * restart AutoSCSI	 *	 * TODO: COMMANDCONTROL_AUTO_COMMAND_PHASE is needed ?	 */	command |= (CLEAR_CDB_FIFO_POINTER |		    AUTO_COMMAND_PHASE     |		    AUTOSCSI_RESTART       );	nsp32_write2(base, COMMAND_CONTROL, command);	nsp32_dbg(NSP32_DEBUG_RESTART, "exit");}/* * cannot run automatically message in occur */static void nsp32_msgin_occur(Scsi_Cmnd     *SCpnt,			      unsigned long  irq_status,			      unsigned short execph){	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;	unsigned int   base = SCpnt->device->host->io_port;	unsigned char  msg;	unsigned char  msgtype;	unsigned char  newlun;	unsigned short command  = 0;	int            msgclear = TRUE;	long           new_sgtp;	int            ret;	/*	 * read first message	 *    Use SCSIDATA_W_ACK instead of SCSIDATAIN, because the procedure	 *    of Message-In have to be processed before sending back SCSI ACK.	 */	msg = nsp32_read1(base, SCSI_DATA_IN);	data->msginbuf[(unsigned char)data->msgin_len] = msg;	msgtype = data->msginbuf[0];	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR,		  "enter: msglen: 0x%x msgin: 0x%x msgtype: 0x%x",		  data->msgin_len, msg, msgtype);	/*	 * TODO: We need checking whether bus phase is message in?	 */	/*	 * assert SCSI ACK	 */	nsp32_sack_assert(data);	/*	 * processing IDENTIFY	 */	if (msgtype & 0x80) {		if (!(irq_status & IRQSTATUS_RESELECT_OCCUER)) {			/* Invalid (non reselect) phase */			goto reject;		}		newlun = msgtype & 0x1f; /* TODO: SPI-3 compliant? */		ret = nsp32_reselection(SCpnt, newlun);		if (ret == TRUE) {			goto restart;		} else {			goto reject;		}	}		/*	 * processing messages except for IDENTIFY	 *	 * TODO: Messages are all SCSI-2 terminology. SCSI-3 compliance is TODO.	 */	switch (msgtype) {	/*	 * 1-byte message	 */	case COMMAND_COMPLETE:	case DISCONNECT:		/*		 * These messages should not be occurred.		 * They should be processed on AutoSCSI sequencer.		 */		nsp32_msg(KERN_WARNING, 			   "unexpected message of AutoSCSI MsgIn: 0x%x", msg);		break;			case RESTORE_POINTERS:		/*		 * AutoMsgIn03 is disabled, and HBA gets this message.		 */		if ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE)) {			unsigned int s_sacklen;			s_sacklen = nsp32_read4(base, SAVED_SACK_CNT);			if ((execph & MSGIN_02_VALID) && (s_sacklen > 0)) {				nsp32_adjust_busfree(SCpnt, s_sacklen);			} else {				/* No need to rewrite SGT */			}		}		data->cur_lunt->msgin03 = FALSE;		/* Update with the new value */		/* reset SACK/SavedACK counter (or ALL clear?) */		nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);		/*		 * set new sg pointer		 */		new_sgtp = data->cur_lunt->sglun_paddr + 			(data->cur_lunt->cur_entry * sizeof(nsp32_sgtable));		nsp32_write4(base, SGT_ADR, new_sgtp);		break;	case SAVE_POINTERS:		/*		 * These messages should not be occurred.		 * They should be processed on AutoSCSI sequencer.		 */		nsp32_msg (KERN_WARNING, 			   "unexpected message of AutoSCSI MsgIn: SAVE_POINTERS");				break;			case MESSAGE_REJECT:		/* If previous message_out is sending SDTR, and get 		   message_reject from target, SDTR negotiation is failed */		if (data->cur_target->sync_flag &				(SDTR_INITIATOR | SDTR_TARGET)) {			/*			 * Current target is negotiating SDTR, but it's			 * failed.  Fall back to async transfer mode, and set			 * SDTR_DONE.			 */			nsp32_set_async(data, data->cur_target);			data->cur_target->sync_flag &= ~SDTR_INITIATOR;			data->cur_target->sync_flag |= SDTR_DONE;		}		break;	case LINKED_CMD_COMPLETE:	case LINKED_FLG_CMD_COMPLETE:		/* queue tag is not supported currently */		nsp32_msg (KERN_WARNING, 			   "unsupported message: 0x%x", msgtype);		break;	case INITIATE_RECOVERY:		/* staring ECA (Extended Contingent Allegiance) state. */		/* This message is declined in SPI2 or later. */		goto reject;	/*	 * 2-byte message	 */	case SIMPLE_QUEUE_TAG:	case 0x23:		/*		 * 0x23: Ignore_Wide_Residue is not declared in scsi.h.		 * No support is needed.		 */		if (data->msgin_len >= 1) {			goto reject;		}		/* current position is 1-byte of 2 byte */		msgclear = FALSE;		break;	/*	 * extended message	 */	case EXTENDED_MESSAGE:		if (data->msgin_len < 1) {			/*			 * Current position does not reach 2-byte			 * (2-byte is extended message length).			 */			msgclear = FALSE;			break;		}		if ((data->msginbuf[1] + 1) > data->msgin_len) {			/*			 * Current extended message has msginbuf[1] + 2			 * (msgin_len starts counting from 0, so buf[1] + 1).			 * If current message position is not finished,			 * continue receiving message.			 */			msgclear = FALSE;			break;		}		/*		 * Reach here means regular length of each type of 		 * extended messages.		 */		switch (data->msginbuf[2]) {		case EXTENDED_MODIFY_DATA_POINTER:			/* TODO */			goto reject; /* not implemented yet */			break;		case EXTENDED_SDTR:			/*			 * Exchange this message between initiator and target.			 */			if (data->msgin_len != EXTENDED_SDTR_LEN + 1) {				/*				 * received inappropriate message.				 */				goto reject;				break;			}			nsp32_analyze_sdtr(SCpnt);			break;		case EXTENDED_EXTENDED_IDENTIFY:			/* SCSI-I only, not supported. */			goto reject; /* not implemented yet */			break;		case EXTENDED_WDTR:			goto reject; /* not implemented yet */			break;					default:			goto reject;		}		break;			default:		goto reject;	} restart:	if (msgclear == TRUE) {		data->msgin_len = 0;		/*		 * If restarting AutoSCSI, but there are some message to out		 * (msgout_len > 0), set AutoATN, and set SCSIMSGOUT as 0		 * (MV_VALID = 0). When commandcontrol is written with		 * AutoSCSI restart, at the same time MsgOutOccur should be		 * happened (however, such situation is really possible...?).		 */		if (data->msgout_len > 0) {				nsp32_write4(base, SCSI_MSG_OUT, 0);			command |= AUTO_ATN;		}		/*		 * restart AutoSCSI		 * If it's failed, COMMANDCONTROL_AUTO_COMMAND_PHASE is needed.		 */		command |= (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02);		/*		 * If current msgin03 is TRUE, then flag on.		 */		if (data->cur_lunt->msgin03 == TRUE) {			command |= AUTO_MSGIN_03;		}		data->cur_lunt->msgin03 = FALSE;	} else {		data->msgin_len++;	}	/*	 * restart AutoSCSI	 */	nsp32_restart_autoscsi(SCpnt, command);	/*	 * wait SCSI REQ negate for REQ-ACK handshake	 */	nsp32_wait_req(data, NEGATE);	/*	 * negate SCSI ACK	 */	nsp32_sack_negate(data);	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit");	return; reject:	nsp32_msg(KERN_WARNING, 		  "invalid or unsupported MessageIn, rejected. "		  "current msg: 0x%x (len: 0x%x), processing msg: 0x%x",		  msg, data->msgin_len, msgtype);	nsp32_build_reject(SCpnt);	data->msgin_len = 0;	goto restart;}/* *  */static void nsp32_analyze_sdtr(Scsi_Cmnd *SCpnt){	nsp32_hw_data   *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;	nsp32_target     *target     = data->cur_target;	nsp32_sync_table *synct;	unsigned char     get_period = data->msginbuf[3];	unsigned char     get_offset = data->msginbuf[4];	int               entry;	int               syncnum;	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "enter");	synct   = data->synct;	syncnum = data->syncnum;	/*	 * If this inititor sent the SDTR message, then target responds SDTR,	 * initiator SYNCREG, ACKWIDTH from SDTR parameter.	 * Messages are not appropriate, then send back reject message.	 * If initiator did not send the SDTR, but target sends SDTR, 	 * initiator calculator the appropriate parameter and send back SDTR.	 */		if (target->sync_flag & SDTR_INITIATOR) {		/*		 * Initiator sent SDTR, the target responds and		 * send back negotiation SDTR.		 */		nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target responds SDTR");			target->sync_flag &= ~SDTR_INITIATOR;		target->sync_flag |= SDTR_DONE;		/*		 * offset:		 */		if (get_offset > SYNC_OFFSET) {			/*			 * Negotiation is failed, the target send back			 * unexpected offset value.			 */			goto reject;		}				if (get_offset == ASYNC_OFFSET) {			/*			 * Negotiation is succeeded, the target want			 * to fall back into asynchronous transfer mode.			 */			goto async;		}		/*		 * period:		 *    Check whether sync period is too short. If too short,		 *    fall back to async mode. If it's ok, then investigate		 *    the received sync period. If sync period is acceptable		 *    between sync table start_period and end_period, then		 *    set this I_T nexus as sent offset and period.		 *    If it's not acceptable, send back r

⌨️ 快捷键说明

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