All of lore.kernel.org
 help / color / mirror / Atom feed
From: <Jordan_Hargrave@Dell.com>
To: <alexander.duyck@gmail.com>
Cc: <hare@suse.de>, <bhelgaas@google.com>, <mkubecek@suse.com>,
	<shane.seymour@hpe.com>, <linux-pci@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>, <helgaas@kernel.org>
Subject: RE: [PATCH 2/2] pci: Update VPD size with correct length
Date: Tue, 29 Dec 2015 13:01:35 -0600	[thread overview]
Message-ID: <8B8F62BE6EB1824D91A8BF961FDC40B9179AE6E3DF@AUSX7MCPS305.AMER.DELL.COM> (raw)
In-Reply-To: <CAKgT0UffHMebLKB3pwG9YxoBL0m9sjjoBLhF8s-q12LJDK5tEg@mail.gmail.com>

>On Mon, Dec 28, 2015 at 9:29 PM,  <Jordan_Hargrave@dell.com> wrote:
>> I had posted a patch recently to enable exposing the VPD-R valyes to sysfs.  I need access
>> to these to parse into systemd for network naming (biosdevname style names).
>>
>>
>> The VPD-R is a readonly area contained within the PCI Vital Product
>> data.  There are some standard and vendor-specific keys stored in
>> this region.
>>
>> PN = Part Number
>> SN = Serial Number
>> MN = Manufacturer ID
>> Vx = Vendor-specific (x=0..9 A..Z)
>>
>> Biosdevname/Systemd will use these VPD keys for determining Network
>> partitioning and port numbers for NIC cards
>
>Can you please repost this as a patch instead of as a reply to our
>thread about VPD size.  The fact is the subject is misleading as your
>patch isn't actually related to VPD sizing.
>

I had already posted this a few weeks back but never got any feedback.

[PATCH] Create sysfs entries for VPD-R keys
https://marc.info/?l=linux-pci&m=144959803316031&w=2

>> Signed-off-by: Jordan Hargrave <Jordan_Hargrave@dell.com>
>> ---
>>  drivers/pci/pci-sysfs.c |  216 +++++++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/pci.h     |    2 +
>>  2 files changed, 218 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
>> index eead54c..4966ece 100644
>> --- a/drivers/pci/pci-sysfs.c
>> +++ b/drivers/pci/pci-sysfs.c
>> @@ -1295,6 +1295,210 @@ static struct bin_attribute pcie_config_attr = {
>>         .write = pci_write_config,
>>  };
>>
>> +static umode_t vpd_attr_exist(struct kobject *kobj,
>> +                             struct attribute *attr, int n)
>> +{
>> +       struct device *dev;
>> +       struct pci_dev *pdev;
>> +       const char *name;
>> +       int i;
>> +
>> +       dev = container_of(kobj, struct device, kobj);
>> +       pdev = to_pci_dev(dev);
>> +
>> +       name = attr->name;
>> +       if (pdev->vpdr_data == NULL)
>> +               return 0;
>> +       i = pci_vpd_find_info_keyword(pdev->vpdr_data, 0,
>> +                                     pdev->vpdr_len, name);
>> +       return (i >= 0 ? S_IRUGO : 0);
>> +}
>> +
>
>So I assume there is another patch that implements
>pci_vpd_find_info_keyword so that it can go through the vpdr_data and
>parse it?
>

That's already an existing function in drivers/pci/vpd.c

