in ncr53c8xx.c [6518:6959]
void ncr_int_sir (struct ncb *np)
{
u_char scntl3;
u_char chg, ofs, per, fak, wide;
u_char num = INB (nc_dsps);
struct ccb *cp=NULL;
u_long dsa = INL (nc_dsa);
u_char target = INB (nc_sdid) & 0x0f;
struct tcb *tp = &np->target[target];
struct scsi_target *starget = tp->starget;
if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
switch (num) {
case SIR_INTFLY:
/*
** This is used for HP Zalon/53c720 where INTFLY
** operation is currently broken.
*/
ncr_wakeup_done(np);
#ifdef SCSI_NCR_CCB_DONE_SUPPORT
OUTL(nc_dsp, NCB_SCRIPT_PHYS (np, done_end) + 8);
#else
OUTL(nc_dsp, NCB_SCRIPT_PHYS (np, start));
#endif
return;
case SIR_RESEL_NO_MSG_IN:
case SIR_RESEL_NO_IDENTIFY:
/*
** If devices reselecting without sending an IDENTIFY
** message still exist, this should help.
** We just assume lun=0, 1 CCB, no tag.
*/
if (tp->lp[0]) {
OUTL_DSP (scr_to_cpu(tp->lp[0]->jump_ccb[0]));
return;
}
fallthrough;
case SIR_RESEL_BAD_TARGET: /* Will send a TARGET RESET message */
case SIR_RESEL_BAD_LUN: /* Will send a TARGET RESET message */
case SIR_RESEL_BAD_I_T_L_Q: /* Will send an ABORT TAG message */
case SIR_RESEL_BAD_I_T_L: /* Will send an ABORT message */
printk ("%s:%d: SIR %d, "
"incorrect nexus identification on reselection\n",
ncr_name (np), target, num);
goto out;
case SIR_DONE_OVERFLOW:
printk ("%s:%d: SIR %d, "
"CCB done queue overflow\n",
ncr_name (np), target, num);
goto out;
case SIR_BAD_STATUS:
cp = np->header.cp;
if (!cp || CCB_PHYS (cp, phys) != dsa)
goto out;
ncr_sir_to_redo(np, num, cp);
return;
default:
/*
** lookup the ccb
*/
cp = np->ccb;
while (cp && (CCB_PHYS (cp, phys) != dsa))
cp = cp->link_ccb;
BUG_ON(!cp);
BUG_ON(cp != np->header.cp);
if (!cp || cp != np->header.cp)
goto out;
}
switch (num) {
/*-----------------------------------------------------------------------------
**
** Was Sie schon immer ueber transfermode negotiation wissen wollten ...
** ("Everything you've always wanted to know about transfer mode
** negotiation")
**
** We try to negotiate sync and wide transfer only after
** a successful inquire command. We look at byte 7 of the
** inquire data to determine the capabilities of the target.
**
** When we try to negotiate, we append the negotiation message
** to the identify and (maybe) simple tag message.
** The host status field is set to HS_NEGOTIATE to mark this
** situation.
**
** If the target doesn't answer this message immediately
** (as required by the standard), the SIR_NEGO_FAIL interrupt
** will be raised eventually.
** The handler removes the HS_NEGOTIATE status, and sets the
** negotiated value to the default (async / nowide).
**
** If we receive a matching answer immediately, we check it
** for validity, and set the values.
**
** If we receive a Reject message immediately, we assume the
** negotiation has failed, and fall back to standard values.
**
** If we receive a negotiation message while not in HS_NEGOTIATE
** state, it's a target initiated negotiation. We prepare a
** (hopefully) valid answer, set our parameters, and send back
** this answer to the target.
**
** If the target doesn't fetch the answer (no message out phase),
** we assume the negotiation has failed, and fall back to default
** settings.
**
** When we set the values, we adjust them in all ccbs belonging
** to this target, in the controller's register, and in the "phys"
** field of the controller's struct ncb.
**
** Possible cases: hs sir msg_in value send goto
** We try to negotiate:
** -> target doesn't msgin NEG FAIL noop defa. - dispatch
** -> target rejected our msg NEG FAIL reject defa. - dispatch
** -> target answered (ok) NEG SYNC sdtr set - clrack
** -> target answered (!ok) NEG SYNC sdtr defa. REJ--->msg_bad
** -> target answered (ok) NEG WIDE wdtr set - clrack
** -> target answered (!ok) NEG WIDE wdtr defa. REJ--->msg_bad
** -> any other msgin NEG FAIL noop defa. - dispatch
**
** Target tries to negotiate:
** -> incoming message --- SYNC sdtr set SDTR -
** -> incoming message --- WIDE wdtr set WDTR -
** We sent our answer:
** -> target doesn't msgout --- PROTO ? defa. - dispatch
**
**-----------------------------------------------------------------------------
*/
case SIR_NEGO_FAILED:
/*-------------------------------------------------------
**
** Negotiation failed.
** Target doesn't send an answer message,
** or target rejected our message.
**
** Remove negotiation request.
**
**-------------------------------------------------------
*/
OUTB (HS_PRT, HS_BUSY);
fallthrough;
case SIR_NEGO_PROTO:
/*-------------------------------------------------------
**
** Negotiation failed.
** Target doesn't fetch the answer message.
**
**-------------------------------------------------------
*/
if (DEBUG_FLAGS & DEBUG_NEGO) {
PRINT_ADDR(cp->cmd, "negotiation failed sir=%x "
"status=%x.\n", num, cp->nego_status);
}
/*
** any error in negotiation:
** fall back to default mode.
*/
switch (cp->nego_status) {
case NS_SYNC:
spi_period(starget) = 0;
spi_offset(starget) = 0;
ncr_setsync (np, cp, 0, 0xe0);
break;
case NS_WIDE:
spi_width(starget) = 0;
ncr_setwide (np, cp, 0, 0);
break;
}
np->msgin [0] = NOP;
np->msgout[0] = NOP;
cp->nego_status = 0;
break;
case SIR_NEGO_SYNC:
if (DEBUG_FLAGS & DEBUG_NEGO) {
ncr_print_msg(cp, "sync msgin", np->msgin);
}
chg = 0;
per = np->msgin[3];
ofs = np->msgin[4];
if (ofs==0) per=255;
/*
** if target sends SDTR message,
** it CAN transfer synch.
*/
if (ofs && starget)
spi_support_sync(starget) = 1;
/*
** check values against driver limits.
*/
if (per < np->minsync)
{chg = 1; per = np->minsync;}
if (per < tp->minsync)
{chg = 1; per = tp->minsync;}
if (ofs > tp->maxoffs)
{chg = 1; ofs = tp->maxoffs;}
/*
** Check against controller limits.
*/
fak = 7;
scntl3 = 0;
if (ofs != 0) {
ncr_getsync(np, per, &fak, &scntl3);
if (fak > 7) {
chg = 1;
ofs = 0;
}
}
if (ofs == 0) {
fak = 7;
per = 0;
scntl3 = 0;
tp->minsync = 0;
}
if (DEBUG_FLAGS & DEBUG_NEGO) {
PRINT_ADDR(cp->cmd, "sync: per=%d scntl3=0x%x ofs=%d "
"fak=%d chg=%d.\n", per, scntl3, ofs, fak, chg);
}
if (INB (HS_PRT) == HS_NEGOTIATE) {
OUTB (HS_PRT, HS_BUSY);
switch (cp->nego_status) {
case NS_SYNC:
/* This was an answer message */
if (chg) {
/* Answer wasn't acceptable. */
spi_period(starget) = 0;
spi_offset(starget) = 0;
ncr_setsync(np, cp, 0, 0xe0);
OUTL_DSP(NCB_SCRIPT_PHYS (np, msg_bad));
} else {
/* Answer is ok. */
spi_period(starget) = per;
spi_offset(starget) = ofs;
ncr_setsync(np, cp, scntl3, (fak<<5)|ofs);
OUTL_DSP(NCB_SCRIPT_PHYS (np, clrack));
}
return;
case NS_WIDE:
spi_width(starget) = 0;
ncr_setwide(np, cp, 0, 0);
break;
}
}
/*
** It was a request. Set value and
** prepare an answer message
*/
spi_period(starget) = per;
spi_offset(starget) = ofs;
ncr_setsync(np, cp, scntl3, (fak<<5)|ofs);
spi_populate_sync_msg(np->msgout, per, ofs);
cp->nego_status = NS_SYNC;
if (DEBUG_FLAGS & DEBUG_NEGO) {
ncr_print_msg(cp, "sync msgout", np->msgout);
}
if (!ofs) {
OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad));
return;
}
np->msgin [0] = NOP;
break;
case SIR_NEGO_WIDE:
/*
** Wide request message received.
*/
if (DEBUG_FLAGS & DEBUG_NEGO) {
ncr_print_msg(cp, "wide msgin", np->msgin);
}
/*
** get requested values.
*/
chg = 0;
wide = np->msgin[3];
/*
** if target sends WDTR message,
** it CAN transfer wide.
*/
if (wide && starget)
spi_support_wide(starget) = 1;
/*
** check values against driver limits.
*/
if (wide > tp->usrwide)
{chg = 1; wide = tp->usrwide;}
if (DEBUG_FLAGS & DEBUG_NEGO) {
PRINT_ADDR(cp->cmd, "wide: wide=%d chg=%d.\n", wide,
chg);
}
if (INB (HS_PRT) == HS_NEGOTIATE) {
OUTB (HS_PRT, HS_BUSY);
switch (cp->nego_status) {
case NS_WIDE:
/*
** This was an answer message
*/
if (chg) {
/* Answer wasn't acceptable. */
spi_width(starget) = 0;
ncr_setwide(np, cp, 0, 1);
OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad));
} else {
/* Answer is ok. */
spi_width(starget) = wide;
ncr_setwide(np, cp, wide, 1);
OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
}
return;
case NS_SYNC:
spi_period(starget) = 0;
spi_offset(starget) = 0;
ncr_setsync(np, cp, 0, 0xe0);
break;
}
}
/*
** It was a request, set value and
** prepare an answer message
*/
spi_width(starget) = wide;
ncr_setwide(np, cp, wide, 1);
spi_populate_width_msg(np->msgout, wide);
np->msgin [0] = NOP;
cp->nego_status = NS_WIDE;
if (DEBUG_FLAGS & DEBUG_NEGO) {
ncr_print_msg(cp, "wide msgout", np->msgin);
}
break;
/*--------------------------------------------------------------------
**
** Processing of special messages
**
**--------------------------------------------------------------------
*/
case SIR_REJECT_RECEIVED:
/*-----------------------------------------------
**
** We received a MESSAGE_REJECT.
**
**-----------------------------------------------
*/
PRINT_ADDR(cp->cmd, "MESSAGE_REJECT received (%x:%x).\n",
(unsigned)scr_to_cpu(np->lastmsg), np->msgout[0]);
break;
case SIR_REJECT_SENT:
/*-----------------------------------------------
**
** We received an unknown message
**
**-----------------------------------------------
*/
ncr_print_msg(cp, "MESSAGE_REJECT sent for", np->msgin);
break;
/*--------------------------------------------------------------------
**
** Processing of special messages
**
**--------------------------------------------------------------------
*/
case SIR_IGN_RESIDUE:
/*-----------------------------------------------
**
** We received an IGNORE RESIDUE message,
** which couldn't be handled by the script.
**
**-----------------------------------------------
*/
PRINT_ADDR(cp->cmd, "IGNORE_WIDE_RESIDUE received, but not yet "
"implemented.\n");
break;
#if 0
case SIR_MISSING_SAVE:
/*-----------------------------------------------
**
** We received an DISCONNECT message,
** but the datapointer wasn't saved before.
**
**-----------------------------------------------
*/
PRINT_ADDR(cp->cmd, "DISCONNECT received, but datapointer "
"not saved: data=%x save=%x goal=%x.\n",
(unsigned) INL (nc_temp),
(unsigned) scr_to_cpu(np->header.savep),
(unsigned) scr_to_cpu(np->header.goalp));
break;
#endif
}
out:
OUTONB_STD ();
}