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

📄 fas216.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
				"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));		return;	default:		printk("scsi%d.%c: bus service at step %d?\n",			info->host->host_no, fas216_target(info),			ssr & IS_BITS);	}}/* 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, "fas216_funcdone_intr");#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, "fas216_intr");	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("scsi%d.H: bus reset detected\n", instance->host_no);		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;	int tot_msglen, from_queue = 0;	fas216_checkmagic(info, "fas216_kick");	if (info->origSCpnt) {		SCpnt = info->origSCpnt;		info->origSCpnt = NULL;	} else		SCpnt = NULL;	/* retrieve next command */	if (!SCpnt) {		SCpnt = queue_remove_exclude(&info->queues.issue, info->busyluns);		from_queue = 1;	}	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));	}	/*	 * tagged queuing - allocate a new tag to this command	 */	if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE) {		SCpnt->device->current_tag += 1;		if (SCpnt->device->current_tag == 0)		    SCpnt->device->current_tag = 1;		SCpnt->tag = SCpnt->device->current_tag;	}	/*	 * 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		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;		}	}	/* build outgoing message bytes */	msgqueue_flush(&info->scsi.msgs);	if (info->device[SCpnt->target].disconnect_ok)		msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(1, SCpnt->lun));	else		msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(0, SCpnt->lun));	/* add tag message if required */	if (SCpnt->tag)		msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag);#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);	}#ifdef SCSI2_SYNC	else#endif#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);	}#endif	/* 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);	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_done(FAS216_Info *info, unsigned int result) * Purpose : complete processing for command * Params  : info   - interface that completed *	     result - driver byte of result */static void fas216_done(FAS216_Info *info, unsigned int result){	Scsi_Cmnd *SCpnt;	fas216_checkmagic(info, "fas216_done");	SCpnt = info->SCpnt;	if (info->scsi.aborting) {		printk("scsi%d.%c: uncaught abort - returning DID_ABORT\n",			info->host->host_no, fas216_target(info));		result = DID_ABORT;		info->scsi.aborting = 0;	}	info->stats.fins += 1;	if (SCpnt) {	    	info->scsi.phase = PHASE_IDLE;		info->SCpnt = NULL;		SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 |				info->scsi.SCp.Status;		/*		 * In theory, this should not happen, but just in case it does.		 */		if (info->scsi.SCp.ptr &&                    info->scsi.SCp.this_residual &&		    result == DID_OK) {			switch (SCpnt->cmnd[0]) {			case INQUIRY:			case START_STOP:			case READ_CAPACITY:			case TEST_UNIT_READY:			case MODE_SENSE:				break;			default:				switch (status_byte(SCpnt->result)) {				case CHECK_CONDITION:				case COMMAND_TERMINATED:				case BUSY:				case QUEUE_FULL:				case RESERVATION_CONFLICT:					break;				default:					printk(KERN_ERR "scsi%d.H: incomplete data transfer "						"detected: res=%08X ptr=%p len=%X command=",						info->host->host_no, SCpnt->result,						info->scsi.SCp.ptr, info->scsi.SCp.this_residual);					print_command(SCpnt->cmnd);				}			}		}#ifdef DEBUG_CONNECT		printk("scsi%d.%c: scsi command (%p) complete, result=%08X\n",			info->host->host_no, fas216_target(info),			SCpnt, SCpnt->result);#endif		if (!SCpnt->scsi_done)			panic("scsi%d.H: null scsi_done function in "				"fas216_done", info->host->host_no);		clear_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns);		SCpnt->scsi_done(SCpnt);	} else		panic("scsi%d.H: null command in fas216_done", info->host->host_no);	if (info->scsi.irq != NO_IRQ)		fas216_kick(info);}/* Function: int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) * Purpose : queue a command for adapter to process. * Params  : SCpnt - Command to queue *	     done  - done function to call once command is complete * Returns : 0 - success, else error */int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)){	FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;	fas216_checkmagic(info, "fas216_queue_command");#ifdef DEBUG_CONNECT	printk("scsi%d.%c: received queuable command (%p) %02X\n",		SCpnt->host->host_no, '0' + SCpnt->target,		SCpnt, SCpnt->cmnd[0]);#endif	SCpnt->scsi_done = done;	SCpnt->host_scribble = NULL;	SCpnt->result = 0;	SCpnt->SCp.Message = 0;	SCpnt->SCp.Status = 0;	if (SCpnt->use_sg) {		unsigned long len = 0;		int buf;		SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer;		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;		SCpnt->SCp.ptr = (char *) SCpnt->SCp.buffer->address;		SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;		/*		 * Calculate correct buffer length		 */		for (buf = 0; buf <= SCpnt->SCp.buffers_residual; buf++)			len += SCpnt->SCp.buffer[buf].length;		SCpnt->request_bufflen = len;	} else {		SCpnt->SCp.buffer = NULL;		SCpnt->SCp.buffers_residual = 0;		SCpnt->SCp.ptr = (unsigned char *)SCpnt->request_buffer;		SCpnt->SCp.this_residual = SCpnt->request_bufflen;	}	info->stats.queues += 1;	SCpnt->tag = 0;	if (info->scsi.irq != NO_IRQ) {		unsigned long flags;		/* add command into execute queue and let it complete under		 * the drivers interrupts.		 */		if (!queue_add_cmd_ordered(&info->queues.issue, SCpnt)) {

⌨️ 快捷键说明

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