mirror of
https://github.com/ipmitool/ipmitool.git
synced 2026-01-23 15:12:19 +08:00
- added fru parsing address table
- added fru parsing shelf power dist - added fru parsing shelf activation - added fru parsing amc current requirement - added fru parsing amc p2p - added fru parsing amc carrier info - added fru parsing clk p2p - added fru parsing clk config - enhancement in baord p2p
This commit is contained in:
parent
94865441a1
commit
f4a6a73184
@ -239,7 +239,7 @@ write_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
|
|||||||
req.msg.data_len = tmp + 3;
|
req.msg.data_len = tmp + 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeLength = req.msg.data_len - 3;
|
writeLength = req.msg.data_len-3;
|
||||||
|
|
||||||
rsp = intf->sendrecv(intf, &req);
|
rsp = intf->sendrecv(intf, &req);
|
||||||
if (!rsp) {
|
if (!rsp) {
|
||||||
@ -254,7 +254,6 @@ write_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
off += writeLength;
|
off += writeLength;
|
||||||
|
|
||||||
} while ((doffset+off) < finish);
|
} while ((doffset+off) < finish);
|
||||||
|
|
||||||
return ((doffset+off) >= finish);
|
return ((doffset+off) >= finish);
|
||||||
@ -308,7 +307,6 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
|
|||||||
if (fru->access && fru_data_rqst_size > 16)
|
if (fru->access && fru_data_rqst_size > 16)
|
||||||
#endif
|
#endif
|
||||||
fru_data_rqst_size = 16;
|
fru_data_rqst_size = 16;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
tmp = fru->access ? off >> 1 : off;
|
tmp = fru->access ? off >> 1 : off;
|
||||||
msg_data[0] = id;
|
msg_data[0] = id;
|
||||||
@ -1032,15 +1030,80 @@ static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FRU_PICMG_ADDRESS_TABLE:
|
case FRU_PICMG_ADDRESS_TABLE:
|
||||||
|
{
|
||||||
|
unsigned char entries = 0;
|
||||||
|
unsigned char i;
|
||||||
|
|
||||||
printf(" FRU_PICMG_ADDRESS_TABLE\n");
|
printf(" FRU_PICMG_ADDRESS_TABLE\n");
|
||||||
|
|
||||||
|
printf(" Type/Len: 0x%02x\n", fru_data[offset++]);
|
||||||
|
printf(" Shelf Addr: ");
|
||||||
|
for (i=0;i<20;i++) {
|
||||||
|
printf("0x%02x ", fru_data[offset++]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
entries = fru_data[offset++];
|
||||||
|
printf(" Addr Table Entries: 0x%02x\n", entries);
|
||||||
|
|
||||||
|
for (i=0; i<entries; i++) {
|
||||||
|
printf(" HWAddr: 0x%02x - SiteNum: 0x%02x - SiteType: 0x%02x \n",
|
||||||
|
fru_data[offset++], fru_data[offset++], fru_data[offset++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FRU_PICMG_SHELF_POWER_DIST:
|
case FRU_PICMG_SHELF_POWER_DIST:
|
||||||
|
{
|
||||||
|
unsigned char i,j;
|
||||||
|
unsigned char feeds = 0;
|
||||||
|
|
||||||
printf(" FRU_PICMG_SHELF_POWER_DIST\n");
|
printf(" FRU_PICMG_SHELF_POWER_DIST\n");
|
||||||
|
|
||||||
|
feeds = fru_data[offset++];
|
||||||
|
printf(" Number of Power Feeds: 0x%02x\n", feeds);
|
||||||
|
|
||||||
|
for (i=0; i<feeds; i++) {
|
||||||
|
unsigned char entries;
|
||||||
|
|
||||||
|
printf(" Max Ext Current: 0x%04x\n", fru_data[offset+0] | (fru_data[offset+1]<<8));
|
||||||
|
offset += 2;
|
||||||
|
printf(" Max Int Current: 0x%04x\n", fru_data[offset+0] | (fru_data[offset+1]<<8));
|
||||||
|
offset += 2;
|
||||||
|
printf(" Min Exp Voltage: 0x%02x\n", fru_data[offset++]);
|
||||||
|
|
||||||
|
entries = fru_data[offset++];
|
||||||
|
printf(" Feed to FRU count: 0x%02x\n", entries);
|
||||||
|
|
||||||
|
for (j=0; j<entries; j++) {
|
||||||
|
printf(" HW: 0x%02x", fru_data[offset++]);
|
||||||
|
printf(" FRU ID: 0x%02x\n", fru_data[offset++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FRU_PICMG_SHELF_ACTIVATION:
|
case FRU_PICMG_SHELF_ACTIVATION:
|
||||||
|
{
|
||||||
|
unsigned char i;
|
||||||
|
unsigned char count = 0;
|
||||||
|
|
||||||
printf(" FRU_PICMG_SHELF_ACTIVATION\n");
|
printf(" FRU_PICMG_SHELF_ACTIVATION\n");
|
||||||
|
|
||||||
|
printf(" Allowance for FRU Act Readiness: 0x%02x\n", fru_data[offset++]);
|
||||||
|
|
||||||
|
count = fru_data[offset++];
|
||||||
|
printf(" FRU activation and Power Desc Cnt: 0x%02x\n", count);
|
||||||
|
|
||||||
|
for (i=0; i<count; i++) {
|
||||||
|
printf(" HW Addr: 0x%02x ", fru_data[offset++]);
|
||||||
|
printf(" FRU ID: 0x%02x ", fru_data[offset++]);
|
||||||
|
printf(" Max FRU Power: 0x%04x ", fru_data[offset+0] | (fru_data[offset+1]<<8));
|
||||||
|
offset += 2;
|
||||||
|
printf(" Config: 0x%02x \n", fru_data[offset++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FRU_PICMG_SHMC_IP_CONN:
|
case FRU_PICMG_SHMC_IP_CONN:
|
||||||
@ -1049,24 +1112,78 @@ static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length)
|
|||||||
|
|
||||||
case FRU_PICMG_BOARD_P2P:
|
case FRU_PICMG_BOARD_P2P:
|
||||||
printf(" FRU_PICMG_BOARD_P2P\n");
|
printf(" FRU_PICMG_BOARD_P2P\n");
|
||||||
guid_count = fru_data[offset];
|
|
||||||
printf(" GUID count: %2d\n", guid_count);
|
|
||||||
|
|
||||||
for (i = 0; i < guid_count; i++) {
|
guid_count = fru_data[offset++];
|
||||||
printf(" GUID %2d:\n", i);
|
printf(" GUID count: %2d\n", guid_count);
|
||||||
offset += sizeof(struct fru_picmgext_guid);
|
for (i = 0 ; i < guid_count; i++ ) {
|
||||||
|
int j;
|
||||||
|
printf(" GUID [%2d]: 0x", i);
|
||||||
|
|
||||||
|
for (j=0; j < sizeof(struct fru_picmgext_guid); j++) {
|
||||||
|
printf("%02x", fru_data[offset+j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (++offset;
|
printf("\n");
|
||||||
offset < (off + length);
|
offset += sizeof(struct fru_picmgext_guid);
|
||||||
offset += sizeof(struct fru_picmgext_link_desc)) {
|
}
|
||||||
struct fru_picmgext_link_desc * d =
|
printf("\n");
|
||||||
(struct fru_picmgext_link_desc *) &fru_data[offset];
|
|
||||||
|
for (offset; offset < off + length; offset += sizeof(struct fru_picmgext_link_desc)) {
|
||||||
|
|
||||||
|
/* to solve little endian /big endian problem */
|
||||||
|
unsigned long data = (fru_data[offset+0])
|
||||||
|
| (fru_data[offset+1] << 8)
|
||||||
|
| (fru_data[offset+2] << 16)
|
||||||
|
| (fru_data[offset+3] << 24);
|
||||||
|
|
||||||
|
struct fru_picmgext_link_desc * d = (struct fru_picmgext_link_desc *) &data;
|
||||||
|
|
||||||
printf(" Link Grouping ID: 0x%02x\n", d->grouping);
|
printf(" Link Grouping ID: 0x%02x\n", d->grouping);
|
||||||
printf(" Link Type Extension: 0x%02x\n", d->ext);
|
printf(" Link Type Extension: 0x%02x - ", d->ext);
|
||||||
printf(" Link Type: ");
|
if (d->type == FRU_PICMGEXT_LINK_TYPE_BASE){
|
||||||
if (d->type == 0 || d->type == 0xff) {
|
switch (d->ext)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
printf("10/100/1000BASE-T Link (four-pair)\n");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
printf("ShMC Cross-connect (two-pair)\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Unknwon\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET){
|
||||||
|
switch (d->ext)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
printf("Fixed 1000Base-BX\n");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
printf("Fixed 10GBASE-BX4 [XAUI]\n");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
printf("FC-PI\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Unknwon\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND){
|
||||||
|
printf("Unknwon\n");
|
||||||
|
}else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR){
|
||||||
|
printf("Unknwon\n");
|
||||||
|
}else if (d->type == FRU_PICMGEXT_LINK_TYPE_PCIE){
|
||||||
|
printf("Unknwon\n");
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
printf("Unknwon\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(" Link Type: 0x%02x - ",d->type);
|
||||||
|
if (d->type == 0 || d->type == 0xff)
|
||||||
|
{
|
||||||
printf("Reserved\n");
|
printf("Reserved\n");
|
||||||
}
|
}
|
||||||
else if (d->type >= 0x06 && d->type <= 0xef) {
|
else if (d->type >= 0x06 && d->type <= 0xef) {
|
||||||
@ -1091,15 +1208,17 @@ static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length)
|
|||||||
printf("PICMG 3.3 Star Fabric Interface\n");
|
printf("PICMG 3.3 Star Fabric Interface\n");
|
||||||
break;
|
break;
|
||||||
case FRU_PICMGEXT_LINK_TYPE_PCIE:
|
case FRU_PICMGEXT_LINK_TYPE_PCIE:
|
||||||
printf("PCI Express Fabric Interface\n");
|
printf("PICMG 3.4 PCI Express Fabric Interface\n");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf("Invalid\n");
|
printf("Invalid\n");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf(" Link Designator: 0x%03x\n", d->designator);
|
printf(" Link Designator: \n");
|
||||||
printf(" Port Flag: 0x%02x\n", d->designator >> 8);
|
printf(" Port Flag: 0x%02x\n", d->desig_port);
|
||||||
printf(" Interface: ");
|
printf(" Interface: 0x%02x - ", d->desig_if);
|
||||||
switch ((d->designator & 0xff) >> 6)
|
switch (d->desig_if)
|
||||||
{
|
{
|
||||||
case FRU_PICMGEXT_DESIGN_IF_BASE:
|
case FRU_PICMGEXT_DESIGN_IF_BASE:
|
||||||
printf("Base Interface\n");
|
printf("Base Interface\n");
|
||||||
@ -1112,16 +1231,29 @@ static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length)
|
|||||||
break;
|
break;
|
||||||
case FRU_PICMGEXT_DESIGN_IF_RESERVED:
|
case FRU_PICMGEXT_DESIGN_IF_RESERVED:
|
||||||
printf("Reserved\n");
|
printf("Reserved\n");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf("Invalid");
|
printf("Invalid");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
printf(" Channel Number: 0x%02x\n", d->designator & 0x1f);
|
printf(" Channel Number: 0x%02x\n", d->desig_channel);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FRU_AMC_CURRENT:
|
case FRU_AMC_CURRENT:
|
||||||
|
{
|
||||||
|
unsigned char recVersion;
|
||||||
|
unsigned char current;
|
||||||
printf(" FRU_AMC_CURRENT\n");
|
printf(" FRU_AMC_CURRENT\n");
|
||||||
|
|
||||||
|
//recVersion = fru_data[offset++];
|
||||||
|
current = fru_data[offset];
|
||||||
|
printf(" Current draw: %.1f A @ 12V => %.2f Watt\n",
|
||||||
|
(float) current/10.0, ((float)current/10.0)*12.0);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FRU_AMC_ACTIVATION:
|
case FRU_AMC_ACTIVATION:
|
||||||
@ -1131,20 +1263,21 @@ static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length)
|
|||||||
|
|
||||||
max_current = fru_data[offset];
|
max_current = fru_data[offset];
|
||||||
max_current |= fru_data[++offset]<<8;
|
max_current |= fru_data[++offset]<<8;
|
||||||
|
printf(" Maximum Internal Current(@12V): %.2f A [ %.2f Watt ]\n",
|
||||||
|
(float) max_current / 10,
|
||||||
|
(float) max_current / 10 * 12);
|
||||||
|
printf(" Module Activation Readiness: %i sec.\n", fru_data[++offset]);
|
||||||
|
|
||||||
printf(" Maximum Internal Current(@12V): %i A\n", max_current / 10);
|
|
||||||
printf(" Module Activation Rediness: %i sec.\n", fru_data[++offset]);
|
|
||||||
printf(" Descriptor Count: %i\n", fru_data[++offset]);
|
printf(" Descriptor Count: %i\n", fru_data[++offset]);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
for (++offset;
|
for(++offset; offset < off + length; offset += sizeof(struct fru_picmgext_activation_record))
|
||||||
offset < (off + length);
|
{
|
||||||
offset += sizeof(struct fru_picmgext_activation_record)) {
|
|
||||||
struct fru_picmgext_activation_record * a =
|
struct fru_picmgext_activation_record * a =
|
||||||
(struct fru_picmgext_activation_record *) &fru_data[offset];
|
(struct fru_picmgext_activation_record *) &fru_data[offset];
|
||||||
|
|
||||||
printf(" IPMB-Address: 0x%x\n", a->ibmb_addr);
|
printf(" IPMB-Address: 0x%x\n", a->ibmb_addr);
|
||||||
printf(" Max. Module Current: %i A\n", a->max_module_curr/10);
|
printf(" Max. Module Current: %.2f A\n", (float)a->max_module_curr/10);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1155,7 +1288,7 @@ static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length)
|
|||||||
{
|
{
|
||||||
uint16_t index;
|
uint16_t index;
|
||||||
|
|
||||||
while (offset < (off + length))
|
for(offset; offset < off + length; )
|
||||||
{
|
{
|
||||||
struct fru_picmgext_carrier_p2p_record * h =
|
struct fru_picmgext_carrier_p2p_record * h =
|
||||||
(struct fru_picmgext_carrier_p2p_record *) &fru_data[offset];
|
(struct fru_picmgext_carrier_p2p_record *) &fru_data[offset];
|
||||||
@ -1174,15 +1307,28 @@ static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length)
|
|||||||
|
|
||||||
for (index = 0; index < h->p2p_count; index++)
|
for (index = 0; index < h->p2p_count; index++)
|
||||||
{
|
{
|
||||||
struct fru_picmgext_carrier_p2p_descriptor * d =
|
/* to solve little endian /big endian problem */
|
||||||
(struct fru_picmgext_carrier_p2p_descriptor*)&fru_data[offset];
|
unsigned char data[3];
|
||||||
|
struct fru_picmgext_carrier_p2p_descriptor * desc;
|
||||||
|
|
||||||
|
#ifndef WORDS_BIGENDIAN
|
||||||
|
data[0] = fru_data[offset+0];
|
||||||
|
data[1] = fru_data[offset+1];
|
||||||
|
data[2] = fru_data[offset+2];
|
||||||
|
#else
|
||||||
|
data[0] = fru_data[offset+2];
|
||||||
|
data[1] = fru_data[offset+1];
|
||||||
|
data[2] = fru_data[offset+0];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
desc = (struct fru_picmgext_carrier_p2p_descriptor*)&data;
|
||||||
|
|
||||||
printf(" Port: %02d\t-> Remote Port: %02d\t",
|
printf(" Port: %02d\t-> Remote Port: %02d\t",
|
||||||
d->local_port, d->remote_port);
|
desc->local_port, desc->remote_port);
|
||||||
if((d->remote_resource_id >> 7) == 1)
|
if((desc->remote_resource_id >> 7) == 1)
|
||||||
printf("[ AMC ID: %02d ]\n", d->remote_resource_id & 0x07);
|
printf("[ AMC ID: %02d ]\n", desc->remote_resource_id & 0x0F);
|
||||||
else
|
else
|
||||||
printf("[ local ID: %02d ]\n", d->remote_resource_id & 0x07);
|
printf("[ local ID: %02d ]\n", desc->remote_resource_id & 0x0F);
|
||||||
|
|
||||||
offset += sizeof(struct fru_picmgext_carrier_p2p_descriptor);
|
offset += sizeof(struct fru_picmgext_carrier_p2p_descriptor);
|
||||||
}
|
}
|
||||||
@ -1192,10 +1338,330 @@ static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length)
|
|||||||
|
|
||||||
case FRU_AMC_P2P:
|
case FRU_AMC_P2P:
|
||||||
printf(" FRU_AMC_P2P\n");
|
printf(" FRU_AMC_P2P\n");
|
||||||
|
{
|
||||||
|
unsigned int index;
|
||||||
|
unsigned char channel_count;
|
||||||
|
struct fru_picmgext_amc_p2p_record * h;
|
||||||
|
|
||||||
|
guid_count = fru_data[offset];
|
||||||
|
printf(" GUID count: %2d\n", guid_count);
|
||||||
|
|
||||||
|
for (i = 0 ; i < guid_count; i++ )
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
printf(" GUID %2d: ", i);
|
||||||
|
|
||||||
|
for (j=0; j < sizeof(struct fru_picmgext_guid); j++) {
|
||||||
|
printf("%02x", fru_data[offset+j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += sizeof(struct fru_picmgext_guid);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
h = (struct fru_picmgext_amc_p2p_record *) &fru_data[++offset];
|
||||||
|
printf(" %s", (h->record_type?"AMC Module:":"On-Carrier Device"));
|
||||||
|
printf(" Recource ID: %i\n", h->resource_id);
|
||||||
|
|
||||||
|
offset += sizeof(struct fru_picmgext_amc_p2p_record);
|
||||||
|
|
||||||
|
channel_count = fru_data[offset++];
|
||||||
|
printf(" Descriptor Count: %i\n", channel_count);
|
||||||
|
|
||||||
|
for (index=0 ;index < channel_count; index++)
|
||||||
|
{
|
||||||
|
struct fru_picmgext_amc_channel_desc_record * d =
|
||||||
|
(struct fru_picmgext_amc_channel_desc_record *) &fru_data[offset];
|
||||||
|
|
||||||
|
printf(" Lane 0 Port: %i\n", d->lane0port);
|
||||||
|
printf(" Lane 1 Port: %i\n", d->lane1port);
|
||||||
|
printf(" Lane 2 Port: %i\n", d->lane2port);
|
||||||
|
printf(" Lane 3 Port: %i\n\n", d->lane3port);
|
||||||
|
|
||||||
|
|
||||||
|
offset += sizeof(struct fru_picmgext_amc_channel_desc_record);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( offset; offset < off + length;)
|
||||||
|
{
|
||||||
|
struct fru_picmgext_amc_link_desc_record * l =
|
||||||
|
(struct fru_picmgext_amc_link_desc_record *) &fru_data[offset];
|
||||||
|
|
||||||
|
printf(" Link Designator: Channel ID: %i\n"
|
||||||
|
" Port Flag 0: %s%s%s%s\n",
|
||||||
|
l->channel_id,
|
||||||
|
(l->port_flag_0)?"o":"-",
|
||||||
|
(l->port_flag_1)?"o":"-",
|
||||||
|
(l->port_flag_2)?"o":"-",
|
||||||
|
(l->port_flag_3)?"o":"-" );
|
||||||
|
|
||||||
|
switch (l->type)
|
||||||
|
{
|
||||||
|
/* AMC.1 */
|
||||||
|
case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE:
|
||||||
|
printf(" Link Type: %02x - "
|
||||||
|
"AMC.1 PCI Express\n", l->type);
|
||||||
|
switch (l->type_ext)
|
||||||
|
{
|
||||||
|
case AMC_LINK_TYPE_EXT_PCIE_G1_NSSC:
|
||||||
|
printf(" Link Type Ext: %i - "
|
||||||
|
" Gen 1 capable - non SSC\n", l->type_ext);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AMC_LINK_TYPE_EXT_PCIE_G1_SSC:
|
||||||
|
printf(" Link Type Ext: %i - "
|
||||||
|
" Gen 1 capable - SSC\n", l->type_ext);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AMC_LINK_TYPE_EXT_PCIE_G2_NSSC:
|
||||||
|
printf(" Link Type Ext: %i - "
|
||||||
|
" Gen 2 capable - non SSC\n", l->type_ext);
|
||||||
|
break;
|
||||||
|
case AMC_LINK_TYPE_EXT_PCIE_G2_SSC:
|
||||||
|
printf(" Link Type Ext: %i - "
|
||||||
|
" Gen 2 capable - SSC\n", l->type_ext);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf(" Link Type Ext: %i - "
|
||||||
|
" Invalid\n", l->type_ext);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* AMC.1 */
|
||||||
|
case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1:
|
||||||
|
case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2:
|
||||||
|
printf(" Link Type: %02x - "
|
||||||
|
"AMC.1 PCI Express Advanced Switching\n", l->type);
|
||||||
|
printf(" Link Type Ext: %i\n", l->type_ext);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* AMC.2 */
|
||||||
|
case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET:
|
||||||
|
printf(" Link Type: %02x - "
|
||||||
|
"AMC.2 Ethernet\n", l->type);
|
||||||
|
switch (l->type_ext)
|
||||||
|
{
|
||||||
|
case AMC_LINK_TYPE_EXT_ETH_1000_BX:
|
||||||
|
printf(" Link Type Ext: %i - "
|
||||||
|
" 1000Base-Bx (SerDES Gigabit) Ethernet Link\n", l->type_ext);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AMC_LINK_TYPE_EXT_ETH_10G_XAUI:
|
||||||
|
printf(" Link Type Ext: %i - "
|
||||||
|
" 10Gbit XAUI Ethernet Link\n", l->type_ext);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf(" Link Type Ext: %i - "
|
||||||
|
" Invalid\n", l->type_ext);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* AMC.3 */
|
||||||
|
case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE:
|
||||||
|
printf(" Link Type: %02x - "
|
||||||
|
"AMC.3 Storage\n", l->type);
|
||||||
|
switch (l->type_ext)
|
||||||
|
{
|
||||||
|
case AMC_LINK_TYPE_EXT_STORAGE_FC:
|
||||||
|
printf(" Link Type Ext: %i - "
|
||||||
|
" Fibre Channel\n", l->type_ext);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AMC_LINK_TYPE_EXT_STORAGE_SATA:
|
||||||
|
printf(" Link Type Ext: %i - "
|
||||||
|
" Serial ATA\n", l->type_ext);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AMC_LINK_TYPE_EXT_STORAGE_SAS:
|
||||||
|
printf(" Link Type Ext: %i - "
|
||||||
|
" Serial Attached SCSI\n", l->type_ext);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf(" Link Type Ext: %i - "
|
||||||
|
" Invalid\n", l->type_ext);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* AMC.4 */
|
||||||
|
case FRU_PICMGEXT_AMC_LINK_TYPE_RAPIDIO:
|
||||||
|
printf(" Link Type: %02x - "
|
||||||
|
"AMC.4 Serial Rapid IO\n", l->type);
|
||||||
|
printf(" Link Type Ext: %i\n", l->type_ext);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf(" Link Type: %02x - "
|
||||||
|
"reserved or OEM GUID", l->type);
|
||||||
|
printf(" Link Type Ext: %i\n", l->type_ext);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(" Link group Id: %i\n", l->group_id);
|
||||||
|
printf(" Link Asym Match: %i\n\n",l->asym_match);
|
||||||
|
|
||||||
|
offset += sizeof(struct fru_picmgext_amc_link_desc_record);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FRU_AMC_CARRIER_INFO:
|
case FRU_AMC_CARRIER_INFO:
|
||||||
|
{
|
||||||
|
unsigned char extVersion;
|
||||||
|
unsigned char siteCount;
|
||||||
|
|
||||||
printf(" FRU_CARRIER_INFO\n");
|
printf(" FRU_CARRIER_INFO\n");
|
||||||
|
|
||||||
|
extVersion = fru_data[offset++];
|
||||||
|
siteCount = fru_data[offset++];
|
||||||
|
|
||||||
|
printf(" AMC.0 extension version: R%d.%d\n",
|
||||||
|
(extVersion >> 0)& 0x0F,
|
||||||
|
(extVersion >> 4)& 0x0F );
|
||||||
|
printf(" Carrier Sie Number Cnt: %d\n", siteCount);
|
||||||
|
|
||||||
|
for (i = 0 ; i < siteCount; i++ ){
|
||||||
|
printf(" Site ID: %i \n", fru_data[offset++]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FRU_PICMG_CLK_CARRIER_P2P:
|
||||||
|
{
|
||||||
|
unsigned char desc_count;
|
||||||
|
int i,j;
|
||||||
|
|
||||||
|
printf(" FRU_PICMG_CLK_CARRIER_P2P\n");
|
||||||
|
|
||||||
|
desc_count = fru_data[offset++];
|
||||||
|
|
||||||
|
for(i=0; i<desc_count; i++){
|
||||||
|
unsigned char resource_id;
|
||||||
|
unsigned char channel_count;
|
||||||
|
|
||||||
|
resource_id = fru_data[offset++];
|
||||||
|
channel_count = fru_data[offset++];
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf(" Clock Resource ID: 0x%02x Type: ", resource_id);
|
||||||
|
if((resource_id & 0xC0)>>6 == 0) {printf("On-Carrier-Device\n");}
|
||||||
|
else if((resource_id & 0xC0)>>6 == 1) {printf("AMC slot\n");}
|
||||||
|
else if((resource_id & 0xC0)>>6 == 2) {printf("Backplane\n");}
|
||||||
|
else{ printf("reserved\n");}
|
||||||
|
printf(" Channel Count: 0x%02x\n", channel_count);
|
||||||
|
|
||||||
|
for(j=0; j<channel_count; j++){
|
||||||
|
unsigned char loc_channel, rem_channel, rem_resource;
|
||||||
|
|
||||||
|
loc_channel = fru_data[offset++];
|
||||||
|
rem_channel = fru_data[offset++];
|
||||||
|
rem_resource = fru_data[offset++];
|
||||||
|
|
||||||
|
printf(" CLK-ID: 0x%02x ->", loc_channel);
|
||||||
|
printf(" remote CLKID: 0x%02x ", rem_channel);
|
||||||
|
if((rem_resource & 0xC0)>>6 == 0) {printf("[ Carrier-Dev");}
|
||||||
|
else if((rem_resource & 0xC0)>>6 == 1) {printf("[ AMC slot ");}
|
||||||
|
else if((rem_resource & 0xC0)>>6 == 2) {printf("[ Backplane ");}
|
||||||
|
else{ printf("reserved ");}
|
||||||
|
printf(" 0x%02x ]\n", rem_resource&0xF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FRU_PICMG_CLK_CONFIG:
|
||||||
|
{
|
||||||
|
unsigned char resource_id, descr_count;
|
||||||
|
int i,j;
|
||||||
|
|
||||||
|
printf(" FRU_PICMG_CLK_CONFIG\n");
|
||||||
|
|
||||||
|
resource_id = fru_data[offset++];
|
||||||
|
descr_count = fru_data[offset++];
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf(" Clock Resource ID: 0x%02x\n", resource_id);
|
||||||
|
printf(" Descr. Count: 0x%02x\n", descr_count);
|
||||||
|
|
||||||
|
for(i=0; i<descr_count; i++){
|
||||||
|
unsigned char channel_id, control;
|
||||||
|
unsigned char indirect_cnt, direct_cnt;
|
||||||
|
|
||||||
|
channel_id = fru_data[offset++];
|
||||||
|
control = fru_data[offset++];
|
||||||
|
printf(" CLK-ID: 0x%02x - ", channel_id);
|
||||||
|
printf("CTRL 0x%02x [ %12s ]\n",
|
||||||
|
control,
|
||||||
|
((control&0x1)==0)?"Carrier IPMC":"Application");
|
||||||
|
|
||||||
|
indirect_cnt = fru_data[offset++];
|
||||||
|
direct_cnt = fru_data[offset++];
|
||||||
|
printf(" Cnt: Indirect 0x%02x / Direct 0x%02x\n",
|
||||||
|
indirect_cnt,
|
||||||
|
direct_cnt );
|
||||||
|
|
||||||
|
/* indirect desc */
|
||||||
|
for(j=0; j<indirect_cnt; j++){
|
||||||
|
unsigned char feature;
|
||||||
|
unsigned char dep_chn_id;
|
||||||
|
|
||||||
|
feature = fru_data[offset++];
|
||||||
|
dep_chn_id = fru_data[offset++];
|
||||||
|
|
||||||
|
printf(" Feature: 0x%02x [%8s] - ", feature, (feature&0x1)==1?"Source":"Receiver");
|
||||||
|
printf(" Dep. CLK-ID: 0x%02x\n", dep_chn_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* direct desc */
|
||||||
|
for(j=0; j<direct_cnt; j++){
|
||||||
|
unsigned char feature, family, accuracy;
|
||||||
|
unsigned long freq, min_freq, max_freq;
|
||||||
|
|
||||||
|
feature = fru_data[offset++];
|
||||||
|
family = fru_data[offset++];
|
||||||
|
accuracy = fru_data[offset++];
|
||||||
|
freq = (fru_data[offset+0] << 0 ) | (fru_data[offset+1] << 8 )
|
||||||
|
| (fru_data[offset+2] << 16) | (fru_data[offset+3] << 24);
|
||||||
|
offset += 4;
|
||||||
|
min_freq = (fru_data[offset+0] << 0 ) | (fru_data[offset+1] << 8 )
|
||||||
|
| (fru_data[offset+2] << 16) | (fru_data[offset+3] << 24);
|
||||||
|
offset += 4;
|
||||||
|
max_freq = (fru_data[offset+0] << 0 ) | (fru_data[offset+1] << 8 )
|
||||||
|
| (fru_data[offset+2] << 16) | (fru_data[offset+3] << 24);
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
printf(" - Feature: 0x%02x - PLL: %x / Asym: %s\n",
|
||||||
|
feature,
|
||||||
|
(feature > 1) & 1,
|
||||||
|
(feature&1)?"Source":"Receiver");
|
||||||
|
printf(" Family: 0x%02x - AccLVL: 0x%02x\n", family, accuracy);
|
||||||
|
printf(" FRQ: %-9d - min: %-9d - max: %-9d\n",
|
||||||
|
freq, min_freq, max_freq);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FRU_UTCA_FRU_INFO_TABLE:
|
||||||
|
case FRU_UTCA_CARRIER_MNG_IP:
|
||||||
|
case FRU_UTCA_CARRIER_INFO:
|
||||||
|
case FRU_UTCA_CARRIER_LOCATION:
|
||||||
|
case FRU_UTCA_SHMC_IP_LINK:
|
||||||
|
case FRU_UTCA_POWER_POLICY:
|
||||||
|
case FRU_UTCA_ACTIVATION:
|
||||||
|
case FRU_UTCA_PM_CAPABILTY:
|
||||||
|
case FRU_UTCA_FAN_GEOGRAPHY:
|
||||||
|
case FRU_UTCA_CLOCK_MAPPING:
|
||||||
|
case FRU_UTCA_MSG_BRIDGE_POLICY:
|
||||||
|
case FRU_UTCA_OEM_MODULE_DESC:
|
||||||
|
printf(" Not implemented yet. uTCA specific record found!!\n");
|
||||||
|
printf(" - Record ID: 0x%02x\n", h->record_id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1333,6 +1799,9 @@ __ipmi_fru_print(struct ipmi_intf * intf, uint8_t id)
|
|||||||
fru_area_print_product(intf, &fru, id, header.offset.product*8);
|
fru_area_print_product(intf, &fru, id, header.offset.product*8);
|
||||||
|
|
||||||
/* multirecord area */
|
/* multirecord area */
|
||||||
|
if( verbose==0 ) /* scipp parsing multirecord */
|
||||||
|
return 0;
|
||||||
|
|
||||||
if ((header.offset.multi*8) >= sizeof(struct fru_header))
|
if ((header.offset.multi*8) >= sizeof(struct fru_header))
|
||||||
fru_area_print_multirec(intf, &fru, id, header.offset.multi*8);
|
fru_area_print_multirec(intf, &fru, id, header.offset.multi*8);
|
||||||
|
|
||||||
@ -1482,7 +1951,7 @@ ipmi_fru_read_to_bin(struct ipmi_intf * intf,
|
|||||||
|
|
||||||
if (rsp->ccode > 0) {
|
if (rsp->ccode > 0) {
|
||||||
if (rsp->ccode == 0xc3)
|
if (rsp->ccode == 0xc3)
|
||||||
printf(" Timeout accessing FRU info. (Device not present?)\n");
|
printf (" Timeout accessing FRU info. (Device not present?)\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fru.size = (rsp->data[1] << 8) | rsp->data[0];
|
fru.size = (rsp->data[1] << 8) | rsp->data[0];
|
||||||
@ -1502,10 +1971,10 @@ ipmi_fru_read_to_bin(struct ipmi_intf * intf,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pFruBuf != NULL)
|
if(pFruBuf != NULL)
|
||||||
{
|
{
|
||||||
FILE * pFile;
|
FILE * pFile;
|
||||||
pFile = fopen(pFileName, "wb");
|
pFile = fopen(pFileName,"wb");
|
||||||
if (pFile) {
|
if (pFile) {
|
||||||
fwrite(pFruBuf, fru.size, 1, pFile);
|
fwrite(pFruBuf, fru.size, 1, pFile);
|
||||||
printf("Done\n");
|
printf("Done\n");
|
||||||
@ -1763,7 +2232,7 @@ ipmi_fru_upg_ekeying(struct ipmi_intf * intf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retStatus == 0)
|
if(retStatus == 0)
|
||||||
{
|
{
|
||||||
ipmi_fru_get_adjust_size_from_buffer(buf, &fileMultiRecSize);
|
ipmi_fru_get_adjust_size_from_buffer(buf, &fileMultiRecSize);
|
||||||
if (buf)
|
if (buf)
|
||||||
@ -1771,7 +2240,7 @@ ipmi_fru_upg_ekeying(struct ipmi_intf * intf,
|
|||||||
fileMultiRecSize, buf);
|
fileMultiRecSize, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retStatus == 0)
|
if(retStatus == 0 )
|
||||||
lprintf(LOG_INFO, "Done");
|
lprintf(LOG_INFO, "Done");
|
||||||
else
|
else
|
||||||
lprintf(LOG_ERR, "Failed");
|
lprintf(LOG_ERR, "Failed");
|
||||||
@ -1793,7 +2262,7 @@ ipmi_fru_get_multirec_size_from_file(char * pFileName,
|
|||||||
uint32_t end = 0;
|
uint32_t end = 0;
|
||||||
*pSize = 0;
|
*pSize = 0;
|
||||||
|
|
||||||
pFile = fopen(pFileName, "rb");
|
pFile = fopen(pFileName,"rb");
|
||||||
if (pFile) {
|
if (pFile) {
|
||||||
rewind(pFile);
|
rewind(pFile);
|
||||||
len = fread(&header, 1, 8, pFile);
|
len = fread(&header, 1, 8, pFile);
|
||||||
@ -1811,7 +2280,7 @@ ipmi_fru_get_multirec_size_from_file(char * pFileName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (header.version != 0x01) {
|
if (header.version != 0x01) {
|
||||||
printf("Unknown FRU header version %02x.\n", header.version);
|
printf ("Unknown FRU header version %02x.\n", header.version);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1843,7 +2312,7 @@ ipmi_fru_get_adjust_size_from_buffer(uint8_t * fru_data,
|
|||||||
uint32_t *pSize)
|
uint32_t *pSize)
|
||||||
{
|
{
|
||||||
struct fru_multirec_header * head;
|
struct fru_multirec_header * head;
|
||||||
#define CHUNK_SIZE (255 + sizeof(struct fru_multirec_header))
|
#define CHUNK_SIZE (255 + sizeof(struct fru_multirec_header))
|
||||||
uint16_t count = 0;
|
uint16_t count = 0;
|
||||||
uint16_t status = 0;
|
uint16_t status = 0;
|
||||||
uint8_t counter;
|
uint8_t counter;
|
||||||
@ -1853,23 +2322,23 @@ ipmi_fru_get_adjust_size_from_buffer(uint8_t * fru_data,
|
|||||||
checksum = 0;
|
checksum = 0;
|
||||||
head = (struct fru_multirec_header *) (fru_data + count);
|
head = (struct fru_multirec_header *) (fru_data + count);
|
||||||
|
|
||||||
if (verbose)
|
if(verbose )
|
||||||
printf("Adding (");
|
printf("Adding (");
|
||||||
|
|
||||||
for (counter = 0; counter < sizeof(struct fru_multirec_header); counter++) {
|
for (counter = 0; counter < sizeof(struct fru_multirec_header); counter++) {
|
||||||
if (verbose)
|
if(verbose )
|
||||||
printf(" %02X", *(fru_data + count + counter));
|
printf(" %02X", *(fru_data + count + counter));
|
||||||
checksum += *(fru_data + count + counter);
|
checksum += *(fru_data + count + counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if( verbose )
|
||||||
printf(")");
|
printf(")");
|
||||||
|
|
||||||
if (checksum != 0) {
|
if (checksum != 0) {
|
||||||
printf("Bad checksum in Multi Records\n");
|
printf("Bad checksum in Multi Records\n");
|
||||||
status = -1;
|
status = -1;
|
||||||
}
|
}
|
||||||
else if (verbose)
|
else if ( verbose )
|
||||||
printf("--> OK");
|
printf("--> OK");
|
||||||
|
|
||||||
if (verbose > 1 && checksum == 0) {
|
if (verbose > 1 && checksum == 0) {
|
||||||
@ -1878,13 +2347,11 @@ ipmi_fru_get_adjust_size_from_buffer(uint8_t * fru_data,
|
|||||||
sizeof(struct fru_multirec_header)));
|
sizeof(struct fru_multirec_header)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(verbose )
|
||||||
if (verbose)
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
count += head->len + sizeof (struct fru_multirec_header);
|
count += head->len + sizeof (struct fru_multirec_header);
|
||||||
|
} while( (!(head->format & 0x80)) && (status == 0));
|
||||||
} while ((!(head->format & 0x80)) && (status == 0));
|
|
||||||
|
|
||||||
*pSize = count;
|
*pSize = count;
|
||||||
|
|
||||||
@ -1900,7 +2367,7 @@ ipmi_fru_get_multirec_from_file(char * pFileName,
|
|||||||
FILE * pFile;
|
FILE * pFile;
|
||||||
uint32_t len = 0;
|
uint32_t len = 0;
|
||||||
|
|
||||||
pFile = fopen(pFileName, "rb");
|
pFile = fopen(pFileName,"rb");
|
||||||
if (pFile) {
|
if (pFile) {
|
||||||
fseek(pFile, offset,SEEK_SET);
|
fseek(pFile, offset,SEEK_SET);
|
||||||
len = fread(pBufArea, size, 1, pFile);
|
len = fread(pBufArea, size, 1, pFile);
|
||||||
@ -1949,12 +2416,11 @@ ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf * intf,
|
|||||||
|
|
||||||
if (rsp->ccode > 0) {
|
if (rsp->ccode > 0) {
|
||||||
if (rsp->ccode == 0xc3)
|
if (rsp->ccode == 0xc3)
|
||||||
printf(" Timeout accessing FRU info. (Device not present?)\n");
|
printf (" Timeout accessing FRU info. (Device not present?)\n");
|
||||||
else
|
else
|
||||||
printf(" CCODE = 0x%02x\n", rsp->ccode);
|
printf (" CCODE = 0x%02x\n", rsp->ccode);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pFruInfo->size = (rsp->data[1] << 8) | rsp->data[0];
|
pFruInfo->size = (rsp->data[1] << 8) | rsp->data[0];
|
||||||
pFruInfo->access = rsp->data[2] & 0x1;
|
pFruInfo->access = rsp->data[2] & 0x1;
|
||||||
|
|
||||||
@ -1977,11 +2443,12 @@ ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf * intf,
|
|||||||
req.msg.data_len = 4;
|
req.msg.data_len = 4;
|
||||||
|
|
||||||
rsp = intf->sendrecv(intf, &req);
|
rsp = intf->sendrecv(intf, &req);
|
||||||
|
|
||||||
if (!rsp)
|
if (!rsp)
|
||||||
return -1;
|
return -1;
|
||||||
if (rsp->ccode > 0) {
|
if (rsp->ccode > 0) {
|
||||||
if (rsp->ccode == 0xc3)
|
if (rsp->ccode == 0xc3)
|
||||||
printf(" Timeout while reading FRU data. (Device not present?)\n");
|
printf (" Timeout while reading FRU data. (Device not present?)\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1991,7 +2458,7 @@ ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf * intf,
|
|||||||
memcpy(&header, rsp->data + 1, 8);
|
memcpy(&header, rsp->data + 1, 8);
|
||||||
|
|
||||||
if (header.version != 0x01) {
|
if (header.version != 0x01) {
|
||||||
printf(" Unknown FRU header version %02x.\n", header.version);
|
printf (" Unknown FRU header version %02x.\n", header.version);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2022,7 +2489,7 @@ ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf * intf,
|
|||||||
|
|
||||||
int
|
int
|
||||||
ipmi_fru_main(struct ipmi_intf * intf, int argc, char ** argv)
|
ipmi_fru_main(struct ipmi_intf * intf, int argc, char ** argv)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (argc == 0) {
|
if (argc == 0) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user