Compare commits

..

11 Commits

Author SHA1 Message Date
geos_one
cfe47daa9a Import Upstream version 0.4.5 2025-08-06 16:36:24 +02:00
Mario Fetka
64807cf811 update compat 2023-07-01 12:04:23 +02:00
Mario Fetka
fa0d36dc5b Merge tag 'upstream/0.4.1.1'
Upstream version 0.4.1.1
2017-04-22 17:55:53 +02:00
Mario Fetka
5874481e38 Bump 2017-04-22 17:55:48 +02:00
Mario Fetka
0795bec8ef add device id patch 2017-04-22 17:21:07 +02:00
Mario Fetka
43e942c2b5 force m32 2017-04-22 16:58:36 +02:00
Mario Fetka
8fae4f9e81 megatrace in own package 2017-04-22 16:51:10 +02:00
Mario Fetka
c617d59dcb compat 5 2017-04-22 16:13:57 +02:00
Mario Fetka
ce791a790d new relase 2017-04-22 15:08:27 +02:00
Mario Fetka
8a4c5cc630 new relase 2017-04-22 15:03:01 +02:00
Mario Fetka
05d4ad85da Initial commit 2017-04-22 15:01:27 +02:00
91 changed files with 489 additions and 66 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
custom: [https://www.buymeacoffee.com/namiltd]

62
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@ -0,0 +1,62 @@
name: "CodeQL"
on:
push:
branches: [master]
pull_request:
# The branches below must be a subset of the branches above
branches: [master]
schedule:
- cron: '0 20 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ['cpp']
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.o
/megatrace
/megactl
/megasasctl

View File

@ -1,11 +1,17 @@
DESTDIR:=
PREFIX:= /usr
BINDIR:= $(PREFIX)/bin
METAINFODIR:= $(PREFIX)/share/metainfo/
INSTALL= install
SRCS= megactl.c adapter.c megaioctl.c megatrace.c callinfo.c dumpbytes.c logpage.c ntrim.c
INC= -I./schily -Iincludes-hack
HDRS= mega.h adapter.h megaioctl.h callinfo.h logpage.h dumpbytes.h
ARCH= -m32
CFLAGS= -g -Wall $(INC) $(ARCH)
LDFLAGS= -g $(ARCH)
PROGRAMS= megactl megasasctl megatrace
CPPFLAGS+=
CFLAGS+= -g -Wall $(INC) $(ARCH) $(CPPFLAGS)
LDFLAGS+= -g $(ARCH)
PROGRAMS= megactl megasasctl
all: $(PROGRAMS)
@ -24,6 +30,12 @@ megasasctl.o: megactl.c
%.o: Makefile.bak %.c
$(CC) $(CFLAGS) -c -o $@ $*.c
install: $(PROGRAMS)
$(INSTALL) -d $(DESTDIR)$(BINDIR)/
$(INSTALL) $(PROGRAMS) $(DESTDIR)$(BINDIR)
$(INSTALL) -d $(DESTDIR)$(METAINFODIR)/
$(INSTALL) -m644 megactl.metainfo.xml $(DESTDIR)$(METAINFODIR)/
clean:
$(RM) $(PROGRAMS) *.o

View File

@ -57,7 +57,8 @@ static void batteryStatus5 (struct adapter_config *a)
a->battery.module_missing = !(a->q.v5.adapinfo.hw_present.bbu);
a->battery.pack_missing = b->type == MEGA_BATTERY_TYPE_NONE;
a->battery.low_voltage = b->remaining_capacity_alarm || b->remaining_time_alarm || b->fully_discharged;
/*a->battery.low_voltage = b->remaining_capacity_alarm || b->remaining_time_alarm || b->fully_discharged;*/
a->battery.low_voltage = !b->fully_charged && (b->remaining_time_alarm || b->remaining_capacity_alarm || b->fully_discharged) ;
a->battery.high_temperature = b->over_temperature != 0;
a->battery.over_charged = b->over_charged != 0;
switch (b->charger_status)
@ -69,7 +70,7 @@ static void batteryStatus5 (struct adapter_config *a)
}
a->battery.voltage = b->voltage;
a->battery.temperature = b->temperature;
a->battery.healthy = !(a->battery.module_missing || a->battery.pack_missing || a->battery.low_voltage || a->battery.high_temperature || a->battery.cycles_exceeded || (a->battery.charger_state != ChargerStateComplete) || (!b->health));
a->battery.healthy = !(a->battery.module_missing || a->battery.pack_missing || a->battery.low_voltage || a->battery.high_temperature /*|| a->battery.cycles_exceeded */|| (a->battery.charger_state != ChargerStateComplete) || (!b->health));
}
@ -136,7 +137,7 @@ struct log_page_list *getDriveLogPage (struct physical_drive_info *d, uint8_t pa
}
int cmpPhysical (const void *a, const void *b)
static int cmpPhysical (const void *a, const void *b)
{
struct physical_drive_info *x = *((struct physical_drive_info **) a);
struct physical_drive_info *y = *((struct physical_drive_info **) b);
@ -192,6 +193,9 @@ struct physical_drive_info *getPhysicalDriveInfo (struct adapter_config *a, uint
d->channel = info->enclosure;
d->id = info->slot;
if (d->channel == DISK_NOENC)
snprintf (d->name, sizeof (d->name), "%se*s%u", a->name, d->id);
else
snprintf (d->name, sizeof (d->name), "%se%us%u", a->name, d->channel, d->id);
d->inquiry = info->inquiry.inq;
@ -369,7 +373,7 @@ static char *getAdapterConfig2 (struct adapter_config *a)
return "invalid number of logical drives";
a->num_channels = pinfo->nchannels;
if ((a->channel = (uint8_t *) malloc (a->num_channels * sizeof (*a->channel))) == NULL)
if ((a->channel = (uint16_t *) malloc (a->num_channels * sizeof (*a->channel))) == NULL)
return "out of memory (channels)";
for (k = 0; k < a->num_channels; ++k)
a->channel[k] = k;
@ -503,7 +507,7 @@ static char *getAdapterConfig3 (struct adapter_config *a)
case 4: break;
default: return "invalid number of channels";
}
strncpy (a->product, (char *) pinfo->product_name, sizeof (pinfo->product_name));
strncpy (a->product, (char *) pinfo->product_name, sizeof (a->product));
a->product[sizeof (a->product) - 1] = '\0';
ntrim (a->product);
strncpy (a->bios, (char *) pinfo->bios_version, sizeof (a->bios));
@ -519,7 +523,7 @@ static char *getAdapterConfig3 (struct adapter_config *a)
return "invalid number of logical drives";
a->num_channels = pinfo->nchannels;
if ((a->channel = (uint8_t *) malloc (a->num_channels * sizeof (*a->channel))) == NULL)
if ((a->channel = (uint16_t *) malloc (a->num_channels * sizeof (*a->channel))) == NULL)
return "out of memory (channels)";
for (k = 0; k < a->num_channels; ++k)
a->channel[k] = k;
@ -630,7 +634,7 @@ static char *getAdapterConfig3 (struct adapter_config *a)
}
int cmpChannel (const void *a, const void *b)
static int cmpChannel (const void *a, const void *b)
{
int x = (int) *((uint8_t *) a);
int y = (int) *((uint8_t *) b);
@ -661,7 +665,7 @@ static char *getAdapterConfig5 (struct adapter_config *a)
a->dram_size = pinfo->memory_size;
snprintf (a->name, sizeof (a->name), "a%u", a->target.adapno);
strncpy (a->product, (char *) pinfo->product_name, sizeof (pinfo->product_name));
strncpy (a->product, (char *) pinfo->product_name, sizeof (a->product));
a->product[sizeof (a->product) - 1] = '\0';
ntrim (a->product);
@ -696,13 +700,37 @@ static char *getAdapterConfig5 (struct adapter_config *a)
/* Didn't find this enclosure; extend the map */
++a->num_channels;
if ((a->channel = (uint8_t *) realloc (a->channel, a->num_channels * sizeof (*a->channel))) == NULL)
if ((a->channel = (uint16_t *) realloc (a->channel, a->num_channels * sizeof (*a->channel))) == NULL)
return "out of memory (channels)";
a->channel[a->num_channels - 1] = device->device[k].enclosure;
}
qsort (a->channel, a->num_channels, sizeof (*a->channel), cmpChannel);
a->num_physicals = pinfo->pd_present_count;
/* Some notes:
Different meanings on different models.
- FC_MAX_PHYSICAL_DEVICES used on older controllers, which is 256
disks (overallocation)
- pd_disk_present_count is number of working drives, not counting
missing drives
- pd_present_count is unclear. It is pd_disk_present_count + 1 on some
controllers
- device_interface.port_count contains number of physical ports on the
controller
pd_present_count was used here, but in some controllers causes segfaults
when there is a failed drive, and not enough space is allocated.
Since there cannot be more devices than there are ports, that is a safe
number to set without going overboard.
*/
a->num_physicals = pinfo->device_interface.port_count;
/* On some controllers, namely the PERC6e, the controller does not know
how many ports there are in the enclosure. Fall back to the worst case
scenario. */
if (a->num_physicals < pinfo->pd_disk_present_count)
a->num_physicals = FC_MAX_PHYSICAL_DEVICES;
if ((a->physical = (struct physical_drive_info *) malloc (a->num_physicals * sizeof (*a->physical))) == NULL)
return "out of memory (physical drives)";
memset (a->physical, 0, a->num_physicals * sizeof (*a->physical));

