wd33c93.c

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

C
2,078
字号
		/* From esp.c:		 * There is a window of time within the scsi_done() path		 * of execution where interrupts are turned back on full		 * blast and left that way.  During that time we could		 * reconnect to a disconnected command, then we'd bomb		 * out below.  We could also end up executing two commands		 * at _once_.  ...just so you know why the restore_flags()		 * is here...		 */		spin_unlock_irqrestore(&hostdata->lock, flags);/* We are not connected to a target - check to see if there * are commands waiting to be executed. */		wd33c93_execute(instance);		break;/* Note: this interrupt should not occur in a LEVEL2 command */	case CSR_SELECT:		DB(DB_INTR, printk("SELECT"))		    hostdata->connected = cmd =		    (struct scsi_cmnd *) hostdata->selecting;		hostdata->selecting = NULL;		/* construct an IDENTIFY message with correct disconnect bit */		hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->device->lun);		if (cmd->SCp.phase)			hostdata->outgoing_msg[0] |= 0x40;		if (hostdata->sync_stat[cmd->device->id] == SS_FIRST) {#ifdef SYNC_DEBUG			printk(" sending SDTR ");#endif			hostdata->sync_stat[cmd->device->id] = SS_WAITING;/* Tack on a 2nd message to ask about synchronous transfers. If we've * been asked to do only asynchronous transfers on this device, we * request a fifo depth of 0, which is equivalent to async - should * solve the problems some people have had with GVP's Guru ROM. */			hostdata->outgoing_msg[1] = EXTENDED_MESSAGE;			hostdata->outgoing_msg[2] = 3;			hostdata->outgoing_msg[3] = EXTENDED_SDTR;			if (hostdata->no_sync & (1 << cmd->device->id)) {				hostdata->outgoing_msg[4] =				    hostdata->default_sx_per / 4;				hostdata->outgoing_msg[5] = 0;			} else {				hostdata->outgoing_msg[4] = OPTIMUM_SX_PER / 4;				hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;			}			hostdata->outgoing_len = 6;		} else			hostdata->outgoing_len = 1;		hostdata->state = S_CONNECTED;		spin_unlock_irqrestore(&hostdata->lock, flags);		break;	case CSR_XFER_DONE | PHS_DATA_IN:	case CSR_UNEXP | PHS_DATA_IN:	case CSR_SRV_REQ | PHS_DATA_IN:		DB(DB_INTR,		   printk("IN-%d.%d", cmd->SCp.this_residual,			  cmd->SCp.buffers_residual))		    transfer_bytes(regs, cmd, DATA_IN_DIR);		if (hostdata->state != S_RUNNING_LEVEL2)			hostdata->state = S_CONNECTED;		spin_unlock_irqrestore(&hostdata->lock, flags);		break;	case CSR_XFER_DONE | PHS_DATA_OUT:	case CSR_UNEXP | PHS_DATA_OUT:	case CSR_SRV_REQ | PHS_DATA_OUT:		DB(DB_INTR,		   printk("OUT-%d.%d", cmd->SCp.this_residual,			  cmd->SCp.buffers_residual))		    transfer_bytes(regs, cmd, DATA_OUT_DIR);		if (hostdata->state != S_RUNNING_LEVEL2)			hostdata->state = S_CONNECTED;		spin_unlock_irqrestore(&hostdata->lock, flags);		break;/* Note: this interrupt should not occur in a LEVEL2 command */	case CSR_XFER_DONE | PHS_COMMAND:	case CSR_UNEXP | PHS_COMMAND:	case CSR_SRV_REQ | PHS_COMMAND:		DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->pid))		    transfer_pio(regs, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR,				 hostdata);		hostdata->state = S_CONNECTED;		spin_unlock_irqrestore(&hostdata->lock, flags);		break;	case CSR_XFER_DONE | PHS_STATUS:	case CSR_UNEXP | PHS_STATUS:	case CSR_SRV_REQ | PHS_STATUS:		DB(DB_INTR, printk("STATUS="))		cmd->SCp.Status = read_1_byte(regs);		DB(DB_INTR, printk("%02x", cmd->SCp.Status))		    if (hostdata->level2 >= L2_BASIC) {			sr = read_wd33c93(regs, WD_SCSI_STATUS);	/* clear interrupt */			hostdata->state = S_RUNNING_LEVEL2;			write_wd33c93(regs, WD_COMMAND_PHASE, 0x50);			write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);		} else {			hostdata->state = S_CONNECTED;		}		spin_unlock_irqrestore(&hostdata->lock, flags);		break;	case CSR_XFER_DONE | PHS_MESS_IN:	case CSR_UNEXP | PHS_MESS_IN:	case CSR_SRV_REQ | PHS_MESS_IN:		DB(DB_INTR, printk("MSG_IN="))		msg = read_1_byte(regs);		sr = read_wd33c93(regs, WD_SCSI_STATUS);	/* clear interrupt */		hostdata->incoming_msg[hostdata->incoming_ptr] = msg;		if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE)			msg = EXTENDED_MESSAGE;		else			hostdata->incoming_ptr = 0;		cmd->SCp.Message = msg;		switch (msg) {		case COMMAND_COMPLETE:			DB(DB_INTR, printk("CCMP-%ld", cmd->pid))			    write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);			hostdata->state = S_PRE_CMP_DISC;			break;		case SAVE_POINTERS:			DB(DB_INTR, printk("SDP"))			    write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);			hostdata->state = S_CONNECTED;			break;		case RESTORE_POINTERS:			DB(DB_INTR, printk("RDP"))			    if (hostdata->level2 >= L2_BASIC) {				write_wd33c93(regs, WD_COMMAND_PHASE, 0x45);				write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);				hostdata->state = S_RUNNING_LEVEL2;			} else {				write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);				hostdata->state = S_CONNECTED;			}			break;		case DISCONNECT:			DB(DB_INTR, printk("DIS"))			    cmd->device->disconnect = 1;			write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);			hostdata->state = S_PRE_TMP_DISC;			break;		case MESSAGE_REJECT:			DB(DB_INTR, printk("REJ"))#ifdef SYNC_DEBUG			    printk("-REJ-");#endif			if (hostdata->sync_stat[cmd->device->id] == SS_WAITING)				hostdata->sync_stat[cmd->device->id] = SS_SET;			write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);			hostdata->state = S_CONNECTED;			break;		case EXTENDED_MESSAGE:			DB(DB_INTR, printk("EXT"))			    ucp = hostdata->incoming_msg;#ifdef SYNC_DEBUG			printk("%02x", ucp[hostdata->incoming_ptr]);#endif			/* Is this the last byte of the extended message? */			if ((hostdata->incoming_ptr >= 2) &&			    (hostdata->incoming_ptr == (ucp[1] + 1))) {				switch (ucp[2]) {	/* what's the EXTENDED code? */				case EXTENDED_SDTR:					id = calc_sync_xfer(ucp[3], ucp[4]);					if (hostdata->sync_stat[cmd->device->id] !=					    SS_WAITING) {/* A device has sent an unsolicited SDTR message; rather than go * through the effort of decoding it and then figuring out what * our reply should be, we're just gonna say that we have a * synchronous fifo depth of 0. This will result in asynchronous * transfers - not ideal but so much easier. * Actually, this is OK because it assures us that if we don't * specifically ask for sync transfers, we won't do any. */						write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */						hostdata->outgoing_msg[0] =						    EXTENDED_MESSAGE;						hostdata->outgoing_msg[1] = 3;						hostdata->outgoing_msg[2] =						    EXTENDED_SDTR;						hostdata->outgoing_msg[3] =						    hostdata->default_sx_per /						    4;						hostdata->outgoing_msg[4] = 0;						hostdata->outgoing_len = 5;						hostdata->sync_xfer[cmd->device->id] =						    calc_sync_xfer(hostdata->								   default_sx_per								   / 4, 0);					} else {						hostdata->sync_xfer[cmd->device->id] = id;					}#ifdef SYNC_DEBUG					printk("sync_xfer=%02x",					       hostdata->sync_xfer[cmd->device->id]);#endif					hostdata->sync_stat[cmd->device->id] =					    SS_SET;					write_wd33c93_cmd(regs,							  WD_CMD_NEGATE_ACK);					hostdata->state = S_CONNECTED;					break;				case EXTENDED_WDTR:					write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */					printk("sending WDTR ");					hostdata->outgoing_msg[0] =					    EXTENDED_MESSAGE;					hostdata->outgoing_msg[1] = 2;					hostdata->outgoing_msg[2] =					    EXTENDED_WDTR;					hostdata->outgoing_msg[3] = 0;	/* 8 bit transfer width */					hostdata->outgoing_len = 4;					write_wd33c93_cmd(regs,							  WD_CMD_NEGATE_ACK);					hostdata->state = S_CONNECTED;					break;				default:					write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */					printk					    ("Rejecting Unknown Extended Message(%02x). ",					     ucp[2]);					hostdata->outgoing_msg[0] =					    MESSAGE_REJECT;					hostdata->outgoing_len = 1;					write_wd33c93_cmd(regs,							  WD_CMD_NEGATE_ACK);					hostdata->state = S_CONNECTED;					break;				}				hostdata->incoming_ptr = 0;			}			/* We need to read more MESS_IN bytes for the extended message */			else {				hostdata->incoming_ptr++;				write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);				hostdata->state = S_CONNECTED;			}			break;		default:			printk("Rejecting Unknown Message(%02x) ", msg);			write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */			hostdata->outgoing_msg[0] = MESSAGE_REJECT;			hostdata->outgoing_len = 1;			write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);			hostdata->state = S_CONNECTED;		}		spin_unlock_irqrestore(&hostdata->lock, flags);		break;/* Note: this interrupt will occur only after a LEVEL2 command */	case CSR_SEL_XFER_DONE:/* Make sure that reselection is enabled at this point - it may * have been turned off for the command that just completed. */		write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);		if (phs == 0x60) {			DB(DB_INTR, printk("SX-DONE-%ld", cmd->pid))			    cmd->SCp.Message = COMMAND_COMPLETE;			lun = read_wd33c93(regs, WD_TARGET_LUN);			DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun))			    hostdata->connected = NULL;			hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);			hostdata->state = S_UNCONNECTED;			if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE)				cmd->SCp.Status = lun;			if (cmd->cmnd[0] == REQUEST_SENSE			    && cmd->SCp.Status != GOOD)				cmd->result =				    (cmd->				     result & 0x00ffff) | (DID_ERROR << 16);			else				cmd->result =				    cmd->SCp.Status | (cmd->SCp.Message << 8);			cmd->scsi_done(cmd);/* We are no longer  connected to a target - check to see if * there are commands waiting to be executed. */			spin_unlock_irqrestore(&hostdata->lock, flags);			wd33c93_execute(instance);		} else {			printk			    ("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---",			     asr, sr, phs, cmd->pid);			spin_unlock_irqrestore(&hostdata->lock, flags);		}		break;/* Note: this interrupt will occur only after a LEVEL2 command */	case CSR_SDP:		DB(DB_INTR, printk("SDP"))		    hostdata->state = S_RUNNING_LEVEL2;		write_wd33c93(regs, WD_COMMAND_PHASE, 0x41);		write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);		spin_unlock_irqrestore(&hostdata->lock, flags);		break;	case CSR_XFER_DONE | PHS_MESS_OUT:	case CSR_UNEXP | PHS_MESS_OUT:	case CSR_SRV_REQ | PHS_MESS_OUT:		DB(DB_INTR, printk("MSG_OUT="))/* To get here, we've probably requested MESSAGE_OUT and have * already put the correct bytes in outgoing_msg[] and filled * in outgoing_len. We simply send them out to the SCSI bus. * Sometimes we get MESSAGE_OUT phase when we're not expecting * it - like when our SDTR message is rejected by a target. Some * targets send the REJECT before receiving all of the extended * message, and then seem to go back to MESSAGE_OUT for a byte * or two. Not sure why, or if I'm doing something wrong to * cause this to happen. Regardless, it seems that sending * NOP messages in these situations results in no harm and * makes everyone happy. */		    if (hostdata->outgoing_len == 0) {			hostdata->outgoing_len = 1;			hostdata->outgoing_msg[0] = NOP;		}		transfer_pio(regs, hostdata->outgoing_msg,			     hostdata->outgoing_len, DATA_OUT_DIR, hostdata);		DB(DB_INTR, printk("%02x", hostdata->outgoing_msg[0]))		    hostdata->outgoing_len = 0;		hostdata->state = S_CONNECTED;		spin_unlock_irqrestore(&hostdata->lock, flags);		break;	case CSR_UNEXP_DISC:/* I think I've seen this after a request-sense that was in response * to an error condition, but not sure. We certainly need to do * something when we get this interrupt - the question is 'what?'. * Let's think positively, and assume some command has finished * in a legal manner (like a command that provokes a request-sense), * so we treat it as a normal command-complete-disconnect. *//* Make sure that reselection is enabled at this point - it may * have been turned off for the command that just completed. */		write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);		if (cmd == NULL) {			printk(" - Already disconnected! ");			hostdata->state = S_UNCONNECTED;			spin_unlock_irqrestore(&hostdata->lock, flags);			return;		}		DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->pid))		    hostdata->connected = NULL;		hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);		hostdata->state = S_UNCONNECTED;		if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)			cmd->result =			    (cmd->result & 0x00ffff) | (DID_ERROR << 16);		else			cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);		cmd->scsi_done(cmd);/* We are no longer connected to a target - check to see if * there are commands waiting to be executed. */		/* look above for comments on scsi_done() */		spin_unlock_irqrestore(&hostdata->lock, flags);		wd33c93_execute(instance);		break;	case CSR_DISC:/* Make sure that reselection is enabled at this point - it may * have been turned off for the command that just completed. */		write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);		DB(DB_INTR, printk("DISC-%ld", cmd->pid))		    if (cmd == NULL) {			printk(" - Already disconnected! ");			hostdata->state = S_UNCONNECTED;

⌨️ 快捷键说明

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