mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-11-29 21:52:45 +00:00
The NCR script has grown beyond one page (4KB). Since malloc() returns
contiguous memory in virtual space, but doesn't guarantee any particular physical layout of pages, the script may be not contguous in physical memory. This made the first write command fail in very rare cases. This has been fixed by checking the region returned by malloc() for being contiguous, but there should be a physical memory allocate and later mapping to virtual memory instead. A few assertions and error messages are improved.
This commit is contained in:
parent
66f1d0dbc6
commit
8befc21fbd
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=10567
143
sys/pci/ncr.c
143
sys/pci/ncr.c
@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** $Id: ncr.c,v 1.41 1995/08/15 20:19:14 se Exp $
|
||||
** $Id: ncr.c,v 1.42 1995/08/23 23:03:25 gibbs Exp $
|
||||
**
|
||||
** Device driver for the NCR 53C810 PCI-SCSI-Controller.
|
||||
**
|
||||
@ -591,7 +591,7 @@ struct lcb {
|
||||
** with SFBR set to the "Identify" message.
|
||||
** if it's not this lun, jump to the next.
|
||||
**
|
||||
** JUMP IF (SFBR == #lun#)
|
||||
** JUMP IF (SFBR != #lun#)
|
||||
** @(next lcb of this target)
|
||||
*/
|
||||
|
||||
@ -709,7 +709,7 @@ struct head {
|
||||
**
|
||||
** The last four bytes are used inside the script by "COPY" commands.
|
||||
** Because source and destination must have the same alignment
|
||||
** in a longword, the fields HAVE to be on the selected offsets.
|
||||
** in a longword, the fields HAVE to be at the choosen offsets.
|
||||
** xerr_st (4) 0 (0x34) scratcha
|
||||
** sync_st (5) 1 (0x05) sxfer
|
||||
** wide_st (7) 3 (0x03) scntl3
|
||||
@ -1188,7 +1188,7 @@ static void ncr_negotiate (struct ncb* np, struct tcb* tp);
|
||||
static void ncr_opennings (ncb_p np, lcb_p lp, struct scsi_xfer * xp);
|
||||
static void ncb_profile (ncb_p np, ccb_p cp);
|
||||
static void ncr_script_copy_and_bind
|
||||
(struct script * script, ncb_p np);
|
||||
(ncb_p np);
|
||||
static void ncr_script_fill (struct script * scr);
|
||||
static int ncr_scatter (struct dsb* phys,u_long vaddr,u_long datalen);
|
||||
static void ncr_setmaxtags (tcb_p tp, u_long usrtags);
|
||||
@ -1223,7 +1223,7 @@ static void ncr_attach (pcici_t tag, int unit);
|
||||
|
||||
|
||||
static char ident[] =
|
||||
"\n$Id: ncr.c,v 1.41 1995/08/15 20:19:14 se Exp $\n";
|
||||
"\n$Id: ncr.c,v 1.42 1995/08/23 23:03:25 gibbs Exp $\n";
|
||||
|
||||
u_long ncr_version = NCR_VERSION
|
||||
+ (u_long) sizeof (struct ncb)
|
||||
@ -1240,7 +1240,7 @@ ncb_p ncrp [MAX_UNITS];
|
||||
|
||||
static int ncr_debug = SCSI_DEBUG_FLAGS;
|
||||
|
||||
int ncr_cache; /* to be alligned _NOT_ static */
|
||||
int ncr_cache; /* to be aligned _NOT_ static */
|
||||
|
||||
/*==========================================================
|
||||
**
|
||||
@ -1434,7 +1434,7 @@ static struct script script0 = {
|
||||
** head starts with launch,
|
||||
** so actually the processor jumps to
|
||||
** the lauch part.
|
||||
** If the entry is scheduled to be executed,
|
||||
** If the entry is scheduled for execution,
|
||||
** then launch contains a jump to SELECT.
|
||||
** If it's not scheduled, it contains a jump to IDLE.
|
||||
*/
|
||||
@ -1486,7 +1486,7 @@ static struct script script0 = {
|
||||
**
|
||||
** Set Initiator mode.
|
||||
**
|
||||
** (Target mode is left as an exercise for the student)
|
||||
** (Target mode is left as an exercise for the reader)
|
||||
*/
|
||||
|
||||
SCR_CLR (SCR_TRG),
|
||||
@ -2303,7 +2303,7 @@ static struct script script0 = {
|
||||
/*>>>*/ /*
|
||||
** Check if temp==savep or temp==goalp:
|
||||
** if not, log a missing save pointer message.
|
||||
** In fact, it's a comparation mod 256.
|
||||
** In fact, it's a comparison mod 256.
|
||||
**
|
||||
** Hmmm, I hadn't thought that I would be urged to
|
||||
** write this kind of ugly self modifying code.
|
||||
@ -2315,6 +2315,8 @@ static struct script script0 = {
|
||||
0,
|
||||
/*
|
||||
** You are not expected to understand this ..
|
||||
**
|
||||
** CAUTION: only little endian architectures supported! XXX
|
||||
*/
|
||||
SCR_COPY (1),
|
||||
NADDR (header.savep),
|
||||
@ -2935,25 +2937,57 @@ void ncr_script_fill (struct script * scr)
|
||||
**==========================================================
|
||||
*/
|
||||
|
||||
static void ncr_script_copy_and_bind (struct script *script, ncb_p np)
|
||||
static ncrcmd *src = (ncrcmd *)&script0;
|
||||
|
||||
static void ncr_script_copy_and_bind (ncb_p np)
|
||||
{
|
||||
ncrcmd opcode, new, old;
|
||||
ncrcmd *src, *dst, *start, *end;
|
||||
ncrcmd *dst, *start, *end;
|
||||
int relocs;
|
||||
u_long p_script;
|
||||
|
||||
np->script = (struct script *)
|
||||
/*
|
||||
* Test whether last byte of script is at the right
|
||||
* PHYSICAL address, since the NCR uses phys. addresses only.
|
||||
* Assumes that the script fits into two 4KB pages ...
|
||||
*/
|
||||
assert (sizeof(struct script) <= 8192);
|
||||
|
||||
while ((p_script = vtophys (src)) + sizeof (struct script) !=
|
||||
vtophys ((char *)src + sizeof (struct script))) {
|
||||
|
||||
struct script *newsrc = (struct script *)
|
||||
malloc (sizeof (struct script), M_DEVBUF, M_WAITOK);
|
||||
np->p_script = vtophys(np->script);
|
||||
memcpy (newsrc, src, sizeof(struct script));
|
||||
src = (ncrcmd *) newsrc;
|
||||
|
||||
src = script->start;
|
||||
dst = np->script->start;
|
||||
printf ("%s: NCR script not physically contigous, retrying\n",
|
||||
ncr_name(np));
|
||||
}
|
||||
|
||||
np->script = (struct script*) src;
|
||||
np->p_script = p_script;
|
||||
|
||||
dst = (ncrcmd *) malloc (sizeof (struct script), M_DEVBUF, M_WAITOK);
|
||||
|
||||
/*
|
||||
* Copy the script to keep an unmodified version
|
||||
* to bind for another NCR chip, if present.
|
||||
*/
|
||||
memcpy (dst, src, sizeof(struct script));
|
||||
|
||||
/*
|
||||
* Patch the "src" of the memcpy to become the script to execute.
|
||||
* The copy in the malloc()ed memory at "dst" will be the src of
|
||||
* the script for the next NCR, if there are multiple chips.
|
||||
*/
|
||||
|
||||
start = src;
|
||||
end = src + (sizeof(struct script) / 4);
|
||||
|
||||
while (src < end) {
|
||||
|
||||
*dst++ = opcode = *src++;
|
||||
opcode = *src++;
|
||||
|
||||
/*
|
||||
** If we forget to change the length
|
||||
@ -3021,7 +3055,7 @@ static void ncr_script_copy_and_bind (struct script *script, ncb_p np)
|
||||
|
||||
if (relocs) {
|
||||
while (relocs--) {
|
||||
old = *src++;
|
||||
old = *src;
|
||||
|
||||
switch (old & RELOC_MASK) {
|
||||
case RELOC_REGISTER:
|
||||
@ -3045,12 +3079,17 @@ static void ncr_script_copy_and_bind (struct script *script, ncb_p np)
|
||||
break;
|
||||
}
|
||||
|
||||
*dst++ = new;
|
||||
*src++ = new;
|
||||
}
|
||||
} else
|
||||
*dst++ = *src++;
|
||||
src++;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* next time use the (unmodified) copy of the script as "src"
|
||||
*/
|
||||
src = dst;
|
||||
}
|
||||
|
||||
/*==========================================================
|
||||
@ -3137,7 +3176,7 @@ static char* ncr_probe (pcici_t tag, pcidi_t type)
|
||||
case NCR_825_ID:
|
||||
return ("ncr 53c825 wide scsi");
|
||||
}
|
||||
return (0);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
#endif /* !__NetBSD__ */
|
||||
@ -3266,7 +3305,7 @@ static void ncr_attach (pcici_t config_id, int unit)
|
||||
*/
|
||||
|
||||
ncr_script_fill (&script0);
|
||||
ncr_script_copy_and_bind (&script0, np);
|
||||
ncr_script_copy_and_bind (np);
|
||||
|
||||
/*
|
||||
** init data structure
|
||||
@ -3486,6 +3525,7 @@ static INT32 ncr_start (struct scsi_xfer * xp)
|
||||
|
||||
if (flags & SCSI_RESET) {
|
||||
OUTB (nc_scntl1, CRST);
|
||||
DELAY (1000);
|
||||
return(COMPLETE);
|
||||
};
|
||||
|
||||
@ -3670,19 +3710,6 @@ static INT32 ncr_start (struct scsi_xfer * xp)
|
||||
};
|
||||
} else {
|
||||
cp->tag=0;
|
||||
#if 0
|
||||
/*
|
||||
** @GENSCSI@ Bug in "/sys/scsi/cd.c"
|
||||
**
|
||||
** /sys/scsi/cd.c initializes opennings with 2.
|
||||
** Our info value of 1 is not respected.
|
||||
*/
|
||||
if (xp->sc_link && xp->sc_link->opennings) {
|
||||
PRINT_ADDR(xp);
|
||||
printf ("opennings set to 0.\n");
|
||||
xp->sc_link->opennings = 0;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
/*----------------------------------------------------
|
||||
@ -4851,7 +4878,6 @@ void ncr_exception (ncb_p np)
|
||||
u_char istat, dstat;
|
||||
u_short sist;
|
||||
u_long dsp, dsa;
|
||||
ccb_p cp;
|
||||
int i, script_ofs;
|
||||
|
||||
/*
|
||||
@ -5023,18 +5049,12 @@ void ncr_exception (ncb_p np)
|
||||
|
||||
for (vpci = vpc; vpci >= 4; vpci -= 4);
|
||||
while (vpci <= vpc) {
|
||||
printf ("\tvirt.addr: 0x%08x instr: 0x%08x\n",
|
||||
printf ("\tvirt.addr: 0x%08lx instr: 0x%08lx\n",
|
||||
vpci, *(ncrcmd *)(vpci));
|
||||
vpci += 4;
|
||||
}
|
||||
}
|
||||
|
||||
cp = &np->ccb;
|
||||
printf ("\tgather/scatter table:\n");
|
||||
for (i = 0; i < MAX_SCATTER; i++) {
|
||||
printf ("\t%02d\t0x%08x\n", i, cp->phys.data[i]);
|
||||
}
|
||||
|
||||
/*----------------------------------------
|
||||
** clean up the dma fifo
|
||||
**----------------------------------------
|
||||
@ -5112,8 +5132,8 @@ void ncr_exception (ncb_p np)
|
||||
** @RECOVER@ HTH, SGE, ABRT.
|
||||
**
|
||||
** We should try to recover from these interrupts.
|
||||
** They may occur if there are problems with synch transfers,
|
||||
** or if targets are powerswitched while the driver is running.
|
||||
** They may occur if there are problems with synch transfers, or
|
||||
** if targets are switched on or off while the driver is running.
|
||||
*/
|
||||
|
||||
if (sist & SGE) {
|
||||
@ -5288,13 +5308,13 @@ static void ncr_int_ma (ncb_p np)
|
||||
cp = cp->link_ccb;
|
||||
|
||||
if (!cp) {
|
||||
printf ("%s: SCSI phase error fixup: CCB already dequeued (0x%08x)\n",
|
||||
ncr_name (np), np->header.cp);
|
||||
printf ("%s: SCSI phase error fixup: CCB already dequeued (0x%08lx)\n",
|
||||
ncr_name (np), (u_long) np->header.cp);
|
||||
return;
|
||||
}
|
||||
if (cp != np->header.cp) {
|
||||
printf ("%s: SCSI phase error fixup: CCB address mismatch (0x%08x != 0x%08x)\n",
|
||||
ncr_name (np), cp, np->header.cp);
|
||||
printf ("%s: SCSI phase error fixup: CCB address mismatch (0x%08lx != 0x%08lx)\n",
|
||||
ncr_name (np), (u_long) cp, (u_long) np->header.cp);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -5356,7 +5376,13 @@ static void ncr_int_ma (ncb_p np)
|
||||
** if old phase not dataphase, leave here.
|
||||
*/
|
||||
|
||||
assert (cmd == (vdsp[0] >> 24));
|
||||
if (cmd != (vdsp[0] >> 24)) {
|
||||
PRINT_ADDR(cp->xfer);
|
||||
printf ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
|
||||
cmd, vdsp[0] >> 24);
|
||||
|
||||
return;
|
||||
}
|
||||
if (cmd & 0x06) {
|
||||
PRINT_ADDR(cp->xfer);
|
||||
printf ("phase change %d-%d %d@%x resid=%d.\n",
|
||||
@ -6011,14 +6037,14 @@ static ccb_p ncr_get_ccb
|
||||
(ncb_p np, u_long flags, u_long target, u_long lun)
|
||||
{
|
||||
lcb_p lp;
|
||||
ccb_p cp = (ccb_p ) 0;
|
||||
ccb_p cp = (ccb_p) 0;
|
||||
|
||||
/*
|
||||
** Lun structure available ?
|
||||
*/
|
||||
|
||||
lp = np->target[target].lp[lun];
|
||||
if (lp)
|
||||
if (lp) {
|
||||
cp = lp->next_ccb;
|
||||
|
||||
/*
|
||||
@ -6026,6 +6052,7 @@ static ccb_p ncr_get_ccb
|
||||
*/
|
||||
|
||||
while (cp && cp->magic) cp = cp->next_ccb;
|
||||
}
|
||||
|
||||
/*
|
||||
** if nothing available, take the default.
|
||||
@ -6065,7 +6092,7 @@ void ncr_free_ccb (ncb_p np, ccb_p cp, int flags)
|
||||
** sanity
|
||||
*/
|
||||
|
||||
if (!cp) return;
|
||||
assert (cp != NULL);
|
||||
|
||||
cp -> host_status = HS_IDLE;
|
||||
cp -> magic = 0;
|
||||
@ -6091,8 +6118,8 @@ static void ncr_alloc_ccb (ncb_p np, struct scsi_xfer * xp)
|
||||
u_long target;
|
||||
u_long lun;
|
||||
|
||||
if (!np) return;
|
||||
if (!xp) return;
|
||||
assert (np != NULL);
|
||||
assert (xp != NULL);
|
||||
|
||||
target = xp->sc_link->target;
|
||||
lun = xp->sc_link->lun;
|
||||
@ -6307,11 +6334,11 @@ static int ncr_scatter
|
||||
|
||||
/*
|
||||
** insert extra break points at a distance of chunk.
|
||||
** We try to reduce the number of interrupts due to
|
||||
** unexpected phase changes due to disconnects.
|
||||
** We try to reduce the number of interrupts caused
|
||||
** by unexpected phase changes due to disconnects.
|
||||
** A typical harddisk may disconnect before ANY block.
|
||||
** If we want to avoid unexpected phase changes at all
|
||||
** we have to use a break point every 512 bytes.
|
||||
** If we wanted to avoid unexpected phase changes at all
|
||||
** we had to use a break point every 512 bytes.
|
||||
** Of course the number of scatter/gather blocks is
|
||||
** limited.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user