Message ID | 20160223003444.10635.20204.stgit@bhelgaas-glaptop2.roam.corp.google.com (mailing list archive) |
---|---|
State | New, archived |
Delegated to: | Bjorn Helgaas |
Headers | show |
Hi Hannes, Thanks for taking a look at the rest of these. On Mon, Feb 22, 2016 at 06:46:23PM -0600, Bjorn Helgaas wrote: > Hi Hannes, > > This is a revision of your v3 series: > http://lkml.kernel.org/r/1455525722-122040-1-git-send-email-hare@suse.de > > Here's the description from your v3 posting: > > the current PCI VPD page access assumes that the entire possible VPD > data is readable. However, the spec only guarantees a VPD data up to > the 'end' marker, with everything beyond that being undefined. > This causes a system lockup on certain devices. > > With this patch we always set the VPD sysfs attribute size to '0', and > calculate the available VPD size on the first access. > If no valid data can be read an I/O error is returned. Just to see if I have this right: the VPD file size in sysfs will always appear as zero, regardless of whether it has been read or written, right? I don't think the user-visible size should change. Bjorn -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Mon, Feb 22, 2016 at 06:46:23PM -0600, Bjorn Helgaas wrote: > Hi Hannes, > > This is a revision of your v3 series: > http://lkml.kernel.org/r/1455525722-122040-1-git-send-email-hare@suse.de > > Here's the description from your v3 posting: > > the current PCI VPD page access assumes that the entire possible VPD > data is readable. However, the spec only guarantees a VPD data up to > the 'end' marker, with everything beyond that being undefined. > This causes a system lockup on certain devices. > > With this patch we always set the VPD sysfs attribute size to '0', and > calculate the available VPD size on the first access. > If no valid data can be read an I/O error is returned. > > I've also included the patch from Babu to blacklists devices which > are known to lockup when accessing the VPD data. > > I tweaked a few things, mostly whitespace and printk changes. The > appended diff shows the changes I made. > > I added some patches on top to clean up and simplify the VPD code. > These shouldn't make any functional difference unless I've made a > mistake. I've built these, but I don't really have a way to test > them. > > I am still waiting for bugzilla links from Babu for the blacklist > patch. > > Bjorn > > --- > > Babu Moger (1): > FIXME need bugzilla link > > Bjorn Helgaas (7): > PCI: Use bitfield instead of bool for struct pci_vpd_pci22.busy > PCI: Move pci_read_vpd() and pci_write_vpd() close to other VPD code > PCI: Move pci_vpd_release() from header file to pci/access.c > PCI: Remove struct pci_vpd_ops.release function pointer > PCI: Rename VPD symbols to remove unnecessary "pci22" > PCI: Fold struct pci_vpd_pci22 into struct pci_vpd > PCI: Sleep rather than busy-wait for VPD access completion > > Hannes Reinecke (3): > PCI: Update VPD definitions > PCI: Allow access to VPD attributes with size 0 > PCI: Determine actual VPD size on first access > > > drivers/pci/access.c | 240 ++++++++++++++++++++++++++++++----------------- > drivers/pci/pci-sysfs.c | 22 +++- > drivers/pci/pci.h | 16 ++- > drivers/pci/probe.c | 2 > drivers/pci/quirks.c | 29 ++++++ > include/linux/pci.h | 27 +++++ > 6 files changed, 231 insertions(+), 105 deletions(-) I added Hannes' reviewed-by and applied these, with the exception of "PCI: Prevent VPD access for buggy devices" (I'm waiting for bugzilla links for those quirks), to pci/vpd for v4.6. Bjorn -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 02/23/2016 10:07 PM, Bjorn Helgaas wrote: > Hi Hannes, > > Thanks for taking a look at the rest of these. > > On Mon, Feb 22, 2016 at 06:46:23PM -0600, Bjorn Helgaas wrote: >> Hi Hannes, >> >> This is a revision of your v3 series: >> http://lkml.kernel.org/r/1455525722-122040-1-git-send-email-hare@suse.de >> >> Here's the description from your v3 posting: >> >> the current PCI VPD page access assumes that the entire possible VPD >> data is readable. However, the spec only guarantees a VPD data up to >> the 'end' marker, with everything beyond that being undefined. >> This causes a system lockup on certain devices. >> >> With this patch we always set the VPD sysfs attribute size to '0', and >> calculate the available VPD size on the first access. >> If no valid data can be read an I/O error is returned. > > Just to see if I have this right: the VPD file size in sysfs will > always appear as zero, regardless of whether it has been read or > written, right? I don't think the user-visible size should change. > That is correct. As the actual size is evaluated on the first access, we don't have it available when creating the sysfs attribute itself. And when using the nominal size of 32k some bright program might try to jump to somewhere in the middle of the data, which will make calculating the validity of this horribly complex. Setting it to '0' is an easy way of avoiding this kinda games. So yes, there will be a user-visible change, but it shouldn't affect the programs accessing this attribute. lspci works happily with these changes Cheers, Hannes
On Wed, Feb 24, 2016 at 05:48:33AM +0800, Hannes Reinecke wrote: > On 02/23/2016 10:07 PM, Bjorn Helgaas wrote: > > Hi Hannes, > > > > Thanks for taking a look at the rest of these. > > > > On Mon, Feb 22, 2016 at 06:46:23PM -0600, Bjorn Helgaas wrote: > >> Hi Hannes, > >> > >> This is a revision of your v3 series: > >> http://lkml.kernel.org/r/1455525722-122040-1-git-send-email-hare@suse.de > >> > >> Here's the description from your v3 posting: > >> > >> the current PCI VPD page access assumes that the entire possible VPD > >> data is readable. However, the spec only guarantees a VPD data up to > >> the 'end' marker, with everything beyond that being undefined. > >> This causes a system lockup on certain devices. > >> > >> With this patch we always set the VPD sysfs attribute size to '0', and > >> calculate the available VPD size on the first access. > >> If no valid data can be read an I/O error is returned. > > > > Just to see if I have this right: the VPD file size in sysfs will > > always appear as zero, regardless of whether it has been read or > > written, right? I don't think the user-visible size should change. > > > That is correct. > As the actual size is evaluated on the first access, we don't have it > available when creating the sysfs attribute itself. > And when using the nominal size of 32k some bright program might try to > jump to somewhere in the middle of the data, which will make calculating > the validity of this horribly complex. > Setting it to '0' is an easy way of avoiding this kinda games. > > So yes, there will be a user-visible change, but it shouldn't affect the > programs accessing this attribute. > lspci works happily with these changes What is the user-visible change? Here's what I'm thinking. If we do this: ls -l /sys/.../vpd dd if=/sys/.../vpd bs=1 count=1 ls -l /sys/.../vpd Do we see different sizes from the two "ls" invocations? My thought is that we should see '0' both times, because I don't really think that output should change depending on previous actions of this user or other users. I though you were confirming that we do always see '0', but then you mentioned a user-visible change; is there a different change you're thinking of? Bjorn -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 02/24/2016 06:36 AM, Bjorn Helgaas wrote: > On Wed, Feb 24, 2016 at 05:48:33AM +0800, Hannes Reinecke wrote: >> On 02/23/2016 10:07 PM, Bjorn Helgaas wrote: >>> Hi Hannes, >>> >>> Thanks for taking a look at the rest of these. >>> >>> On Mon, Feb 22, 2016 at 06:46:23PM -0600, Bjorn Helgaas wrote: >>>> Hi Hannes, >>>> >>>> This is a revision of your v3 series: >>>> http://lkml.kernel.org/r/1455525722-122040-1-git-send-email-hare@suse.de >>>> >>>> Here's the description from your v3 posting: >>>> >>>> the current PCI VPD page access assumes that the entire possible VPD >>>> data is readable. However, the spec only guarantees a VPD data up to >>>> the 'end' marker, with everything beyond that being undefined. >>>> This causes a system lockup on certain devices. >>>> >>>> With this patch we always set the VPD sysfs attribute size to '0', and >>>> calculate the available VPD size on the first access. >>>> If no valid data can be read an I/O error is returned. >>> >>> Just to see if I have this right: the VPD file size in sysfs will >>> always appear as zero, regardless of whether it has been read or >>> written, right? I don't think the user-visible size should change. >>> >> That is correct. >> As the actual size is evaluated on the first access, we don't have it >> available when creating the sysfs attribute itself. >> And when using the nominal size of 32k some bright program might try to >> jump to somewhere in the middle of the data, which will make calculating >> the validity of this horribly complex. >> Setting it to '0' is an easy way of avoiding this kinda games. >> >> So yes, there will be a user-visible change, but it shouldn't affect the >> programs accessing this attribute. >> lspci works happily with these changes > > What is the user-visible change? Here's what I'm thinking. If we do > this: > > ls -l /sys/.../vpd > dd if=/sys/.../vpd bs=1 count=1 > ls -l /sys/.../vpd > > Do we see different sizes from the two "ls" invocations? My thought > is that we should see '0' both times, because I don't really think > that output should change depending on previous actions of this user > or other users. > Originally we have: # ls -l 0000:07:00.0/vpd -rw------- 1 root root 32768 Feb 24 01:29 0000:07:00.0/vpd and with this patchset we have: # ls -l 0000:07:00.0/vpd -rw------- 1 root root 0 Feb 24 01:29 0000:07:00.0/vpd So only programs doing a 'stat' on the device node will see a difference. Cheers, Hannes
On Wed, Feb 24, 2016 at 08:30:38AM +0800, Hannes Reinecke wrote: > On 02/24/2016 06:36 AM, Bjorn Helgaas wrote: > > On Wed, Feb 24, 2016 at 05:48:33AM +0800, Hannes Reinecke wrote: > >> On 02/23/2016 10:07 PM, Bjorn Helgaas wrote: > >>> Hi Hannes, > >>> > >>> Thanks for taking a look at the rest of these. > >>> > >>> On Mon, Feb 22, 2016 at 06:46:23PM -0600, Bjorn Helgaas wrote: > >>>> Hi Hannes, > >>>> > >>>> This is a revision of your v3 series: > >>>> http://lkml.kernel.org/r/1455525722-122040-1-git-send-email-hare@suse.de > >>>> > >>>> Here's the description from your v3 posting: > >>>> > >>>> the current PCI VPD page access assumes that the entire possible VPD > >>>> data is readable. However, the spec only guarantees a VPD data up to > >>>> the 'end' marker, with everything beyond that being undefined. > >>>> This causes a system lockup on certain devices. > >>>> > >>>> With this patch we always set the VPD sysfs attribute size to '0', and > >>>> calculate the available VPD size on the first access. > >>>> If no valid data can be read an I/O error is returned. > >>> > >>> Just to see if I have this right: the VPD file size in sysfs will > >>> always appear as zero, regardless of whether it has been read or > >>> written, right? I don't think the user-visible size should change. > >>> > >> That is correct. > >> As the actual size is evaluated on the first access, we don't have it > >> available when creating the sysfs attribute itself. > >> And when using the nominal size of 32k some bright program might try to > >> jump to somewhere in the middle of the data, which will make calculating > >> the validity of this horribly complex. > >> Setting it to '0' is an easy way of avoiding this kinda games. > >> > >> So yes, there will be a user-visible change, but it shouldn't affect the > >> programs accessing this attribute. > >> lspci works happily with these changes > > > > What is the user-visible change? Here's what I'm thinking. If we do > > this: > > > > ls -l /sys/.../vpd > > dd if=/sys/.../vpd bs=1 count=1 > > ls -l /sys/.../vpd > > > > Do we see different sizes from the two "ls" invocations? My thought > > is that we should see '0' both times, because I don't really think > > that output should change depending on previous actions of this user > > or other users. > > > Originally we have: > > # ls -l 0000:07:00.0/vpd > -rw------- 1 root root 32768 Feb 24 01:29 0000:07:00.0/vpd > > and with this patchset we have: > > # ls -l 0000:07:00.0/vpd > -rw------- 1 root root 0 Feb 24 01:29 0000:07:00.0/vpd > > So only programs doing a 'stat' on the device node will see a difference. Oh, I think I see: you mean there's a user-visible difference between the current tree and the tree with your patches applied. I was hoping that on a single kernel, the "vpd" attribute size was always the same, regardless of whether anybody had read or written it. If we always report zero size for all "vpd" files, I think that's OK. Bjorn -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Retested v4. For the series tested two PCIe cards that support VPD:
0d:00.0 Serial Attached SCSI controller: LSI Logic / Symbios Logic SAS2308 PCI-Express Fusion-MPT SAS-2 (rev 05)
1e:00.0 Fibre Channel: QLogic Corp. ISP2432-based 4Gb Fibre Channel to PCI Express HBA (rev 03)
The first card exposes 32KiB of NUL bytes as VPD and the second 154 bytes of non-NUL data repeating every 4KiB for 32KiB before the change. After the change the first card returns no data for VPD (since it contains only NUL bytes) and the second the expected 154 bytes of data.
The following warning message comes out as expected for the LSI card (changed from dyn debug controlled message):
[ 614.475984] mpt3sas 0000:0d:00.0: invalid short VPD tag 00 at offset 1
lspci works correctly with the patch in the kernel. The only change on the system (apart from the size of the vpd file) was that with the LSI card lspci with -vvvv as root it now says "Not readable" instead of "Unknown small resource type 00, will not decode more." in the VPD section.
---
Tested-by: Shane Seymour <shane.seymour@hpe.com>
Hi Bjorn, On 2/22/2016 6:46 PM, Bjorn Helgaas wrote: > Hi Hannes, > > This is a revision of your v3 series: > http://lkml.kernel.org/r/1455525722-122040-1-git-send-email-hare@suse.de > > Here's the description from your v3 posting: > > the current PCI VPD page access assumes that the entire possible VPD > data is readable. However, the spec only guarantees a VPD data up to > the 'end' marker, with everything beyond that being undefined. > This causes a system lockup on certain devices. > > With this patch we always set the VPD sysfs attribute size to '0', and > calculate the available VPD size on the first access. > If no valid data can be read an I/O error is returned. > > I've also included the patch from Babu to blacklists devices which > are known to lockup when accessing the VPD data. > > I tweaked a few things, mostly whitespace and printk changes. The > appended diff shows the changes I made. > > I added some patches on top to clean up and simplify the VPD code. > These shouldn't make any functional difference unless I've made a > mistake. I've built these, but I don't really have a way to test > them. > > I am still waiting for bugzilla links from Babu for the blacklist > patch. Sorry. I was on vacation. Just back in office today. Here is the Bugzilla link. https://bugzilla.kernel.org/show_bug.cgi?id=110681 > > Bjorn > > --- > > Babu Moger (1): > FIXME need bugzilla link > > Bjorn Helgaas (7): > PCI: Use bitfield instead of bool for struct pci_vpd_pci22.busy > PCI: Move pci_read_vpd() and pci_write_vpd() close to other VPD code > PCI: Move pci_vpd_release() from header file to pci/access.c > PCI: Remove struct pci_vpd_ops.release function pointer > PCI: Rename VPD symbols to remove unnecessary "pci22" > PCI: Fold struct pci_vpd_pci22 into struct pci_vpd > PCI: Sleep rather than busy-wait for VPD access completion > > Hannes Reinecke (3): > PCI: Update VPD definitions > PCI: Allow access to VPD attributes with size 0 > PCI: Determine actual VPD size on first access > > > drivers/pci/access.c | 240 ++++++++++++++++++++++++++++++----------------- > drivers/pci/pci-sysfs.c | 22 +++- > drivers/pci/pci.h | 16 ++- > drivers/pci/probe.c | 2 > drivers/pci/quirks.c | 29 ++++++ > include/linux/pci.h | 27 +++++ > 6 files changed, 231 insertions(+), 105 deletions(-) > > > Below are the changes I made to your v3 series: > > diff --git a/drivers/pci/access.c b/drivers/pci/access.c > index 8b6f5a2..4850f06 100644 > --- a/drivers/pci/access.c > +++ b/drivers/pci/access.c > @@ -283,9 +283,9 @@ struct pci_vpd_pci22 { > struct pci_vpd base; > struct mutex lock; > u16 flag; > + u8 cap; > u8 busy:1; > u8 valid:1; > - u8 cap; > }; > > /** > @@ -311,9 +311,9 @@ static size_t pci_vpd_pci22_size(struct pci_dev *dev, size_t old_size) > (tag == PCI_VPD_LTIN_RW_DATA)) { > if (pci_read_vpd(dev, off+1, 2, > &header[1]) != 2) { > - dev_dbg(&dev->dev, > - "invalid large VPD tag %02x size at offset %zu", > - tag, off + 1); > + dev_warn(&dev->dev, > + "invalid large VPD tag %02x size at offset %zu", > + tag, off + 1); > return 0; > } > off += PCI_VPD_LRDT_TAG_SIZE + > @@ -325,15 +325,17 @@ static size_t pci_vpd_pci22_size(struct pci_dev *dev, size_t old_size) > pci_vpd_srdt_size(header); > tag = pci_vpd_srdt_tag(header); > } > + > if (tag == PCI_VPD_STIN_END) /* End tag descriptor */ > return off; > + > if ((tag != PCI_VPD_LTIN_ID_STRING) && > (tag != PCI_VPD_LTIN_RO_DATA) && > (tag != PCI_VPD_LTIN_RW_DATA)) { > - dev_dbg(&dev->dev, > - "invalid %s VPD tag %02x at offset %zu", > - (header[0] & PCI_VPD_LRDT) ? "large" : "short", > - tag, off); > + dev_warn(&dev->dev, > + "invalid %s VPD tag %02x at offset %zu", > + (header[0] & PCI_VPD_LRDT) ? "large" : "short", > + tag, off); > return 0; > } > } > @@ -366,7 +368,7 @@ static int pci_vpd_pci22_wait(struct pci_dev *dev) > return ret; > > if ((status & PCI_VPD_ADDR_F) == vpd->flag) { > - vpd->busy = false; > + vpd->busy = 0; > return 0; > } > > @@ -393,16 +395,18 @@ static ssize_t pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count, > if (pos < 0) > return -EINVAL; > > - if (!vpd->valid && vpd->base.len > 0) { > - vpd->valid = true; > + if (!vpd->valid) { > + vpd->valid = 1; > vpd->base.len = pci_vpd_pci22_size(dev, vpd->base.len); > } > + > if (vpd->base.len == 0) > return -EIO; > > + if (pos >= vpd->base.len) > + return 0; > + > if (end > vpd->base.len) { > - if (pos > vpd->base.len) > - return 0; > end = vpd->base.len; > count = end - pos; > } > @@ -422,7 +426,7 @@ static ssize_t pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count, > pos & ~3); > if (ret < 0) > break; > - vpd->busy = true; > + vpd->busy = 1; > vpd->flag = PCI_VPD_ADDR_F; > ret = pci_vpd_pci22_wait(dev); > if (ret < 0) > @@ -459,10 +463,11 @@ static ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count > if (pos < 0 || (pos & 3) || (count & 3)) > return -EINVAL; > > - if (!vpd->valid && vpd->base.len > 0) { > - vpd->valid = true; > + if (!vpd->valid) { > + vpd->valid = 1; > vpd->base.len = pci_vpd_pci22_size(dev, vpd->base.len); > } > + > if (vpd->base.len == 0) > return -EIO; > > @@ -492,7 +497,7 @@ static ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count > if (ret < 0) > break; > > - vpd->busy = true; > + vpd->busy = 1; > vpd->flag = 0; > ret = pci_vpd_pci22_wait(dev); > if (ret < 0) > @@ -572,8 +577,8 @@ int pci_vpd_pci22_init(struct pci_dev *dev) > vpd->base.ops = &pci_vpd_pci22_ops; > mutex_init(&vpd->lock); > vpd->cap = cap; > - vpd->busy = false; > - vpd->valid = false; > + vpd->busy = 0; > + vpd->valid = 0; > dev->vpd = &vpd->base; > return 0; > } > diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c > index df1178f..626c3b2 100644 > --- a/drivers/pci/quirks.c > +++ b/drivers/pci/quirks.c > @@ -2135,45 +2135,31 @@ static void quirk_via_cx700_pci_parking_caching(struct pci_dev *dev) > DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching); > > /* > - * A read/write to sysfs entry ('/sys/bus/pci/devices/<id>/vpd') > - * will dump 32k of data. The default length is set as 32768. > - * Reading a full 32k will cause an access beyond the VPD end tag. > - * The system behaviour at that point is mostly unpredictable. > - * Apparently, some vendors have not implemented this VPD headers properly. > - * Adding a generic function disable vpd data for these buggy adapters > - * Add the DECLARE_PCI_FIXUP_FINAL line below with the specific with > - * vendor and device of interest to use this quirk. > + * If a device follows the VPD format spec, the PCI core will not read or > + * write past the VPD End Tag. But some vendors do not follow the VPD > + * format spec, so we can't tell how much data is safe to access. Devices > + * may behave unpredictably if we access too much. Blacklist these devices > + * so we don't touch VPD at all. > */ > static void quirk_blacklist_vpd(struct pci_dev *dev) > { > if (dev->vpd) { > dev->vpd->len = 0; > - dev_warn(&dev->dev, "PCI vpd access has been disabled due to firmware bug\n"); > + dev_warn(&dev->dev, FW_BUG "VPD access disabled\n"); > } > } > > -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0060, > - quirk_blacklist_vpd); > -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x007c, > - quirk_blacklist_vpd); > -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0413, > - quirk_blacklist_vpd); > -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0078, > - quirk_blacklist_vpd); > -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0079, > - quirk_blacklist_vpd); > -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0073, > - quirk_blacklist_vpd); > -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0071, > - quirk_blacklist_vpd); > -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005b, > - quirk_blacklist_vpd); > -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x002f, > - quirk_blacklist_vpd); > -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005d, > - quirk_blacklist_vpd); > -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005f, > - quirk_blacklist_vpd); > +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0060, quirk_blacklist_vpd); > +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x007c, quirk_blacklist_vpd); > +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0413, quirk_blacklist_vpd); > +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0078, quirk_blacklist_vpd); > +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0079, quirk_blacklist_vpd); > +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0073, quirk_blacklist_vpd); > +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0071, quirk_blacklist_vpd); > +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005b, quirk_blacklist_vpd); > +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x002f, quirk_blacklist_vpd); > +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005d, quirk_blacklist_vpd); > +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005f, quirk_blacklist_vpd); > DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, PCI_ANY_ID, > quirk_blacklist_vpd); > > -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 2/23/2016 10:52 PM, Seymour, Shane M wrote: > Retested v4. For the series tested two PCIe cards that support VPD: > > 0d:00.0 Serial Attached SCSI controller: LSI Logic / Symbios Logic SAS2308 PCI-Express Fusion-MPT SAS-2 (rev 05) > 1e:00.0 Fibre Channel: QLogic Corp. ISP2432-based 4Gb Fibre Channel to PCI Express HBA (rev 03) > > The first card exposes 32KiB of NUL bytes as VPD and the second 154 bytes of non-NUL data repeating every 4KiB for 32KiB before the change. After the change the first card returns no data for VPD (since it contains only NUL bytes) and the second the expected 154 bytes of data. > > The following warning message comes out as expected for the LSI card (changed from dyn debug controlled message): > > [ 614.475984] mpt3sas 0000:0d:00.0: invalid short VPD tag 00 at offset 1 > > lspci works correctly with the patch in the kernel. The only change on the system (apart from the size of the vpd file) was that with the LSI card lspci with -vvvv as root it now says "Not readable" instead of "Unknown small resource type 00, will not decode more." in the VPD section. > --- > Tested-by: Shane Seymour <shane.seymour@hpe.com> > I have also retested the V4 series. Did not see any side effects. Once again here is the bug I opened for this issue. https://bugzilla.kernel.org/show_bug.cgi?id=110681 --- Tested-by: Babu Moger <babu.moger@oracle.com> -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 8b6f5a2..4850f06 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -283,9 +283,9 @@ struct pci_vpd_pci22 { struct pci_vpd base; struct mutex lock; u16 flag; + u8 cap; u8 busy:1; u8 valid:1; - u8 cap; }; /** @@ -311,9 +311,9 @@ static size_t pci_vpd_pci22_size(struct pci_dev *dev, size_t old_size) (tag == PCI_VPD_LTIN_RW_DATA)) { if (pci_read_vpd(dev, off+1, 2, &header[1]) != 2) { - dev_dbg(&dev->dev, - "invalid large VPD tag %02x size at offset %zu", - tag, off + 1); + dev_warn(&dev->dev, + "invalid large VPD tag %02x size at offset %zu", + tag, off + 1); return 0; } off += PCI_VPD_LRDT_TAG_SIZE + @@ -325,15 +325,17 @@ static size_t pci_vpd_pci22_size(struct pci_dev *dev, size_t old_size) pci_vpd_srdt_size(header); tag = pci_vpd_srdt_tag(header); } + if (tag == PCI_VPD_STIN_END) /* End tag descriptor */ return off; + if ((tag != PCI_VPD_LTIN_ID_STRING) && (tag != PCI_VPD_LTIN_RO_DATA) && (tag != PCI_VPD_LTIN_RW_DATA)) { - dev_dbg(&dev->dev, - "invalid %s VPD tag %02x at offset %zu", - (header[0] & PCI_VPD_LRDT) ? "large" : "short", - tag, off); + dev_warn(&dev->dev, + "invalid %s VPD tag %02x at offset %zu", + (header[0] & PCI_VPD_LRDT) ? "large" : "short", + tag, off); return 0; } } @@ -366,7 +368,7 @@ static int pci_vpd_pci22_wait(struct pci_dev *dev) return ret; if ((status & PCI_VPD_ADDR_F) == vpd->flag) { - vpd->busy = false; + vpd->busy = 0; return 0; } @@ -393,16 +395,18 @@ static ssize_t pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count, if (pos < 0) return -EINVAL; - if (!vpd->valid && vpd->base.len > 0) { - vpd->valid = true; + if (!vpd->valid) { + vpd->valid = 1; vpd->base.len = pci_vpd_pci22_size(dev, vpd->base.len); } + if (vpd->base.len == 0) return -EIO; + if (pos >= vpd->base.len) + return 0; + if (end > vpd->base.len) { - if (pos > vpd->base.len) - return 0; end = vpd->base.len; count = end - pos; } @@ -422,7 +426,7 @@ static ssize_t pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count, pos & ~3); if (ret < 0) break; - vpd->busy = true; + vpd->busy = 1; vpd->flag = PCI_VPD_ADDR_F; ret = pci_vpd_pci22_wait(dev); if (ret < 0) @@ -459,10 +463,11 @@ static ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count if (pos < 0 || (pos & 3) || (count & 3)) return -EINVAL; - if (!vpd->valid && vpd->base.len > 0) { - vpd->valid = true; + if (!vpd->valid) { + vpd->valid = 1; vpd->base.len = pci_vpd_pci22_size(dev, vpd->base.len); } + if (vpd->base.len == 0) return -EIO; @@ -492,7 +497,7 @@ static ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count if (ret < 0) break; - vpd->busy = true; + vpd->busy = 1; vpd->flag = 0; ret = pci_vpd_pci22_wait(dev); if (ret < 0) @@ -572,8 +577,8 @@ int pci_vpd_pci22_init(struct pci_dev *dev) vpd->base.ops = &pci_vpd_pci22_ops; mutex_init(&vpd->lock); vpd->cap = cap; - vpd->busy = false; - vpd->valid = false; + vpd->busy = 0; + vpd->valid = 0; dev->vpd = &vpd->base; return 0; } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index df1178f..626c3b2 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2135,45 +2135,31 @@ static void quirk_via_cx700_pci_parking_caching(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching); /* - * A read/write to sysfs entry ('/sys/bus/pci/devices/<id>/vpd') - * will dump 32k of data. The default length is set as 32768. - * Reading a full 32k will cause an access beyond the VPD end tag. - * The system behaviour at that point is mostly unpredictable. - * Apparently, some vendors have not implemented this VPD headers properly. - * Adding a generic function disable vpd data for these buggy adapters - * Add the DECLARE_PCI_FIXUP_FINAL line below with the specific with - * vendor and device of interest to use this quirk. + * If a device follows the VPD format spec, the PCI core will not read or + * write past the VPD End Tag. But some vendors do not follow the VPD + * format spec, so we can't tell how much data is safe to access. Devices + * may behave unpredictably if we access too much. Blacklist these devices + * so we don't touch VPD at all. */ static void quirk_blacklist_vpd(struct pci_dev *dev) { if (dev->vpd) { dev->vpd->len = 0; - dev_warn(&dev->dev, "PCI vpd access has been disabled due to firmware bug\n"); + dev_warn(&dev->dev, FW_BUG "VPD access disabled\n"); } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0060, - quirk_blacklist_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x007c, - quirk_blacklist_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0413, - quirk_blacklist_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0078, - quirk_blacklist_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0079, - quirk_blacklist_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0073, - quirk_blacklist_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0071, - quirk_blacklist_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005b, - quirk_blacklist_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x002f, - quirk_blacklist_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005d, - quirk_blacklist_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005f, - quirk_blacklist_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0060, quirk_blacklist_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x007c, quirk_blacklist_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0413, quirk_blacklist_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0078, quirk_blacklist_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0079, quirk_blacklist_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0073, quirk_blacklist_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0071, quirk_blacklist_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005b, quirk_blacklist_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x002f, quirk_blacklist_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005d, quirk_blacklist_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005f, quirk_blacklist_vpd); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, PCI_ANY_ID, quirk_blacklist_vpd);