Compare commits
11 Commits
191eba7834
...
cfe47daa9a
Author | SHA1 | Date | |
---|---|---|---|
|
cfe47daa9a | ||
|
64807cf811 | ||
|
fa0d36dc5b | ||
|
5874481e38 | ||
|
0795bec8ef | ||
|
43e942c2b5 | ||
|
8fae4f9e81 | ||
|
c617d59dcb | ||
|
ce791a790d | ||
|
8a4c5cc630 | ||
|
05d4ad85da |
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
custom: [https://www.buymeacoffee.com/namiltd]
|
62
.github/workflows/codeql-analysis.yml
vendored
Normal file
62
.github/workflows/codeql-analysis.yml
vendored
Normal 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
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
*.o
|
||||
/megatrace
|
||||
/megactl
|
||||
/megasasctl
|
@ -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
|
||||
|
@ -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,7 +193,10 @@ struct physical_drive_info *getPhysicalDriveInfo (struct adapter_config *a, uint
|
||||
d->channel = info->enclosure;
|
||||
d->id = info->slot;
|
||||
|
||||
snprintf (d->name, sizeof (d->name), "%se%us%u", a->name, d->channel, d->id);
|
||||
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;
|
||||
strncpy (d->vendor, d->inquiry.vendor_info, sizeof (d->vendor) - 1);
|
||||
@ -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));
|
@ -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;
|
@ -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
83
megactl.1
Normal 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.
|
@ -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);
|
||||
@ -290,7 +297,7 @@ void describeLogicalDrive (FILE *f, struct logical_drive_info *l, int verbosity)
|
||||
int j;
|
||||
|
||||
r = &l->span[k];
|
||||
fprintf (f, " row %2d:", k);
|
||||
fprintf (f, " row %2d:", k);
|
||||
for (j = 0, p = r->span->disk; j < r->span->num_disks; ++j, ++p)
|
||||
{
|
||||
char *flag = (*p)->state != PdStateOnline ? "*" : " ";
|
||||
@ -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
|
||||
@ -588,8 +600,33 @@ int main (int argc, char **argv)
|
||||
|
||||
if ((fd = open (device, O_RDONLY)) < 0)
|
||||
{
|
||||
fprintf (stderr, "unable to open device %s: %s\n", device, strerror (errno));
|
||||
return 1;
|
||||
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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -806,9 +843,9 @@ int main (int argc, char **argv)
|
||||
if (d->state == PdStateHotspare)
|
||||
{
|
||||
if (x == 0)
|
||||
fprintf (stdout, "hot spares :");
|
||||
fprintf (stdout, "hot spares :");
|
||||
else if ((x % 8) == 0)
|
||||
fprintf (stdout, " :");
|
||||
fprintf (stdout, " :");
|
||||
fprintf (stdout, " %-8s", d->name);
|
||||
if (((++x) % 8) == 0)
|
||||
fprintf (stdout, "\n");
|
||||
@ -830,9 +867,9 @@ int main (int argc, char **argv)
|
||||
if ((!(d->span)) && (d->state != PdStateHotspare))
|
||||
{
|
||||
if (x == 0)
|
||||
fprintf (stdout, "unconfigured :");
|
||||
fprintf (stdout, "unconfigured:");
|
||||
else if ((x % 8) == 0)
|
||||
fprintf (stdout, " :");
|
||||
fprintf (stdout, " :");
|
||||
fprintf (stdout, " %-8s", d->name);
|
||||
if (((++x) % 8) == 0)
|
||||
fprintf (stdout, "\n");
|
53
megactl.metainfo.xml
Normal file
53
megactl.metainfo.xml
Normal 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>
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
83
megasasctl.1
Normal 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.
|
@ -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;
|
Loading…
x
Reference in New Issue
Block a user