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

📄 sym_hipd.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
			assert(np->features & FE_U3EN);			uval |= U3EN;		}	} else {		wval = wval & ~ULTRA;		if (per <= 12)	wval |= ULTRA;	}	/*	 *   Stop there if sync parameters are unchanged.	 */	if (tp->head.sval == sval && 	    tp->head.wval == wval &&	    tp->head.uval == uval)		return;	tp->head.sval = sval;	tp->head.wval = wval;	tp->head.uval = uval;	/*	 *  Disable extended Sreq/Sack filtering if per < 50.	 *  Not supported on the C1010.	 */	if (per < 50 && !(np->features & FE_C10))		OUTOFFB(np, nc_stest2, EXT);	/*	 *  set actual value and sync_status	 */	OUTB(np, nc_sxfer,  tp->head.sval);	OUTB(np, nc_scntl3, tp->head.wval);	if (np->features & FE_C10) {		OUTB(np, nc_scntl4, tp->head.uval);	}	/*	 *  patch ALL busy ccbs of this target.	 */	FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {		struct sym_ccb *cp;		cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);		if (cp->target != target)			continue;		cp->phys.select.sel_scntl3 = tp->head.wval;		cp->phys.select.sel_sxfer  = tp->head.sval;		if (np->features & FE_C10) {			cp->phys.select.sel_scntl4 = tp->head.uval;		}	}}/* *  We received a WDTR. *  Let everything be aware of the changes. */static void sym_setwide(struct sym_hcb *np, int target, u_char wide){	struct sym_tcb *tp = &np->target[target];	struct scsi_target *starget = tp->starget;	if (spi_width(starget) == wide)		return;	sym_settrans(np, target, 0, 0, 0, wide, 0, 0);	tp->tgoal.width = wide;	spi_offset(starget) = 0;	spi_period(starget) = 0;	spi_width(starget) = wide;	spi_iu(starget) = 0;	spi_dt(starget) = 0;	spi_qas(starget) = 0;	if (sym_verbose >= 3)		spi_display_xfer_agreement(starget);}/* *  We received a SDTR. *  Let everything be aware of the changes. */static voidsym_setsync(struct sym_hcb *np, int target,            u_char ofs, u_char per, u_char div, u_char fak){	struct sym_tcb *tp = &np->target[target];	struct scsi_target *starget = tp->starget;	u_char wide = (tp->head.wval & EWS) ? BUS_16_BIT : BUS_8_BIT;	sym_settrans(np, target, 0, ofs, per, wide, div, fak);	spi_period(starget) = per;	spi_offset(starget) = ofs;	spi_iu(starget) = spi_dt(starget) = spi_qas(starget) = 0;	if (!tp->tgoal.dt && !tp->tgoal.iu && !tp->tgoal.qas) {		tp->tgoal.period = per;		tp->tgoal.offset = ofs;		tp->tgoal.check_nego = 0;	}	spi_display_xfer_agreement(starget);}/* *  We received a PPR. *  Let everything be aware of the changes. */static void sym_setpprot(struct sym_hcb *np, int target, u_char opts, u_char ofs,             u_char per, u_char wide, u_char div, u_char fak){	struct sym_tcb *tp = &np->target[target];	struct scsi_target *starget = tp->starget;	sym_settrans(np, target, opts, ofs, per, wide, div, fak);	spi_width(starget) = tp->tgoal.width = wide;	spi_period(starget) = tp->tgoal.period = per;	spi_offset(starget) = tp->tgoal.offset = ofs;	spi_iu(starget) = tp->tgoal.iu = !!(opts & PPR_OPT_IU);	spi_dt(starget) = tp->tgoal.dt = !!(opts & PPR_OPT_DT);	spi_qas(starget) = tp->tgoal.qas = !!(opts & PPR_OPT_QAS);	tp->tgoal.check_nego = 0;	spi_display_xfer_agreement(starget);}/* *  generic recovery from scsi interrupt * *  The doc says that when the chip gets an SCSI interrupt, *  it tries to stop in an orderly fashion, by completing  *  an instruction fetch that had started or by flushing  *  the DMA fifo for a write to memory that was executing. *  Such a fashion is not enough to know if the instruction  *  that was just before the current DSP value has been  *  executed or not. * *  There are some small SCRIPTS sections that deal with  *  the start queue and the done queue that may break any  *  assomption from the C code if we are interrupted  *  inside, so we reset if this happens. Btw, since these  *  SCRIPTS sections are executed while the SCRIPTS hasn't  *  started SCSI operations, it is very unlikely to happen. * *  All the driver data structures are supposed to be  *  allocated from the same 4 GB memory window, so there  *  is a 1 to 1 relationship between DSA and driver data  *  structures. Since we are careful :) to invalidate the  *  DSA when we complete a command or when the SCRIPTS  *  pushes a DSA into a queue, we can trust it when it  *  points to a CCB. */static void sym_recover_scsi_int (struct sym_hcb *np, u_char hsts){	u32	dsp	= INL(np, nc_dsp);	u32	dsa	= INL(np, nc_dsa);	struct sym_ccb *cp	= sym_ccb_from_dsa(np, dsa);	/*	 *  If we haven't been interrupted inside the SCRIPTS 	 *  critical pathes, we can safely restart the SCRIPTS 	 *  and trust the DSA value if it matches a CCB.	 */	if ((!(dsp > SCRIPTA_BA(np, getjob_begin) &&	       dsp < SCRIPTA_BA(np, getjob_end) + 1)) &&	    (!(dsp > SCRIPTA_BA(np, ungetjob) &&	       dsp < SCRIPTA_BA(np, reselect) + 1)) &&	    (!(dsp > SCRIPTB_BA(np, sel_for_abort) &&	       dsp < SCRIPTB_BA(np, sel_for_abort_1) + 1)) &&	    (!(dsp > SCRIPTA_BA(np, done) &&	       dsp < SCRIPTA_BA(np, done_end) + 1))) {		OUTB(np, nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo  */		OUTB(np, nc_stest3, TE|CSF);		/* clear scsi fifo */		/*		 *  If we have a CCB, let the SCRIPTS call us back for 		 *  the handling of the error with SCRATCHA filled with 		 *  STARTPOS. This way, we will be able to freeze the 		 *  device queue and requeue awaiting IOs.		 */		if (cp) {			cp->host_status = hsts;			OUTL_DSP(np, SCRIPTA_BA(np, complete_error));		}		/*		 *  Otherwise just restart the SCRIPTS.		 */		else {			OUTL(np, nc_dsa, 0xffffff);			OUTL_DSP(np, SCRIPTA_BA(np, start));		}	}	else		goto reset_all;	return;reset_all:	sym_start_reset(np);}/* *  chip exception handler for selection timeout */static void sym_int_sto (struct sym_hcb *np){	u32 dsp	= INL(np, nc_dsp);	if (DEBUG_FLAGS & DEBUG_TINY) printf ("T");	if (dsp == SCRIPTA_BA(np, wf_sel_done) + 8)		sym_recover_scsi_int(np, HS_SEL_TIMEOUT);	else		sym_start_reset(np);}/* *  chip exception handler for unexpected disconnect */static void sym_int_udc (struct sym_hcb *np){	printf ("%s: unexpected disconnect\n", sym_name(np));	sym_recover_scsi_int(np, HS_UNEXPECTED);}/* *  chip exception handler for SCSI bus mode change * *  spi2-r12 11.2.3 says a transceiver mode change must  *  generate a reset event and a device that detects a reset  *  event shall initiate a hard reset. It says also that a *  device that detects a mode change shall set data transfer  *  mode to eight bit asynchronous, etc... *  So, just reinitializing all except chip should be enough. */static void sym_int_sbmc (struct sym_hcb *np){	u_char scsi_mode = INB(np, nc_stest4) & SMODE;	/*	 *  Notify user.	 */	printf("%s: SCSI BUS mode change from %s to %s.\n", sym_name(np),		sym_scsi_bus_mode(np->scsi_mode), sym_scsi_bus_mode(scsi_mode));	/*	 *  Should suspend command processing for a few seconds and 	 *  reinitialize all except the chip.	 */	sym_start_up (np, 2);}/* *  chip exception handler for SCSI parity error. * *  When the chip detects a SCSI parity error and is  *  currently executing a (CH)MOV instruction, it does  *  not interrupt immediately, but tries to finish the  *  transfer of the current scatter entry before  *  interrupting. The following situations may occur: * *  - The complete scatter entry has been transferred  *    without the device having changed phase. *    The chip will then interrupt with the DSP pointing  *    to the instruction that follows the MOV. * *  - A phase mismatch occurs before the MOV finished  *    and phase errors are to be handled by the C code. *    The chip will then interrupt with both PAR and MA  *    conditions set. * *  - A phase mismatch occurs before the MOV finished and  *    phase errors are to be handled by SCRIPTS. *    The chip will load the DSP with the phase mismatch  *    JUMP address and interrupt the host processor. */static void sym_int_par (struct sym_hcb *np, u_short sist){	u_char	hsts	= INB(np, HS_PRT);	u32	dsp	= INL(np, nc_dsp);	u32	dbc	= INL(np, nc_dbc);	u32	dsa	= INL(np, nc_dsa);	u_char	sbcl	= INB(np, nc_sbcl);	u_char	cmd	= dbc >> 24;	int phase	= cmd & 7;	struct sym_ccb *cp	= sym_ccb_from_dsa(np, dsa);	printf("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n",		sym_name(np), hsts, dbc, sbcl);	/*	 *  Check that the chip is connected to the SCSI BUS.	 */	if (!(INB(np, nc_scntl1) & ISCON)) {		sym_recover_scsi_int(np, HS_UNEXPECTED);		return;	}	/*	 *  If the nexus is not clearly identified, reset the bus.	 *  We will try to do better later.	 */	if (!cp)		goto reset_all;	/*	 *  Check instruction was a MOV, direction was INPUT and 	 *  ATN is asserted.	 */	if ((cmd & 0xc0) || !(phase & 1) || !(sbcl & 0x8))		goto reset_all;	/*	 *  Keep track of the parity error.	 */	OUTONB(np, HF_PRT, HF_EXT_ERR);	cp->xerr_status |= XE_PARITY_ERR;	/*	 *  Prepare the message to send to the device.	 */	np->msgout[0] = (phase == 7) ? M_PARITY : M_ID_ERROR;	/*	 *  If the old phase was DATA IN phase, we have to deal with	 *  the 3 situations described above.	 *  For other input phases (MSG IN and STATUS), the device 	 *  must resend the whole thing that failed parity checking 	 *  or signal error. So, jumping to dispatcher should be OK.	 */	if (phase == 1 || phase == 5) {		/* Phase mismatch handled by SCRIPTS */		if (dsp == SCRIPTB_BA(np, pm_handle))			OUTL_DSP(np, dsp);		/* Phase mismatch handled by the C code */		else if (sist & MA)			sym_int_ma (np);		/* No phase mismatch occurred */		else {			sym_set_script_dp (np, cp, dsp);			OUTL_DSP(np, SCRIPTA_BA(np, dispatch));		}	}	else if (phase == 7)	/* We definitely cannot handle parity errors */#if 1				/* in message-in phase due to the relection  */		goto reset_all; /* path and various message anticipations.   */#else		OUTL_DSP(np, SCRIPTA_BA(np, clrack));#endif	else		OUTL_DSP(np, SCRIPTA_BA(np, dispatch));	return;reset_all:	sym_start_reset(np);	return;}/* *  chip exception handler for phase errors. * *  We have to construct a new transfer descriptor, *  to transfer the rest of the current block. */static void sym_int_ma (struct sym_hcb *np){	u32	dbc;	u32	rest;	u32	dsp;	u32	dsa;	u32	nxtdsp;	u32	*vdsp;	u32	oadr, olen;	u32	*tblp;        u32	newcmd;	u_int	delta;	u_char	cmd;	u_char	hflags, hflags0;	struct	sym_pmc *pm;	struct sym_ccb *cp;	dsp	= INL(np, nc_dsp);	dbc	= INL(np, nc_dbc);	dsa	= INL(np, nc_dsa);	cmd	= dbc >> 24;	rest	= dbc & 0xffffff;	delta	= 0;	/*	 *  locate matching cp if any.	 */	cp = sym_ccb_from_dsa(np, dsa);	/*	 *  Donnot take into account dma fifo and various buffers in 	 *  INPUT phase since the chip flushes everything before 	 *  raising the MA interrupt for interrupted INPUT phases.	 *  For DATA IN phase, we will check for the SWIDE later.	 */	if ((cmd & 7) != 1 && (cmd & 7) != 5) {		u_char ss0, ss2;		if (np->features & FE_DFBC)			delta = INW(np, nc_dfbc);		else {			u32 dfifo;			/*			 * Read DFIFO, CTEST[4-6] using 1 PCI bus ownership.			 */			dfifo = INL(np, nc_dfifo);			/*			 *  Calculate remaining bytes in DMA fifo.			 *  (CTEST5 = dfifo >> 16)			 */			if (dfifo & (DFS << 16))				delta = ((((dfifo >> 8) & 0x300) |				          (dfifo & 0xff)) - rest) & 0x3ff;			else				delta = ((dfifo & 0xff) - rest) & 0x7f;		}		/*		 *  The data in the dma fifo has not been transfered to		 *  the target -> add the amount to the rest		 *  and clear the data.		 *  Check the sstat2 register in case of wide transfer.		 */		rest += delta;		ss0  = INB(np, nc_sstat0);		if (ss0 & OLF) rest++;		if (!(np->features & FE_C10))			if (ss0 & ORF) rest++;		if (cp && (cp->phys.select.sel_scntl3 & EWS)) {			ss2 = INB(np, nc_sstat2);			if (ss2 & OLF1) rest++;			if (!(np->features & FE_C10))				if (ss2 & ORF1) rest++;		}		/*		 *  Clear fifos.		 */		OUTB(np, nc_ctest3, np->rv_ctest3 | CLF);	/* dma fifo  */		OUTB(np, nc_stest3, TE|CSF);		/* scsi fifo */	}	/*	 *  log the information	 */	if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))		printf ("P%x%x RL=%d D=%d ", cmd&7, INB(np, nc_sbcl)&7,			(unsigned) rest, (unsigned) delta);	/*	 *  try to find the interrupted script command,	 *  and the address at which to continue.	 */	vdsp	= NULL;	nxtdsp	= 0;	if	(dsp >  np->scripta_ba &&		 dsp <= np->scripta_ba + np->scripta_sz) {		vdsp = (u32 *)((char*)np->scripta0 + (dsp-np->scripta_ba-8));		nxtdsp = dsp;	}	else if	(dsp >  np->scriptb_ba &&		 dsp <= np->scriptb_ba + np->scriptb_sz) {		vdsp = (u32 *)((char*)np->scriptb0 + (dsp-np->scriptb_ba-8));		nxtdsp = dsp;	}	/*	 *  log the information	 */	if (DEBUG_FLAGS & DEBUG_PHASE) {		printf ("\nCP=%p DSP=%x NXT=%x VDSP=%p CMD=%x ",			cp, (unsigned)dsp, (unsigned)nxtdsp, vdsp, cmd);	}	if (!vdsp) {		printf ("%s: interrupted SCRIPT address not found.\n", 			sym_name (np));		goto reset_all;	}	if (!cp) {		printf ("%s: SCSI phase error fixup: CCB already dequeued.\n", 			sym_name (np));		goto reset_all;	}	/*	 *  get old startaddress and old length.	 */	oadr = scr_to_cpu(vdsp[1]);	if (cmd & 0x10) {	/* Table indirect */		tblp = (u32 *) ((char*) &cp->phys + oadr);		olen = scr_to_cpu(tblp[0]);		oadr = scr_to_cpu(tblp[1]);	} else {		tblp = (u32 *) 0;

⌨️ 快捷键说明

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