qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 4/8] ipmi: add FRU support
@ 2016-01-05 17:29 Cédric Le Goater
  2016-01-08 19:41 ` Corey Minyard
  0 siblings, 1 reply; 3+ messages in thread
From: Cédric Le Goater @ 2016-01-05 17:29 UTC (permalink / raw)
  To: Corey Minyard; +Cc: Cédric Le Goater, qemu-devel, Michael S. Tsirkin

This patch provides a simplistic FRU support for the IPMI BMC
simulator.  The FRU area contains 32 entries * 256 bytes which should
be enough to start some simulation.

Signed-off-by: Cédric Le Goater <clg@fr.ibm.com>
---
 hw/ipmi/ipmi_bmc_sim.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c
index 5db94491b130..60586a67104e 100644
--- a/hw/ipmi/ipmi_bmc_sim.c
+++ b/hw/ipmi/ipmi_bmc_sim.c
@@ -81,6 +81,9 @@
 #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE   0x2A
 #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE    0x2B
 #define IPMI_CMD_RUN_INIT_AGENT           0x2C
+#define IPMI_CMD_GET_FRU_AREA_INFO        0x10
+#define IPMI_CMD_READ_FRU_DATA            0x11
+#define IPMI_CMD_WRITE_FRU_DATA           0x12
 #define IPMI_CMD_GET_SEL_INFO             0x40
 #define IPMI_CMD_GET_SEL_ALLOC_INFO       0x41
 #define IPMI_CMD_RESERVE_SEL              0x42
@@ -123,6 +126,14 @@ typedef struct IPMISdr {
     uint8_t overflow;
 } IPMISdr;
 
+/* theoretically, the offset being 16bits, it should be 65536 */
+#define MAX_FRU_SIZE 256
+#define MAX_FRU_ID 32
+
+typedef struct IPMIFru {
+    uint8_t data[MAX_FRU_SIZE][MAX_FRU_ID];
+} IPMIFru;
+
 typedef struct IPMISensor {
     uint8_t status;
     uint8_t reading;
@@ -206,6 +217,7 @@ struct IPMIBmcSim {
 
     IPMISel sel;
     IPMISdr sdr;
+    IPMIFru fru;
     IPMISensor sensors[MAX_SENSORS];
 
     /* Odd netfns are for responses, so we only need the even ones. */
@@ -1305,6 +1317,110 @@ static void get_sel_info(IPMIBmcSim *ibs,
     return;
 }
 
+static void get_fru_area_info(IPMIBmcSim *ibs,
+                         uint8_t *cmd, unsigned int cmd_len,
+                         uint8_t *rsp, unsigned int *rsp_len,
+                         unsigned int max_rsp_len)
+{
+    uint8_t fruid;
+    uint16_t fru_entry_size;
+
+    IPMI_CHECK_CMD_LEN(3);
+
+    fruid = cmd[2];
+
+    if (fruid > MAX_FRU_ID) {
+        rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
+        goto out;
+    }
+
+    fru_entry_size = MAX_FRU_SIZE;
+
+    IPMI_ADD_RSP_DATA(fru_entry_size & 0xff);
+    IPMI_ADD_RSP_DATA(fru_entry_size >> 8 & 0xff);
+    IPMI_ADD_RSP_DATA(0x0);
+out:
+    return;
+}
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#define max(x, y) ((x) > (y) ? (x) : (y))
+
+static void read_fru_data(IPMIBmcSim *ibs,
+                         uint8_t *cmd, unsigned int cmd_len,
+                         uint8_t *rsp, unsigned int *rsp_len,
+                         unsigned int max_rsp_len)
+{
+    uint8_t fruid;
+    uint16_t offset;
+    int i;
+    uint8_t *fru_entry;
+    unsigned int count;
+
+    IPMI_CHECK_CMD_LEN(5);
+
+    fruid = cmd[2];
+    offset = (cmd[3] | cmd[4] << 8);
+
+    if (fruid > MAX_FRU_ID) {
+        rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
+        goto out;
+    }
+
+    if (offset >= MAX_FRU_SIZE - 1) {
+        rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
+        goto out;
+    }
+
+    fru_entry = ibs->fru.data[fruid];
+
+    count = min(cmd[5], MAX_FRU_SIZE - offset);
+
+    IPMI_ADD_RSP_DATA(count & 0xff);
+    for (i = 0; i < count; i++) {
+        IPMI_ADD_RSP_DATA(fru_entry[offset + i]);
+    }
+
+ out:
+    return;
+}
+
+static void write_fru_data(IPMIBmcSim *ibs,
+                         uint8_t *cmd, unsigned int cmd_len,
+                         uint8_t *rsp, unsigned int *rsp_len,
+                         unsigned int max_rsp_len)
+{
+    uint8_t fruid;
+    uint16_t offset;
+    uint8_t *fru_entry;
+    unsigned int count;
+
+    IPMI_CHECK_CMD_LEN(5);
+
+    fruid = cmd[2];
+    offset = (cmd[3] | cmd[4] << 8);
+
+    if (fruid > MAX_FRU_ID) {
+        rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
+        goto out;
+    }
+
+    if (offset >= MAX_FRU_SIZE - 1) {
+        rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
+        goto out;
+    }
+
+    fru_entry = ibs->fru.data[fruid];
+
+    count = min(cmd_len - 5, MAX_FRU_SIZE - offset);
+
+    memcpy(fru_entry + offset, cmd + 5, count);
+
+    IPMI_ADD_RSP_DATA(count & 0xff);
+ out:
+    return;
+}
+
 static void reserve_sel(IPMIBmcSim *ibs,
                         uint8_t *cmd, unsigned int cmd_len,
                         uint8_t *rsp, unsigned int *rsp_len,
@@ -1682,6 +1798,9 @@ static const IPMINetfn app_netfn = {
 };
 
 static const IPMICmdHandler storage_cmds[IPMI_NETFN_STORAGE_MAXCMD] = {
+    [IPMI_CMD_GET_FRU_AREA_INFO] = get_fru_area_info,
+    [IPMI_CMD_READ_FRU_DATA] = read_fru_data,
+    [IPMI_CMD_WRITE_FRU_DATA] = write_fru_data,
     [IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info,
     [IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep,
     [IPMI_CMD_GET_SDR] = get_sdr,
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [Qemu-devel] [PATCH 4/8] ipmi: add FRU support
  2016-01-05 17:29 [Qemu-devel] [PATCH 4/8] ipmi: add FRU support Cédric Le Goater
@ 2016-01-08 19:41 ` Corey Minyard
  2016-01-12  7:35   ` Cédric Le Goater
  0 siblings, 1 reply; 3+ messages in thread
From: Corey Minyard @ 2016-01-08 19:41 UTC (permalink / raw)
  To: Cédric Le Goater; +Cc: qemu-devel, Michael S. Tsirkin

On 01/05/2016 11:29 AM, Cédric Le Goater wrote:
> This patch provides a simplistic FRU support for the IPMI BMC
> simulator.  The FRU area contains 32 entries * 256 bytes which should
> be enough to start some simulation.
>
> Signed-off-by: Cédric Le Goater <clg@fr.ibm.com>
> ---
>   hw/ipmi/ipmi_bmc_sim.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 119 insertions(+)
>
> diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c
> index 5db94491b130..60586a67104e 100644
> --- a/hw/ipmi/ipmi_bmc_sim.c
> +++ b/hw/ipmi/ipmi_bmc_sim.c
> @@ -81,6 +81,9 @@
>   #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE   0x2A
>   #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE    0x2B
>   #define IPMI_CMD_RUN_INIT_AGENT           0x2C
> +#define IPMI_CMD_GET_FRU_AREA_INFO        0x10
> +#define IPMI_CMD_READ_FRU_DATA            0x11
> +#define IPMI_CMD_WRITE_FRU_DATA           0x12
>   #define IPMI_CMD_GET_SEL_INFO             0x40
>   #define IPMI_CMD_GET_SEL_ALLOC_INFO       0x41
>   #define IPMI_CMD_RESERVE_SEL              0x42
> @@ -123,6 +126,14 @@ typedef struct IPMISdr {
>       uint8_t overflow;
>   } IPMISdr;
>   
> +/* theoretically, the offset being 16bits, it should be 65536 */
> +#define MAX_FRU_SIZE 256
> +#define MAX_FRU_ID 32
> +
> +typedef struct IPMIFru {
> +    uint8_t data[MAX_FRU_SIZE][MAX_FRU_ID];
> +} IPMIFru;

Instead of a static table like this, I think it would be better to make 
this configurable somehow.  I say this because I've never seen a system 
with 32 FRU devices on a BMC, but I've seen plenty with FRU data larger 
than 256 bytes.  By default, 1 FRU device with 2048 bytes is pretty 
reasonable, I think.

I'm not exactly sure the best way to make it configurable.  I assume 
that you need your platform code to be able to provide that information, 
and it could be passed in as BMC configuration parameters.  The ability 
to load the FRU data at startup is probably also necessary.

-corey

> +
>   typedef struct IPMISensor {
>       uint8_t status;
>       uint8_t reading;
> @@ -206,6 +217,7 @@ struct IPMIBmcSim {
>   
>       IPMISel sel;
>       IPMISdr sdr;
> +    IPMIFru fru;
>       IPMISensor sensors[MAX_SENSORS];
>   
>       /* Odd netfns are for responses, so we only need the even ones. */
> @@ -1305,6 +1317,110 @@ static void get_sel_info(IPMIBmcSim *ibs,
>       return;
>   }
>   
> +static void get_fru_area_info(IPMIBmcSim *ibs,
> +                         uint8_t *cmd, unsigned int cmd_len,
> +                         uint8_t *rsp, unsigned int *rsp_len,
> +                         unsigned int max_rsp_len)
> +{
> +    uint8_t fruid;
> +    uint16_t fru_entry_size;
> +
> +    IPMI_CHECK_CMD_LEN(3);
> +
> +    fruid = cmd[2];
> +
> +    if (fruid > MAX_FRU_ID) {
> +        rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
> +        goto out;
> +    }
> +
> +    fru_entry_size = MAX_FRU_SIZE;
> +
> +    IPMI_ADD_RSP_DATA(fru_entry_size & 0xff);
> +    IPMI_ADD_RSP_DATA(fru_entry_size >> 8 & 0xff);
> +    IPMI_ADD_RSP_DATA(0x0);
> +out:
> +    return;
> +}
> +
> +#define min(x, y) ((x) < (y) ? (x) : (y))
> +#define max(x, y) ((x) > (y) ? (x) : (y))
> +
> +static void read_fru_data(IPMIBmcSim *ibs,
> +                         uint8_t *cmd, unsigned int cmd_len,
> +                         uint8_t *rsp, unsigned int *rsp_len,
> +                         unsigned int max_rsp_len)
> +{
> +    uint8_t fruid;
> +    uint16_t offset;
> +    int i;
> +    uint8_t *fru_entry;
> +    unsigned int count;
> +
> +    IPMI_CHECK_CMD_LEN(5);
> +
> +    fruid = cmd[2];
> +    offset = (cmd[3] | cmd[4] << 8);
> +
> +    if (fruid > MAX_FRU_ID) {
> +        rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
> +        goto out;
> +    }
> +
> +    if (offset >= MAX_FRU_SIZE - 1) {
> +        rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
> +        goto out;
> +    }
> +
> +    fru_entry = ibs->fru.data[fruid];
> +
> +    count = min(cmd[5], MAX_FRU_SIZE - offset);
> +
> +    IPMI_ADD_RSP_DATA(count & 0xff);
> +    for (i = 0; i < count; i++) {
> +        IPMI_ADD_RSP_DATA(fru_entry[offset + i]);
> +    }
> +
> + out:
> +    return;
> +}
> +
> +static void write_fru_data(IPMIBmcSim *ibs,
> +                         uint8_t *cmd, unsigned int cmd_len,
> +                         uint8_t *rsp, unsigned int *rsp_len,
> +                         unsigned int max_rsp_len)
> +{
> +    uint8_t fruid;
> +    uint16_t offset;
> +    uint8_t *fru_entry;
> +    unsigned int count;
> +
> +    IPMI_CHECK_CMD_LEN(5);
> +
> +    fruid = cmd[2];
> +    offset = (cmd[3] | cmd[4] << 8);
> +
> +    if (fruid > MAX_FRU_ID) {
> +        rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
> +        goto out;
> +    }
> +
> +    if (offset >= MAX_FRU_SIZE - 1) {
> +        rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
> +        goto out;
> +    }
> +
> +    fru_entry = ibs->fru.data[fruid];
> +
> +    count = min(cmd_len - 5, MAX_FRU_SIZE - offset);
> +
> +    memcpy(fru_entry + offset, cmd + 5, count);
> +
> +    IPMI_ADD_RSP_DATA(count & 0xff);
> + out:
> +    return;
> +}
> +
>   static void reserve_sel(IPMIBmcSim *ibs,
>                           uint8_t *cmd, unsigned int cmd_len,
>                           uint8_t *rsp, unsigned int *rsp_len,
> @@ -1682,6 +1798,9 @@ static const IPMINetfn app_netfn = {
>   };
>   
>   static const IPMICmdHandler storage_cmds[IPMI_NETFN_STORAGE_MAXCMD] = {
> +    [IPMI_CMD_GET_FRU_AREA_INFO] = get_fru_area_info,
> +    [IPMI_CMD_READ_FRU_DATA] = read_fru_data,
> +    [IPMI_CMD_WRITE_FRU_DATA] = write_fru_data,
>       [IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info,
>       [IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep,
>       [IPMI_CMD_GET_SDR] = get_sdr,

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Qemu-devel] [PATCH 4/8] ipmi: add FRU support
  2016-01-08 19:41 ` Corey Minyard
