Message ID | 1452015002-28493-5-git-send-email-clg@fr.ibm.com |
---|---|
State | New |
Headers | show |
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,
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, >
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,
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(+)