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

📄 fas216.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		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));		fas216_cmd(info, CMD_SETATN);		fas216_set_stc(info, 15);		fas216_cmd(info, CMD_PADBYTES | CMD_WITHDMA);		msgqueue_flush(&info->scsi.msgs);		msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);		info->scsi.phase = PHASE_MSGOUT_EXPECT;		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);		fas216_cmd(info, CMD_SETATN);		msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);		info->scsi.phase = PHASE_MSGOUT_EXPECT;		info->scsi.aborting = 1;		fas216_cmd(info, CMD_TRANSFERINFO);		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:	fas216_log(info, 0, "bus service at step %d?", is & IS_BITS);	fas216_dumpstate(info);	print_debug_list();	fas216_done(info, DID_ERROR);}/** * fas216_funcdone_intr - handle a function done interrupt from FAS216 chip * @info: interface which caused function done interrupt * @stat: Status register contents * @is: SCSI Status register contents * * Handle a function done interrupt from FAS216 chip */static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned int is){	unsigned int fifo_len = fas216_readb(info, REG_CFIS) & CFIS_CF;	fas216_checkmagic(info);	fas216_log(info, LOG_FUNCTIONDONE,		   "function done: stat=%02x is=%02x phase=%02x",		   stat, is, info->scsi.phase);	switch (info->scsi.phase) {	case PHASE_STATUS:			/* status phase - read status and msg	*/		if (fifo_len != 2) {			fas216_log(info, 0, "odd number of bytes in FIFO: %d", fifo_len);		}		/*		 * Read status then message byte.		 */		info->scsi.SCp.Status = fas216_readb(info, REG_FF);		info->scsi.SCp.Message = fas216_readb(info, REG_FF);		info->scsi.phase = PHASE_DONE;		fas216_cmd(info, CMD_MSGACCEPTED);		break;	case PHASE_IDLE:	case PHASE_SELECTION:	case PHASE_SELSTEPS:		break;	case PHASE_MSGIN:			/* message in phase			*/		if ((stat & STAT_BUSMASK) == STAT_MESGIN) {			info->scsi.msgin_fifo = fifo_len;			fas216_message(info);			break;		}	default:		fas216_log(info, 0, "internal phase %s for function done?"			"  What do I do with this?",			fas216_target(info), fas216_drv_phase(info));	}}static void fas216_bus_reset(FAS216_Info *info){	neg_t sync_state;	int i;	msgqueue_flush(&info->scsi.msgs);	sync_state = neg_invalid;#ifdef SCSI2_SYNC	if (info->ifcfg.capabilities & (FASCAP_DMA|FASCAP_PSEUDODMA))		sync_state = neg_wait;#endif	info->scsi.phase = PHASE_IDLE;	info->SCpnt = NULL; /* bug! */	memset(&info->scsi.SCp, 0, sizeof(info->scsi.SCp));	for (i = 0; i < 8; i++) {		info->device[i].disconnect_ok	= info->ifcfg.disconnect_ok;		info->device[i].sync_state	= sync_state;		info->device[i].period		= info->ifcfg.asyncperiod / 4;		info->device[i].stp		= info->scsi.async_stp;		info->device[i].sof		= 0;		info->device[i].wide_xfer	= 0;	}	info->rst_bus_status = 1;	wake_up(&info->eh_wait);}/** * fas216_intr - handle interrupts to progress a command * @info: interface to service * * Handle interrupts from the interface to progress a command */irqreturn_t fas216_intr(FAS216_Info *info){	unsigned char inst, is, stat;	int handled = IRQ_NONE;	fas216_checkmagic(info);	stat = fas216_readb(info, REG_STAT);	is = fas216_readb(info, REG_IS);	inst = fas216_readb(info, REG_INST);	add_debug_list(stat, is, inst, info->scsi.phase);	if (stat & STAT_INT) {		if (inst & INST_BUSRESET) {			fas216_log(info, 0, "bus reset detected");			fas216_bus_reset(info);			scsi_report_bus_reset(info->host, 0);		} else if (inst & INST_ILLEGALCMD) {			fas216_log(info, LOG_ERROR, "illegal command given\n");			fas216_dumpstate(info);			print_debug_list();		} else if (inst & INST_DISCONNECT)			fas216_disconnect_intr(info);		else if (inst & INST_RESELECTED)	/* reselected			*/			fas216_reselected_intr(info);		else if (inst & INST_BUSSERVICE)	/* bus service request		*/			fas216_busservice_intr(info, stat, is);		else if (inst & INST_FUNCDONE)		/* function done		*/			fas216_funcdone_intr(info, stat, is);		else		    	fas216_log(info, 0, "unknown interrupt received:"				" phase %s inst %02X is %02X stat %02X",				fas216_drv_phase(info), inst, is, stat);		handled = IRQ_HANDLED;	}	return handled;}static void __fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt){	int tot_msglen;	/* following what the ESP driver says */	fas216_set_stc(info, 0);	fas216_cmd(info, CMD_NOP | CMD_WITHDMA);	/* flush FIFO */	fas216_cmd(info, CMD_FLUSHFIFO);	/* load bus-id and timeout */	fas216_writeb(info, REG_SDID, BUSID(SCpnt->device->id));	fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout);	/* synchronous transfers */	fas216_set_sync(info, SCpnt->device->id);	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->device->id);		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++)				fas216_writeb(info, REG_FF, msg->msg[i]);			msg->fifo = tot_msglen - (fas216_readb(info, REG_CFIS) & CFIS_CF);		}		/* load command */		for (i = 0; i < SCpnt->cmd_len; i++)			fas216_writeb(info, REG_FF, SCpnt->cmnd[i]);		if (tot_msglen == 1)			fas216_cmd(info, CMD_SELECTATN);		else			fas216_cmd(info, CMD_SELECTATN3);	} 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);		fas216_writeb(info, REG_FF, msg->msg[0]);		msg->fifo = 1;		fas216_cmd(info, CMD_SELECTATNSTOP);	}}/* * Decide whether we need to perform a parity test on this device. * Can also be used to force parity error conditions during initial * information transfer phase (message out) for test purposes. */static int parity_test(FAS216_Info *info, int target){#if 0	if (target == 3) {		info->device[target].parity_check = 0;		return 1;	}#endif	return info->device[target].parity_check;}static void fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt){	int disconnect_ok;	/*	 * claim host busy	 */	info->scsi.phase = PHASE_SELECTION;	info->scsi.SCp = SCpnt->SCp;	info->SCpnt = SCpnt;	info->dma.transfer_type = fasdma_none;	if (parity_test(info, SCpnt->device->id))		fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0] | CNTL1_PTE);	else		fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);	/*	 * Don't allow request sense commands to disconnect.	 */	disconnect_ok = SCpnt->cmnd[0] != REQUEST_SENSE &&			info->device[SCpnt->device->id].disconnect_ok;	/*	 * build outgoing message bytes	 */	msgqueue_flush(&info->scsi.msgs);	msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(disconnect_ok, SCpnt->device->lun));	/*	 * add tag message if required	 */	if (SCpnt->tag)		msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag);	do {#ifdef SCSI2_SYNC		if ((info->device[SCpnt->device->id].sync_state == neg_wait ||		     info->device[SCpnt->device->id].sync_state == neg_complete) &&		    (SCpnt->cmnd[0] == REQUEST_SENSE ||		     SCpnt->cmnd[0] == INQUIRY)) {			info->device[SCpnt->device->id].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);	__fas216_start_command(info, SCpnt);}static void fas216_allocate_tag(FAS216_Info *info, Scsi_Cmnd *SCpnt){#ifdef SCSI2_TAG	/*	 * tagged queuing - allocate a new tag to this command	 */	if (SCpnt->device->simple_tags && 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->device->id * 8 + SCpnt->device->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;	}}static void fas216_do_bus_device_reset(FAS216_Info *info, Scsi_Cmnd *SCpnt){	struct message *msg;	/*	 * claim host busy	 */	info->scsi.phase = PHASE_SELECTION;	info->scsi.SCp = SCpnt->SCp;	info->SCpnt = SCpnt;	info->dma.transfer_type = fasdma_none;	fas216_log(info, LOG_ERROR, "sending bus device reset");	msgqueue_flush(&info->scsi.msgs);	msgqueue_addmsg(&info->scsi.msgs, 1, BUS_DEVICE_RESET);	/* following what the ESP driver says */	fas216_set_stc(info, 0);	fas216_cmd(info, CMD_NOP | CMD_WITHDMA);	/* flush FIFO */	fas216_cmd(info, CMD_FLUSHFIFO);	/* load bus-id and timeout */	fas216_writeb(info, REG_SDID, BUSID(SCpnt->device->id));	fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout);	/* synchronous transfers */	fas216_set_sync(info, SCpnt->device->id);	msg = msgqueue_getmsg(&info->scsi.msgs, 0);	fas216_writeb(info, REG_FF, BUS_DEVICE_RESET);	msg->fifo = 1;	fas216_cmd(info, CMD_SELECTATNSTOP);}/** * fas216_kick - kick a command to the interface * @info: our host interface to kick * * Kick a command to the interface, interface should be idle. * Notes: Interrupts are always disabled! */static void fas216_kick(FAS216_Info *info){	Scsi_Cmnd *SCpnt = NULL;#define TYPE_OTHER	0#define TYPE_RESET	1#define TYPE_QUEUE	2	int where_from = TYPE_OTHER;	fas216_checkmagic(info);	/*	 * Obtain the next command to process.	 */	do {		if (info->rstSCpnt) {			SCpnt = info->rstSCpnt;			/* don't remove it */			where_from = TYPE_RESET;			break;		}		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);			where_from = TYPE_QUEUE;			break;		}	} while (0);	if (!SCpnt) {		/*		 * no command pending, so enable reselection.		 */		fas216_cmd(info, CMD_ENABLESEL);		return;	}	/*	 * We're going to start a command, so disable reselection	 */	fas216_cmd(info, CMD_DISABLESEL);	if (info->scsi.disconnectable && info->SCpnt) {		fas216_log(info, LOG_CONNECT,			"moved command for %d to disconnected queue",			info->SCpnt->device->id);		queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt);		info->scsi.disconnectable = 0;		info->SCpnt = NULL;	}	fas216_log_command(info, LOG_CONNECT | LOG_MESSAGES, SCpnt,			   "starting");	switch (where_from) {	case TYPE_QUEUE:		fas216_allocate_tag(info, SCpnt);	case TYPE_OTHER:		fas216_start_command(info, SCpnt);		break;	case TYPE_RESET:		fas216_do_bus_device_reset(info, SCpnt);		break;	}	fas216_log(info, LOG_CONNECT, "select: data pointers [%p, %X]",		info->scsi.SCp.ptr, info->scsi.SCp.this_residual);	/*	 * should now get either DISCONNECT or	 * (FUNCTION DONE with BUS SERVICE) interrupt	 */}/* * Clean up from issuing a BUS DEVICE RESET message to a device. */

⌨️ 快捷键说明

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