@ 2016-01-12  7:35   ` Cédric Le Goater
  0 siblings, 0 replies; 3+ messages in thread
From: Cédric Le Goater @ 2016-01-12  7:35 UTC (permalink / raw)
  To: Corey Minyard; +Cc: qemu-devel, Michael S. Tsirkin

Hello,

On 01/08/2016 08:41 PM, Corey Minyard wrote:
> On 01/05/2016 11:29 AM, Cédric Le Goater wrote:
>> This patch provides a simplistic FRU support for the IPMI BMC
>> simulator.  The FRU area contains 32 entries * 256 bytes which should
>> be enough to start some simulation.
>>
>> Signed-off-by: Cédric Le Goater <clg@fr.ibm.com>
>> ---
>>   hw/ipmi/ipmi_bmc_sim.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 119 insertions(+)
>>
>> diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c
>> index 5db94491b130..60586a67104e 100644
>> --- a/hw/ipmi/ipmi_bmc_sim.c
>> +++ b/hw/ipmi/ipmi_bmc_sim.c
>> @@ -81,6 +81,9 @@
>>   #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE   0x2A
>>   #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE    0x2B
>>   #define IPMI_CMD_RUN_INIT_AGENT           0x2C
>> +#define IPMI_CMD_GET_FRU_AREA_INFO        0x10
>> +#define IPMI_CMD_READ_FRU_DATA            0x11
>> +#define IPMI_CMD_WRITE_FRU_DATA           0x12
>>   #define IPMI_CMD_GET_SEL_INFO             0x40
>>   #define IPMI_CMD_GET_SEL_ALLOC_INFO       0x41
>>   #define IPMI_CMD_RESERVE_SEL              0x42
>> @@ -123,6 +126,14 @@ typedef struct IPMISdr {
>>       uint8_t overflow;
>>   } IPMISdr;
>>   +/* theoretically, the offset being 16bits, it should be 65536 */
>> +#define MAX_FRU_SIZE 256
>> +#define MAX_FRU_ID 32
>> +
>> +typedef struct IPMIFru {
>> +    uint8_t data[MAX_FRU_SIZE][MAX_FRU_ID];
>> +} IPMIFru;
> 
> Instead of a static table like this, I think it would be better to make this 
> configurable somehow.  I say this because I've never seen a system with 32 FRU 
> devices on a BMC, but I've seen plenty with FRU data larger than 256 bytes.  
> By default, 1 FRU device with 2048 bytes is pretty reasonable, I think.
> 
> I'm not exactly sure the best way to make it configurable. 

I guess we can use an object property to configure the numbers of FRU devices 
and start with a minimum of 1.

> I assume that you 
> need your platform code to be able to provide that information, and it could 
> be passed in as BMC configuration parameters.  The ability to load the FRU 
> data at startup is probably also necessary.

I will see what API we can provide after doing the above.

Thanks,

C. 

> -corey
> 
>> +
>>   typedef struct IPMISensor {
>>       uint8_t status;
>>       uint8_t reading;
>> @@ -206,6 +217,7 @@ struct IPMIBmcSim {
>>         IPMISel sel;
>>       IPMISdr sdr;
>> +    IPMIFru fru;
>>       IPMISensor sensors[MAX_SENSORS];
>>         /* Odd netfns are for responses, so we only need the even ones. */
>> @@ -1305,6 +1317,110 @@ static void get_sel_info(IPMIBmcSim *ibs,
>>       return;
>>   }
>>   +static void get_fru_area_info(IPMIBmcSim *ibs,
>> +                         uint8_t *cmd, unsigned int cmd_len,
>> +                         uint8_t *rsp, unsigned int *rsp_len,
>> +                         unsigned int max_rsp_len)
>> +{
>> +    uint8_t fruid;
>> +    uint16_t fru_entry_size;
>> +
>> +    IPMI_CHECK_CMD_LEN(3);
>> +
>> +    fruid = cmd[2];
>> +
>> +    if (fruid > MAX_FRU_ID) {
>> +        rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
>> +        goto out;
>> +    }
>> +
>> +    fru_entry_size = MAX_FRU_SIZE;
>> +
>> +    IPMI_ADD_RSP_DATA(fru_entry_size & 0xff);
>> +    IPMI_ADD_RSP_DATA(fru_entry_size >> 8 & 0xff);
>> +    IPMI_ADD_RSP_DATA(0x0);
>> +out:
>> +    return;
>> +}
>> +
>> +#define min(x, y) ((x) < (y) ? (x) : (y))
>> +#define max(x, y) ((x) > (y) ? (x) : (y))
>> +
>> +static void read_fru_data(IPMIBmcSim *ibs,
>> +                         uint8_t *cmd, unsigned int cmd_len,
>> +                         uint8_t *rsp, unsigned int *rsp_len,
>> +                         unsigned int max_rsp_len)
>> +{
>> +    uint8_t fruid;
>> +    uint16_t offset;
>> +    int i;
>> +    uint8_t *fru_entry;
>> +    unsigned int count;
>> +
>> +    IPMI_CHECK_CMD_LEN(5);
>> +
>> +    fruid = cmd[2];
>> +    offset = (cmd[3] | cmd[4] << 8);
>> +
>> +    if (fruid > MAX_FRU_ID) {
>> +        rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
>> +        goto out;
>> +    }
>> +
>> +    if (offset >= MAX_FRU_SIZE - 1) {
>> +        rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
>> +        goto out;
>> +    }
>> +
>> +    fru_entry = ibs->fru.data[fruid];
>> +
>> +    count = min(cmd[5], MAX_FRU_SIZE - offset);
>> +
>> +    IPMI_ADD_RSP_DATA(count & 0xff);
>> +    for (i = 0; i < count; i++) {
>> +        IPMI_ADD_RSP_DATA(fru_entry[offset + i]);
>> +    }
>> +
>> + out:
>> +    return;
>> +}
>> +
>> +static void write_fru_data(IPMIBmcSim *ibs,
>> +                         uint8_t *cmd, unsigned int cmd_len,
>> +                         uint8_t *rsp, unsigned int *rsp_len,
>> +                         unsigned int max_rsp_len)
>> +{
>> +    uint8_t fruid;
>> +    uint16_t offset;
>> +    uint8_t *fru_entry;
>> +    unsigned int count;
>> +
>> +    IPMI_CHECK_CMD_LEN(5);
>> +
>> +    fruid = cmd[2];
>> +    offset = (cmd[3] | cmd[4] << 8);
>> +
>> +    if (fruid > MAX_FRU_ID) {
>> +        rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
>> +        goto out;
>> +    }
>> +
>> +    if (offset >= MAX_FRU_SIZE - 1) {
>> +        rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
>> +        goto out;
>> +    }
>> +
>> +    fru_entry = ibs->fru.data[fruid];
>> +
>> +    count = min(cmd_len - 5, MAX_FRU_SIZE - offset);
>> +
>> +    memcpy(fru_entry + offset, cmd + 5, count);
>> +
>> +    IPMI_ADD_RSP_DATA(count & 0xff);
>> + out:
>> +    return;
>> +}
>> +
>>   static void reserve_sel(IPMIBmcSim *ibs,
>>                           uint8_t *cmd, unsigned int cmd_len,
>>                           uint8_t *rsp, unsigned int *rsp_len,
>> @@ -1682,6 +1798,9 @@ static const IPMINetfn app_netfn = {
>>   };
>>     static const IPMICmdHandler storage_cmds[IPMI_NETFN_STORAGE_MAXCMD] = {
>> +    [IPMI_CMD_GET_FRU_AREA_INFO] = get_fru_area_info,
>> +    [IPMI_CMD_READ_FRU_DATA] = read_fru_data,
>> +    [IPMI_CMD_WRITE_FRU_DATA] = write_fru_data,
>>       [IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info,
>>       [IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep,
>>       [IPMI_CMD_GET_SDR] = get_sdr,
> 

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2016-01-12  7:36 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-01-05 17:29 [Qemu-devel] [PATCH 4/8] ipmi: add FRU support Cédric Le Goater
2016-01-08 19:41 ` Corey Minyard
2016-01-12  7:35   ` Cédric Le Goater

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).