|
Packit |
7e09eb |
/*
|
|
Packit |
7e09eb |
* Dell Backplane LED control
|
|
Packit |
7e09eb |
* Copyright (C) 2011, Dell Inc.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This program is free software; you can redistribute it and/or modify it
|
|
Packit |
7e09eb |
* under the terms and conditions of the GNU General Public License,
|
|
Packit |
7e09eb |
* version 2, as published by the Free Software Foundation.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
Packit |
7e09eb |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
Packit |
7e09eb |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
Packit |
7e09eb |
* more details.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* You should have received a copy of the GNU General Public License along with
|
|
Packit |
7e09eb |
* this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit |
7e09eb |
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
#include <errno.h>
|
|
Packit |
7e09eb |
#include <fcntl.h>
|
|
Packit |
7e09eb |
#include <limits.h>
|
|
Packit |
7e09eb |
#include <stdint.h>
|
|
Packit |
7e09eb |
#include <stdio.h>
|
|
Packit |
7e09eb |
#include <stdlib.h>
|
|
Packit |
7e09eb |
#include <string.h>
|
|
Packit |
7e09eb |
#include <unistd.h>
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
#include <sys/ioctl.h>
|
|
Packit |
7e09eb |
#include <linux/ipmi.h>
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
#if _HAVE_DMALLOC_H
|
|
Packit |
7e09eb |
#include <dmalloc.h>
|
|
Packit |
7e09eb |
#endif
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
#include "ahci.h"
|
|
Packit |
7e09eb |
#include "cntrl.h"
|
|
Packit |
7e09eb |
#include "config.h"
|
|
Packit |
7e09eb |
#include "dellssd.h"
|
|
Packit |
7e09eb |
#include "ibpi.h"
|
|
Packit |
7e09eb |
#include "list.h"
|
|
Packit |
7e09eb |
#include "raid.h"
|
|
Packit |
7e09eb |
#include "scsi.h"
|
|
Packit |
7e09eb |
#include "slave.h"
|
|
Packit |
7e09eb |
#include "smp.h"
|
|
Packit |
7e09eb |
#include "status.h"
|
|
Packit |
7e09eb |
#include "sysfs.h"
|
|
Packit |
7e09eb |
#include "utils.h"
|
|
Packit |
7e09eb |
#include "ipmi.h"
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
#define BP_PRESENT (1L << 0)
|
|
Packit |
7e09eb |
#define BP_ONLINE (1L << 1)
|
|
Packit |
7e09eb |
#define BP_HOTSPARE (1L << 2)
|
|
Packit |
7e09eb |
#define BP_IDENTIFY (1L << 3)
|
|
Packit |
7e09eb |
#define BP_REBUILDING (1L << 4)
|
|
Packit |
7e09eb |
#define BP_FAULT (1L << 5)
|
|
Packit |
7e09eb |
#define BP_PREDICT (1L << 6)
|
|
Packit |
7e09eb |
#define BP_CRITICALARRAY (1L << 9)
|
|
Packit |
7e09eb |
#define BP_FAILEDARRAY (1L << 10)
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static const unsigned int ibpi2ssd[] = {
|
|
Packit |
7e09eb |
[IBPI_PATTERN_UNKNOWN] = BP_ONLINE,
|
|
Packit |
7e09eb |
[IBPI_PATTERN_ONESHOT_NORMAL] = BP_ONLINE,
|
|
Packit |
7e09eb |
[IBPI_PATTERN_NORMAL] = BP_ONLINE,
|
|
Packit |
7e09eb |
[IBPI_PATTERN_DEGRADED] = BP_CRITICALARRAY|BP_ONLINE,
|
|
Packit |
7e09eb |
[IBPI_PATTERN_REBUILD] = BP_REBUILDING|BP_ONLINE,
|
|
Packit |
7e09eb |
[IBPI_PATTERN_FAILED_ARRAY] = BP_FAILEDARRAY|BP_ONLINE,
|
|
Packit |
7e09eb |
[IBPI_PATTERN_HOTSPARE] = BP_HOTSPARE|BP_ONLINE,
|
|
Packit |
7e09eb |
[IBPI_PATTERN_PFA] = BP_PREDICT|BP_ONLINE,
|
|
Packit |
7e09eb |
[IBPI_PATTERN_FAILED_DRIVE] = BP_FAULT|BP_ONLINE,
|
|
Packit |
7e09eb |
[IBPI_PATTERN_LOCATE] = BP_IDENTIFY|BP_ONLINE,
|
|
Packit |
7e09eb |
[IBPI_PATTERN_LOCATE_OFF] = BP_ONLINE
|
|
Packit |
7e09eb |
};
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
#define DELL_OEM_NETFN 0x30
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
#define DELL_OEM_STORAGE_CMD 0xD5
|
|
Packit |
7e09eb |
#define DELL_OEM_STORAGE_GETDRVMAP_12G 0x07
|
|
Packit |
7e09eb |
#define DELL_OEM_STORAGE_SETDRVSTATUS_12G 0x04
|
|
Packit |
7e09eb |
#define DELL_OEM_STORAGE_GETDRVMAP_13G 0x17
|
|
Packit |
7e09eb |
#define DELL_OEM_STORAGE_SETDRVSTATUS_13G 0x14
|
|
Packit |
7e09eb |
#define DELL_OEM_STORAGE_GETDRVMAP_14G 0x37
|
|
Packit |
7e09eb |
#define DELL_OEM_STORAGE_SETDRVSTATUS_14G 0x34
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
#define APP_NETFN 0x06
|
|
Packit |
7e09eb |
#define APP_GET_SYSTEM_INFO 0x59
|
|
Packit |
7e09eb |
#define DELL_GET_IDRAC_INFO 0xDD
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
enum {
|
|
Packit |
7e09eb |
DELL_12G_MONOLITHIC = 0x10,
|
|
Packit |
7e09eb |
DELL_12G_MODULAR = 0x11,
|
|
Packit |
7e09eb |
DELL_13G_MONOLITHIC = 0x20,
|
|
Packit |
7e09eb |
DELL_13G_MODULAR = 0x21,
|
|
Packit |
7e09eb |
DELL_14G_MONOLITHIC = 0x30,
|
|
Packit |
7e09eb |
DELL_14G_MODULAR = 0x31,
|
|
Packit |
7e09eb |
};
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
int get_dell_server_type()
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
static int gen;
|
|
Packit |
7e09eb |
uint8_t data[4], rdata[20];
|
|
Packit |
7e09eb |
int rc, rlen;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* Don't requery if we already know have ID */
|
|
Packit |
7e09eb |
if (gen)
|
|
Packit |
7e09eb |
return gen;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* Get Dell Generation */
|
|
Packit |
7e09eb |
memset(data, 0, sizeof(data));
|
|
Packit |
7e09eb |
memset(rdata, 0, sizeof(rdata));
|
|
Packit |
7e09eb |
data[0] = 0x00;
|
|
Packit |
7e09eb |
data[1] = DELL_GET_IDRAC_INFO;
|
|
Packit |
7e09eb |
data[2] = 0x02;
|
|
Packit |
7e09eb |
data[3] = 0x00;
|
|
Packit |
7e09eb |
rc = ipmicmd(BMC_SA, 0, APP_NETFN, APP_GET_SYSTEM_INFO, 4, data,
|
|
Packit |
7e09eb |
20, &rlen, rdata);
|
|
Packit |
7e09eb |
if (rc) {
|
|
Packit |
7e09eb |
log_debug("Unable to issue IPMI command GetSystemInfo\n");
|
|
Packit |
7e09eb |
return 0;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
switch (rdata[10]) {
|
|
Packit |
7e09eb |
case DELL_12G_MONOLITHIC:
|
|
Packit |
7e09eb |
case DELL_12G_MODULAR:
|
|
Packit |
7e09eb |
case DELL_13G_MONOLITHIC:
|
|
Packit |
7e09eb |
case DELL_13G_MODULAR:
|
|
Packit |
7e09eb |
case DELL_14G_MONOLITHIC:
|
|
Packit |
7e09eb |
case DELL_14G_MODULAR:
|
|
Packit |
7e09eb |
gen = rdata[10];
|
|
Packit |
7e09eb |
return gen;
|
|
Packit |
7e09eb |
default:
|
|
Packit |
7e09eb |
log_debug("Unable to determine Dell Server type\n");
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
return 0;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static int ipmi_setled(int b, int d, int f, int state)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
uint8_t data[20], rdata[20];
|
|
Packit |
7e09eb |
int rc, rlen, bay = 0xFF, slot = 0xFF, devfn, gen = 0;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* Check if this is a supported Dell server */
|
|
Packit |
7e09eb |
gen = get_dell_server_type();
|
|
Packit |
7e09eb |
if (!gen)
|
|
Packit |
7e09eb |
return 0;
|
|
Packit |
7e09eb |
devfn = (((d & 0x1F) << 3) | (f & 0x7));
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* Get mapping of BDF to bay:slot */
|
|
Packit |
7e09eb |
memset(data, 0, sizeof(data));
|
|
Packit |
7e09eb |
memset(rdata, 0, sizeof(rdata));
|
|
Packit |
7e09eb |
data[0] = 0x01; /* get */
|
|
Packit |
7e09eb |
data[2] = 0x06; /* length lsb */
|
|
Packit |
7e09eb |
data[3] = 0x00; /* length msb */
|
|
Packit |
7e09eb |
data[4] = 0x00; /* offset lsb */
|
|
Packit |
7e09eb |
data[5] = 0x00; /* offset msb */
|
|
Packit |
7e09eb |
data[6] = b; /* bus */
|
|
Packit |
7e09eb |
data[7] = devfn; /* devfn */
|
|
Packit |
7e09eb |
switch (gen) {
|
|
Packit |
7e09eb |
case DELL_12G_MONOLITHIC:
|
|
Packit |
7e09eb |
case DELL_12G_MODULAR:
|
|
Packit |
7e09eb |
data[1] = DELL_OEM_STORAGE_GETDRVMAP_12G;
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
case DELL_13G_MONOLITHIC:
|
|
Packit |
7e09eb |
case DELL_13G_MODULAR:
|
|
Packit |
7e09eb |
data[1] = DELL_OEM_STORAGE_GETDRVMAP_13G;
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
case DELL_14G_MONOLITHIC:
|
|
Packit |
7e09eb |
case DELL_14G_MODULAR:
|
|
Packit |
7e09eb |
data[1] = DELL_OEM_STORAGE_GETDRVMAP_14G;
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
rc = ipmicmd(BMC_SA, 0, DELL_OEM_NETFN, DELL_OEM_STORAGE_CMD, 8, data,
|
|
Packit |
7e09eb |
20, &rlen, rdata);
|
|
Packit |
7e09eb |
if (!rc) {
|
|
Packit |
7e09eb |
bay = rdata[7];
|
|
Packit |
7e09eb |
slot = rdata[8];
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
if (bay == 0xFF || slot == 0xFF) {
|
|
Packit |
7e09eb |
log_error("Unable to determine bay/slot for device %.2x:%.2x.%x\n",
|
|
Packit |
7e09eb |
b, d, f);
|
|
Packit |
7e09eb |
return 0;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* Set Bay:Slot to Mask */
|
|
Packit |
7e09eb |
memset(data, 0, sizeof(data));
|
|
Packit |
7e09eb |
memset(rdata, 0, sizeof(rdata));
|
|
Packit |
7e09eb |
data[0] = 0x00; /* set */
|
|
Packit |
7e09eb |
data[2] = 0x0e; /* length lsb */
|
|
Packit |
7e09eb |
data[3] = 0x00; /* length msb */
|
|
Packit |
7e09eb |
data[4] = 0x00; /* offset lsb */
|
|
Packit |
7e09eb |
data[5] = 0x00; /* offset msb */
|
|
Packit |
7e09eb |
data[6] = 0x0e; /* length lsb */
|
|
Packit |
7e09eb |
data[7] = 0x00; /* length msb */
|
|
Packit |
7e09eb |
data[8] = bay; /* bayid */
|
|
Packit |
7e09eb |
data[9] = slot; /* slotid */
|
|
Packit |
7e09eb |
data[10] = state & 0xff; /* state LSB */
|
|
Packit |
7e09eb |
data[11] = state >> 8; /* state MSB */
|
|
Packit |
7e09eb |
switch (gen) {
|
|
Packit |
7e09eb |
case DELL_12G_MONOLITHIC:
|
|
Packit |
7e09eb |
case DELL_12G_MODULAR:
|
|
Packit |
7e09eb |
data[1] = DELL_OEM_STORAGE_SETDRVSTATUS_12G;
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
case DELL_13G_MONOLITHIC:
|
|
Packit |
7e09eb |
case DELL_13G_MODULAR:
|
|
Packit |
7e09eb |
data[1] = DELL_OEM_STORAGE_SETDRVSTATUS_13G;
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
case DELL_14G_MONOLITHIC:
|
|
Packit |
7e09eb |
case DELL_14G_MODULAR:
|
|
Packit |
7e09eb |
data[1] = DELL_OEM_STORAGE_SETDRVSTATUS_14G;
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
rc = ipmicmd(BMC_SA, 0, DELL_OEM_NETFN, DELL_OEM_STORAGE_CMD, 20, data,
|
|
Packit |
7e09eb |
20, &rlen, rdata);
|
|
Packit |
7e09eb |
if (rc) {
|
|
Packit |
7e09eb |
log_error("Unable to issue SetDriveState for %.2x:%.2x.%x\n",
|
|
Packit |
7e09eb |
b,d,f);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
return 0;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
char *dellssd_get_path(const char *cntrl_path)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
return str_dup(cntrl_path);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
int dellssd_write(struct block_device *device, enum ibpi_pattern ibpi)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
unsigned int mask, bus, dev, fun;
|
|
Packit |
7e09eb |
char *t;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* write only if state has changed */
|
|
Packit |
7e09eb |
if (ibpi == device->ibpi_prev)
|
|
Packit |
7e09eb |
return 1;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if ((ibpi < IBPI_PATTERN_NORMAL) || (ibpi > IBPI_PATTERN_LOCATE_OFF))
|
|
Packit |
7e09eb |
__set_errno_and_return(ERANGE);
|
|
Packit |
7e09eb |
mask = ibpi2ssd[ibpi];
|
|
Packit |
7e09eb |
t = strrchr(device->cntrl_path, '/');
|
|
Packit |
7e09eb |
if (t != NULL) {
|
|
Packit |
7e09eb |
/* Extract PCI bus:device.function */
|
|
Packit |
7e09eb |
if (sscanf(t + 1, "%*x:%x:%x.%x", &bus, &dev, &fun) == 3)
|
|
Packit |
7e09eb |
ipmi_setled(bus, dev, fun, mask);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
return 0;
|
|
Packit |
7e09eb |
}
|