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

📄 aic79xx_core.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
				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);		/*	 * Try to find the SCB associated with this error.	 */	silent = FALSE;	if (lqistat1 == 0	 || (lqistat1 & LQICRCI_NLQ) != 0) {	 	if ((lqistat1 & (LQICRCI_NLQ|LQIOVERI_NLQ)) != 0)			ahd_set_active_fifo(ahd);		scbid = ahd_get_scbptr(ahd);		scb = ahd_lookup_scb(ahd, scbid);		if (scb != NULL && SCB_IS_SILENT(scb))			silent = TRUE;	}	cur_col = 0;	if (silent == FALSE) {		printf("%s: Transmission error detected\n", ahd_name(ahd));		ahd_lqistat1_print(lqistat1, &cur_col, 50);		ahd_lastphase_print(lastphase, &cur_col, 50);		ahd_scsisigi_print(curphase, &cur_col, 50);		ahd_perrdiag_print(perrdiag, &cur_col, 50);		printf("\n");		ahd_dump_card_state(ahd);	}	if ((lqistat1 & (LQIOVERI_LQ|LQIOVERI_NLQ)) != 0) {		if (silent == FALSE) {			printf("%s: Gross protocol error during incoming "			       "packet.  lqistat1 == 0x%x.  Resetting bus.\n",			       ahd_name(ahd), lqistat1);		}		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);		return;	} else if ((lqistat1 & LQICRCI_LQ) != 0) {		/*		 * A CRC error has been detected on an incoming LQ.		 * The bus is currently hung on the last ACK.		 * Hit LQIRETRY to release the last ack, and		 * wait for the sequencer to determine that ATNO		 * is asserted while in message out to take us		 * to our host message loop.  No NONPACKREQ or		 * LQIPHASE type errors will occur in this		 * scenario.  After this first LQIRETRY, the LQI		 * manager will be in ISELO where it will		 * happily sit until another packet phase begins.		 * Unexpected bus free detection is enabled		 * through any phases that occur after we release		 * this last ack until the LQI manager sees a		 * packet phase.  This implies we may have to		 * ignore a perfectly valid "unexected busfree"		 * after our "initiator detected error" message is		 * sent.  A busfree is the expected response after		 * we tell the target that it's L_Q was corrupted.		 * (SPI4R09 10.7.3.3.3)		 */		ahd_outb(ahd, LQCTL2, LQIRETRY);		printf("LQIRetry for LQICRCI_LQ to release ACK\n");	} else if ((lqistat1 & LQICRCI_NLQ) != 0) {		/*		 * We detected a CRC error in a NON-LQ packet.		 * The hardware has varying behavior in this situation		 * depending on whether this packet was part of a		 * stream or not.		 *		 * PKT by PKT mode:		 * The hardware has already acked the complete packet.		 * If the target honors our outstanding ATN condition,		 * we should be (or soon will be) in MSGOUT phase.		 * This will trigger the LQIPHASE_LQ status bit as the		 * hardware was expecting another LQ.  Unexpected		 * busfree detection is enabled.  Once LQIPHASE_LQ is		 * true (first entry into host message loop is much		 * the same), we must clear LQIPHASE_LQ and hit		 * LQIRETRY so the hardware is ready to handle		 * a future LQ.  NONPACKREQ will not be asserted again		 * once we hit LQIRETRY until another packet is		 * processed.  The target may either go busfree		 * or start another packet in response to our message.		 *		 * Read Streaming P0 asserted:		 * If we raise ATN and the target completes the entire		 * stream (P0 asserted during the last packet), the		 * hardware will ack all data and return to the ISTART		 * state.  When the target reponds to our ATN condition,		 * LQIPHASE_LQ will be asserted.  We should respond to		 * this with an LQIRETRY to prepare for any future		 * packets.  NONPACKREQ will not be asserted again		 * once we hit LQIRETRY until another packet is		 * processed.  The target may either go busfree or		 * start another packet in response to our message.		 * Busfree detection is enabled.		 *		 * Read Streaming P0 not asserted:		 * If we raise ATN and the target transitions to		 * MSGOUT in or after a packet where P0 is not		 * asserted, the hardware will assert LQIPHASE_NLQ.		 * We should respond to the LQIPHASE_NLQ with an		 * LQIRETRY.  Should the target stay in a non-pkt		 * phase after we send our message, the hardware		 * will assert LQIPHASE_LQ.  Recovery is then just as		 * listed above for the read streaming with P0 asserted.		 * Busfree detection is enabled.		 */		if (silent == FALSE)			printf("LQICRC_NLQ\n");		if (scb == NULL) {			printf("%s: No SCB valid for LQICRC_NLQ.  "			       "Resetting bus\n", ahd_name(ahd));			ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);			return;		}	} else if ((lqistat1 & LQIBADLQI) != 0) {		printf("Need to handle BADLQI!\n");		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);		return;	} else if ((perrdiag & (PARITYERR|PREVPHASE)) == PARITYERR) {		if ((curphase & ~P_DATAIN_DT) != 0) {			/* Ack the byte.  So we can continue. */			if (silent == FALSE)				printf("Acking %s to clear perror\n",				    ahd_lookup_phase_entry(curphase)->phasemsg);			ahd_inb(ahd, SCSIDAT);		}			if (curphase == P_MESGIN)			msg_out = MSG_PARITY_ERROR;	}	/*	 * We've set the hardware to assert ATN if we 	 * get a parity error on "in" phases, so all we	 * need to do is stuff the message buffer with	 * the appropriate message.  "In" phases have set	 * mesg_out to something other than MSG_NOP.	 */	ahd->send_msg_perror = msg_out;	if (scb != NULL && msg_out == MSG_INITIATOR_DET_ERR)		scb->flags |= SCB_TRANSMISSION_ERROR;	ahd_outb(ahd, MSG_OUT, HOST_MSG);	ahd_outb(ahd, CLRINT, CLRSCSIINT);	ahd_unpause(ahd);}static voidahd_handle_lqiphase_error(struct ahd_softc *ahd, u_int lqistat1){	/*	 * Clear the sources of the interrupts.	 */	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);	ahd_outb(ahd, CLRLQIINT1, lqistat1);	/*	 * If the "illegal" phase changes were in response	 * to our ATN to flag a CRC error, AND we ended up	 * on packet boundaries, clear the error, restart the	 * LQI manager as appropriate, and go on our merry	 * way toward sending the message.  Otherwise, reset	 * the bus to clear the error.	 */	ahd_set_active_fifo(ahd);	if ((ahd_inb(ahd, SCSISIGO) & ATNO) != 0	 && (ahd_inb(ahd, MDFFSTAT) & DLZERO) != 0) {		if ((lqistat1 & LQIPHASE_LQ) != 0) {			printf("LQIRETRY for LQIPHASE_LQ\n");			ahd_outb(ahd, LQCTL2, LQIRETRY);		} else if ((lqistat1 & LQIPHASE_NLQ) != 0) {			printf("LQIRETRY for LQIPHASE_NLQ\n");			ahd_outb(ahd, LQCTL2, LQIRETRY);		} else			panic("ahd_handle_lqiphase_error: No phase errors\n");		ahd_dump_card_state(ahd);		ahd_outb(ahd, CLRINT, CLRSCSIINT);		ahd_unpause(ahd);	} else {		printf("Reseting Channel for LQI Phase error\n");		ahd_dump_card_state(ahd);		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);	}}/* * Packetized unexpected or expected busfree. * Entered in mode based on busfreetime. */static intahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime){	u_int lqostat1;	AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),			 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));	lqostat1 = ahd_inb(ahd, LQOSTAT1);	if ((lqostat1 & LQOBUSFREE) != 0) {		struct scb *scb;		u_int scbid;		u_int saved_scbptr;		u_int waiting_h;		u_int waiting_t;		u_int next;		if ((busfreetime & BUSFREE_LQO) == 0)			printf("%s: Warning, BUSFREE time is 0x%x.  "			       "Expected BUSFREE_LQO.\n",			       ahd_name(ahd), busfreetime);		/*		 * The LQO manager detected an unexpected busfree		 * either:		 *		 * 1) During an outgoing LQ.		 * 2) After an outgoing LQ but before the first		 *    REQ of the command packet.		 * 3) During an outgoing command packet.		 *		 * In all cases, CURRSCB is pointing to the		 * SCB that encountered the failure.  Clean		 * up the queue, clear SELDO and LQOBUSFREE,		 * and allow the sequencer to restart the select		 * out at its lesure.		 */		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);		scbid = ahd_inw(ahd, CURRSCB);		scb = ahd_lookup_scb(ahd, scbid);		if (scb == NULL)		       panic("SCB not valid during LQOBUSFREE");		/*		 * Clear the status.		 */		ahd_outb(ahd, CLRLQOINT1, CLRLQOBUSFREE);		if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0)			ahd_outb(ahd, CLRLQOINT1, 0);		ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);		ahd_flush_device_writes(ahd);		ahd_outb(ahd, CLRSINT0, CLRSELDO);		/*		 * Return the LQO manager to its idle loop.  It will		 * not do this automatically if the busfree occurs		 * after the first REQ of either the LQ or command		 * packet or between the LQ and command packet.		 */		ahd_outb(ahd, LQCTL2, ahd_inb(ahd, LQCTL2) | LQOTOIDLE);		/*		 * Update the waiting for selection queue so		 * we restart on the correct SCB.		 */		waiting_h = ahd_inw(ahd, WAITING_TID_HEAD);		saved_scbptr = ahd_get_scbptr(ahd);		if (waiting_h != scbid) {			ahd_outw(ahd, WAITING_TID_HEAD, scbid);			waiting_t = ahd_inw(ahd, WAITING_TID_TAIL);			if (waiting_t == waiting_h) {				ahd_outw(ahd, WAITING_TID_TAIL, scbid);				next = SCB_LIST_NULL;			} else {				ahd_set_scbptr(ahd, waiting_h);				next = ahd_inw_scbram(ahd, SCB_NEXT2);			}			ahd_set_scbptr(ahd, scbid);			ahd_outw(ahd, SCB_NEXT2, next);		}		ahd_set_scbptr(ahd, saved_scbptr);		if (scb->crc_retry_count < AHD_MAX_LQ_CRC_ERRORS) {			if (SCB_IS_SILENT(scb) == FALSE) {				ahd_print_path(ahd, scb);				printf("Probable outgoing LQ CRC error.  "				       "Retrying command\n");			}			scb->crc_retry_count++;		} else {			ahd_set_transaction_status(scb, CAM_UNCOR_PARITY);			ahd_freeze_scb(scb);			ahd_freeze_devq(ahd, scb);		}		/* Return unpausing the sequencer. */		return (0);	} else if ((ahd_inb(ahd, PERRDIAG) & PARITYERR) != 0) {		/*		 * Ignore what are really parity errors that		 * occur on the last REQ of a free running		 * clock prior to going busfree.  Some drives		 * do not properly active negate just before		 * going busfree resulting in a parity glitch.		 */		ahd_outb(ahd, CLRSINT1, CLRSCSIPERR|CLRBUSFREE);#ifdef AHD_DEBUG		if ((ahd_debug & AHD_SHOW_MASKED_ERRORS) != 0)			printf("%s: Parity on last REQ detected "			       "during busfree phase.\n",			       ahd_name(ahd));#endif		/* Return unpausing the sequencer. */		return (0);	}	if (ahd->src_mode != AHD_MODE_SCSI) {		u_int	scbid;		struct	scb *scb;		scbid = ahd_get_scbptr(ahd);		scb = ahd_lookup_scb(ahd, scbid);		ahd_print_path(ahd, scb);		printf("Unexpected PKT busfree condition\n");		ahd_dump_card_state(ahd);		ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 'A',			       SCB_GET_LUN(scb), SCB_GET_TAG(scb),			       ROLE_INITIATOR, CAM_UNEXP_BUSFREE);		/* Return restarting the sequencer. */		return (1);	}	printf("%s: Unexpected PKT busfree condition\n", ahd_name(ahd));	ahd_dump_card_state(ahd);	/* Restart the sequencer. */	return (1);}/* * Non-packetized unexpected or expected busfree. */static intahd_handle_nonpkt_busfree(struct ahd_softc *ahd){

⌨️ 快捷键说明

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