View File

@ -107,23 +107,12 @@ static char *friendlySize (uint64_t b, char *unit)
for (k = 0; (b >= 1024) && (k < sizeof (suffix) / sizeof (suffix[0]) - 1); ++k, b /= 1024)
;
snprintf (bytes, sizeof bytes, "%3llu%s%s", b, suffix[k], unit);
snprintf (bytes, sizeof bytes, "%3llu%s%s",
(long long unsigned int)b, suffix[k], unit);
return bytes;
}
static uint32_t blocksToGB (uint32_t blocks)
{
return (long) (((uint64_t) blocks) * 512 / 1000000000);
}
static uint32_t blocksToGiB (uint32_t blocks)
{
return blocks / 2 / 1024 / 1024;
}
static uint64_t extractInt64 (void *u, size_t len)
{
uint64_t x;
@ -378,7 +367,8 @@ void dumpLogPage (FILE *f, struct logData *x, void *log, size_t len, int verbosi
default: result = "unknown result"; notice = 0; break;
}
if (verbosity > notice)
fprintf (f, " %2d: timestamp %4ud%02uh: %10s %-30s seg:%u lba:%-8lld sk:%u asc:%u ascq:%u vs:%u\n", k, t->timestamp / 24, t->timestamp % 24, test, result, t->number, t->lba, t->sense_key, t->additional_sense_code, t->additional_sense_code_qualifier, t->vendor_specific);
fprintf (f, " %2d: timestamp %4ud%02uh: %10s %-30s seg:%u lba:%-8lld sk:%u asc:%u ascq:%u vs:%u\n", k, t->timestamp / 24, t->timestamp % 24, test, result, t->number,
(long long int)t->lba, t->sense_key, t->additional_sense_code, t->additional_sense_code_qualifier, t->vendor_specific);
}
}
break;

