/* * Intel(R) Enclosure LED Utilities * Copyright (C) 2009-2019 Intel Corporation. * * 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 #if _HAVE_DMALLOC_H #include #endif #include "ahci.h" #include "config.h" #include "utils.h" /** * Time interval in nano seconds to wait before enclosure management message * is being sent to AHCI controller. */ #define EM_MSG_WAIT 1500000 /* 0.0015 seconds */ /** * This array maps IBPI pattern to value recognized by AHCI driver. The driver * uses this control number to issue SGPIO signals appropriately. */ static const unsigned int ibpi2sgpio[] = { [IBPI_PATTERN_REBUILD] = 0x00480000, [IBPI_PATTERN_FAILED_DRIVE] = 0x00400000, [IBPI_PATTERN_LOCATE] = 0x00080000, [IBPI_PATTERN_UNKNOWN] = 0x00000000, [IBPI_PATTERN_ONESHOT_NORMAL] = 0x00000000, [IBPI_PATTERN_NORMAL] = 0x00000000, [IBPI_PATTERN_LOCATE_OFF] = 0x00000000, #ifdef DEBUG_IBPI [IBPI_PATTERN_DEGRADED] = 0x00200000, [IBPI_PATTERN_FAILED_ARRAY] = 0x00280000, [IBPI_PATTERN_HOTSPARE] = 0x01800000, [IBPI_PATTERN_PFA] = 0x01400000 #else [IBPI_PATTERN_DEGRADED] = 0x00000000, [IBPI_PATTERN_FAILED_ARRAY] = 0x00000000, [IBPI_PATTERN_HOTSPARE] = 0x00000000, [IBPI_PATTERN_PFA] = 0x00000000 #endif }; /* * The function sends a LED control message to AHCI controller. It uses * SGPIO to control the LEDs. See ahci.h for details. */ int ahci_sgpio_write(struct block_device *device, enum ibpi_pattern ibpi) { char temp[WRITE_BUFFER_SIZE]; char path[PATH_MAX]; char *sysfs_path = device->cntrl_path; const struct timespec waittime = { .tv_sec = 0, .tv_nsec = EM_MSG_WAIT }; /* write only if state has changed */ if (ibpi == device->ibpi_prev) return 1; if (sysfs_path == NULL) __set_errno_and_return(EINVAL); if ((ibpi < IBPI_PATTERN_NORMAL) || (ibpi > IBPI_PATTERN_LOCATE_OFF)) __set_errno_and_return(ERANGE); sprintf(temp, "%u", ibpi2sgpio[ibpi]); snprintf(path, sizeof(path), "%s/em_message", sysfs_path); nanosleep(&waittime, NULL); return buf_write(path, temp) > 0; } #define SCSI_HOST "/scsi_host" /* * The function return path to SATA port in sysfs tree. See ahci.h for details. */ char *ahci_get_port_path(const char *path) { char *p; char tmp[PATH_MAX]; char *buf; size_t buf_size; p = strstr(path, "/target"); if (p == NULL) return NULL; if (sizeof(tmp) <= (p - path)) return NULL; strncpy(tmp, path, p - path); tmp[p - path] = '\0'; p = strrchr(tmp, PATH_DELIM); if (p == NULL) return NULL; buf_size = strlen(tmp) + strlen(p) + strlen(SCSI_HOST) + 1; buf = malloc(buf_size); if (buf == NULL) return NULL; snprintf(buf, buf_size, "%s%s%s", tmp, SCSI_HOST, p); return buf; }