SleepyTami
Cadet
- Joined
 - Aug 25, 2021
 
- Messages
 - 2
 
Hey Guys,
Just thought this simple app might help a few of you. Unfortunately, I don't have time to create a plugin for Truenas Core but it would be nice if someone else did.
Enjoy!!
	
		
			
		
		
	
			
			Just thought this simple app might help a few of you. Unfortunately, I don't have time to create a plugin for Truenas Core but it would be nice if someone else did.
Enjoy!!
Code:
/*
 * Broadcom/Avago/LSI HBA/RAID cards are made to be used in servers where there's plenty of airflow (minimum of 200 linear feet per minute (LFM)).
 * These conditions are not always attainable in Desktop PCs without generating a considerable amount of noise.
 * In this scenario, there's a need of constantly monitoring the IOC core temperature to dynamically regulate fan speed.
 *
 * Unfortunately, those idiotic devs at Broadcom couldn't be bothered to add this feature to "sas3ircu" so a DIY approach had to be followed.
 *
 * The IOC has internal sensors that measure the temperature of each core.
 *
 * This very simple PoC displays the IOC core temperature (MAX(Sensor[0->N-1])) for Broadcom/Avago/LSI HBA cards. No kernel mods required.
 *
 * Tested against:
 *
 * Broadcom/Avago/LSI 9305-16i 12Gb/s HBA
 *
 * Tested on:
 *
 * FreeBSD 13.0-RELEASE
 *
 * Compile with:
 *
 * gcc lsi_temp.c -o lsi_temp
 *
 * Output:
 *
 * ./lsi_temp /dev/mpr0
 * IOC Temp: 43 (C)
 * Board Temp: 0 (N/A)
 *
 * tami@ombra.org.uk
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#define MPI2_IOCSTATUS_MASK (0x7FFF)
#define MPI2_IOCSTATUS_SUCCESS (0x0000)
#define MPRIO_READ_CFG_PAGE _IOWR('M', 201, struct mpr_cfg_page_req)
#define MPRIO_READ_CFG_HEADER _IOWR('M', 200, struct mpr_cfg_page_req)
#define MPI2_CONFIG_PAGETYPE_IO_UNIT (0x00)
#define MPI2_IOUNITPAGE7_PAGEVERSION (0x05)
#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00)
#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01)
#define MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS (0x02)
typedef struct _MPI2_CONFIG_PAGE_HEADER
{
  uint8_t PageVersion;
  uint8_t PageLength;
  uint8_t PageNumber;
  uint8_t PageType;
} MPI2_CONFIG_PAGE_HEADER, Mpi2ConfigPageHeader_t;
struct mpr_cfg_page_req
{
  MPI2_CONFIG_PAGE_HEADER header;
  uint32_t page_address;
  void *buf;
  int len;
  uint16_t ioc_status;
};
typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7
{
  MPI2_CONFIG_PAGE_HEADER Header;
  uint8_t CurrentPowerMode;
  uint8_t PreviousPowerMode;
  uint8_t PCIeWidth;
  uint8_t PCIeSpeed;
  uint32_t ProcessorState;
  uint32_t PowerManagementCapabilities;
  uint16_t IOCTemperature;
  uint8_t IOCTemperatureUnits;
  uint8_t IOCSpeed;
  uint16_t BoardTemperature;
  uint8_t BoardTemperatureUnits;
  uint8_t Reserved3;
  uint32_t BoardPowerRequirement;
  uint32_t PCISlotPowerAllocation;
  uint8_t Flags;
  uint8_t Reserved6;
  uint16_t Reserved7;
  uint32_t Reserved8;
} MPI2_CONFIG_PAGE_IO_UNIT_7, Mpi2IOUnitPage7_t;
/* Application specific methods */
char *utos (uint8_t unit)
{
  switch (unit)
  {
  case MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT:
    return "F";
  case MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS:
    return "C";
  default:
    return "N/A";
  }
}
int main (int argc, char **argv)
{
  int fd = 0, ret = 0;
  struct mpr_cfg_page_req req;
  Mpi2IOUnitPage7_t pg7;
  if (argc != 2)
  {
    printf("%s: </dev/mpr0>\n", argv[0]);
    return 1;
  }
  if(geteuid() != 0)
  {
    printf("Error: Not root!!\n");
    return 1;
  }
  fd = open(argv[1], O_RDWR);
  if(fd == 0)
  {
    printf("Error: Could not open device file!!\n");
    return 1;
  }
  /* Initialize structs */
  memset(&req, 0x00, sizeof(struct mpr_cfg_page_req));
  memset(&pg7, 0x00, sizeof(Mpi2IOUnitPage7_t));
  /* Get config page 7 header */
  req.header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
  req.header.PageNumber = 7;
  req.header.PageVersion = MPI2_IOUNITPAGE7_PAGEVERSION;
  req.buf = (Mpi2IOUnitPage7_t *) & pg7;
  req.len = sizeof (Mpi2IOUnitPage7_t);
  if(req.buf == NULL)
  {
    printf("Error: Out of memory!!\n");
    close(fd);
    return 1;
  }
  pg7.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
  pg7.Header.PageNumber = 7;
  pg7.Header.PageVersion = MPI2_IOUNITPAGE7_PAGEVERSION;
  ret = ioctl(fd, MPRIO_READ_CFG_HEADER, &req);
  if(ret != 0)
  {
    printf("Error: MPRIO_READ_CFG_HEADER: IOCTL request failed with error num %d!!\n", ret);
    close (fd);
    return 1;
  }
  if((req.ioc_status & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
  {
    printf("Error: MPRIO_READ_CFG_HEADER: Reply ioc_status != 0x0000 (%x)!!\n", req.ioc_status);
    close(fd);
    return 1;
  }
  /* Get config page 7 content */
  memcpy(req.buf, &req.header, sizeof(MPI2_CONFIG_PAGE_HEADER));
  ret = ioctl(fd, MPRIO_READ_CFG_PAGE, &req);
  if(ret != 0)
  {
    printf("Error: MPRIO_READ_CFG_PAGE: IOCTL request failed with error num %d!!\n", ret);
    close(fd);
    return 1;
  }
  if((req.ioc_status & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
  {
    printf("Error: MPRIO_READ_CFG_PAGE: Reply ioc_status != 0x0000 (%x)!!\n", req.ioc_status);
    close(fd);
    return 1;
  }
  /* Display info */
  printf("IOC Temp: %hu (%s)\n", pg7.IOCTemperature, utos(pg7.IOCTemperatureUnits));
  printf("Board Temp: %hu (%s)\n", pg7.BoardTemperature, utos(pg7.BoardTemperatureUnits));
  /* Exit */
  close(fd);
  return 0;
}