View File

@ -114,6 +114,8 @@ struct list_head {
#define SCSI_SELFTEST_FOREGROUND_SHORT 0x05
#define SCSI_SELFTEST_FOREGROUND_LONG 0x06
/* Drives without enclosure report this as the enclosure ID */
#define DISK_NOENC 0xffff
/* megaraid2 header file gets this wrong. */
typedef struct {
@ -545,7 +547,7 @@ struct adapter_config
uint16_t dram_size; /* size of DRAM in MB */
uint16_t rebuild_rate; /* rebuild rate as percentage */
uint16_t num_channels; /* number of channels or enclosures */
uint8_t *channel; /* channel/enclosure map */
uint16_t *channel; /* channel/enclosure map */
uint16_t num_physicals;
struct physical_drive_info *physical;
struct physical_drive_info **physical_list; /* ordered list of physical devices */

83
megactl.1 Normal file
View File

@ -0,0 +1,83 @@
.\" Text automatically generated by txt2man
.TH megactl 1 "03 March 2024" ""
.SH NAME
megactl \- diagnostics on megaraid adapters and attached disks.
.SH SYNOPSIS
megactl [\fB-vest\fP] [\fB-H\fP] [\fB-l\fP log-page-nr] [\fB-T\fP long|short] [target \.\.\.]
.PP
Reports diagnostics on megaraid adapters and attached disks. Permits
dumping of controller log pages for inspection of error, temperature,
and self-test conditions, initiates self-test diagnostics, and documents
adapter and logical drive configuration. Target devices may be adapters,
(e.g. a0), channels (e.g. a0c0), or individual disks (e.g. a0c0t0). If
no target is specified, reports configuration and drive state on all
adapters. If a target matches a collection of disks, operations are
applied to all matching devices. Options are:
.TP
.B
\fB-v\fP
Increase program verbosity.
.TP
.B
\fB-e\fP
Dump read (0x03), write (0x02), and verify (0x05) error log
pages.
.TP
.B
\fB-s\fP
Dump self-test (0x10) log page.
.TP
.B
\fB-t\fP
Dump temperature (0x0d) log page.
.TP
.B
\fB-l\fP page
Dump the specified log page. Log page 0 documents the log pages
the device supports.
.TP
.B
\fB-p\fP
Do not report physical disks. Reports only adapters and logical
drives. Useful for concisely documenting adapter configuration.
.TP
.B
\fB-T\fP test
Initiate the background short or long self-test procedure. The
test may take up to an hour to complete, but does not inhibit
access to the device. The test may be monitored using the \fB-s\fP
option.
.TP
.B
\fB-H\fP
Perform an adapter health check. Inspects state of all logical
and physical drives and battery backup unit and reports problem
conditions. If all is well, generates no output. Useful in a
cron job.
.TP
.B
\fB-B\fP
When performing health check, do not treat battery problems as
failures.
.TP
.B
\fB-V\fP
Show version.
.PP
N.B. The background long self test is a useful tool for diagnosing
problems with individual disks. But be cautious with program usage.
"megactl \fB-T\fP long" with no targets will initiate a background long self
test on every drive on every adapter. This may not be what you want.
.PP
By default, the health check option inspects log pages 0x02, 0x03, and
0x05 for uncorrected read, write, and verify errors, 0x0d for excess
temperature conditions, and 0x10 for failed self tests. If, however, any
of the log page options is specified, only the designated log pages are
inspected.
.PP
This program requires the device file /dev/megadev0 to be present on
the system. If your system does not have this device file, you may
create it either by executing Dell's "dellmgr" program once, or by
locating the megadev entry in /proc/devices and creating /dev/megadev0
as a character device with suitable permissions with a matching major
device number and a minor number of 0.

View File

@ -43,6 +43,8 @@ Cleaner log page output.
Fixes for 64-bit systems. Currently builds only with -m32.
Fetch TTY logs.
********************************************************************/
#include "mega.h"
@ -61,6 +63,8 @@ Fixes for 64-bit systems. Currently builds only with -m32.
#include <signal.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <scg/scsireg.h>
@ -72,17 +76,19 @@ Fixes for 64-bit systems. Currently builds only with -m32.
#ifdef MEGA_SAS_CTL
#define MEGA_DEVICE "/dev/megaraid_sas_ioctl_node"
#define MEGA_NAME "megaraid_sas_ioctl"
#else
#define MEGA_DEVICE "/dev/megadev0"
#define MEGA_NAME "megadev"
#define MEGA_MIN_VERSION 0x118c
#endif /* defined(MEGA_SAS_CTL) */
static char *version = "0.4.1";
static char *version = "0.4.3-hmage";
static int verbosity = 0;
@ -155,7 +161,7 @@ MEGA_DEVICE " as a character device with suitable",
};
void usage (const int ec, const char *format, ...)
static void usage (const int ec, const char *format, ...)
{
char **u;
va_list ap;
@ -205,14 +211,14 @@ static char *friendlySize (uint64_t b, char *unit)
int k;
static char bytes[128];
for (k = 0; (b >= 1024) && (k < sizeof (suffix) / sizeof (suffix[0]) - 1); ++k, b /= 1024)
for (k = 0; (b >= 10000) && (k < sizeof (suffix) / sizeof (suffix[0]) - 1); ++k, b /= 1024)
;
snprintf (bytes, sizeof bytes, "%3llu%s%s", b, suffix[k], unit);
snprintf (bytes, sizeof bytes, "%4"PRIu64"%s%s", b, suffix[k], unit);
return bytes;
}
void describePhysicalDrive (FILE *f, struct physical_drive_info *d, int verbosity)
static void describePhysicalDrive (FILE *f, struct physical_drive_info *d, int verbosity)
{
char *state;
@ -235,7 +241,7 @@ void describePhysicalDrive (FILE *f, struct physical_drive_info *d, int verbosit
fprintf (f, " %8s %-16s", d->vendor, d->model);
if (verbosity > 1)
fprintf (f, " rev:%-4s s/n:%-20s", d->revision, d->serial);
fprintf (f, " %7s", friendlySize (d->blocks << 9, "B"));
fprintf (f, " %8s", friendlySize (d->blocks << 9, "B"));
fprintf (f, " %5s%c", d->span && d->span->num_logical_drives ? d->span->logical_drive[0]->name : "", d->span && (d->span->num_logical_drives > 1) ? '+' : ' ');
fprintf (f, " %-8s", state);
if (d->media_errors || d->other_errors)
@ -248,7 +254,7 @@ void describePhysicalDrive (FILE *f, struct physical_drive_info *d, int verbosit
}
void describeLogicalDrive (FILE *f, struct logical_drive_info *l, int verbosity)
static void describeLogicalDrive (FILE *f, struct logical_drive_info *l, int verbosity)
{
char *state;
uint64_t blocks;
@ -273,11 +279,12 @@ void describeLogicalDrive (FILE *f, struct logical_drive_info *l, int verbosity)
case 0: blocks += r->blocks_per_disk * r->span->num_disks; break;
case 1: blocks += r->blocks_per_disk * r->span->num_disks / 2; break;
case 5: blocks += r->blocks_per_disk * (r->span->num_disks - 1); break;
case 6: blocks += r->blocks_per_disk * (r->span->num_disks - 2); break;
}
}
fprintf (f, "%-8s", l->name);
fprintf (f, " %s", friendlySize (blocks << 9, "B"));
fprintf (f, " %8s", friendlySize (blocks << 9, "B"));
fprintf (f, " RAID %u%s", l->raid_level, l->num_spans > 1 ? "0" : " ");
fprintf (f, " %2ux%-2u", l->num_spans, l->span_size);
fprintf (f, " %s", state);
@ -302,7 +309,7 @@ void describeLogicalDrive (FILE *f, struct logical_drive_info *l, int verbosity)
}
void describeBattery (FILE *f, struct adapter_config *a, int verbosity)
static void describeBattery (FILE *f, struct adapter_config *a, int verbosity)
{
if (a->battery.healthy)
fprintf (f, "good");
@ -339,7 +346,7 @@ void describeBattery (FILE *f, struct adapter_config *a, int verbosity)
}
void describeAdapter (FILE *f, struct adapter_config *a, int verbosity)
static void describeAdapter (FILE *f, struct adapter_config *a, int verbosity)
{
fprintf (f, "%-8s %-24s", a->name, a->product);
if (verbosity > 0)
@ -359,8 +366,8 @@ int main (int argc, char **argv)
{
int k;
int fd;
uint32_t driverVersion = 0;
uint32_t numAdapters;
uint32_t driverVersion;
int startSelfTest = -1;
int healthCheck = 0;
int checkBattery = 1;
@ -374,6 +381,11 @@ int main (int argc, char **argv)
uint8_t readLog[LOG_PAGE_MAX] = { 0, };
int reportPhysical = 1;
int showVersion = 0;
FILE *fp;
char *line = NULL;
int major;
size_t len = 0;
char lf;
#ifdef MEGA_SAS_CTL
int sas = 1;
#else
@ -586,11 +598,36 @@ int main (int argc, char **argv)
}
}
if ((fd = open (device, O_RDONLY)) < 0)
{
if ((fp = fopen ("/proc/devices", "r")) == NULL)
{
fprintf (stderr, "file /proc/devices access error\n");
return 1;
} else {
while (getline(&line, &len, fp) != -1)
{
if ((sscanf(line, "%d "MEGA_NAME"%c", &major, &lf) == 2) && (lf = 10))
{
mknod(device, S_IFCHR /*| 0666*/, makedev(major, 0));
free(line);
break;
}
if (line)
{
free(line);
line = NULL;
}
}
fclose(fp);
}
if ((fd = open (device, O_RDONLY)) < 0)
{
fprintf (stderr, "unable to open device %s: %s\n", device, strerror (errno));
return 1;
}
}
#ifndef MEGA_SAS_CTL
if (megaGetDriverVersion (fd, &driverVersion) < 0)
@ -608,7 +645,7 @@ int main (int argc, char **argv)
if (megaGetNumAdapters (fd, &numAdapters, sas) < 0)
{
fprintf (stderr, "unable to determine number of adapters: %s\n", megaErrorString ());
fprintf (stderr, "unable to find any adapters: %s\n", megaErrorString ());
return 1;
}

53
megactl.metainfo.xml Normal file
View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<component>
<id>com.github.namiltd.megactl</id>
<metadata_license>CC0-1.0</metadata_license>
<name>megactl</name>
<summary>LSI Megaraid Control and Monitoring Tools</summary>
<description>
<p>
Provide tools to query hard drive and RAID volume status from
PERC2, PERC3, PERC4 and PERC5 adapters.
</p>
</description>
<url type="homepage">https://github.com/namiltd/megactl/</url>
<developer_name>Mieczyslaw Nalewaj</developer_name>
<provides>
<modalias>lkmodule:megaraid</modalias>
<modalias>lkmodule:megaraid_sas</modalias>
<modalias>pci:v00001000d000010E7sv*</modalias>
<modalias>pci:v00001000d000010E4sv*</modalias>
<modalias>pci:v00001000d000010E3sv*</modalias>
<modalias>pci:v00001000d000010E0sv*</modalias>
<modalias>pci:v00001000d000010E6sv*</modalias>
<modalias>pci:v00001000d000010E5sv*</modalias>
<modalias>pci:v00001000d000010E2sv*</modalias>
<modalias>pci:v00001000d000010E1sv*</modalias>
<modalias>pci:v00001000d0000001Csv*</modalias>
<modalias>pci:v00001000d0000001Bsv*</modalias>
<modalias>pci:v00001000d00000017sv*</modalias>
<modalias>pci:v00001000d00000016sv*</modalias>
<modalias>pci:v00001000d00000015sv*</modalias>
<modalias>pci:v00001000d00000014sv*</modalias>
<modalias>pci:v00001000d00000053sv*</modalias>
<modalias>pci:v00001000d00000052sv*</modalias>
<modalias>pci:v00001000d000000CFsv*</modalias>
<modalias>pci:v00001000d000000CEsv*</modalias>
<modalias>pci:v00001000d0000005Fsv*</modalias>
<modalias>pci:v00001000d0000005Dsv*</modalias>
<modalias>pci:v00001000d0000002Fsv*</modalias>
<modalias>pci:v00001000d0000005Bsv*</modalias>
<modalias>pci:v00001028d00000015sv*</modalias>
<modalias>pci:v00001000d00000413sv*</modalias>
<modalias>pci:v00001000d00000071sv*</modalias>
<modalias>pci:v00001000d00000073sv*</modalias>
<modalias>pci:v00001000d00000079sv*</modalias>
<modalias>pci:v00001000d00000078sv*</modalias>
<modalias>pci:v00001000d0000007Csv*</modalias>
<modalias>pci:v00001000d00000060sv*</modalias>
<modalias>pci:v00001000d00000411sv*</modalias>
<modalias>pci:v00008086d00001960sv*</modalias>
<modalias>pci:v0000101Ed00009060sv*</modalias>
<modalias>pci:v0000101Ed00009010sv*</modalias>
</provides>
</component>

View File

@ -25,6 +25,7 @@
/* Don't include <sys/types.h> */
#include <assert.h>
#include <memory.h>
#include <malloc.h>
#include <errno.h>
@ -32,9 +33,30 @@
#include <scsi/scsi.h>
/* This is arbitrary. */
#define MEGA_MAX_ADAPTERS 16
struct mega_adapter_map
{
uint8_t count; /* number of adapters found */
uint8_t host[MEGA_MAX_ADAPTERS]; /* map of adapter index to host number */
};
static struct mega_adapter_map *adapterMap = NULL;
int megaErrno = 0;
static u16 hostMap (u16 adapno)
{
if ((adapterMap == NULL) || (adapno >= adapterMap->count))
return 0;
return adapterMap->host[adapno];
}
static int doIoctl (struct mega_adapter_path *adapter, void *u)
{
switch (adapter->type)
@ -49,7 +71,7 @@ static int doIoctl (struct mega_adapter_path *adapter, void *u)
}
static int driverQuery (int fd, uint16_t adap, void *data, uint32_t len, uint8_t subop)
static int driverQuery (int fd, void *data, uint32_t len, uint8_t subop)
{
struct uioctl_t u;
struct mega_adapter_path adapter;
@ -64,6 +86,7 @@ static int driverQuery (int fd, uint16_t adap, void *data, uint32_t len, uint8_t
memset (data, 0, len);
adapter.fd = fd;
adapter.adapno = 0;
adapter.type = MEGA_ADAPTER_V34;
if (doIoctl (&adapter, &u) < 0)
{
@ -82,11 +105,12 @@ static int oldCommand (struct mega_adapter_path *adapter, void *data, uint32_t l
memset (&u, 0, sizeof u);
u.outlen = len;
u.ui.fcs.opcode = M_RD_IOCTL_CMD;
u.ui.fcs.adapno = MKADAP(adapter->adapno);
u.ui.fcs.adapno = MKADAP(hostMap (adapter->adapno));
u.data = data;
m->cmd = cmd;
m->opcode = opcode;
m->subopcode = subopcode;
assert(UINT32_MAX > (uint32_t) data);
m->xferaddr = (uint32_t) data;
if (data)
memset (data, 0, len);
@ -108,13 +132,14 @@ static int newCommand (struct mega_adapter_path *adapter, void *data, uint32_t l
memset (&u, 0, sizeof u);
u.outlen = len;
u.ui.fcs.opcode = M_RD_IOCTL_CMD_NEW;
u.ui.fcs.adapno = MKADAP(adapter->adapno);
u.ui.fcs.adapno = MKADAP(hostMap (adapter->adapno));
u.ui.fcs.buffer = data;
u.ui.fcs.length = len;
u.data = data;
m->cmd = cmd;
m->opcode = opcode;
m->subopcode = subopcode;
assert(UINT32_MAX > (uint32_t) data);
m->xferaddr = (uint32_t) data;
if (data)
memset (data, 0, len);
@ -134,7 +159,7 @@ static int sasCommand (struct mega_adapter_path *adapter, void *data, uint32_t l
struct megasas_dcmd_frame *f = (struct megasas_dcmd_frame *) &u.frame;
memset (&u, 0, sizeof u);
u.host_no = (u16) adapter->adapno;
u.host_no = hostMap (adapter->adapno);
f->cmd = MFI_CMD_DCMD;
f->flags = (u16) flags;
@ -147,6 +172,7 @@ static int sasCommand (struct mega_adapter_path *adapter, void *data, uint32_t l
u.sgl[0].iov_base = data;
u.sgl[0].iov_len = len;
f->sge_count = 1;
assert(UINT32_MAX > (uint32_t) data);
f->data_xfer_len = (u32) len;
f->sgl.sge32[0].phys_addr = (u32) data;
f->sgl.sge32[0].length = (u32) len;
@ -175,13 +201,15 @@ static int passthruCommand (struct mega_adapter_path *adapter, void *data, uint3
memset (&u, 0, sizeof u);
u.outlen = len;
u.ui.fcs.opcode = M_RD_IOCTL_CMD;
u.ui.fcs.adapno = MKADAP(adapter->adapno);
u.ui.fcs.adapno = MKADAP(hostMap (adapter->adapno));
u.data = data;
m->cmd = MBOXCMD_PASSTHRU;
assert(UINT32_MAX > (uint32_t) p);
m->xferaddr = (uint32_t) p;
p->timeout = 3;
p->ars = 1;
p->target = target;
assert(UINT32_MAX > (uint32_t) data);
p->dataxferaddr = (uint32_t) data;
p->dataxferlen = len;
p->scsistatus = 239; /* HMMM */
@ -219,7 +247,7 @@ static int passthruCommand (struct mega_adapter_path *adapter, void *data, uint3
struct megasas_pthru_frame *f = (struct megasas_pthru_frame *) &u.frame;
memset (&u, 0, sizeof u);
u.host_no = (u16) adapter->adapno;
u.host_no = hostMap (adapter->adapno);
f->cmd = MFI_CMD_PD_SCSI_IO;
f->target_id = target;
@ -235,6 +263,7 @@ static int passthruCommand (struct mega_adapter_path *adapter, void *data, uint3
u.sgl[0].iov_len = len;
f->sge_count = 1;
assert(UINT32_MAX > (uint32_t) len);
f->data_xfer_len = (u32) len;
f->sgl.sge32[0].phys_addr = (u32) data;
f->sgl.sge32[0].length = (u32) len;
@ -386,7 +415,7 @@ int megaGetDriveErrorCount (struct mega_adapter_path *adapter, uint8_t target, s
int megaSasGetDeviceList (struct mega_adapter_path *adapter, struct mega_device_list_sas **data)
{
unsigned char buf[0x20];
unsigned char buf[sizeof(struct mega_device_list_sas)];
uint32_t len;
if (sasCommand (adapter, buf, sizeof buf, 0x02010000, MFI_FRAME_DIR_READ, NULL, 0) < 0)
@ -451,23 +480,55 @@ int megaSasGetBatteryInfo (struct mega_adapter_path *adapter, struct mega_batter
int megaGetDriverVersion (int fd, uint32_t *version)
{
return driverQuery (fd, 0, version, sizeof (*version), 'e');
return driverQuery (fd, version, sizeof (*version), 'e');
}
int megaGetNumAdapters (int fd, uint32_t *numAdapters, int sas)
{
static struct mega_adapter_map realMap;
uint8_t k;
uint8_t count;
if (sas)
{
uint8_t k;
for (k = 0; k < 16; ++k)
if (megaSasAdapterPing (fd, k) < 0)
break;
*numAdapters = k;
return 0;
if (adapterMap == NULL)
{
struct mega_adapter_map fakeMap;
/* initialize fake map to 1-to-1 map */
for (k = 0; k < MEGA_MAX_ADAPTERS; ++k)
fakeMap.host[k] = k;
fakeMap.count = k;
adapterMap = &fakeMap;
/* ping all possible adapters to build real map */
count = 0;
for (k = 0; k < MEGA_MAX_ADAPTERS; ++k)
if (megaSasAdapterPing (fd, k) >= 0)
realMap.host[count++] = k;
realMap.count = count;
adapterMap = &realMap;
}
}
else
return driverQuery (fd, 0, numAdapters, sizeof (*numAdapters), 'm');
{
if (adapterMap == NULL)
{
if (driverQuery (fd, &count, sizeof (count), 'm') < 0)
return -1;
if (count > MEGA_MAX_ADAPTERS)
count = MEGA_MAX_ADAPTERS;
for (k = 0; k < count; ++k)
realMap.host[k] = k;
realMap.count = count;
adapterMap = &realMap;
}
}
*numAdapters = adapterMap->count;
return 0;
}

View File

@ -60,6 +60,10 @@ struct uioctl_t {
#pragma pack()
/* Timestamps in the megaraid_sas event log are offset by this quantity. This is the epoch time of 2000-01-01T00:00:00 +0000. */
#define MEGA_SAS_TIME_OFFSET 0x386d4380
extern int megaErrno;
extern int megaScsiDriveInquiry (struct mega_adapter_path *adapter, uint8_t target, void *data, uint32_t len, uint8_t pageCode, uint8_t evpd);
@ -80,7 +84,10 @@ extern int megaSasGetArrayConfig (struct mega_adapter_path *adapter, struct mega
extern int megaSasGetBatteryInfo (struct mega_adapter_path *adapter, struct mega_battery_info_sas *data);
extern int megaGetDriverVersion (int fd, uint32_t *version);
/* You must call megaGetNumAdapters() before you issue any other inquiries, other than megaGetDriverVersion(). */
extern int megaGetNumAdapters (int fd, uint32_t *numAdapters, int sas);
extern int megaGetAdapterProductInfo (int fd, uint8_t adapno, mraid_pinfo_t *info);
extern int megaSasGetAdapterProductInfo (int fd, uint8_t adapno, struct megasas_ctrl_info *info);
extern int megaSasAdapterPing (int fd, uint8_t adapno);

83
megasasctl.1 Normal file
View File

@ -0,0 +1,83 @@
.\" Text automatically generated by txt2man
.TH megasasctl 1 "03 March 2024" ""
.SH NAME
megasasctl \- diagnostics on megaraid adapters and attached disks.
.SH SYNOPSIS
megasasctl [\fB-vest\fP] [\fB-H\fP] [\fB-l\fP log-page-nr] [\fB-T\fP long|short] [target \.\.\.]
.PP
Reports diagnostics on megaraid adapters and attached disks. Permits
dumping of controller log pages for inspection of error, temperature,
and self-test conditions, initiates self-test diagnostics, and documents
adapter and logical drive configuration. Target devices may be adapters,
(e.g. a0), enclosures (e.g. a0e0), or individual disks (e.g. a0e0s0). If
no target is specified, reports configuration and drive state on all
adapters. If a target matches a collection of disks, operations are
applied to all matching devices. Options are:
.TP
.B
\fB-v\fP
Increase program verbosity.
.TP
.B
\fB-e\fP
Dump read (0x03), write (0x02), and verify (0x05) error log
pages.
.TP
.B
\fB-s\fP
Dump self-test (0x10) log page.
.TP
.B
\fB-t\fP
Dump temperature (0x0d) log page.
.TP
.B
\fB-l\fP page
Dump the specified log page. Log page 0 documents the log pages
the device supports.
.TP
.B
\fB-p\fP
Do not report physical disks. Reports only adapters and logical
drives. Useful for concisely documenting adapter configuration.
.TP
.B
\fB-T\fP test
Initiate the background short or long self-test procedure. The
test may take up to an hour to complete, but does not inhibit
access to the device. The test may be monitored using the \fB-s\fP
option.
.TP
.B
\fB-H\fP
Perform an adapter health check. Inspects state of all logical
and physical drives and battery backup unit and reports problem
conditions. If all is well, generates no output. Useful in a
cron job.
.TP
.B
\fB-B\fP
When performing health check, do not treat battery problems as
failures.
.TP
.B
\fB-V\fP
Show version.
.PP
N.B. The background long self test is a useful tool for diagnosing
problems with individual disks. But be cautious with program usage.
"megasasctl \fB-T\fP long" with no targets will initiate a background long self
test on every drive on every adapter. This may not be what you want.
.PP
By default, the health check option inspects log pages 0x02, 0x03, and
0x05 for uncorrected read, write, and verify errors, 0x0d for excess
temperature conditions, and 0x10 for failed self tests. If, however, any
of the log page options is specified, only the designated log pages are
inspected.
.PP
This program requires the device file /dev/megaraid_sas_ioctl_node to be
present on the system. If your system does not have this device file,
you may create it either by executing LSI's "MegaCli" program once,
or by locating the megadev_sas_ioctl entry in /proc/devices and creating
/dev/megaraid_sas_ioctl_node as a character device with suitable
permissions with a matching major device number and a minor number of 0.

View File

@ -63,7 +63,7 @@ Fixes for 64-bit systems.
enum state { UNTRACED, INBOUND, OUTBOUND };
void copyout (void *buf, size_t len, pid_t pid, uint32_t addr)
static inline void copyout (void *buf, size_t len, pid_t pid, uint32_t addr)
{
off_t k;
uint32_t *z = (uint32_t *) buf;
@ -77,7 +77,7 @@ void copyout (void *buf, size_t len, pid_t pid, uint32_t addr)
}
void copyin (void *buf, size_t len, pid_t pid, uint32_t addr)
static inline void copyin (void *buf, size_t len, pid_t pid, uint32_t addr)
{
off_t k;
uint32_t *z = (uint32_t *) buf;