📄 sym_hipd.c
字号:
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 + -