Blame src/dellssd.c

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
}