mpt: Unable to memory map registers

John Baldwin jhb at freebsd.org
Mon Jun 11 20:23:13 UTC 2012


On Monday, June 11, 2012 11:25:38 am Andrey Zonov wrote:
> On 6/11/12 6:19 PM, John Baldwin wrote:
> > On Saturday, June 09, 2012 3:06:19 pm Andrey Zonov wrote:
> >> On 6/9/12 9:35 PM, Marius Strobl wrote:
> >>> On Sat, Jun 09, 2012 at 12:58:05PM +0400, Andrey Zonov wrote:
> >>>> On 6/8/12 10:27 PM, John Baldwin wrote:
> >>>>> On Friday, June 08, 2012 11:48:50 am Andrey Zonov wrote:
> >>>>>> On Fri, Jun 8, 2012 at 7:19 PM, John Baldwin<jhb at freebsd.org>    wrote:
> >>>>>>> On Friday, June 08, 2012 3:14:19 am Andrey Zonov wrote:
> >>>>>>>> On 6/7/12 10:02 PM, Andrey Zonov wrote:
> >>>>>>>>> Hi,
> >>>>>>>>>
> >>>>>>>>> I just upgraded a few machines from 8.2-STABLE (r221983) to 9.0-
> > STABLE
> >>>>>>>>> (r234600) and now they can't find any disk because SAS controller
> >>>>>>>>> cannot
> >>>>>>>>> initialize with the following diagnostic:
> >>>>>>>>>
> >>>>>>>>> mpt0:<LSILogic SAS/SATA Adapter>    port 0xd000-0xd0ff irq 26 at
> > device
> >>>>>>>>> 3.0 on pci6
> >>>>>>>>> mpt0: 0x4000 bytes of rid 0x14 res 3 failed (0, 0xffffffffffffffff).
> >>>>>>>>> mpt0: Unable to memory map registers.
> >>>>>>>>> mpt0: Giving Up.
> >>>>>>>>>
> >>>>>>>>> pciconf -lv:
> >>>>>>>>> mpt0 at pci0:6:3:0: class=0x010000 card=0x81dd1043 chip=0x00541000
> >>>>>>>>> rev=0x02
> >>>>>>>>> hdr=0x00
> >>>>>>>>> vendor = 'LSI Logic / Symbios Logic'
> >>>>>>>>> device = 'SAS1068 PCI-X Fusion-MPT SAS'
> >>>>>>>>> class = mass storage
> >>>>>>>>> subclass = SCSI
> >>>>>>>>>
> >>>>>>>>> I tried to boot to latest HEAD and found the same problem. I also
> > tried
> >>>>>>>>> to build kernel with mpt driver from my 8.2. Controller didn't
> >>>>>>>>> initialize with the same diagnostic. So it looks like the problem is
> >>>>>>>>> not
> >>>>>>>>> in mpt driver.
> >>>>>>>>>
> >>>>>>>>> Any help would be appreciated.
> >>>>>>>>>
> >>>>>>>>
> >>>>>>>> +jhb@
> >>>>>>>>
> >>>>>>>> Hi John,
> >>>>>>>>
> >>>>>>>> Could you please help me with the problem above?  It looks like the
> >>>>>>>> problem is in PCI code and you changed things there.
> >>>>>>>
> >>>>>>> Can you get a verbose dmesg?
> >>>>>>>
> >>>>>>
> >>>>>> Yes, it's in attach.
> >>>>>
> >>>>> Can you get the output of 'devinfo -u' and 'devinfo -rv' from a broken
> >>>>> kernel?
> >>>>>
> >>>>
> >>>> Attached.
> >>>>
> >>>>> Can you also try setting 'debug.acpi.disable=sysres' in the loader?
> >>>>>
> >>>>
> >>>> Didn't help.
> >>>>
> >>>
> >>> That's probably due to a typo, the corret loader tunable is
> >>> debug.acpi.disabled=sysres (note the 'd').
> >>>
> >>
> >> This helps, thanks!  Please explain what this means.
> >
> > Well, it's working around a bug in your BIOS, but in this case FreeBSD should
> > have coped fine and it didn't.  Please try using this patch without that
> > tunable and get a verbose dmesg please:
> 
> Unfortunately didn't work.

Ah, it did work a bit, but it uncovered a larger bug.  I didn't make the
PCI-PCI bridge driver recursively grow windows.  Try this:

Index: sys/dev/pci/pci_pci.c
===================================================================
--- pci_pci.c	(revision 236888)
+++ pci_pci.c	(working copy)
@@ -113,23 +113,27 @@ DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclas
 
 /*
  * Is a resource from a child device sub-allocated from one of our
- * resource managers?
+ * resource managers?  If so, return the associated window.
  */
