Blame src/scsi.c

Packit 7e09eb
/*
Packit 7e09eb
 * Intel(R) Enclosure LED Utilities
Packit Service cb68d2
 * Copyright (C) 2009-2021 Intel Corporation.
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 <dirent.h>
Packit 7e09eb
#include <errno.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
#if _HAVE_DMALLOC_H
Packit 7e09eb
#include <dmalloc.h>
Packit 7e09eb
#endif
Packit 7e09eb
Packit 7e09eb
#include "cntrl.h"
Packit 7e09eb
#include "config.h"
Packit 7e09eb
#include "enclosure.h"
Packit 7e09eb
#include "list.h"
Packit 7e09eb
#include "scsi.h"
Packit 7e09eb
#include "ses.h"
Packit 7e09eb
#include "status.h"
Packit 7e09eb
#include "sysfs.h"
Packit 7e09eb
#include "utils.h"
Packit 7e09eb
Packit 7e09eb
static char *get_drive_end_dev(const char *path)
Packit 7e09eb
{
Packit 7e09eb
	char *s, *c, *p;
Packit 7e09eb
Packit 7e09eb
	c = strstr(path, "end_device");
Packit 7e09eb
	if (!c)
Packit 7e09eb
		return NULL;
Packit 7e09eb
	s = strchr(c, '/');
Packit 7e09eb
	if (!s)
Packit 7e09eb
		return NULL;
Packit 7e09eb
	p = calloc(s - c + 1, sizeof(*p));
Packit 7e09eb
	if (!p)
Packit 7e09eb
		return NULL;
Packit 7e09eb
Packit 7e09eb
	strncpy(p, c, s - c);
Packit 7e09eb
	return p;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static uint64_t get_drive_sas_addr(const char *path)
Packit 7e09eb
{
Packit 7e09eb
	uint64_t ret = 0;
Packit 7e09eb
	size_t size = strlen(path) * 2;
Packit 7e09eb
	char *buff, *end_dev;
Packit 7e09eb
Packit 7e09eb
	/* Make big buffer. */
Packit 7e09eb
	buff = malloc(size + 1);
Packit 7e09eb
	if (!buff)
Packit 7e09eb
		return ret;
Packit 7e09eb
Packit 7e09eb
	end_dev = get_drive_end_dev(path);
Packit 7e09eb
	if (!end_dev) {
Packit 7e09eb
		free(buff);
Packit 7e09eb
		return ret;
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	snprintf(buff, size, "/sys/class/sas_end_device/%s/device/sas_device/%s",
Packit 7e09eb
		 end_dev, end_dev);
Packit 7e09eb
Packit 7e09eb
	ret = get_uint64(buff, ret, "sas_address");
Packit 7e09eb
Packit 7e09eb
	free(end_dev);
Packit 7e09eb
	free(buff);
Packit 7e09eb
Packit 7e09eb
	return ret;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
int scsi_get_enclosure(struct block_device *device)
Packit 7e09eb
{
Packit 7e09eb
	struct enclosure_device *encl;
Packit Service cb68d2
	uint64_t addr;
Packit 7e09eb
Packit 7e09eb
	if (!device || !device->sysfs_path)
Packit 7e09eb
		return 0;
Packit 7e09eb
Packit Service cb68d2
	addr = get_drive_sas_addr(device->sysfs_path);
Packit Service cb68d2
	if (!addr)
Packit Service cb68d2
		return 0;
Packit Service cb68d2
Packit 7e09eb
	list_for_each(sysfs_get_enclosure_devices(), encl) {
Packit Service cb68d2
		int i;
Packit Service cb68d2
Packit Service cb68d2
		for (i = 0; i < encl->slots_count; i++) {
Packit Service cb68d2
			if (encl->slots[i].sas_addr == addr) {
Packit Service cb68d2
				device->enclosure = encl;
Packit Service cb68d2
				device->encl_index = device->enclosure->slots[i].index;
Packit Service cb68d2
				return 1;
Packit Service cb68d2
			}
Packit 7e09eb
		}
Packit 7e09eb
	}
Packit 7e09eb
Packit Service cb68d2
	return 0;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 */
Packit 7e09eb
int scsi_ses_write(struct block_device *device, enum ibpi_pattern ibpi)
Packit 7e09eb
{
Packit 7e09eb
	if (!device || !device->sysfs_path || !device->enclosure ||
Packit 7e09eb
	    device->encl_index == -1)
Packit 7e09eb
		__set_errno_and_return(EINVAL);
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 > SES_REQ_FAULT))
Packit 7e09eb
		__set_errno_and_return(ERANGE);
Packit 7e09eb
Packit Service cb68d2
	return ses_write_msg(ibpi, &device->enclosure->ses_pages, device->encl_index);
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
int scsi_ses_flush(struct block_device *device)
Packit 7e09eb
{
Packit 7e09eb
	int ret;
Packit Service cb68d2
	int fd;
Packit 7e09eb
Packit 7e09eb
	if (!device || !device->enclosure)
Packit 7e09eb
		return 1;
Packit 7e09eb
Packit Service cb68d2
	if (!device->enclosure->ses_pages.changes)
Packit 7e09eb
		return 0;
Packit 7e09eb
Packit Service cb68d2
	fd = enclosure_open(device->enclosure);
Packit Service cb68d2
	if (fd == -1)
Packit Service cb68d2
		return 1;
Packit Service cb68d2
Packit Service cb68d2
	ret = ses_send_diag(fd, &device->enclosure->ses_pages);
Packit Service cb68d2
Packit Service cb68d2
	close(fd);
Packit 7e09eb
Packit 7e09eb
	return ret;
Packit 7e09eb
}
Packit 7e09eb
Packit Service cb68d2
char *scsi_get_host_path(const char *path, const char *ctrl_path)
Packit 7e09eb
{
Packit 7e09eb
	char *host;
Packit 7e09eb
	char host_path[PATH_MAX] = { 0 };
Packit 7e09eb
	size_t ctrl_path_len = strlen(ctrl_path);
Packit 7e09eb
Packit 7e09eb
	if (strncmp(path, ctrl_path, ctrl_path_len) != 0)
Packit 7e09eb
		return NULL;
Packit 7e09eb
	host = get_path_hostN(path);
Packit 7e09eb
	if (host) {
Packit 7e09eb
		snprintf(host_path, sizeof(host_path), "%s/%s/bsg/sas_%s",
Packit 7e09eb
			 ctrl_path, host, host);
Packit 7e09eb
		free(host);
Packit 7e09eb
	}
Packit 7e09eb
	return str_dup(host_path);
Packit 7e09eb
}