Blame src/scsi.c

Packit 7e09eb
/*
Packit 7e09eb
 * Intel(R) Enclosure LED Utilities
Packit 7e09eb
 * Copyright (C) 2009-2019 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 <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 <sys/stat.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 <scsi/sg_lib.h>
Packit 7e09eb
#include <scsi/sg_cmds_extra.h>
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 int debug = 0;
Packit 7e09eb
Packit 7e09eb
static int get_ses_page(int fd, struct ses_page *p, int pg_code)
Packit 7e09eb
{
Packit 7e09eb
	int ret;
Packit 7e09eb
	int retry_count = 3;
Packit 7e09eb
Packit 7e09eb
	do {
Packit 7e09eb
		ret = sg_ll_receive_diag(fd, 1, pg_code, p->buf, sizeof(p->buf),
Packit 7e09eb
					 0, debug);
Packit 7e09eb
	} while (ret && retry_count--);
Packit 7e09eb
Packit 7e09eb
	if (!ret)
Packit 7e09eb
		p->len = (p->buf[2] << 8) + p->buf[3] + 4;
Packit 7e09eb
	return ret;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static int process_page1(struct ses_pages *sp)
Packit 7e09eb
{
Packit 7e09eb
	int num_encl;		/* number of subenclosures */
Packit 7e09eb
	unsigned char *ed;	/* Enclosure Descriptor */
Packit 7e09eb
	int len = 0;
Packit 7e09eb
	int sum_headers = 0;	/* Number of Type descriptor headers */
Packit 7e09eb
	int i = 0;
Packit 7e09eb
Packit 7e09eb
	/* How many enclosures is in the main enclosure? */
Packit 7e09eb
	num_encl = sp->page1->buf[1] + 1;
Packit 7e09eb
	/* Go to Enclosure Descriptor */
Packit 7e09eb
	ed = sp->page1->buf + 8;