>> +static ssize_t vpd_attr_show(struct device *dev,
>> +                            struct device_attribute *attr, char *buf)
>> +{
>> +       struct pci_dev *pdev;
>> +       const char *name;
>> +       char kv_data[257] = { 0 };
>> +       int i, len;
>> +
>> +       pdev = to_pci_dev(dev);
>> +       name = attr->attr.name;
>> +       if (pdev->vpdr_data == NULL)
>> +               return 0;
>> +       i = pci_vpd_find_info_keyword(pdev->vpdr_data, 0,
>> +                                     pdev->vpdr_len, name);
>> +       if (i >= 0) {
>> +               len = pci_vpd_info_field_size(&pdev->vpdr_data[i]);
>> +               memcpy(kv_data, pdev->vpdr_data + i +
>> +                      PCI_VPD_INFO_FLD_HDR_SIZE, len);
>> +               return scnprintf(buf, PAGE_SIZE, "%s\n", kv_data);
>> +       }
>> +       return 0;
>> +}
>> +
>> +#define VPD_ATTR_RO(x) \
>> +struct device_attribute vpd ## x = { \
>> +       .attr = { .name = #x, .mode = S_IRUGO | S_IWUSR }, \
>> +       .show = vpd_attr_show \
>> +}
>> +
>> +VPD_ATTR_RO(PN);
>> +VPD_ATTR_RO(EC);
>> +VPD_ATTR_RO(MN);
>> +VPD_ATTR_RO(SN);
>> +VPD_ATTR_RO(V0);
>> +VPD_ATTR_RO(V1);
>> +VPD_ATTR_RO(V2);
>> +VPD_ATTR_RO(V3);
>> +VPD_ATTR_RO(V4);
>> +VPD_ATTR_RO(V5);
>> +VPD_ATTR_RO(V6);
>> +VPD_ATTR_RO(V7);
>> +VPD_ATTR_RO(V8);
>> +VPD_ATTR_RO(V9);
>> +VPD_ATTR_RO(VA);
>> +VPD_ATTR_RO(VB);
>> +VPD_ATTR_RO(VC);
>> +VPD_ATTR_RO(VD);
>> +VPD_ATTR_RO(VE);
>> +VPD_ATTR_RO(VF);
>> +VPD_ATTR_RO(VG);
>> +VPD_ATTR_RO(VH);
>> +VPD_ATTR_RO(VI);
>> +VPD_ATTR_RO(VJ);
>> +VPD_ATTR_RO(VK);
>> +VPD_ATTR_RO(VL);
>> +VPD_ATTR_RO(VM);
>> +VPD_ATTR_RO(VN);
>> +VPD_ATTR_RO(VO);
>> +VPD_ATTR_RO(VP);
>> +VPD_ATTR_RO(VQ);
>> +VPD_ATTR_RO(VR);
>> +VPD_ATTR_RO(VS);
>> +VPD_ATTR_RO(VT);
>> +VPD_ATTR_RO(VU);
>> +VPD_ATTR_RO(VV);
>> +VPD_ATTR_RO(VW);
>> +VPD_ATTR_RO(VX);
>> +VPD_ATTR_RO(VY);
>> +VPD_ATTR_RO(VZ);
>> +
>> +static struct attribute *vpd_attributes[] = {
>> +       &vpdPN.attr,
>> +       &vpdEC.attr,
>> +       &vpdMN.attr,
>> +       &vpdSN.attr,
>> +       &vpdV0.attr,
>> +       &vpdV1.attr,
>> +       &vpdV2.attr,
>> +       &vpdV3.attr,
>> +       &vpdV4.attr,
>> +       &vpdV5.attr,
>> +       &vpdV6.attr,
>> +       &vpdV7.attr,
>> +       &vpdV8.attr,
>> +       &vpdV9.attr,
>> +       &vpdVA.attr,
>> +       &vpdVB.attr,
>> +       &vpdVC.attr,
>> +       &vpdVD.attr,
>> +       &vpdVE.attr,
>> +       &vpdVF.attr,
>> +       &vpdVG.attr,
>> +       &vpdVH.attr,
>> +       &vpdVI.attr,
>> +       &vpdVJ.attr,
>> +       &vpdVK.attr,
>> +       &vpdVL.attr,
>> +       &vpdVM.attr,
>> +       &vpdVN.attr,
>> +       &vpdVO.attr,
>> +       &vpdVP.attr,
>> +       &vpdVQ.attr,
>> +       &vpdVR.attr,
>> +       &vpdVS.attr,
>> +       &vpdVT.attr,
>> +       &vpdVU.attr,
>> +       &vpdVV.attr,
>> +       &vpdVW.attr,
>> +       &vpdVX.attr,
>> +       &vpdVY.attr,
>> +       &vpdVZ.attr,
>> +       NULL,
>> +};
>> +
>> +static struct attribute_group vpd_attr_group = {
>> +       .name = "vpdr",
>> +       .attrs = vpd_attributes,
>> +       .is_visible = vpd_attr_exist,
>> +};
>> +
>> +
>> +static int pci_get_vpd_tag(struct pci_dev *dev, int off, int *len)
>> +{
>> +       u8  tag[3];
>> +       int rc, tlen;
>> +
>> +       *len = 0;
>> +       /* Quirk Atheros cards, reading VPD hangs system for 20s */
>> +       if (dev->vendor == PCI_VENDOR_ID_ATHEROS ||
>> +           dev->vendor == PCI_VENDOR_ID_ATTANSIC)
>> +               return -ENOENT;
>
>I'm not really sure this is the right place for this type of quirk.
>If this is really an issue maybe we should just disable VPD for these
>devices.  Otherwise there isn't anything to stop someone from going in
>and reading the VPD region via the existing VPD interfaces.
>

This could be moved elsewhere. There's a similar quirk for megaraid cards that was posted recently.
[PATCH v4] pci: Limit VPD length for megaraid_sas adapter

>> +       rc = pci_read_vpd(dev, off, 1, tag);
>> +       if (rc != 1)
>> +               return -ENOENT;
>> +       if (tag[0] == 0x00 || tag[0] == 0xFF || tag[0] == 0x7F)
>> +               return -ENOENT;
>> +       if (tag[0] & PCI_VPD_LRDT) {
>> +               rc = pci_read_vpd(dev, off+1, 2, tag+1);
>> +               if (rc != 2)
>> +                       return -ENOENT;
>> +               tlen = pci_vpd_lrdt_size(tag) +
>> +                       PCI_VPD_LRDT_TAG_SIZE;
>> +       } else {
>> +               tlen = pci_vpd_srdt_size(tag) +
>> +                       PCI_VPD_SRDT_TAG_SIZE;
>> +               tag[0] &= ~PCI_VPD_SRDT_LEN_MASK;
>> +       }
>> +       /* Verify VPD tag fits in area */
>> +       if (tlen + off > dev->vpd->len)
>> +               return -ENOENT;
>> +       *len = tlen;
>> +       return tag[0];
>> +}
>> +
>> +static int pci_load_vpdr(struct pci_dev *dev)
>> +{
>> +       int rlen, ilen, tag, rc;
>> +
>> +       /* Check for VPD-I and VPD-R tag */
>> +       tag = pci_get_vpd_tag(dev, 0, &ilen);
>> +       if (tag != PCI_VPD_LRDT_ID_STRING)
>> +               return -ENOENT;
>> +       tag = pci_get_vpd_tag(dev, ilen, &rlen);
>> +       if (tag != PCI_VPD_LRDT_RO_DATA)
>> +               return -ENOENT;
>> +
>> +       rlen -= PCI_VPD_LRDT_TAG_SIZE;
>> +       dev->vpdr_len = rlen;
>> +       dev->vpdr_data = kzalloc(rlen, GFP_ATOMIC);
>> +       if (dev->vpdr_data == NULL)
>> +               return -ENOMEM;
>> +
>
>Why not cache the ID string as well?  Seems like it might be a field
>people would want to read on a regular basis in order to find out what
>is there.
>
I could add that. What should attribute be called, 'vpdinfo', 'vpdi', etc?

>> +       rc = pci_read_vpd(dev, ilen + PCI_VPD_LRDT_TAG_SIZE,
>> +                         rlen, dev->vpdr_data);
>> +       if (rc != rlen)
>> +               goto error;
>> +       if (sysfs_create_group(&dev->dev.kobj, &vpd_attr_group))
>> +               goto error;
>> +       return 0;
>> + error:
>> +       kfree(dev->vpdr_data);
>> +       dev->vpdr_len = 0;
>> +       return -ENOENT;
>> +}
>> +
>
>This bit here needs to reset vpdr_data back to NULL.  Otherwise you
>could cause memory corruption via a double free in your two clean-up
>routines called out below.