-static int
+static struct pcib_window *
 pcib_is_resource_managed(struct pcib_softc *sc, int type, struct resource *r)
 {
 
 	switch (type) {
 	case SYS_RES_IOPORT:
-		return (rman_is_region_manager(r, &sc->io.rman));
+		if (rman_is_region_manager(r, &sc->io.rman))
+			return (&sc->io);
+		break;
 	case SYS_RES_MEMORY:
 		/* Prefetchable resources may live in either memory rman. */
 		if (rman_get_flags(r) & RF_PREFETCHABLE &&
 		    rman_is_region_manager(r, &sc->pmem.rman))
-			return (1);
-		return (rman_is_region_manager(r, &sc->mem.rman));
+			return (&sc->pmem);
+		if (rman_is_region_manager(r, &sc->mem.rman))
+			return (&sc->mem);
+		break;
 	}
-	return (0);
+	return (NULL);
 }
 
 static int
@@ -871,6 +875,10 @@ pcib_grow_window(struct pcib_softc *sc, struct pci
 		goto updatewin;
 	}
 
+	/* Nothing to do if the request fits in the current window. */
+	if (start >= rman_get_start(w->res) && end <= rman_get_end(w->res))
+		return (ENOSPC);
+
 	/*
 	 * See if growing the window would help.  Compute the minimum
 	 * amount of address space needed on both the front and back
@@ -881,6 +889,10 @@ pcib_grow_window(struct pcib_softc *sc, struct pci
 	 * edge of the window, grow from the inner edge of the free
 	 * region.  Otherwise grow from the window boundary.
 	 *
+	 * As a special case, if the new region is an exact region
+	 * that is a superset of the current window, align the ends
+	 * and make a single adjust request to our parent.
+	 *
 	 * XXX: Special case: if w->res is completely empty and the
 	 * request size is larger than w->res, we should find the
 	 * optimal aligned buffer containing w->res and allocate that.
@@ -890,12 +902,22 @@ pcib_grow_window(struct pcib_softc *sc, struct pci
 		    "attempting to grow %s window for (%#lx-%#lx,%#lx)\n",
 		    w->name, start, end, count);
 	align = 1ul << RF_ALIGNMENT(flags);
+	if (start + count - 1 == end && start <= rman_get_start(w->res) &&
+	    end >= rman_get_end(w->res)) {
+		start &= (1ul << w->step) - 1;
+		end = roundup2(end + 1, 1ul << w->step) - 1;
+		if (bootverbose)
+			printf("\twide candidate range: %#lx-%#lx\n",
+			    start, end);
+		error = bus_adjust_resource(sc->dev, type, w->res, start, end);
+		goto adjusted;
+	}
 	if (start < rman_get_start(w->res)) {
 		if (rman_first_free_region(&w->rman, &start_free, &end_free) !=
 		    0 || start_free != rman_get_start(w->res))
-			end_free = rman_get_start(w->res) - 1;
+			end_free = rman_get_start(w->res);
 		if (end_free > end)
-			end_free = end;
+			end_free = end + 1;
 
 		/* Move end_free down until it is properly aligned. */
 		end_free &= ~(align - 1);
@@ -971,6 +993,7 @@ pcib_grow_window(struct pcib_softc *sc, struct pci
 		}
 	}
 
+adjusted:
 	if (error)
 		return (error);
 	if (bootverbose)
@@ -1099,10 +1122,25 @@ pcib_adjust_resource(device_t bus, device_t child,
     u_long start, u_long end)
 {
 	struct pcib_softc *sc;
+	struct pcib_window *w;
+	int error;
 
 	sc = device_get_softc(bus);
-	if (pcib_is_resource_managed(sc, type, r))
-		return (rman_adjust_resource(r, start, end));
+	w = pcib_is_resource_managed(sc, type, r);
+	if (w != NULL) {
+		error = rman_adjust_resource(r, start, end);
+		if (error == 0)
+			return (error);
+
+		/*
+		 * If the initial adjustment fails, try to grow the
+		 * window that backs this resource.
+		 */
+		if (pcib_grow_window(sc, w, type, start, end, end - start + 1,
+		    rman_get_flags(r)) == 0)
+			error = rman_adjust_resource(r, start, end);
+		return (error);
+	}
 	return (bus_generic_adjust_resource(bus, child, type, r, start, end));
 }
 
@@ -1114,7 +1152,7 @@ pcib_release_resource(device_t dev, device_t child
 	int error;
 
 	sc = device_get_softc(dev);
-	if (pcib_is_resource_managed(sc, type, r)) {
+	if (pcib_is_resource_managed(sc, type, r) != NULL) {
 		if (rman_get_flags(r) & RF_ACTIVE) {
 			error = bus_deactivate_resource(child, type, rid, r);
 			if (error)

-- 
John Baldwin


More information about the freebsd-stable mailing list