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

📄 aic79xx_core.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		 * Set this and it will take effect when the		 * target does a command complete.		 */		ahd_freeze_devq(ahd, scb);		ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR);		ahd_freeze_scb(scb);		break;	}	case MKMSG_FAILED:	{		struct ahd_devinfo devinfo;		struct scb *scb;		u_int scbid;		ahd_fetch_devinfo(ahd, &devinfo);		printf("%s:%c:%d:%d: Attempt to issue message failed\n",		       ahd_name(ahd), devinfo.channel, devinfo.target,		       devinfo.lun);		scbid = ahd_get_scbptr(ahd);		scb = ahd_lookup_scb(ahd, scbid);		if (scb != NULL		 && (scb->flags & SCB_RECOVERY_SCB) != 0)			/*			 * Ensure that we didn't put a second instance of this			 * SCB into the QINFIFO.			 */			ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb),					   SCB_GET_CHANNEL(ahd, scb),					   SCB_GET_LUN(scb), SCB_GET_TAG(scb),					   ROLE_INITIATOR, /*status*/0,					   SEARCH_REMOVE);		ahd_outb(ahd, SCB_CONTROL,			 ahd_inb_scbram(ahd, SCB_CONTROL) & ~MK_MESSAGE);		break;	}	case TASKMGMT_FUNC_COMPLETE:	{		u_int	scbid;		struct	scb *scb;		scbid = ahd_get_scbptr(ahd);		scb = ahd_lookup_scb(ahd, scbid);		if (scb != NULL) {			u_int	   lun;			u_int	   tag;			cam_status error;			ahd_print_path(ahd, scb);			printf("Task Management Func 0x%x Complete\n",			       scb->hscb->task_management);			lun = CAM_LUN_WILDCARD;			tag = SCB_LIST_NULL;			switch (scb->hscb->task_management) {			case SIU_TASKMGMT_ABORT_TASK:				tag = SCB_GET_TAG(scb);			case SIU_TASKMGMT_ABORT_TASK_SET:			case SIU_TASKMGMT_CLEAR_TASK_SET:				lun = scb->hscb->lun;				error = CAM_REQ_ABORTED;				ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb),					       'A', lun, tag, ROLE_INITIATOR,					       error);				break;			case SIU_TASKMGMT_LUN_RESET:				lun = scb->hscb->lun;			case SIU_TASKMGMT_TARGET_RESET:			{				struct ahd_devinfo devinfo;				ahd_scb_devinfo(ahd, &devinfo, scb);				error = CAM_BDR_SENT;				ahd_handle_devreset(ahd, &devinfo, lun,						    CAM_BDR_SENT,						    lun != CAM_LUN_WILDCARD						    ? "Lun Reset"						    : "Target Reset",						    /*verbose_level*/0);				break;			}			default:				panic("Unexpected TaskMgmt Func\n");				break;			}		}		break;	}	case TASKMGMT_CMD_CMPLT_OKAY:	{		u_int	scbid;		struct	scb *scb;		/*		 * An ABORT TASK TMF failed to be delivered before		 * the targeted command completed normally.		 */		scbid = ahd_get_scbptr(ahd);		scb = ahd_lookup_scb(ahd, scbid);		if (scb != NULL) {			/*			 * Remove the second instance of this SCB from			 * the QINFIFO if it is still there.                         */			ahd_print_path(ahd, scb);			printf("SCB completes before TMF\n");			/*			 * Handle losing the race.  Wait until any			 * current selection completes.  We will then			 * set the TMF back to zero in this SCB so that			 * the sequencer doesn't bother to issue another			 * sequencer interrupt for its completion.			 */			while ((ahd_inb(ahd, SCSISEQ0) & ENSELO) != 0			    && (ahd_inb(ahd, SSTAT0) & SELDO) == 0			    && (ahd_inb(ahd, SSTAT1) & SELTO) == 0)				;			ahd_outb(ahd, SCB_TASK_MANAGEMENT, 0);			ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb),					   SCB_GET_CHANNEL(ahd, scb),  					   SCB_GET_LUN(scb), SCB_GET_TAG(scb), 					   ROLE_INITIATOR, /*status*/0,   					   SEARCH_REMOVE);		}		break;	}	case TRACEPOINT0:	case TRACEPOINT1:	case TRACEPOINT2:	case TRACEPOINT3:		printf("%s: Tracepoint %d\n", ahd_name(ahd),		       seqintcode - TRACEPOINT0);		break;	case NO_SEQINT:		break;	case SAW_HWERR:		ahd_handle_hwerrint(ahd);		break;	default:		printf("%s: Unexpected SEQINTCODE %d\n", ahd_name(ahd),		       seqintcode);		break;	}	/*	 *  The sequencer is paused immediately on	 *  a SEQINT, so we should restart it when	 *  we're done.	 */	ahd_unpause(ahd);}voidahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat){	struct scb	*scb;	u_int		 status0;	u_int		 status3;	u_int		 status;	u_int		 lqistat1;	u_int		 lqostat0;	u_int		 scbid;	u_int		 busfreetime;	ahd_update_modes(ahd);	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);	status3 = ahd_inb(ahd, SSTAT3) & (NTRAMPERR|OSRAMPERR);	status0 = ahd_inb(ahd, SSTAT0) & (IOERR|OVERRUN|SELDI|SELDO);	status = ahd_inb(ahd, SSTAT1) & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR);	lqistat1 = ahd_inb(ahd, LQISTAT1);	lqostat0 = ahd_inb(ahd, LQOSTAT0);	busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME;	if ((status0 & (SELDI|SELDO)) != 0) {		u_int simode0;		ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);		simode0 = ahd_inb(ahd, SIMODE0);		status0 &= simode0 & (IOERR|OVERRUN|SELDI|SELDO);		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);	}	scbid = ahd_get_scbptr(ahd);	scb = ahd_lookup_scb(ahd, scbid);	if (scb != NULL	 && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) != 0)		scb = NULL;	/* Make sure the sequencer is in a safe location. */	ahd_clear_critical_section(ahd);	if ((status0 & IOERR) != 0) {		u_int now_lvd;		now_lvd = ahd_inb(ahd, SBLKCTL) & ENAB40;		printf("%s: Transceiver State Has Changed to %s mode\n",		       ahd_name(ahd), now_lvd ? "LVD" : "SE");		ahd_outb(ahd, CLRSINT0, CLRIOERR);		/*		 * A change in I/O mode is equivalent to a bus reset.		 */		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);		ahd_pause(ahd);		ahd_setup_iocell_workaround(ahd);		ahd_unpause(ahd);	} else if ((status0 & OVERRUN) != 0) {		printf("%s: SCSI offset overrun detected.  Resetting bus.\n",		       ahd_name(ahd));		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);	} else if ((status & SCSIRSTI) != 0) {		printf("%s: Someone reset channel A\n", ahd_name(ahd));		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/FALSE);	} else if ((status & SCSIPERR) != 0) {		ahd_handle_transmission_error(ahd);	} else if (lqostat0 != 0) {		printf("%s: lqostat0 == 0x%x!\n", ahd_name(ahd), lqostat0);		ahd_outb(ahd, CLRLQOINT0, lqostat0);		if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) {			ahd_outb(ahd, CLRLQOINT1, 0);		}	} else if ((status & SELTO) != 0) {		u_int  scbid;		/* Stop the selection */		ahd_outb(ahd, SCSISEQ0, 0);		/* No more pending messages */		ahd_clear_msg_state(ahd);		/* Clear interrupt state */		ahd_outb(ahd, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR);		/*		 * Although the driver does not care about the		 * 'Selection in Progress' status bit, the busy		 * LED does.  SELINGO is only cleared by a sucessfull		 * selection, so we must manually clear it to insure		 * the LED turns off just incase no future successful		 * selections occur (e.g. no devices on the bus).		 */		ahd_outb(ahd, CLRSINT0, CLRSELINGO);		scbid = ahd_inw(ahd, WAITING_TID_HEAD);		scb = ahd_lookup_scb(ahd, scbid);		if (scb == NULL) {			printf("%s: ahd_intr - referenced scb not "			       "valid during SELTO scb(0x%x)\n",			       ahd_name(ahd), scbid);			ahd_dump_card_state(ahd);		} else {			struct ahd_devinfo devinfo;#ifdef AHD_DEBUG			if ((ahd_debug & AHD_SHOW_SELTO) != 0) {				ahd_print_path(ahd, scb);				printf("Saw Selection Timeout for SCB 0x%x\n",				       scbid);			}#endif			/*			 * Force a renegotiation with this target just in			 * case the cable was pulled and will later be			 * re-attached.  The target may forget its negotiation			 * settings with us should it attempt to reselect			 * during the interruption.  The target will not issue			 * a unit attention in this case, so we must always			 * renegotiate.			 */			ahd_scb_devinfo(ahd, &devinfo, scb);			ahd_force_renegotiation(ahd, &devinfo);			ahd_set_transaction_status(scb, CAM_SEL_TIMEOUT);			ahd_freeze_devq(ahd, scb);		}		ahd_outb(ahd, CLRINT, CLRSCSIINT);		ahd_iocell_first_selection(ahd);		ahd_unpause(ahd);	} else if ((status0 & (SELDI|SELDO)) != 0) {		ahd_iocell_first_selection(ahd);		ahd_unpause(ahd);	} else if (status3 != 0) {		printf("%s: SCSI Cell parity error SSTAT3 == 0x%x\n",		       ahd_name(ahd), status3);		ahd_outb(ahd, CLRSINT3, status3);	} else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) {		ahd_handle_lqiphase_error(ahd, lqistat1);	} else if ((lqistat1 & LQICRCI_NLQ) != 0) {		/*		 * This status can be delayed during some		 * streaming operations.  The SCSIPHASE		 * handler has already dealt with this case		 * so just clear the error.		 */		ahd_outb(ahd, CLRLQIINT1, CLRLQICRCI_NLQ);	} else if ((status & BUSFREE) != 0) {		u_int lqostat1;		int   restart;		int   clear_fifo;		int   packetized;		u_int mode;		/*		 * Clear our selection hardware as soon as possible.		 * We may have an entry in the waiting Q for this target,		 * that is affected by this busfree and we don't want to		 * go about selecting the target while we handle the event.		 */		ahd_outb(ahd, SCSISEQ0, 0);		/*		 * Determine what we were up to at the time of		 * the busfree.		 */		mode = AHD_MODE_SCSI;		busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME;		lqostat1 = ahd_inb(ahd, LQOSTAT1);		switch (busfreetime) {		case BUSFREE_DFF0:		case BUSFREE_DFF1:		{			u_int	scbid;			struct	scb *scb;			mode = busfreetime == BUSFREE_DFF0			     ? AHD_MODE_DFF0 : AHD_MODE_DFF1;			ahd_set_modes(ahd, mode, mode);			scbid = ahd_get_scbptr(ahd);			scb = ahd_lookup_scb(ahd, scbid);			if (scb == NULL) {				printf("%s: Invalid SCB %d in DFF%d "				       "during unexpected busfree\n",				       ahd_name(ahd), scbid, mode);				packetized = 0;			} else				packetized = (scb->flags & SCB_PACKETIZED) != 0;			clear_fifo = 1;			break;		}		case BUSFREE_LQO:			clear_fifo = 0;			packetized = 1;			break;		default:			clear_fifo = 0;			packetized =  (lqostat1 & LQOBUSFREE) != 0;			if (!packetized			 && ahd_inb(ahd, LASTPHASE) == P_BUSFREE)				packetized = 1;			break;		}#ifdef AHD_DEBUG		if ((ahd_debug & AHD_SHOW_MISC) != 0)			printf("Saw Busfree.  Busfreetime = 0x%x.\n",			       busfreetime);#endif		/*		 * Busfrees that occur in non-packetized phases are		 * handled by the nonpkt_busfree handler.		 */		if (packetized && ahd_inb(ahd, LASTPHASE) == P_BUSFREE) {			restart = ahd_handle_pkt_busfree(ahd, busfreetime);		} else {			packetized = 0;			restart = ahd_handle_nonpkt_busfree(ahd);		}		/*		 * Clear the busfree interrupt status.  The setting of		 * the interrupt is a pulse, so in a perfect world, we		 * would not need to muck with the ENBUSFREE logic.  This		 * would ensure that if the bus moves on to another		 * connection, busfree protection is still in force.  If		 * BUSFREEREV is broken, however, we must manually clear		 * the ENBUSFREE if the busfree occurred during a non-pack		 * connection so that we don't get false positives during		 * future, packetized, connections.		 */		ahd_outb(ahd, CLRSINT1, CLRBUSFREE);		if (packetized == 0		 && (ahd->bugs & AHD_BUSFREEREV_BUG) != 0)			ahd_outb(ahd, SIMODE1,				 ahd_inb(ahd, SIMODE1) & ~ENBUSFREE);		if (clear_fifo)			ahd_clear_fifo(ahd, mode);		ahd_clear_msg_state(ahd);		ahd_outb(ahd, CLRINT, CLRSCSIINT);		if (restart) {			ahd_restart(ahd);		} else {			ahd_unpause(ahd);		}	} else {		printf("%s: Missing case in ahd_handle_scsiint. status = %x\n",		       ahd_name(ahd), status);		ahd_dump_card_state(ahd);		ahd_clear_intstat(ahd);		ahd_unpause(ahd);	}}static voidahd_handle_transmission_error(struct ahd_softc *ahd){	struct	scb *scb;	u_int	scbid;	u_int	lqistat1;	u_int	lqistat2;	u_int	msg_out;	u_int	curphase;	u_int	lastphase;	u_int	perrdiag;	u_int	cur_col;	int	silent;	scb = NULL;	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);	lqistat1 = ahd_inb(ahd, LQISTAT1) & ~(LQIPHASE_LQ|LQIPHASE_NLQ);	lqistat2 = ahd_inb(ahd, LQISTAT2);	if ((lqistat1 & (LQICRCI_NLQ|LQICRCI_LQ)) == 0	 && (ahd->bugs & AHD_NLQICRC_DELAYED_BUG) != 0) {		u_int lqistate;		ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);		lqistate = ahd_inb(ahd, LQISTATE);		if ((lqistate >= 0x1E && lqistate <= 0x24)		 || (lqistate == 0x29)) {#ifdef AHD_DEBUG			if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {				printf("%s: NLQCRC found via LQISTATE\n",				       ahd_name(ahd));			}#endif			lqistat1 |= LQICRCI_NLQ;		}		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);	}	ahd_outb(ahd, CLRLQIINT1, lqistat1);	lastphase = ahd_inb(ahd, LASTPHASE);	curphase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK;	perrdiag = ahd_inb(ahd, PERRDIAG);	msg_out = MSG_INITIATOR_DET_ERR;	ahd_outb(ahd, CLRSINT1, CLRSCSIPERR);

⌨️ 快捷键说明

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