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

📄 fas216.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 5 页
字号:
	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_starttransfer(info, DMA_OUT, 1);		return;						/* Reselmsgin   -> Status       */	case STATE(STAT_STATUS, PHASE_RECONNECTED):		fas216_finish_reconnect(info);		goto status;	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       */	status:		outb(CMD_INITCMDCOMPLETE, REG_CMD(info));		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 = inb(REG_CFIS(info)) & CFIS_CF;		outb(CMD_FLUSHFIFO, REG_CMD(info));		outb(CMD_TRANSFERINFO, REG_CMD(info));		info->scsi.phase = PHASE_MSGIN;		return;						/* Reselmsgin   -> Message In   */	case STATE(STAT_MESGIN, PHASE_RECONNECTED):	case STATE(STAT_MESGIN, PHASE_MSGIN):		info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;		outb(CMD_TRANSFERINFO, REG_CMD(info));		return;						/* Reselmsgin   -> Command      */	case STATE(STAT_COMMAND, PHASE_RECONNECTED):		fas216_finish_reconnect(info);	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;						/* Any          -> Message Out  */	case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT):		fas216_send_messageout(info, 0);		return;	/* Error recovery rules.	 *   These either attempt to abort or retry the operation.	 * TODO: we need more of these	 */	case STATE(STAT_COMMAND, PHASE_COMMAND):/* Command      -> Command      */		/* error - we've sent out all the command bytes		 * we have.		 * NOTE: we need SAVE DATA POINTERS/RESTORE DATA POINTERS		 * to include the command bytes sent for this to work		 * correctly.		 */		printk(KERN_ERR "scsi%d.%c: "			"target trying to receive more command bytes\n",			info->host->host_no, fas216_target(info));		outb(CMD_SETATN, REG_CMD(info));		outb(15, REG_STCL(info));		outb(0, REG_STCM(info));		outb(0, REG_STCH(info));		outb(CMD_PADBYTES | CMD_WITHDMA, REG_CMD(info));		msgqueue_flush(&info->scsi.msgs);		msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);		info->scsi.phase = PHASE_MSGOUT_EXPECT;		return;						/* Selection    -> Message Out  */	case STATE(STAT_MESGOUT, PHASE_SELSTEPS):	case STATE(STAT_MESGOUT, PHASE_MSGOUT): /* Message Out  -> Message Out  */		/* If we get another message out phase, this		 * usually means some parity error occurred.		 * Resend complete set of messages.  If we have		 * more than 1 byte to send, we need to assert		 * ATN again.		 */		if (msgqueue_msglength(&info->scsi.msgs) > 1)			outb(CMD_SETATN, REG_CMD(info));		fas216_send_messageout(info, 0);		return;	}	if (info->scsi.phase == PHASE_MSGIN_DISCONNECT) {		printk(KERN_ERR "scsi%d.%c: disconnect message received, but bus service %s?\n",			info->host->host_no, fas216_target(info),			fas216_bus_phase(stat));		msgqueue_flush(&info->scsi.msgs);		outb(CMD_SETATN, REG_CMD(info));		msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);		info->scsi.phase = PHASE_MSGOUT_EXPECT;		info->scsi.aborting = 1;		outb(CMD_TRANSFERINFO, REG_CMD(info));		return;	}	printk(KERN_ERR "scsi%d.%c: bus phase %s after %s?\n",		info->host->host_no, fas216_target(info),		fas216_bus_phase(stat),		fas216_drv_phase(info));	print_debug_list();	return;bad_is:	printk("scsi%d.%c: bus service at step %d?\n",		info->host->host_no, fas216_target(info),		ssr & IS_BITS);	print_debug_list();	fas216_done(info, DID_ERROR);}/* Function: void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr) * Purpose : handle a function done interrupt from FAS216 chip * Params  : info - interface which caused function done interrupt *           stat - Status register contents *           ssr  - SCSI Status register contents */static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr){	int status, message;	fas216_checkmagic(info);#ifdef DEBUG_FUNCTIONDONE	printk("scsi%d.%c: function done: stat=%X ssr=%X phase=%02X\n",		info->host->host_no, fas216_target(info), stat, ssr, info->scsi.phase);#endif	switch (info->scsi.phase) {	case PHASE_STATUS:			/* status phase - read status and msg	*/		status = inb(REG_FF(info));		message = inb(REG_FF(info));		info->scsi.SCp.Message = message;		info->scsi.SCp.Status = status;		info->scsi.phase = PHASE_DONE;		outb(CMD_MSGACCEPTED, REG_CMD(info));		break;	case PHASE_IDLE:			/* reselected?				*/	case PHASE_MSGIN:			/* message in phase			*/	case PHASE_RECONNECTED:			/* reconnected command			*/		if ((stat & STAT_BUSMASK) == STAT_MESGIN) {			info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;			fas216_message(info);			break;		}	default:		printk("scsi%d.%c: internal phase %s for function done?"			"  What do I do with this?\n",			info->host->host_no, fas216_target(info),			fas216_drv_phase(info));	}}/* Function: void fas216_intr(struct Scsi_Host *instance) * Purpose : handle interrupts from the interface to progress a command * Params  : instance - interface to service */void fas216_intr(struct Scsi_Host *instance){	FAS216_Info *info = (FAS216_Info *)instance->hostdata;	unsigned char isr, ssr, stat;	fas216_checkmagic(info);	stat = inb(REG_STAT(info));	ssr = inb(REG_IS(info));	isr = inb(REG_INST(info));	add_debug_list(stat, ssr, isr, info->scsi.phase);	if (stat & STAT_INT) {		if (isr & INST_BUSRESET) {			printk(KERN_DEBUG "scsi%d.H: bus reset detected\n", instance->host_no);			scsi_report_bus_reset(instance, 0);		} else if (isr & INST_ILLEGALCMD) {			printk(KERN_CRIT "scsi%d.H: illegal command given\n", instance->host_no);			fas216_dumpstate(info);		} else if (isr & INST_DISCONNECT)			fas216_disconnect_intr(info);		else if (isr & INST_RESELECTED)		/* reselected			*/			fas216_reselected_intr(info);		else if (isr & INST_BUSSERVICE)		/* bus service request		*/			fas216_busservice_intr(info, stat, ssr);		else if (isr & INST_FUNCDONE)		/* function done		*/			fas216_funcdone_intr(info, stat, ssr);		else		    	printk("scsi%d.%c: unknown interrupt received:"				" phase %s isr %02X ssr %02X stat %02X\n",				instance->host_no, fas216_target(info),				fas216_drv_phase(info), isr, ssr, stat);	}}/* Function: void fas216_kick(FAS216_Info *info) * Purpose : kick a command to the interface - interface should be idle * Params  : info - our host interface to kick * Notes   : Interrupts are always disabled! */static void fas216_kick(FAS216_Info *info){	Scsi_Cmnd *SCpnt = NULL;	int tot_msglen, from_queue = 0, disconnect_ok;	fas216_checkmagic(info);	/*	 * Obtain the next command to process.	 */	do {		if (info->reqSCpnt) {			SCpnt = info->reqSCpnt;			info->reqSCpnt = NULL;			break;		}		if (info->origSCpnt) {			SCpnt = info->origSCpnt;			info->origSCpnt = NULL;			break;		}		/* retrieve next command */		if (!SCpnt) {			SCpnt = queue_remove_exclude(&info->queues.issue,						     info->busyluns);			from_queue = 1;			break;		}	} while (0);	if (!SCpnt) /* no command pending - just exit */		return;	if (info->scsi.disconnectable && info->SCpnt) {		queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt);		info->scsi.disconnectable = 0;		info->SCpnt = NULL;		printk("scsi%d.%c: moved command to disconnected queue\n",			info->host->host_no, fas216_target(info));	}	/*	 * claim host busy	 */	info->scsi.phase = PHASE_SELECTION;	info->SCpnt = SCpnt;	info->scsi.SCp = SCpnt->SCp;	info->dma.transfer_type = fasdma_none;#ifdef DEBUG_CONNECT	printk("scsi%d.%c: starting cmd %02X",		info->host->host_no, '0' + SCpnt->target,		SCpnt->cmnd[0]);#endif	if (from_queue) {#ifdef SCSI2_TAG		/*		 * tagged queuing - allocate a new tag to this command		 */		if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE &&		    SCpnt->cmnd[0] != INQUIRY) {		    SCpnt->device->current_tag += 1;			if (SCpnt->device->current_tag == 0)			    SCpnt->device->current_tag = 1;				SCpnt->tag = SCpnt->device->current_tag;		} else#endif			set_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns);		info->stats.removes += 1;		switch (SCpnt->cmnd[0]) {		case WRITE_6:		case WRITE_10:		case WRITE_12:			info->stats.writes += 1;			break;		case READ_6:		case READ_10:		case READ_12:			info->stats.reads += 1;			break;		default:			info->stats.miscs += 1;			break;		}	}	/*	 * Don't allow request sense commands to disconnect.	 */	disconnect_ok = SCpnt->cmnd[0] != REQUEST_SENSE &&			info->device[SCpnt->target].disconnect_ok;	/*	 * build outgoing message bytes	 */	msgqueue_flush(&info->scsi.msgs);	msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(disconnect_ok, SCpnt->lun));	/*	 * add tag message if required	 */	if (SCpnt->tag)		msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag);	do {#ifdef SCSI2_WIDE		if (info->device[SCpnt->target].wide_state == neg_wait) {			info->device[SCpnt->target].wide_state = neg_inprogress;			msgqueue_addmsg(&info->scsi.msgs, 4,					EXTENDED_MESSAGE, 2, EXTENDED_WDTR,					info->ifcfg.wide_max_size);			break;		}#endif#ifdef SCSI2_SYNC		if ((info->device[SCpnt->target].sync_state == neg_wait ||		     info->device[SCpnt->target].sync_state == neg_complete) &&		    (SCpnt->cmnd[0] == REQUEST_SENSE ||		     SCpnt->cmnd[0] == INQUIRY)) {			info->device[SCpnt->target].sync_state = neg_inprogress;			msgqueue_addmsg(&info->scsi.msgs, 5,					EXTENDED_MESSAGE, 3, EXTENDED_SDTR,					1000 / info->ifcfg.clockrate,					info->ifcfg.sync_max_depth);			break;		}#endif	} while (0);	/* following what the ESP driver says */	outb(0, REG_STCL(info));	outb(0, REG_STCM(info));	outb(0, REG_STCH(info));	outb(CMD_NOP | CMD_WITHDMA, REG_CMD(info));	/* flush FIFO */	outb(CMD_FLUSHFIFO, REG_CMD(info));	/* load bus-id and timeout */	outb(BUSID(SCpnt->target), REG_SDID(info));	outb(info->ifcfg.select_timeout, REG_STIM(info));	/* synchronous transfers */	fas216_set_sync(info, SCpnt->target);	tot_msglen = msgqueue_msglength(&info->scsi.msgs);#ifdef DEBUG_MESSAGES	{		struct message *msg;		int msgnr = 0, i;		printk("scsi%d.%c: message out: ",			info->host->host_no, '0' + SCpnt->target);		while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {			printk("{ ");			for (i = 0; i < msg->length; i++)				printk("%02x ", msg->msg[i]);			printk("} ");		}		printk("\n");	}#endif	if (tot_msglen == 1 || tot_msglen == 3) {		/*		 * We have an easy message length to send...		 */		struct message *msg;		int msgnr = 0, i;		info->scsi.phase = PHASE_SELSTEPS;		/* load message bytes */		while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {			for (i = 0; i < msg->length; i++)				outb(msg->msg[i], REG_FF(info));			msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF);		}		/* load command */		for (i = 0; i < SCpnt->cmd_len; i++)			outb(SCpnt->cmnd[i], REG_FF(info));		if (tot_msglen == 1)			outb(CMD_SELECTATN, REG_CMD(info));		else			outb(CMD_SELECTATN3, REG_CMD(info));	} else {		/*		 * We have an unusual number of message bytes to send.		 *  Load first byte into fifo, and issue SELECT with ATN and		 *  stop steps.		 */		struct message *msg = msgqueue_getmsg(&info->scsi.msgs, 0);		outb(msg->msg[0], REG_FF(info));		msg->fifo = 1;		outb(CMD_SELECTATNSTOP, REG_CMD(info));	}#ifdef DEBUG_CONNECT	printk(", data pointers [%p, %X]\n",		info->scsi.SCp.ptr, info->scsi.SCp.this_residual);#endif	/* should now get either DISCONNECT or (FUNCTION DONE with BUS SERVICE) intr */}/* Function: void fas216_rq_sns_done(info, SCpnt, result) * Purpose : Finish processing automatic request sense command * Params  : info   - interface that completed *	     SCpnt  - command that completed *	     result - driver byte of result */static voidfas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result){#ifdef DEBUG_CONNECT	printk("scsi%d.%c: request sense complete, result=%04X%02X%02X\n",		info->host->host_no, '0' + SCpnt->target, result,		SCpnt->SCp.Message, SCpnt->SCp.Status);#endif	if (result != DID_OK || SCpnt->SCp.Status != GOOD)		/*		 * Something went wrong.  Make sure that we don't		 * have valid data in the sense buffer that could		 * confuse the higher levels.		 */		memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));	/*	 * Note that we don't set SCpnt->result, since that should	 * reflect the status of the command that we were asked by	 * the upper layers to process.  This would have been set	 * correctly by fas216_std_done.	 */	SCpnt->scsi_done(SCpnt);}/* Function: void fas216_std_done(info, SCpnt, result) * Purpose : Finish processing of standard command * Params  : info   - interface that completed *	     SCpnt  - command that completed

⌨️ 快捷键说明

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