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

📄 fas216.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		info->scsi.disconnectable = 0;		if (info->SCpnt->device->id  == target &&		    info->SCpnt->device->lun == lun &&		    info->SCpnt->tag         == tag) {			fas216_log(info, LOG_CONNECT, "reconnected previously executing command");		} else {			queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt);			fas216_log(info, LOG_CONNECT, "had to move command to disconnected queue");			info->SCpnt = NULL;		}	}	if (!info->SCpnt) {		info->SCpnt = queue_remove_tgtluntag(&info->queues.disconnected,					target, lun, tag);		fas216_log(info, LOG_CONNECT, "had to get command");	}	if (info->SCpnt) {		/*		 * Restore data pointer from SAVED data pointer		 */		info->scsi.SCp = info->SCpnt->SCp;		fas216_log(info, LOG_CONNECT, "data pointers: [%p, %X]",			info->scsi.SCp.ptr, info->scsi.SCp.this_residual);		info->scsi.phase = PHASE_MSGIN;	} else {		/*		 * Our command structure not found - abort the		 * command on the target.  Since we have no		 * record of this command, we can't send		 * an INITIATOR DETECTED ERROR message.		 */		fas216_cmd(info, CMD_SETATN);#if 0		if (tag)			msgqueue_addmsg(&info->scsi.msgs, 2, ABORT_TAG, tag);		else#endif			msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);		info->scsi.phase = PHASE_MSGOUT_EXPECT;		info->scsi.aborting = 1;	}	fas216_cmd(info, CMD_MSGACCEPTED);	return; initiator_error:	printk(KERN_ERR "scsi%d.H: error during reselection: bytes",		info->host->host_no);	for (i = 0; i < cfis; i++)		printk(" %02x", msg[i]);	printk("\n"); bad_message:	fas216_cmd(info, CMD_SETATN);	msgqueue_flush(&info->scsi.msgs);	msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);	info->scsi.phase = PHASE_MSGOUT_EXPECT;	fas216_cmd(info, CMD_MSGACCEPTED);}static void fas216_parse_message(FAS216_Info *info, unsigned char *message, int msglen){	int i;	switch (message[0]) {	case COMMAND_COMPLETE:		if (msglen != 1)			goto unrecognised;		printk(KERN_ERR "scsi%d.%c: command complete with no "			"status in MESSAGE_IN?\n",			info->host->host_no, fas216_target(info));		break;	case SAVE_POINTERS:		if (msglen != 1)			goto unrecognised;		/*		 * Save current data pointer to SAVED data pointer		 * SCSI II standard says that we must not acknowledge		 * this until we have really saved pointers.		 * NOTE: we DO NOT save the command nor status pointers		 * as required by the SCSI II standard.  These always		 * point to the start of their respective areas.		 */		info->SCpnt->SCp = info->scsi.SCp;		info->SCpnt->SCp.sent_command = 0;		fas216_log(info, LOG_CONNECT | LOG_MESSAGES | LOG_BUFFER,			"save data pointers: [%p, %X]",			info->scsi.SCp.ptr, info->scsi.SCp.this_residual);		break;	case RESTORE_POINTERS:		if (msglen != 1)			goto unrecognised;		/*		 * Restore current data pointer from SAVED data pointer		 */		info->scsi.SCp = info->SCpnt->SCp;		fas216_log(info, LOG_CONNECT | LOG_MESSAGES | LOG_BUFFER,			"restore data pointers: [%p, 0x%x]",			info->scsi.SCp.ptr, info->scsi.SCp.this_residual);		break;	case DISCONNECT:		if (msglen != 1)			goto unrecognised;		info->scsi.phase = PHASE_MSGIN_DISCONNECT;		break;	case MESSAGE_REJECT:		if (msglen != 1)			goto unrecognised;		switch (fas216_get_last_msg(info, info->scsi.msgin_fifo)) {		case EXTENDED_MESSAGE | EXTENDED_SDTR << 8:			fas216_handlesync(info, message);			break;		default:			fas216_log(info, 0, "reject, last message 0x%04x",				fas216_get_last_msg(info, info->scsi.msgin_fifo));		}		break;	case NOP:		break;	case EXTENDED_MESSAGE:		if (msglen < 3)			goto unrecognised;		switch (message[2]) {		case EXTENDED_SDTR:	/* Sync transfer negotiation request/reply */			fas216_handlesync(info, message);			break;		default:			goto unrecognised;		}		break;	default:		goto unrecognised;	}	return;unrecognised:	fas216_log(info, 0, "unrecognised message, rejecting");	printk("scsi%d.%c: message was", info->host->host_no, fas216_target(info));	for (i = 0; i < msglen; i++)		printk("%s%02X", i & 31 ? " " : "\n  ", message[i]);	printk("\n");	/*	 * Something strange seems to be happening here -	 * I can't use SETATN since the chip gives me an	 * invalid command interrupt when I do.  Weird.	 */fas216_cmd(info, CMD_NOP);fas216_dumpstate(info);	fas216_cmd(info, CMD_SETATN);	msgqueue_flush(&info->scsi.msgs);	msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);	info->scsi.phase = PHASE_MSGOUT_EXPECT;fas216_dumpstate(info);}static int fas216_wait_cmd(FAS216_Info *info, int cmd){	int tout;	int stat;	fas216_cmd(info, cmd);	for (tout = 1000; tout; tout -= 1) {		stat = fas216_readb(info, REG_STAT);		if (stat & (STAT_INT|STAT_PARITYERROR))			break;		udelay(1);	}	return stat;}static int fas216_get_msg_byte(FAS216_Info *info){	unsigned int stat = fas216_wait_cmd(info, CMD_MSGACCEPTED);	if ((stat & STAT_INT) == 0)		goto timedout;	if ((stat & STAT_BUSMASK) != STAT_MESGIN)		goto unexpected_phase_change;	fas216_readb(info, REG_INST);	stat = fas216_wait_cmd(info, CMD_TRANSFERINFO);	if ((stat & STAT_INT) == 0)		goto timedout;	if (stat & STAT_PARITYERROR)		goto parity_error;	if ((stat & STAT_BUSMASK) != STAT_MESGIN)		goto unexpected_phase_change;	fas216_readb(info, REG_INST);	return fas216_readb(info, REG_FF);timedout:	fas216_log(info, LOG_ERROR, "timed out waiting for message byte");	return -1;unexpected_phase_change:	fas216_log(info, LOG_ERROR, "unexpected phase change: status = %02x", stat);	return -2;parity_error:	fas216_log(info, LOG_ERROR, "parity error during message in phase");	return -3;}/** * fas216_message - handle a function done interrupt from FAS216 chip * @info: interface which caused function done interrupt * * Handle a function done interrupt from FAS216 chip */static void fas216_message(FAS216_Info *info){	unsigned char *message = info->scsi.message;	unsigned int msglen = 1;	int msgbyte = 0;	fas216_checkmagic(info);	message[0] = fas216_readb(info, REG_FF);	if (message[0] == EXTENDED_MESSAGE) {		msgbyte = fas216_get_msg_byte(info);		if (msgbyte >= 0) {			message[1] = msgbyte;			for (msglen = 2; msglen < message[1] + 2; msglen++) {				msgbyte = fas216_get_msg_byte(info);				if (msgbyte >= 0)					message[msglen] = msgbyte;				else					break;			}		}	}	if (msgbyte == -3)		goto parity_error;#ifdef DEBUG_MESSAGES	{		int i;		printk("scsi%d.%c: message in: ",			info->host->host_no, fas216_target(info));		for (i = 0; i < msglen; i++)			printk("%02X ", message[i]);		printk("\n");	}#endif	fas216_parse_message(info, message, msglen);	fas216_cmd(info, CMD_MSGACCEPTED);	return;parity_error:	fas216_cmd(info, CMD_SETATN);	msgqueue_flush(&info->scsi.msgs);	msgqueue_addmsg(&info->scsi.msgs, 1, MSG_PARITY_ERROR);	info->scsi.phase = PHASE_MSGOUT_EXPECT;	fas216_cmd(info, CMD_MSGACCEPTED);	return;}/** * fas216_send_command - send command after all message bytes have been sent * @info: interface which caused bus service * * Send a command to a target after all message bytes have been sent */static void fas216_send_command(FAS216_Info *info){	int i;	fas216_checkmagic(info);	fas216_cmd(info, CMD_NOP|CMD_WITHDMA);	fas216_cmd(info, CMD_FLUSHFIFO);	/* load command */	for (i = info->scsi.SCp.sent_command; i < info->SCpnt->cmd_len; i++)		fas216_writeb(info, REG_FF, info->SCpnt->cmnd[i]);	fas216_cmd(info, CMD_TRANSFERINFO);	info->scsi.phase = PHASE_COMMAND;}/** * fas216_send_messageout - handle bus service to send a message * @info: interface which caused bus service * * Handle bus service to send a message. * Note: We do not allow the device to change the data direction! */static void fas216_send_messageout(FAS216_Info *info, int start){	unsigned int tot_msglen = msgqueue_msglength(&info->scsi.msgs);	fas216_checkmagic(info);	fas216_cmd(info, CMD_FLUSHFIFO);	if (tot_msglen) {		struct message *msg;		int msgnr = 0;		while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {			int i;			for (i = start; i < msg->length; i++)				fas216_writeb(info, REG_FF, msg->msg[i]);			msg->fifo = tot_msglen - (fas216_readb(info, REG_CFIS) & CFIS_CF);			start = 0;		}	} else		fas216_writeb(info, REG_FF, NOP);	fas216_cmd(info, CMD_TRANSFERINFO);	info->scsi.phase = PHASE_MSGOUT;}/** * fas216_busservice_intr - handle bus service interrupt from FAS216 chip * @info: interface which caused bus service interrupt * @stat: Status register contents * @is: SCSI Status register contents * * Handle a bus service interrupt from FAS216 chip */static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int is){	fas216_checkmagic(info);	fas216_log(info, LOG_BUSSERVICE,		   "bus service: stat=%02x is=%02x phase=%02x",		   stat, is, info->scsi.phase);	switch (info->scsi.phase) {	case PHASE_SELECTION:		if ((is & IS_BITS) != IS_MSGBYTESENT)			goto bad_is;		break;	case PHASE_SELSTEPS:		switch (is & IS_BITS) {		case IS_SELARB:		case IS_MSGBYTESENT:			goto bad_is;		case IS_NOTCOMMAND:		case IS_EARLYPHASE:			if ((stat & STAT_BUSMASK) == STAT_MESGIN)				break;			goto bad_is;		case IS_COMPLETE:			break;		}	default:		break;	}	fas216_cmd(info, CMD_NOP);#define STATE(st,ph) ((ph) << 3 | (st))	/* This table describes the legal SCSI state transitions,	 * as described by the SCSI II spec.	 */	switch (STATE(stat & STAT_BUSMASK, info->scsi.phase)) {	case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> Data In      */	case STATE(STAT_DATAIN, PHASE_MSGOUT):  /* Message Out  -> Data In      */	case STATE(STAT_DATAIN, PHASE_COMMAND): /* Command      -> Data In      */	case STATE(STAT_DATAIN, PHASE_MSGIN):   /* Message In   -> Data In      */		info->scsi.phase = PHASE_DATAIN;		fas216_transfer(info);		return;	case STATE(STAT_DATAIN, PHASE_DATAIN):  /* Data In      -> Data In      */	case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out     -> Data Out     */		fas216_cleanuptransfer(info);		fas216_transfer(info);		return;	case STATE(STAT_DATAOUT, PHASE_SELSTEPS):/* Sel w/ steps-> Data Out     */	case STATE(STAT_DATAOUT, PHASE_MSGOUT): /* Message Out  -> Data Out     */	case STATE(STAT_DATAOUT, PHASE_COMMAND):/* Command      -> Data Out     */	case STATE(STAT_DATAOUT, PHASE_MSGIN):  /* Message In   -> Data Out     */		fas216_cmd(info, CMD_FLUSHFIFO);		info->scsi.phase = PHASE_DATAOUT;		fas216_transfer(info);		return;	case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out     -> Status       */	case STATE(STAT_STATUS, PHASE_DATAIN):  /* Data In      -> Status       */		fas216_stoptransfer(info);	case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status       */	case STATE(STAT_STATUS, PHASE_MSGOUT):  /* Message Out  -> Status       */	case STATE(STAT_STATUS, PHASE_COMMAND): /* Command      -> Status       */	case STATE(STAT_STATUS, PHASE_MSGIN):   /* Message In   -> Status       */		fas216_cmd(info, CMD_INITCMDCOMPLETE);		info->scsi.phase = PHASE_STATUS;		return;	case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out     -> Message In   */	case STATE(STAT_MESGIN, PHASE_DATAIN):  /* Data In      -> Message In   */		fas216_stoptransfer(info);	case STATE(STAT_MESGIN, PHASE_COMMAND):	/* Command	-> Message In	*/	case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In   */	case STATE(STAT_MESGIN, PHASE_MSGOUT):  /* Message Out  -> Message In   */		info->scsi.msgin_fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;		fas216_cmd(info, CMD_FLUSHFIFO);		fas216_cmd(info, CMD_TRANSFERINFO);		info->scsi.phase = PHASE_MSGIN;		return;	case STATE(STAT_MESGIN, PHASE_MSGIN):		info->scsi.msgin_fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;		fas216_cmd(info, CMD_TRANSFERINFO);		return;	case STATE(STAT_COMMAND, PHASE_MSGOUT): /* Message Out  -> Command      */	case STATE(STAT_COMMAND, PHASE_MSGIN):  /* Message In   -> Command      */		fas216_send_command(info);		info->scsi.phase = PHASE_COMMAND;		return;	/*	 * Selection    -> Message Out	 */	case STATE(STAT_MESGOUT, PHASE_SELECTION):		fas216_send_messageout(info, 1);		return;	/*	 * Message Out  -> Message Out	 */	case STATE(STAT_MESGOUT, PHASE_SELSTEPS):	case STATE(STAT_MESGOUT, PHASE_MSGOUT):		/*		 * If we get another message out phase, this usually		 * means some parity error occurred.  Resend complete		 * set of messages.  If we have more than one byte to		 * send, we need to assert ATN again.		 */		if (info->device[info->SCpnt->device->id].parity_check) {			/*			 * We were testing... good, the device			 * supports parity checking.			 */			info->device[info->SCpnt->device->id].parity_check = 0;			info->device[info->SCpnt->device->id].parity_enabled = 1;			fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);		}		if (msgqueue_msglength(&info->scsi.msgs) > 1)			fas216_cmd(info, CMD_SETATN);		/*FALLTHROUGH*/	/*	 * Any          -> Message Out	 */	case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT):		fas216_send_messageout(info, 0);

⌨️ 快捷键说明

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