Packit 7e09eb
	for (i = 0; i < num_encl; i++, ed += len) {
Packit 7e09eb
		if (ed + 3 > sp->page1->buf + sp->page1->len) {
Packit 7e09eb
			log_debug
Packit 7e09eb
			    ("SES: Error, response pare 1 truncated at %d\n",
Packit 7e09eb
			     i);
Packit 7e09eb
			return 1;
Packit 7e09eb
		}
Packit 7e09eb
		sum_headers += ed[2];
Packit 7e09eb
		len = ed[3] + 4;
Packit 7e09eb
		if (len < 40) {
Packit 7e09eb
			log_debug("SES: Response too short for page 1\n");
Packit 7e09eb
			continue;
Packit 7e09eb
		}
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	sp->page1_types = (struct type_descriptor_header *)ed;
Packit 7e09eb
	sp->page1_types_len = sum_headers;
Packit 7e09eb
Packit 7e09eb
	/* ed is on type descr header */
Packit 7e09eb
	for (i = 0; i < sum_headers; i++, ed += 4) {
Packit 7e09eb
		if (ed > sp->page1->buf + sp->page1->len) {
Packit 7e09eb
			log_debug("SES: Response page 1 truncated at %d\n", i);
Packit 7e09eb
			return 1;
Packit 7e09eb
		}
Packit 7e09eb
	}
Packit 7e09eb
	return 0;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static struct ses_pages *ses_init(void)
Packit 7e09eb
{
Packit 7e09eb
	struct ses_pages *sp;
Packit 7e09eb
	sp = calloc(1, sizeof(*sp));
Packit 7e09eb
	if (!sp)
Packit 7e09eb
		return NULL;
Packit 7e09eb
	sp->page1 = calloc(1, sizeof(struct ses_page));
Packit 7e09eb
	if (!sp->page1)
Packit 7e09eb
		goto sp1;
Packit 7e09eb
	sp->page2 = calloc(1, sizeof(struct ses_page));
Packit 7e09eb
	if (!sp->page2)
Packit 7e09eb
		goto sp2;
Packit 7e09eb
	return sp;
Packit 7e09eb
 sp2:
Packit 7e09eb
	free(sp->page1);
Packit 7e09eb
 sp1:
Packit 7e09eb
	free(sp);
Packit 7e09eb
	return NULL;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static void ses_free(struct ses_pages *sp)
Packit 7e09eb
{
Packit 7e09eb
	if (!sp)
Packit 7e09eb
		return;
Packit 7e09eb
	free(sp->page1);
Packit 7e09eb
	free(sp->page2);
Packit 7e09eb
	free(sp->page10);
Packit 7e09eb
	free(sp);
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static void dump_p10(unsigned char *p)
Packit 7e09eb
{
Packit 7e09eb
	int i;
Packit 7e09eb
	printf("----------------------------------------------\n");
Packit 7e09eb
	for (i = 0; i < 8; i++, p += 16) {
Packit 7e09eb
		printf("%p: %02x %02x %02x %02x %02x %02x %02x " \
Packit 7e09eb
		       "%02x %02x %02x %02x %02x %02x %02x %02x %02x\n", (void *)p,
Packit 7e09eb
		       p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
Packit 7e09eb
		       p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
Packit 7e09eb
	}
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static int enclosure_open(const struct enclosure_device *enclosure)
Packit 7e09eb
{
Packit 7e09eb
	int fd = -1;
Packit 7e09eb
Packit 7e09eb
	if (enclosure->dev_path)
Packit 7e09eb
		fd = open(enclosure->dev_path, O_RDWR);
Packit 7e09eb
Packit 7e09eb
	return fd;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static int enclosure_load_pages(struct enclosure_device *enclosure)
Packit 7e09eb
{
Packit 7e09eb
	int ret;
Packit 7e09eb
	int fd;
Packit 7e09eb
	struct ses_pages *sp;
Packit 7e09eb
Packit 7e09eb
	if (enclosure->ses_pages)
Packit 7e09eb
		return 0;
Packit 7e09eb
Packit 7e09eb
	fd = enclosure_open(enclosure);
Packit 7e09eb
	if (fd == -1)
Packit 7e09eb
		return 1;
Packit 7e09eb
Packit 7e09eb
	sp = ses_init();
Packit 7e09eb
	if (!sp) {
Packit 7e09eb
		ret = 1;
Packit 7e09eb
		goto end;
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	/* Read configuration. */
Packit 7e09eb
	ret = get_ses_page(fd, sp->page1, ENCL_CFG_DIAG_STATUS);
Packit 7e09eb
	if (ret)
Packit 7e09eb
		goto end;
Packit 7e09eb
Packit 7e09eb
	ret = process_page1(sp);
Packit 7e09eb
	if (ret)
Packit 7e09eb
		goto end;
Packit 7e09eb
Packit 7e09eb
	/* Get Enclosure Status */
Packit 7e09eb
	ret = get_ses_page(fd, sp->page2, ENCL_CTRL_DIAG_STATUS);
Packit 7e09eb
end:
Packit 7e09eb
	close(fd);
Packit 7e09eb
	if (ret)
Packit 7e09eb
		ses_free(sp);
Packit 7e09eb
	else
Packit 7e09eb
		enclosure->ses_pages = sp;
Packit 7e09eb
	return ret;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static int enclosure_load_page10(struct enclosure_device *enclosure)
Packit 7e09eb
{
Packit 7e09eb
	int ret;
Packit 7e09eb
	int fd;
Packit 7e09eb
	struct ses_page *p;
Packit 7e09eb
Packit 7e09eb
	if (enclosure->ses_pages && enclosure->ses_pages->page10)
Packit 7e09eb
		return 0;
Packit 7e09eb
Packit 7e09eb
	ret = enclosure_load_pages(enclosure);
Packit 7e09eb
	if (ret)
Packit 7e09eb
		return ret;
Packit 7e09eb
Packit 7e09eb
	fd = enclosure_open(enclosure);
Packit 7e09eb
	if (fd == -1)
Packit 7e09eb
		return 1;
Packit 7e09eb
Packit 7e09eb
	p = calloc(1, sizeof(struct ses_page));
Packit 7e09eb
	if (!p) {
Packit 7e09eb
		ret = 1;
Packit 7e09eb
		goto end;
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	/* Additional Element Status */
Packit 7e09eb
	ret = get_ses_page(fd, p, ENCL_ADDITIONAL_EL_STATUS);
Packit 7e09eb
end:
Packit 7e09eb
	close(fd);
Packit 7e09eb
	if (ret)
Packit 7e09eb
		free(p);
Packit 7e09eb
	else
Packit 7e09eb
		enclosure->ses_pages->page10 = p;
Packit 7e09eb
Packit 7e09eb
	return ret;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static void enclosure_free_pages(struct enclosure_device *enclosure)
Packit 7e09eb
{
Packit 7e09eb
	ses_free(enclosure->ses_pages);
Packit 7e09eb
	enclosure->ses_pages = NULL;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static void print_page10(struct ses_pages *sp)
Packit 7e09eb
{
Packit 7e09eb
	unsigned char *ai = sp->page10->buf + 8;
Packit 7e09eb
	int i = 0, len = 0, eip = 0;
Packit 7e09eb
	unsigned char *sas = NULL;
Packit 7e09eb
Packit 7e09eb
	while (ai < sp->page10->buf + sp->page10->len) {
Packit 7e09eb
		printf("%s()[%d]: Inv: %d, EIP: %d, Proto: 0x%04x\n", __func__,
Packit 7e09eb
		       i++, ((ai[0] & 0x80) >> 7), ((ai[0] & 0x10) >> 4),
Packit 7e09eb
		       (unsigned int) (ai[0] & 0xf));
Packit 7e09eb
		printf("\tDescriptor len (x-1): %d\n", ai[1] + 1);
Packit 7e09eb
		eip = ai[0] & 0x10;
Packit 7e09eb
		if (eip)
Packit 7e09eb
			printf("\tElement Index: %d\n", ai[3]);
Packit 7e09eb
		len = ai[1] + 2;
Packit 7e09eb
		if ((ai[0] & 0xf) == SCSI_PROTOCOL_SAS) {
Packit 7e09eb
			if (eip)
Packit 7e09eb
				sas = ai + 4;
Packit 7e09eb
			else
Packit 7e09eb
				sas = ai + 2;
Packit 7e09eb
			printf("\tProtocol SAS:\n");
Packit 7e09eb
			printf("\tNumber of phy descriptors: %d\n", sas[0]);
Packit 7e09eb
			printf("\tNot all phys: %d, descriptor type: 0x%1x\n",
Packit 7e09eb
			       (sas[1] & 1), ((sas[1] & 0xc0) >> 6));
Packit 7e09eb
			if (eip) {
Packit 7e09eb
				printf("\tDevice slot number: %d\n", sas[3]);
Packit 7e09eb
				sas += 2;
Packit 7e09eb
			}
Packit 7e09eb
			sas += 2;
Packit 7e09eb
			printf("\tDevice type: 0x%01x\n",
Packit 7e09eb
				(unsigned int)((sas[0] & 0x70) >> 4));
Packit 7e09eb
			printf("\tSMP Initiator Port: 0x%01x\n",
Packit 7e09eb
				(unsigned int)((sas[2] & 2) >> 1));
Packit 7e09eb
			printf("\tSTP Initiator Port: 0x%01x\n",
Packit 7e09eb
				(unsigned int)((sas[2] & 4) >> 2));
Packit 7e09eb
			printf("\tSSP Initiator Port: 0x%01x\n",
Packit 7e09eb
				(unsigned int)((sas[2] & 8) >> 3));
Packit 7e09eb
			printf("\tSATA DEVICE: 0x%01x\n",
Packit 7e09eb
				(unsigned int)(sas[3] & 1));
Packit 7e09eb
			printf("\tSMP Target Port: 0x%01x\n",
Packit 7e09eb
				(unsigned int)((sas[3] & 2) >> 1));
Packit 7e09eb
			printf("\tSTP Target Port: 0x%01x\n",
Packit 7e09eb
				(unsigned int)((sas[3] & 4) >> 2));
Packit 7e09eb
			printf("\tSSP Target Port: 0x%01x\n",
Packit 7e09eb
				(unsigned int)((sas[3] & 8) >> 3));
Packit 7e09eb
			printf("\tSATA Port Selector: 0x%01x\n",
Packit 7e09eb
				(unsigned int)((sas[3] & 0X80) >> 7));
Packit 7e09eb
			printf
Packit 7e09eb
			    ("\tAttached SAS Address: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
Packit 7e09eb
			     sas[4], sas[5], sas[6], sas[7], sas[8], sas[9],
Packit 7e09eb
			     sas[10], sas[11]);
Packit 7e09eb
			printf
Packit 7e09eb
			    ("\tSAS Address: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
Packit 7e09eb
			     sas[12], sas[13], sas[14], sas[15], sas[16],
Packit 7e09eb
			     sas[17], sas[18], sas[19]);
Packit 7e09eb
			printf("\tPHY Identified: 0x%01x\n", sas[20]);
Packit 7e09eb
		} else
Packit 7e09eb
			printf("\tProtocol not SAS: 0x%02x, skipping\n",
Packit 7e09eb
				(unsigned int)(ai[0] & 0xf));
Packit 7e09eb
		/* */
Packit 7e09eb
		ai += len;
Packit 7e09eb
	}
Packit 7e09eb
	return;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static enum ibpi_pattern ibpi_to_ses(enum ibpi_pattern ibpi)
Packit 7e09eb
{
Packit 7e09eb
	switch (ibpi) {
Packit 7e09eb
	case IBPI_PATTERN_UNKNOWN:
Packit 7e09eb
	case IBPI_PATTERN_ONESHOT_NORMAL:
Packit 7e09eb
	case IBPI_PATTERN_NORMAL:
Packit 7e09eb
		return SES_REQ_OK;
Packit 7e09eb
	case IBPI_PATTERN_FAILED_ARRAY:
Packit 7e09eb
		return SES_REQ_IFA;
Packit 7e09eb
	case IBPI_PATTERN_DEGRADED:
Packit 7e09eb
		return SES_REQ_ICA;
Packit 7e09eb
	case IBPI_PATTERN_REBUILD:
Packit 7e09eb
		return SES_REQ_REBUILD;
Packit 7e09eb
	case IBPI_PATTERN_FAILED_DRIVE:
Packit 7e09eb
		return SES_REQ_FAULT;
Packit 7e09eb
	case IBPI_PATTERN_LOCATE:
Packit 7e09eb
		return SES_REQ_IDENT;
Packit 7e09eb
	case IBPI_PATTERN_HOTSPARE:
Packit 7e09eb
		return SES_REQ_HOSTSPARE;
Packit 7e09eb
	case IBPI_PATTERN_PFA:
Packit 7e09eb
		return SES_REQ_PRDFAIL;
Packit 7e09eb
	default:
Packit 7e09eb
		return ibpi;
Packit 7e09eb
	}
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static int ses_set_message(enum ibpi_pattern ibpi, struct ses_slot_ctrl_elem *el)
Packit 7e09eb
{
Packit 7e09eb
	struct ses_slot_ctrl_elem msg;
Packit 7e09eb
Packit 7e09eb
	memset(&msg, 0, sizeof(msg));
Packit 7e09eb
	if (ibpi == IBPI_PATTERN_LOCATE_OFF) {
Packit 7e09eb
		/*
Packit 7e09eb
		 * For locate_off we don't set a new state, just clear the
Packit 7e09eb
		 * IDENT bit and the bits that are reserved or have different
Packit 7e09eb
		 * meanings in Status and Control pages (RQST ACTIVE and
Packit 7e09eb
		 * RQST MISSING).
Packit 7e09eb
		 */
Packit 7e09eb
		_clr_ident(el->b);
Packit 7e09eb
		el->b2 &= 0x4e;
Packit 7e09eb
		el->b3 &= 0x3c;
Packit 7e09eb
		return 0;
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	switch (ibpi_to_ses(ibpi)) {
Packit 7e09eb
	case SES_REQ_ABORT:
Packit 7e09eb
		_set_abrt(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_REBUILD:
Packit 7e09eb
		_set_rebuild(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_IFA:
Packit 7e09eb
		_set_ifa(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_ICA:
Packit 7e09eb
		_set_ica(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_CONS_CHECK:
Packit 7e09eb
		_set_cons_check(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_HOSTSPARE:
Packit 7e09eb
		_set_hspare(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_RSVD_DEV:
Packit 7e09eb
		_set_rsvd_dev(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_OK:
Packit 7e09eb
		_set_ok(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_IDENT:
Packit 7e09eb
		_set_ident(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_RM:
Packit 7e09eb
		_set_rm(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_INS:
Packit 7e09eb
		_set_ins(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_MISSING:
Packit 7e09eb
		_set_miss(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_DNR:
Packit 7e09eb
		_set_dnr(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_ACTIVE:
Packit 7e09eb
		_set_actv(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_EN_BB:
Packit 7e09eb
		_set_enbb(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_EN_BA:
Packit 7e09eb
		_set_enba(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_DEV_OFF:
Packit 7e09eb
		_set_off(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_FAULT:
Packit 7e09eb
		_set_fault(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	case SES_REQ_PRDFAIL:
Packit 7e09eb
		_set_prdfail(msg.b);
Packit 7e09eb
		break;
Packit 7e09eb
	default:
Packit 7e09eb
		return 1;
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	*el = msg;
Packit 7e09eb
Packit 7e09eb
	return 0;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static int ses_write_msg(enum ibpi_pattern ibpi, struct block_device *device)
Packit 7e09eb
{
Packit 7e09eb
	struct ses_pages *sp = device->enclosure->ses_pages;
Packit 7e09eb
	int idx = device->encl_index;
Packit 7e09eb
	/* Move do descriptors */
Packit 7e09eb
	struct ses_slot_ctrl_elem *descriptors = (void *)(sp->page2->buf + 8);
Packit 7e09eb
	int i;
Packit 7e09eb
	struct ses_slot_ctrl_elem *desc_element = NULL;
Packit 7e09eb
	element_type local_element_type = SES_UNSPECIFIED;
Packit 7e09eb
Packit 7e09eb
	for (i = 0; i < sp->page1_types_len; i++) {
Packit 7e09eb
		struct type_descriptor_header *t = &sp->page1_types[i];
Packit 7e09eb
Packit 7e09eb
		descriptors++; /* At first, skip overall header. */
Packit 7e09eb
Packit 7e09eb
		if (t->element_type == SES_DEVICE_SLOT ||
Packit 7e09eb
		    t->element_type == SES_ARRAY_DEVICE_SLOT) {
Packit 7e09eb
			if (local_element_type < t->element_type &&
Packit 7e09eb
			    t->num_of_elements > idx) {
Packit 7e09eb
				local_element_type = t->element_type;
Packit 7e09eb
				desc_element = &descriptors[idx];
Packit 7e09eb
			}
Packit 7e09eb
		} else {
Packit 7e09eb
			/*
Packit 7e09eb
			 * Device Slot and Array Device Slot elements are
Packit 7e09eb
			 * always first on the type descriptor header list
Packit 7e09eb
			 */
Packit 7e09eb
			break;
Packit 7e09eb
		}
Packit 7e09eb
Packit 7e09eb
		descriptors += t->num_of_elements;
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	if (desc_element) {
Packit 7e09eb
		int ret = ses_set_message(ibpi, desc_element);
Packit 7e09eb
		if (ret)
Packit 7e09eb
			return ret;
Packit 7e09eb
		/* keep PRDFAIL, clear rest */
Packit 7e09eb
		desc_element->common_control &= 0x40;
Packit 7e09eb
		/* set select */
Packit 7e09eb
		desc_element->common_control |= 0x80;
Packit 7e09eb
Packit 7e09eb
		/* second byte is valid only for Array Device Slot */
Packit 7e09eb
		if (local_element_type != SES_ARRAY_DEVICE_SLOT)
Packit 7e09eb
			desc_element->array_slot_control = 0;
Packit 7e09eb
Packit 7e09eb
		return 0;
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	return 1;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static int ses_send_diag(struct enclosure_device *enclosure)
Packit 7e09eb
{
Packit 7e09eb
	int ret;
Packit 7e09eb
	int fd;
Packit 7e09eb
Packit 7e09eb
	fd = enclosure_open(enclosure);
Packit 7e09eb
	if (fd == -1)
Packit 7e09eb
		return 1;
Packit 7e09eb
Packit 7e09eb
	ret = sg_ll_send_diag(fd, 0, 1, 0, 0, 0, 0,
Packit 7e09eb
			      enclosure->ses_pages->page2->buf,
Packit 7e09eb
			      enclosure->ses_pages->page2->len,
Packit 7e09eb
			      0, debug);
Packit 7e09eb
	close(fd);
Packit 7e09eb
	return ret;
Packit 7e09eb
}
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
static int get_encl_slot(struct block_device *device)
Packit 7e09eb
{
Packit 7e09eb
	struct ses_pages *sp;
Packit 7e09eb
	unsigned char *add_desc = NULL;
Packit 7e09eb
	unsigned char *ap = NULL, *addr_p = NULL;
Packit 7e09eb
	int i, j, len = 0;
Packit 7e09eb
	uint64_t addr, addr_cmp;
Packit 7e09eb
	int idx;
Packit 7e09eb
Packit 7e09eb
	/* try to get slot from sysfs */
Packit 7e09eb
	idx = get_int(device->cntrl_path, -1, "slot");
Packit 7e09eb
	if (idx != -1)
Packit 7e09eb
		return idx;
Packit 7e09eb
Packit 7e09eb
	/*
Packit 7e09eb
	 * Older kernels may not have the "slot" sysfs attribute,
Packit 7e09eb
	 * fallback to Page10 method.
Packit 7e09eb
	 */
Packit 7e09eb
	if (enclosure_load_page10(device->enclosure))
Packit 7e09eb
		return -1;
Packit 7e09eb
	sp = device->enclosure->ses_pages;
Packit 7e09eb
Packit 7e09eb
	addr = get_drive_sas_addr(device->sysfs_path);
Packit 7e09eb
	if (!addr)
Packit 7e09eb
		return -1;
Packit 7e09eb
Packit 7e09eb
	if (debug)
Packit 7e09eb
		print_page10(sp);
Packit 7e09eb
Packit 7e09eb
	/* Check Page10 for address. Extract index. */
Packit 7e09eb
	ap = add_desc = sp->page10->buf + 8;
Packit 7e09eb
	for (i = 0; i < sp->page1_types_len; i++) {
Packit 7e09eb
		struct type_descriptor_header *t = &sp->page1_types[i];
Packit 7e09eb
Packit 7e09eb
		if (t->element_type == SES_DEVICE_SLOT ||
Packit 7e09eb
		    t->element_type == SES_ARRAY_DEVICE_SLOT) {
Packit 7e09eb
			for (j = 0; j < t->num_of_elements; j++, ap += len) {
Packit 7e09eb
				if (debug)
Packit 7e09eb
					dump_p10(ap);
Packit 7e09eb
				/* Get Additional Element Status Descriptor */
Packit 7e09eb
				/* length (x-1) */
Packit 7e09eb
				len = ap[1] + 2;
Packit 7e09eb
				if ((ap[0] & 0xf) != SCSI_PROTOCOL_SAS)
Packit 7e09eb
					continue;	/* need SAS PROTO */
Packit 7e09eb
				/* It is a SAS protocol, go on */
Packit 7e09eb
				if ((ap[0] & 0x10))	/* Check EIP */
Packit 7e09eb
					addr_p = ap + 8;
Packit 7e09eb
				else
Packit 7e09eb
					addr_p = ap + 4;
Packit 7e09eb
				/* Process only PHY 0 descriptor. */
Packit 7e09eb
Packit 7e09eb
				/* Convert be64 to le64 */
Packit 7e09eb
				addr_cmp = ((uint64_t)addr_p[12] << 8*7) |
Packit 7e09eb
					   ((uint64_t)addr_p[13] << 8*6) |
Packit 7e09eb
					   ((uint64_t)addr_p[14] << 8*5) |
Packit 7e09eb
					   ((uint64_t)addr_p[15] << 8*4) |
Packit 7e09eb
					   ((uint64_t)addr_p[16] << 8*3) |
Packit 7e09eb
					   ((uint64_t)addr_p[17] << 8*2) |
Packit 7e09eb
					   ((uint64_t)addr_p[18] << 8*1) |
Packit 7e09eb
					   ((uint64_t)addr_p[19]);
Packit 7e09eb
Packit 7e09eb
				if (addr == addr_cmp) {
Packit 7e09eb
					idx = ap[0] & 0x10 ? ap[3] : j;
Packit 7e09eb
					return idx;
Packit 7e09eb
				}
Packit 7e09eb
			}
Packit 7e09eb
		} else {
Packit 7e09eb
			/*
Packit 7e09eb
			 * Device Slot and Array Device Slot elements are
Packit 7e09eb
			 * always first on the type descriptor header list
Packit 7e09eb
			 */
Packit 7e09eb
			break;
Packit 7e09eb
		}
Packit 7e09eb
	}
Packit 7e09eb
	return -1;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 */
Packit 7e09eb
static int _slot_match(const char *slot_path, const char *device_path)
Packit 7e09eb
{
Packit 7e09eb
	char temp[PATH_MAX], link[PATH_MAX];
Packit 7e09eb
Packit 7e09eb
	snprintf(temp, sizeof(temp), "%s/device", slot_path);
Packit 7e09eb
Packit 7e09eb
	if (realpath(temp, link) == NULL)
Packit 7e09eb
		return 0;
Packit 7e09eb
Packit 7e09eb
	return strncmp(link, device_path, strlen(link)) == 0;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 */
Packit 7e09eb
static char *_slot_find(const char *enclo_path, const char *device_path)
Packit 7e09eb
{
Packit 7e09eb
	struct list dir;
Packit 7e09eb
	char *temp, *result = NULL;
Packit 7e09eb
Packit 7e09eb
	if (scan_dir(enclo_path, &dir) == 0) {
Packit 7e09eb
		list_for_each(&dir, temp) {
Packit 7e09eb
			if (_slot_match(temp, device_path)) {
Packit 7e09eb
				result = str_dup(temp);
Packit 7e09eb
				break;
Packit 7e09eb
			}
Packit 7e09eb
		}
Packit 7e09eb
		list_erase(&dir;;
Packit 7e09eb
	}
Packit 7e09eb
	return result;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
int scsi_get_enclosure(struct block_device *device)
Packit 7e09eb
{
Packit 7e09eb
	struct enclosure_device *encl;
Packit 7e09eb
Packit 7e09eb
	if (!device || !device->sysfs_path)
Packit 7e09eb
		return 0;
Packit 7e09eb
Packit 7e09eb
	list_for_each(sysfs_get_enclosure_devices(), encl) {
Packit 7e09eb
		if (_slot_match(encl->sysfs_path, device->cntrl_path)) {
Packit 7e09eb
			device->enclosure = encl;
Packit 7e09eb
			device->encl_index = get_encl_slot(device);
Packit 7e09eb
			break;
Packit 7e09eb
		}
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	return (device->enclosure != NULL && device->encl_index != -1);
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
	int ret;
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 7e09eb
	ret = enclosure_load_pages(device->enclosure);
Packit 7e09eb
	if (ret) {
Packit 7e09eb
		log_warning
Packit 7e09eb
		    ("Unable to send %s message to %s. Device is missing?",
Packit 7e09eb
		     ibpi2str(ibpi), strstr(device->sysfs_path, "host"));
Packit 7e09eb
		return ret;
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	return ses_write_msg(ibpi, device);
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
int scsi_ses_flush(struct block_device *device)
Packit 7e09eb
{
Packit 7e09eb
	int ret;
Packit 7e09eb
Packit 7e09eb
	if (!device || !device->enclosure)
Packit 7e09eb
		return 1;
Packit 7e09eb
Packit 7e09eb
	if (!device->enclosure->ses_pages)
Packit 7e09eb
		return 0;
Packit 7e09eb
Packit 7e09eb
	ret = ses_send_diag(device->enclosure);
Packit 7e09eb
Packit 7e09eb
	enclosure_free_pages(device->enclosure);
Packit 7e09eb
	return ret;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 * @brief Gets a path to slot of sas controller.
Packit 7e09eb
 *
Packit 7e09eb
 * This function returns a sysfs path to component of enclosure the device
Packit 7e09eb
 * belongs to.
Packit 7e09eb
 *
Packit 7e09eb
 * @param[in]      path           Canonical sysfs path to block device.
Packit 7e09eb
 *
Packit 7e09eb
 * @return A sysfs path to controller device associated with the given
Packit 7e09eb
 *         block device if successful, otherwise NULL pointer.
Packit 7e09eb
 */
Packit 7e09eb
static char *sas_get_slot_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
}
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 */
Packit 7e09eb
static char *_get_enc_slot_path(const char *path)
Packit 7e09eb
{
Packit 7e09eb
	struct enclosure_device *device;
Packit 7e09eb
	char *result = NULL;
Packit 7e09eb
Packit 7e09eb
	list_for_each(sysfs_get_enclosure_devices(), device) {
Packit 7e09eb
		result = _slot_find(device->sysfs_path, path);
Packit 7e09eb
		if (result != NULL)
Packit 7e09eb
			break;
Packit 7e09eb
	}
Packit 7e09eb
	return result;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 */
Packit 7e09eb
char *scsi_get_slot_path(const char *path, const char *ctrl_path)
Packit 7e09eb
{
Packit 7e09eb
	char *result = NULL;
Packit 7e09eb
Packit 7e09eb
	result = _get_enc_slot_path(path);
Packit 7e09eb
	if (!result)
Packit 7e09eb
		result = sas_get_slot_path(path, ctrl_path);
Packit 7e09eb
	return result;
Packit 7e09eb
}