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