Ok will fix that.

  reply	other threads:[~2015-12-29 19:15 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-18  8:35 [PATCHv4 0/2] PCI: Safe VPD access Hannes Reinecke
2015-12-18  8:35 ` [PATCH 1/2] pci: Update VPD definitions Hannes Reinecke
2015-12-18  8:35 ` [PATCH 2/2] pci: Update VPD size with correct length Hannes Reinecke
2015-12-18 13:49   ` Alexander Duyck
2015-12-18 13:57     ` Hannes Reinecke
2015-12-18 14:02       ` Alexander Duyck
2015-12-18 14:14         ` Hannes Reinecke
2015-12-29  5:29           ` Jordan_Hargrave
2015-12-29 17:48             ` Alexander Duyck
2015-12-29 19:01               ` Jordan_Hargrave [this message]
2015-12-29 20:26                 ` Alexander Duyck
  -- strict thread matches above, loose matches on Subject: below --
2015-12-17  7:59 [PATCHv3 0/2] PCI: Safe VPD access Hannes Reinecke
2015-12-17  7:59 ` [PATCH 2/2] pci: Update VPD size with correct length Hannes Reinecke
2015-12-17 11:06   ` Seymour, Shane M
2015-12-17 11:10   ` kbuild test robot
2015-12-17 17:13   ` Alexander Duyck
2015-12-18  7:44     ` Hannes Reinecke

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8B8F62BE6EB1824D91A8BF961FDC40B9179AE6E3DF@AUSX7MCPS305.AMER.DELL.COM \
    --to=jordan_hargrave@dell.com \
    --cc=alexander.duyck@gmail.com \
    --cc=bhelgaas@google.com \
    --cc=hare@suse.de \
    --cc=helgaas@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=mkubecek@suse.com \
    --cc=shane.seymour@hpe.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.